mirror of
https://github.com/MetaFam/TheGame.git
synced 2026-04-24 03:00:09 -04:00
Implement list of Guilds in frontend
This commit is contained in:
42
packages/web/components/Guild/GuildHero.tsx
Normal file
42
packages/web/components/Guild/GuildHero.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import { Avatar, Box, MetaButton, Text, VStack } from '@metafam/ds';
|
||||
import { GuildFragmentFragment } from 'graphql/autogen/types';
|
||||
import React from 'react';
|
||||
|
||||
import { ProfileSection } from '../ProfileSection';
|
||||
import { GuildLinks } from './GuildLinks';
|
||||
|
||||
type Props = { guild: GuildFragmentFragment };
|
||||
|
||||
export const GuildHero: React.FC<Props> = ({ guild }) => {
|
||||
return (
|
||||
<ProfileSection>
|
||||
<VStack spacing={8}>
|
||||
{guild.logo ? (
|
||||
<Avatar
|
||||
w={{ base: '32', md: '56' }}
|
||||
h={{ base: '32', md: '56' }}
|
||||
src={guild.logo}
|
||||
name={guild.name}
|
||||
/>
|
||||
) : null}
|
||||
<Box textAlign="center">
|
||||
<Text fontSize="xl" fontFamily="heading" mb="1">
|
||||
{guild.name}
|
||||
</Text>
|
||||
<Text fontFamily="mono" fontSize="md" color="blueLight">
|
||||
{`${guild.type} GUILD`}
|
||||
</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text>{guild.description}</Text>
|
||||
</Box>
|
||||
{guild.join_button_url ? (
|
||||
<MetaButton as="a" href={guild.join_button_url} target="_blank">
|
||||
Join
|
||||
</MetaButton>
|
||||
) : null}
|
||||
<GuildLinks guild={guild} />
|
||||
</VStack>
|
||||
</ProfileSection>
|
||||
);
|
||||
};
|
||||
67
packages/web/components/Guild/GuildLinks.tsx
Normal file
67
packages/web/components/Guild/GuildLinks.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import { Button, Wrap } from '@metafam/ds';
|
||||
import { GuildFragmentFragment } from 'graphql/autogen/types';
|
||||
import React from 'react';
|
||||
import { FaDiscord, FaGlobe } from 'react-icons/fa';
|
||||
|
||||
type Props = {
|
||||
guild: GuildFragmentFragment;
|
||||
};
|
||||
|
||||
export const GuildLinks: React.FC<Props> = ({ guild }) => {
|
||||
return (
|
||||
<Wrap>
|
||||
{guild.website_url ? (
|
||||
<Button
|
||||
as="a"
|
||||
href={guild.website_url}
|
||||
target="_blank"
|
||||
size="xs"
|
||||
colorScheme="blackAlpha"
|
||||
leftIcon={<FaGlobe />}
|
||||
>
|
||||
Website
|
||||
</Button>
|
||||
) : null}
|
||||
{guild.discord_invite_url ? (
|
||||
<Button
|
||||
as="a"
|
||||
href={guild.discord_invite_url}
|
||||
target="_blank"
|
||||
size="xs"
|
||||
bgColor="discord"
|
||||
_hover={{ bgColor: 'discordDark' }}
|
||||
leftIcon={<FaDiscord />}
|
||||
>
|
||||
Discord
|
||||
</Button>
|
||||
) : null}
|
||||
{/*
|
||||
{guild.Accounts.map((acc) => {
|
||||
if (acc.type === 'TWITTER') {
|
||||
const link = `https://twitter.com/${acc.identifier}`;
|
||||
return (
|
||||
|
||||
);
|
||||
}
|
||||
if (acc.type === 'GITHUB') {
|
||||
const link = `https://github.com/${acc.identifier}`;
|
||||
return (
|
||||
<Button
|
||||
as="a"
|
||||
href={link}
|
||||
target="_blank"
|
||||
key={link}
|
||||
size="xs"
|
||||
colorScheme="blackAlpha"
|
||||
backgroundColor="black"
|
||||
leftIcon={<FaGithub />}
|
||||
>
|
||||
{acc.identifier}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})} */}
|
||||
</Wrap>
|
||||
);
|
||||
};
|
||||
78
packages/web/components/Guild/GuildTile.tsx
Normal file
78
packages/web/components/Guild/GuildTile.tsx
Normal file
@@ -0,0 +1,78 @@
|
||||
import {
|
||||
Avatar,
|
||||
Flex,
|
||||
Heading,
|
||||
HStack,
|
||||
MetaButton,
|
||||
MetaTag,
|
||||
Text,
|
||||
VStack,
|
||||
Wrap,
|
||||
} from '@metafam/ds';
|
||||
import { GuildLinks } from 'components/Guild/GuildLinks';
|
||||
import { GuildFragmentFragment } from 'graphql/autogen/types';
|
||||
import React from 'react';
|
||||
|
||||
type Props = {
|
||||
guild: GuildFragmentFragment;
|
||||
};
|
||||
|
||||
export const GuildTile: React.FC<Props> = ({ guild }) => (
|
||||
<Flex
|
||||
direction="column"
|
||||
key={guild.id}
|
||||
bg="whiteAlpha.200"
|
||||
style={{ backdropFilter: 'blur(7px)' }}
|
||||
rounded="lg"
|
||||
p="6"
|
||||
maxW="30rem"
|
||||
w="100%"
|
||||
align="stretch"
|
||||
position="relative"
|
||||
overflow="hidden"
|
||||
justify="space-between"
|
||||
>
|
||||
<VStack w="100%" spacing="6" align="stretch" mb={6} position="relative">
|
||||
<VStack>
|
||||
{guild.logo ? (
|
||||
<Avatar size="xl" src={guild.logo} name={guild.name} />
|
||||
) : null}
|
||||
|
||||
<Heading size="sm" color="white">
|
||||
{guild.name}
|
||||
</Heading>
|
||||
</VStack>
|
||||
<Wrap w="100%" justify="center">
|
||||
{guild.type ? <MetaTag size="md">{guild.type} GUILD</MetaTag> : null}
|
||||
</Wrap>
|
||||
{guild.description ? (
|
||||
<VStack spacing={2} align="stretch">
|
||||
<Text fontFamily="mono" fontSize="sm" color="blueLight">
|
||||
ABOUT
|
||||
</Text>
|
||||
<Text fontSize="sm">{guild.description}</Text>
|
||||
</VStack>
|
||||
) : null}
|
||||
</VStack>
|
||||
<VStack w="100%" spacing="6" align="stretch">
|
||||
<VStack spacing={2} align="stretch">
|
||||
<Text fontFamily="mono" fontSize="sm" color="blueLight">
|
||||
LINKS
|
||||
</Text>
|
||||
<HStack mt="2">
|
||||
<GuildLinks guild={guild} />
|
||||
</HStack>
|
||||
</VStack>
|
||||
{guild.join_button_url ? (
|
||||
<MetaButton
|
||||
as="a"
|
||||
href={guild.join_button_url}
|
||||
target="_blank"
|
||||
fontFamily="mono"
|
||||
>
|
||||
Join
|
||||
</MetaButton>
|
||||
) : null}
|
||||
</VStack>
|
||||
</Flex>
|
||||
);
|
||||
16
packages/web/components/GuildList.tsx
Normal file
16
packages/web/components/GuildList.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import { SimpleGrid } from '@metafam/ds';
|
||||
import { GuildTile } from 'components/Guild/GuildTile';
|
||||
import { GuildFragmentFragment } from 'graphql/autogen/types';
|
||||
import React from 'react';
|
||||
|
||||
type Props = {
|
||||
guilds: GuildFragmentFragment[];
|
||||
};
|
||||
|
||||
export const GuildList: React.FC<Props> = ({ guilds }) => (
|
||||
<SimpleGrid columns={[1, null, 2, 3]} spacing="8">
|
||||
{guilds.map((p) => (
|
||||
<GuildTile key={p.id} guild={p} />
|
||||
))}
|
||||
</SimpleGrid>
|
||||
);
|
||||
@@ -76,7 +76,7 @@ export const PageHeader: React.FC = () => {
|
||||
direction={{ base: 'column', md: 'row' }}
|
||||
spacing={{ base: 4, md: 6, lg: 10 }}
|
||||
>
|
||||
<MenuItem href="/">Players</MenuItem>
|
||||
<MenuItem href="/guilds">Guilds</MenuItem>
|
||||
<MenuItem href="https://discord.gg/VYZPBnx" isExternal>
|
||||
Discord
|
||||
</MenuItem>
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import { Box, Text } from '@metafam/ds';
|
||||
import React from 'react';
|
||||
|
||||
type Props = {
|
||||
title: string;
|
||||
value?: string | null | undefined;
|
||||
} & React.ComponentProps<typeof Text>;
|
||||
|
||||
export const PlayerFeature: React.FC<Props> = ({
|
||||
title,
|
||||
value,
|
||||
children,
|
||||
...props
|
||||
}) => (
|
||||
<Box>
|
||||
<Text
|
||||
fontFamily="body"
|
||||
fontSize="sm"
|
||||
color="blueLight"
|
||||
textTransform="uppercase"
|
||||
mb="2"
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
<Text fontFamily="body" fontSize="md" fontWeight="bold" {...props}>
|
||||
{value || children}
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
@@ -1,58 +0,0 @@
|
||||
import { Container, Divider, MetaTag, Wrap } from '@metafam/ds';
|
||||
import { PlayerFeature } from 'components/Player/PlayerFeature';
|
||||
import { PlayerFragmentFragment } from 'graphql/autogen/types';
|
||||
import React from 'react';
|
||||
|
||||
type Props = { player: PlayerFragmentFragment };
|
||||
|
||||
export const PlayerFeatures: React.FC<Props> = ({ player }) => {
|
||||
return (
|
||||
<Container maxW="xl">
|
||||
<Wrap
|
||||
spacing="8"
|
||||
ml={{ base: '4', lg: '64' }}
|
||||
pt={{ base: '4', md: '12', lg: 0 }}
|
||||
>
|
||||
<PlayerFeature
|
||||
title="XP"
|
||||
value={Math.floor(player.totalXp).toString()}
|
||||
/>
|
||||
{player.rank && (
|
||||
<Divider orientation="vertical" color="whiteAlpha.400" />
|
||||
)}
|
||||
{player.rank && (
|
||||
<PlayerFeature title="Rank">
|
||||
<MetaTag
|
||||
backgroundColor={player.rank?.toLowerCase()}
|
||||
size="md"
|
||||
color="blackAlpha.600"
|
||||
>
|
||||
{player.rank}
|
||||
</MetaTag>
|
||||
</PlayerFeature>
|
||||
)}
|
||||
{player.box_profile?.location && (
|
||||
<Divider orientation="vertical" color="whiteAlpha.400" />
|
||||
)}
|
||||
{player.box_profile?.location && (
|
||||
<PlayerFeature
|
||||
title="Location"
|
||||
value={player.box_profile?.location}
|
||||
/>
|
||||
)}
|
||||
<Divider orientation="vertical" color="whiteAlpha.400" />
|
||||
{/* <PlayerFeature title="Role" value="N/A" color="whiteAlpha.500" /> */}
|
||||
{/* <Divider orientation="vertical" color="whiteAlpha.400" /> */}
|
||||
<PlayerFeature
|
||||
title="Availability"
|
||||
value={
|
||||
player.availability_hours != null
|
||||
? `${player.availability_hours} hr / week`
|
||||
: 'N/A'
|
||||
}
|
||||
color={player.availability_hours ? undefined : 'whiteAlpha.500'}
|
||||
/>
|
||||
</Wrap>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
@@ -2,7 +2,7 @@ import { HStack, Text } from '@metafam/ds';
|
||||
import React from 'react';
|
||||
import { FaMedal } from 'react-icons/fa';
|
||||
|
||||
import { PlayerSection } from './PlayerSection';
|
||||
import { ProfileSection } from '../../ProfileSection';
|
||||
|
||||
// TODO Fake data
|
||||
type Props = { onRemoveClick: () => void };
|
||||
@@ -15,7 +15,7 @@ export const PlayerAchievements: React.FC<Props> = ({ onRemoveClick }) => {
|
||||
];
|
||||
|
||||
return (
|
||||
<PlayerSection title="Achievements" onRemoveClick={onRemoveClick}>
|
||||
<ProfileSection title="Achievements" onRemoveClick={onRemoveClick}>
|
||||
{(fakeData || []).slice(0, show ? 999 : 3).map((title) => (
|
||||
<HStack alignItems="baseline" mb={3}>
|
||||
<FaMedal color="#FBB112" />
|
||||
@@ -34,6 +34,6 @@ export const PlayerAchievements: React.FC<Props> = ({ onRemoveClick }) => {
|
||||
View {show ? 'less' : 'all'}
|
||||
</Text>
|
||||
)}
|
||||
</PlayerSection>
|
||||
</ProfileSection>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ export const PlayerCollab: React.FC<Props> = ({ player }) => {
|
||||
<HStack
|
||||
spacing={6}
|
||||
divider={
|
||||
<Divider height="3rem" color="purpleTag" orientation="vertical" />
|
||||
<Divider height="3rem" color="whiteAlpha.400" orientation="vertical" />
|
||||
}
|
||||
>
|
||||
<Box>
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
import React from 'react';
|
||||
import { FaTimes } from 'react-icons/fa';
|
||||
|
||||
import { PlayerSection } from './PlayerSection';
|
||||
import { ProfileSection } from '../../ProfileSection';
|
||||
|
||||
type Props = { player: PlayerFragmentFragment; onRemoveClick: () => void };
|
||||
|
||||
@@ -67,7 +67,7 @@ export const PlayerGallery: React.FC<Props> = ({ player, onRemoveClick }) => {
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const { favorites, data, loading } = useOpenSeaCollectibles({ player });
|
||||
return (
|
||||
<PlayerSection title="NFT Gallery" onRemoveClick={onRemoveClick}>
|
||||
<ProfileSection title="NFT Gallery" onRemoveClick={onRemoveClick}>
|
||||
{!loading &&
|
||||
favorites?.map((nft) => <GalleryItem nft={nft} key={nft.tokenId} />)}
|
||||
{!loading && data?.length > 3 && (
|
||||
@@ -133,6 +133,6 @@ export const PlayerGallery: React.FC<Props> = ({ player, onRemoveClick }) => {
|
||||
</ModalContent>
|
||||
</ModalOverlay>
|
||||
</Modal>
|
||||
</PlayerSection>
|
||||
</ProfileSection>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,20 +9,20 @@ import {
|
||||
|
||||
import { PersonalityTypes } from '../../../graphql/types';
|
||||
import { FlexContainer } from '../../Container';
|
||||
import { ProfileSection } from '../../ProfileSection';
|
||||
import { PlayerContacts } from '../PlayerContacts';
|
||||
import { PlayerCollab } from './PlayerCollab';
|
||||
import { PlayerSection } from './PlayerSection';
|
||||
|
||||
const BIO_LENGTH = 240;
|
||||
|
||||
type Props = { player: PlayerFragmentFragment };
|
||||
export const PlayerHero: React.FC<Props> = ({ player }) => {
|
||||
const [show, setShow] = React.useState(
|
||||
getPlayerDescription(player).length < 115,
|
||||
getPlayerDescription(player).length < BIO_LENGTH,
|
||||
);
|
||||
|
||||
return (
|
||||
<PlayerSection>
|
||||
<ProfileSection>
|
||||
<VStack spacing={8}>
|
||||
<Avatar
|
||||
w={{ base: '32', md: '56' }}
|
||||
@@ -34,12 +34,7 @@ export const PlayerHero: React.FC<Props> = ({ player }) => {
|
||||
<Text fontSize="xl" fontFamily="heading" mb="1">
|
||||
{getPlayerName(player)}
|
||||
</Text>
|
||||
|
||||
<HStack mt="2">
|
||||
<PlayerContacts player={player} />
|
||||
</HStack>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Text>
|
||||
{`${getPlayerDescription(player).substring(
|
||||
@@ -60,6 +55,10 @@ export const PlayerHero: React.FC<Props> = ({ player }) => {
|
||||
)}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
<HStack mt="2">
|
||||
<PlayerContacts player={player} />
|
||||
</HStack>
|
||||
<Box w="100%">
|
||||
<PlayerCollab player={player} />
|
||||
</Box>
|
||||
@@ -89,6 +88,6 @@ export const PlayerHero: React.FC<Props> = ({ player }) => {
|
||||
</FlexContainer>
|
||||
) : null}
|
||||
</VStack>
|
||||
</PlayerSection>
|
||||
</ProfileSection>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ import metacartelImage from '../../../assets/moloch/metacartel.png';
|
||||
import metaclanImage from '../../../assets/moloch/metaclan.png';
|
||||
import metagameImage from '../../../assets/moloch/metagame.png';
|
||||
import raidGuildImage from '../../../assets/moloch/raid_guild.png';
|
||||
import { PlayerSection } from './PlayerSection';
|
||||
import { ProfileSection } from '../../ProfileSection';
|
||||
|
||||
type Props = { player: PlayerFragmentFragment; onRemoveClick: () => void };
|
||||
export const PlayerMemberships: React.FC<Props> = ({
|
||||
@@ -27,7 +27,7 @@ export const PlayerMemberships: React.FC<Props> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<PlayerSection title="Memberships" onRemoveClick={onRemoveClick}>
|
||||
<ProfileSection title="Memberships" onRemoveClick={onRemoveClick}>
|
||||
<HStack alignItems="center" mb={6}>
|
||||
<Flex bg="purpleBoxLight" width={16} height={16} mr={6}>
|
||||
<Box
|
||||
@@ -94,6 +94,6 @@ export const PlayerMemberships: React.FC<Props> = ({
|
||||
View {show ? 'less' : 'all'}
|
||||
</Text>
|
||||
)}
|
||||
</PlayerSection>
|
||||
</ProfileSection>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import { PlayerFragmentFragment } from 'graphql/autogen/types';
|
||||
import { SkillColors } from 'graphql/types';
|
||||
import React from 'react';
|
||||
|
||||
import { PlayerSection } from './PlayerSection';
|
||||
import { ProfileSection } from '../../ProfileSection';
|
||||
|
||||
type Props = { player: PlayerFragmentFragment; onRemoveClick: () => void };
|
||||
export const PlayerSkills: React.FC<Props> = ({ player, onRemoveClick }) => {
|
||||
@@ -11,7 +11,7 @@ export const PlayerSkills: React.FC<Props> = ({ player, onRemoveClick }) => {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<PlayerSection title="Skills" onRemoveClick={onRemoveClick}>
|
||||
<ProfileSection title="Skills" onRemoveClick={onRemoveClick}>
|
||||
<Wrap>
|
||||
{(player.Player_Skills || []).map(({ Skill }) => (
|
||||
<MetaTag
|
||||
@@ -28,6 +28,6 @@ export const PlayerSkills: React.FC<Props> = ({ player, onRemoveClick }) => {
|
||||
</MetaTag>
|
||||
))}
|
||||
</Wrap>
|
||||
</PlayerSection>
|
||||
</ProfileSection>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Box, HStack, Text } from '@metafam/ds';
|
||||
import React from 'react';
|
||||
import { FaTimes } from 'react-icons/fa';
|
||||
|
||||
export type PlayerSectionProps = {
|
||||
export type ProfileSectionProps = {
|
||||
title?: string;
|
||||
children?: React.ReactNode;
|
||||
onRemoveClick?: () => void;
|
||||
@@ -10,7 +10,7 @@ export type PlayerSectionProps = {
|
||||
};
|
||||
|
||||
// TODO If MetaBox is only used for Player profile maybe merge both component
|
||||
export const PlayerSection: React.FC<PlayerSectionProps> = ({
|
||||
export const ProfileSection: React.FC<ProfileSectionProps> = ({
|
||||
children,
|
||||
title,
|
||||
onRemoveClick,
|
||||
Reference in New Issue
Block a user