feat: profile layout edit + section add/remove

This commit is contained in:
dan13ram
2022-01-01 17:40:14 +05:30
committed by dan13ram
parent f0d7ad61fe
commit c76839f056
20 changed files with 681 additions and 384 deletions

View File

@@ -7,16 +7,16 @@ export const Profile = createIcon({
<g>
<g>
<path
fill-rule="evenodd"
clip-rule="evenodd"
fillRule="evenodd"
clipRule="evenodd"
d="M16 9C16 11.2091 14.2091 13 12 13C9.79086 13 8 11.2091 8 9C8 6.79086 9.79086 5 12 5C14.2091 5 16 6.79086 16 9ZM14 9C14 10.1046 13.1046 11 12 11C10.8954 11 10 10.1046 10 9C10 7.89543 10.8954 7 12 7C13.1046 7 14 7.89543 14 9Z"
fill="currentColor"
/>
</g>
<g>
<path
fill-rule="evenodd"
clip-rule="evenodd"
fillRule="evenodd"
clipRule="evenodd"
d="M12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23C18.0751 23 23 18.0751 23 12C23 5.92487 18.0751 1 12 1ZM3 12C3 14.0902 3.71255 16.014 4.90798 17.5417C6.55245 15.3889 9.14627 14 12.0645 14C14.9448 14 17.5092 15.3531 19.1565 17.4583C20.313 15.9443 21 14.0524 21 12C21 7.02944 16.9706 3 12 3C7.02944 3 3 7.02944 3 12ZM12 21C9.84977 21 7.87565 20.2459 6.32767 18.9878C7.59352 17.1812 9.69106 16 12.0645 16C14.4084 16 16.4833 17.1521 17.7538 18.9209C16.1939 20.2191 14.1881 21 12 21Z"
fill="currentColor"
/>

View File

@@ -11,6 +11,7 @@ export type MetaColors = ChakraTheme['colors'] & {
purpleBoxLight: string;
purpleTag: string;
purpleTag30: string;
purpleTag50: string;
purpleTag70: string;
blueLight: string;
cyanText: string;
@@ -47,6 +48,7 @@ export const colors: MetaColors = {
purpleBoxLight: '#392373',
purpleTag: '#40347C',
purpleTag30: 'rgba(64, 52, 124, 0.3)',
purpleTag50: 'rgba(64, 52, 124, 0.5)',
purpleTag70: 'rgba(64, 52, 124, 0.7)',
blueLight: '#A5B9F6',
cyanText: '#79F8FB',

View File

@@ -57,6 +57,7 @@ export const gridConfig = {
pl: 6,
},
'& > div': {
pointerEvents: editable ? 'none' : 'initial',
bg: editable ? 'blackAlpha.500' : 'blackAlpha.300',
backdropFilter: 'blur(10px)',
borderBottomRadius: 'lg',

View File

@@ -9,13 +9,12 @@ type Props = {
const SHOW_MEMBERSHIPS = 4;
export const PlayerTileMemberships: React.FC<Props> = ({ player }) => {
const displayMemberships =
useMemo(
() => (
player.daohausMemberships?.filter(({ moloch: { title } }) => !!title) ?? []
),
[player.daohausMemberships],
);
const displayMemberships = useMemo(
() =>
player.daohausMemberships?.filter(({ moloch: { title } }) => !!title) ??
[],
[player.daohausMemberships],
);
return displayMemberships.length > 0 ? (
<VStack spacing={2} align="stretch">
<Text textStyle="caption">MEMBER OF</Text>

View File

@@ -1,21 +1,38 @@
import { HStack, Text } from '@metafam/ds';
import { PlayerFragmentFragment } from 'graphql/autogen/types';
import React from 'react';
import { FaMedal } from 'react-icons/fa';
import { BoxType } from 'utils/boxTypes';
import { ProfileSection } from '../../ProfileSection';
// TODO Fake data
type Props = { onRemoveClick?: () => void };
export const PlayerAchievements: React.FC<Props> = ({ onRemoveClick }) => {
type Props = {
player: PlayerFragmentFragment;
isOwnProfile?: boolean;
canEdit?: boolean;
onRemoveClick?: () => void;
};
export const PlayerAchievements: React.FC<Props> = ({
isOwnProfile,
canEdit,
onRemoveClick,
}) => {
const [show, setShow] = React.useState(false);
const fakeData = [
'Fake Achievement No. 1',
'Founding Father of MetaGame',
'Summoner of Meta Fam',
'Dragon Quests Quest',
];
return (
<ProfileSection title="Achievements" onRemoveClick={onRemoveClick}>
<ProfileSection
title="Achievements"
onRemoveClick={onRemoveClick}
isOwnProfile={isOwnProfile}
canEdit={canEdit}
boxType={BoxType.PLAYER_ACHIEVEMENTS}
>
{(fakeData || []).slice(0, show ? 999 : 3).map((title) => (
<HStack alignItems="baseline" mb={3}>
<FaMedal color="#FBB112" />

View File

@@ -1,9 +1,10 @@
import { Button, Flex, FlexProps, HStack, Select } from '@metafam/ds';
import React from 'react';
import { BoxType } from 'utils/boxTypes';
type Props = FlexProps & {
boxList: string[];
setNewBox: (name: string) => void;
boxList: BoxType[];
setNewBox: (name: BoxType) => void;
};
export const PlayerAddSection: React.FC<Props> = ({
@@ -14,7 +15,7 @@ export const PlayerAddSection: React.FC<Props> = ({
const [show, setShow] = React.useState(false);
const addSection = (e: React.ChangeEvent<HTMLSelectElement>) => {
setShow(false);
setNewBox(e.target.value);
setNewBox(e.target.value as BoxType);
};
return (
@@ -25,6 +26,7 @@ export const PlayerAddSection: React.FC<Props> = ({
borderTopRadius="lg"
py={12}
boxShadow="md"
w="100%"
css={{ backdropFilter: 'blur(8px)' }}
{...props}
>

View File

@@ -4,7 +4,7 @@ import { getPersonalityInfo } from 'graphql/queries/enums/getPersonalityInfo';
import { PersonalityOption } from 'graphql/types';
import { useAnimateProfileChanges } from 'lib/hooks/players';
import React, { useEffect, useState } from 'react';
import { BOX_TYPE } from 'utils/boxTypes';
import { BoxType } from 'utils/boxTypes';
import { FlexContainer } from '../../Container';
import { ProfileSection } from '../../ProfileSection';
@@ -13,11 +13,13 @@ import { ColorBar } from '../ColorBar';
type Props = {
player: PlayerFragmentFragment;
isOwnProfile?: boolean;
canEdit?: boolean;
onRemoveClick?: () => void;
};
export const PlayerColorDisposition: React.FC<Props> = ({
player,
isOwnProfile,
canEdit,
onRemoveClick,
}) => {
const [types, setTypes] = useState<{
@@ -45,7 +47,8 @@ export const PlayerColorDisposition: React.FC<Props> = ({
title="Color Disposition"
onRemoveClick={onRemoveClick}
isOwnProfile={isOwnProfile}
boxType={BOX_TYPE.PLAYER.COLOR_DISPOSITION}
canEdit={canEdit}
boxType={BoxType.PLAYER_COLOR_DISPOSITION}
>
{colorDisposition && types && (
<FlexContainer

View File

@@ -16,10 +16,9 @@ import { ProfileSection } from 'components/ProfileSection';
import { PlayerFragmentFragment } from 'graphql/autogen/types';
import { Collectible, useOpenSeaCollectibles } from 'lib/hooks/opensea';
import React from 'react';
import { BoxType } from 'utils/boxTypes';
import { isBackdropFilterSupported } from 'utils/compatibilityHelpers';
type Props = { player: PlayerFragmentFragment; onRemoveClick?: () => void };
const GalleryItem: React.FC<{ nft: Collectible; noMargin?: boolean }> = ({
nft,
noMargin = false,
@@ -60,7 +59,19 @@ const GalleryItem: React.FC<{ nft: Collectible; noMargin?: boolean }> = ({
</Link>
);
export const PlayerGallery: React.FC<Props> = ({ player, onRemoveClick }) => {
type Props = {
player: PlayerFragmentFragment;
isOwnProfile?: boolean;
canEdit?: boolean;
onRemoveClick?: () => void;
};
export const PlayerGallery: React.FC<Props> = ({
player,
onRemoveClick,
isOwnProfile,
canEdit,
}) => {
const { isOpen, onOpen, onClose } = useDisclosure();
const { favorites, data, loading } = useOpenSeaCollectibles({ player });
@@ -74,7 +85,13 @@ export const PlayerGallery: React.FC<Props> = ({ player, onRemoveClick }) => {
};
return (
<ProfileSection title="NFT Gallery" onRemoveClick={onRemoveClick}>
<ProfileSection
title="NFT Gallery"
onRemoveClick={onRemoveClick}
isOwnProfile={isOwnProfile}
canEdit={canEdit}
boxType={BoxType.PLAYER_NFT_GALLERY}
>
{!loading &&
favorites?.map((nft) => <GalleryItem nft={nft} key={nft.tokenId} />)}
{!loading && data?.length > 3 && (

View File

@@ -24,6 +24,7 @@ import { useUser } from 'lib/hooks';
import { useAnimateProfileChanges } from 'lib/hooks/players';
import React, { useEffect, useState } from 'react';
import { FaClock, FaGlobe } from 'react-icons/fa';
import { BoxType } from 'utils/boxTypes';
import { getPlayerTimeZoneDisplay } from 'utils/dateHelpers';
import { getPlayerDescription, getPlayerName } from 'utils/playerHelpers';
@@ -35,13 +36,21 @@ import { PlayerPronouns } from './PlayerPronouns';
const MAX_BIO_LENGTH = 240;
type Props = { player: PlayerFragmentFragment; isOwnProfile: boolean };
type Props = {
player: PlayerFragmentFragment;
isOwnProfile?: boolean;
canEdit?: boolean;
};
type AvailabilityProps = { person: PlayerFragmentFragment | null | undefined };
type TimeZoneDisplayProps = {
person: PlayerFragmentFragment | null | undefined;
};
export const PlayerHero: React.FC<Props> = ({ player, isOwnProfile }) => {
export const PlayerHero: React.FC<Props> = ({
player,
isOwnProfile,
canEdit,
}) => {
const description = getPlayerDescription(player);
const [show, setShow] = useState(description.length <= MAX_BIO_LENGTH);
const { isOpen, onOpen, onClose } = useDisclosure();
@@ -58,8 +67,8 @@ export const PlayerHero: React.FC<Props> = ({ player, isOwnProfile }) => {
}, [person]);
return (
<ProfileSection>
{isOwnProfile && (
<ProfileSection canEdit={canEdit} boxType={BoxType.PLAYER_HERO}>
{isOwnProfile && !canEdit && (
<Box pos="absolute" right={5} top={5}>
<IconButton
_focus={{

View File

@@ -15,6 +15,7 @@ import {
import { PlayerFragmentFragment } from 'graphql/autogen/types';
import { getAllMemberships, GuildMembership } from 'graphql/getMemberships';
import React, { useEffect, useMemo, useState } from 'react';
import { BoxType } from 'utils/boxTypes';
import { isBackdropFilterSupported } from 'utils/compatibilityHelpers';
import { ProfileSection } from '../../ProfileSection';
@@ -93,12 +94,16 @@ const DaoListing: React.FC<DaoListingProps> = ({ membership }) => {
type MembershipSectionProps = {
player: PlayerFragmentFragment;
isOwnProfile?: boolean;
canEdit?: boolean;
onRemoveClick?: () => void;
};
export const PlayerMemberships: React.FC<MembershipSectionProps> = ({
player,
onRemoveClick,
isOwnProfile,
canEdit,
}) => {
const { isOpen, onOpen, onClose } = useDisclosure();
const [guildMemberships, setGuildMemberships] = useState<GuildMembership[]>(
@@ -123,7 +128,13 @@ export const PlayerMemberships: React.FC<MembershipSectionProps> = ({
};
return (
<ProfileSection title="Memberships" onRemoveClick={onRemoveClick}>
<ProfileSection
title="Memberships"
onRemoveClick={onRemoveClick}
isOwnProfile={isOwnProfile}
canEdit={canEdit}
boxType={BoxType.PLAYER_DAO_MEMBERSHIPS}
>
{loadingMemberships && <LoadingState />}
{guildMemberships.slice(0, 4).map((membership) => (

View File

@@ -1,15 +1,52 @@
import { Wrap } from '@metafam/ds';
import { BoxedNextImage, MetaTag, Text, Wrap } from '@metafam/ds';
import { PlayerFragmentFragment } from 'graphql/autogen/types';
import React from 'react';
import { BoxType } from 'utils/boxTypes';
import { ProfileSection } from '../../ProfileSection';
type Props = {
player: PlayerFragmentFragment;
isOwnProfile?: boolean;
canEdit?: boolean;
onRemoveClick?: () => void;
};
export const PlayerRoles: React.FC<Props> = ({ onRemoveClick }) => (
<ProfileSection title="Roles" onRemoveClick={onRemoveClick}>
<Wrap />
export const PlayerRoles: React.FC<Props> = ({
player,
isOwnProfile,
canEdit,
onRemoveClick,
}) => (
<ProfileSection
title="Roles"
onRemoveClick={onRemoveClick}
isOwnProfile={isOwnProfile}
canEdit={canEdit}
boxType={BoxType.PLAYER_ROLES}
>
<Wrap>
{player.roles &&
player.roles
.sort((a, b) => (a.rank > b.rank ? 1 : -1))
.map(({ role, rank, PlayerRole }) => (
<MetaTag>
<BoxedNextImage
src={`/assets/roles/${role.toLowerCase()}.svg`}
alt={PlayerRole.label}
h="4"
w="4"
mr={2}
/>
<Text
color={rank === 0 ? 'cyan.500' : 'white'}
fontWeight="bold"
casing="uppercase"
my={{ base: 0, md: 2 }}
>
{PlayerRole.label}
</Text>
</MetaTag>
))}
</Wrap>
</ProfileSection>
);

View File

@@ -0,0 +1,112 @@
import { PlayerAchievements } from 'components/Player/Section/PlayerAchievements';
import { PlayerColorDisposition } from 'components/Player/Section/PlayerColorDisposition';
import { PlayerGallery } from 'components/Player/Section/PlayerGallery';
import { PlayerHero } from 'components/Player/Section/PlayerHero';
import { PlayerMemberships } from 'components/Player/Section/PlayerMemberships';
import { PlayerRoles } from 'components/Player/Section/PlayerRoles';
import { PlayerSkills } from 'components/Player/Section/PlayerSkills';
import { PlayerType } from 'components/Player/Section/PlayerType';
import { PlayerFragmentFragment } from 'graphql/autogen/types';
import { BoxType } from 'utils/boxTypes';
import { PlayerAddSection } from './PlayerAddSection';
type Props = {
boxType: BoxType;
player: PlayerFragmentFragment;
availableBoxList: BoxType[];
setNewBox: (arg0: BoxType) => void;
isOwnProfile?: boolean;
canEdit?: boolean;
removeBox?: (boxType: BoxType) => void;
};
export const PlayerSection: React.FC<Props> = ({
boxType,
player,
availableBoxList,
setNewBox,
isOwnProfile,
canEdit,
removeBox,
}) => {
switch (boxType) {
case BoxType.PLAYER_HERO:
return (
<PlayerHero
player={player}
isOwnProfile={isOwnProfile}
canEdit={canEdit}
/>
);
case BoxType.PLAYER_SKILLS:
return (
<PlayerSkills
player={player}
isOwnProfile={isOwnProfile}
canEdit={canEdit}
onRemoveClick={() => removeBox?.(boxType)}
/>
);
case BoxType.PLAYER_NFT_GALLERY:
return (
<PlayerGallery
player={player}
isOwnProfile={isOwnProfile}
canEdit={canEdit}
onRemoveClick={() => removeBox?.(boxType)}
/>
);
case BoxType.PLAYER_DAO_MEMBERSHIPS:
return (
<PlayerMemberships
player={player}
isOwnProfile={isOwnProfile}
canEdit={canEdit}
onRemoveClick={() => removeBox?.(boxType)}
/>
);
case BoxType.PLAYER_COLOR_DISPOSITION:
return (
<PlayerColorDisposition
player={player}
isOwnProfile={isOwnProfile}
canEdit={canEdit}
onRemoveClick={() => removeBox?.(boxType)}
/>
);
case BoxType.PLAYER_TYPE:
return (
<PlayerType
player={player}
isOwnProfile={isOwnProfile}
canEdit={canEdit}
onRemoveClick={() => removeBox?.(boxType)}
/>
);
case BoxType.PLAYER_ROLES:
return (
<PlayerRoles
player={player}
isOwnProfile={isOwnProfile}
canEdit={canEdit}
onRemoveClick={() => removeBox?.(boxType)}
/>
);
case BoxType.PLAYER_ACHIEVEMENTS:
return (
<PlayerAchievements
player={player}
isOwnProfile={isOwnProfile}
canEdit={canEdit}
onRemoveClick={() => removeBox?.(boxType)}
/>
);
case BoxType.PLAYER_ADD_BOX:
return (
<PlayerAddSection boxList={availableBoxList} setNewBox={setNewBox} />
);
default:
return <></>;
}
};

View File

@@ -1,4 +1,5 @@
import { MetaTag, Wrap, WrapItem } from '@metafam/ds';
import { ProfileSection } from 'components/ProfileSection';
import {
PlayerFragmentFragment,
SkillCategory_Enum,
@@ -6,18 +7,18 @@ import {
import { SkillColors } from 'graphql/types';
import { useAnimateProfileChanges } from 'lib/hooks/players';
import React, { useState } from 'react';
import { BOX_TYPE } from 'utils/boxTypes';
import { ProfileSection } from '../../ProfileSection';
import { BoxType } from 'utils/boxTypes';
type Props = {
player: PlayerFragmentFragment;
isOwnProfile?: boolean;
canEdit?: boolean;
onRemoveClick?: () => void;
};
export const PlayerSkills: React.FC<Props> = ({
player,
isOwnProfile,
canEdit,
onRemoveClick,
}) => {
const [playerSkills, setPlayerSkills] = useState<
@@ -47,7 +48,8 @@ export const PlayerSkills: React.FC<Props> = ({
title="Skills"
onRemoveClick={onRemoveClick}
isOwnProfile={isOwnProfile}
boxType={BOX_TYPE.PLAYER.SKILLS}
canEdit={canEdit}
boxType={BoxType.PLAYER_SKILLS}
>
<Wrap transition=" opacity 0.4s" opacity={animation === 'fadeIn' ? 1 : 0}>
{(playerSkills || []).map(({ id, name, category }) => (

View File

@@ -2,7 +2,7 @@ import { Text } from '@metafam/ds';
import { Player_Type, PlayerFragmentFragment } from 'graphql/autogen/types';
import { useAnimateProfileChanges } from 'lib/hooks/players';
import React, { useState } from 'react';
import { BOX_TYPE } from 'utils/boxTypes';
import { BoxType } from 'utils/boxTypes';
import { FlexContainer } from '../../Container';
import { ProfileSection } from '../../ProfileSection';
@@ -10,12 +10,14 @@ import { ProfileSection } from '../../ProfileSection';
type Props = {
player: PlayerFragmentFragment;
isOwnProfile?: boolean;
canEdit?: boolean;
onRemoveClick?: () => void;
};
export const PlayerType: React.FC<Props> = ({
player,
isOwnProfile,
canEdit,
onRemoveClick,
}) => {
const [playerType, setPlayerType] = useState<Player_Type | null>();
@@ -28,7 +30,8 @@ export const PlayerType: React.FC<Props> = ({
title="Player type"
onRemoveClick={onRemoveClick}
isOwnProfile={isOwnProfile}
boxType={BOX_TYPE.PLAYER.TYPE}
canEdit={canEdit}
boxType={BoxType.PLAYER_TYPE}
>
{playerType && (
<FlexContainer

View File

@@ -1,80 +1,138 @@
export const tokenId = 'metagame';
export const apiUrl = 'https://api.coingecko.com/api/v3/';
export const tokenQuery = '?localization=false&tickers=true&market_data=true';
export const chartQuery =
'/market_chart?vs_currency=usd&days=30&interval=daily';
export const podcastRSSURL = 'https://anchor.fm/s/57a641c/podcast/rss';
import { Layout, Layouts } from 'react-grid-layout';
import { BoxType } from 'utils/boxTypes';
export const gridData = [
{ i: 'hero', x: 0, y: 0, w: 4, h: 6, static: true, minW: 4, maxW: 4 },
{ i: 'colors', x: 4, y: 1, w: 4, h: 2, minH: 2, maxH: 2, minW: 4, maxW: 4 },
{ i: 'skills', x: 8, y: 1, w: 4, h: 2.5, minH: 2.5, minW: 4, maxW: 4 },
{ i: 'type', x: 4, y: 3, w: 4, h: 2, minH: 2, minW: 4, maxW: 4 },
{ i: 'memberships', x: 8, y: 4, w: 4, h: 4, minW: 4, maxW: 4 },
export const getBoxLayoutItemDefaults = (boxId: BoxType): Layout => {
switch (boxId) {
case BoxType.PLAYER_HERO:
return {
i: BoxType.PLAYER_HERO,
x: 0,
y: 0,
w: 1,
h: 14,
static: true,
maxW: 1,
};
case BoxType.PLAYER_SKILLS:
return { i: BoxType.PLAYER_SKILLS, x: 0, y: 0, w: 1, h: 7, maxW: 1 };
case BoxType.PLAYER_NFT_GALLERY:
return {
i: BoxType.PLAYER_NFT_GALLERY,
x: 0,
y: 0,
w: 1,
h: 10,
maxW: 1,
};
case BoxType.PLAYER_DAO_MEMBERSHIPS:
return {
i: BoxType.PLAYER_DAO_MEMBERSHIPS,
x: 0,
y: 0,
w: 1,
h: 9,
maxW: 1,
};
case BoxType.PLAYER_ACHIEVEMENTS:
return {
i: BoxType.PLAYER_ACHIEVEMENTS,
x: 0,
y: 0,
w: 1,
h: 4,
maxW: 1,
};
case BoxType.PLAYER_TYPE:
return { i: BoxType.PLAYER_TYPE, x: 0, y: 0, w: 1, h: 6, maxW: 1 };
case BoxType.PLAYER_COLOR_DISPOSITION:
return {
i: BoxType.PLAYER_COLOR_DISPOSITION,
x: 0,
y: 0,
w: 1,
h: 5,
maxW: 1,
};
case BoxType.PLAYER_ROLES:
return { i: BoxType.PLAYER_ROLES, x: 0, y: 0, w: 1, h: 3, maxW: 1 };
case BoxType.PLAYER_ADD_BOX:
return {
i: BoxType.PLAYER_ADD_BOX,
x: 0,
y: 0,
w: 1,
h: 3,
maxW: 1,
isResizable: false,
isDraggable: false,
};
default:
return { i: '', x: 0, y: 0, w: 1, h: 1, maxW: 1 };
}
};
const gridDataLg: Layout[] = [
{ ...getBoxLayoutItemDefaults(BoxType.PLAYER_HERO), x: 0, y: -3 },
{ ...getBoxLayoutItemDefaults(BoxType.PLAYER_SKILLS), x: 1, y: 0 },
{
...getBoxLayoutItemDefaults(BoxType.PLAYER_COLOR_DISPOSITION),
x: 1,
y: 7,
},
{ ...getBoxLayoutItemDefaults(BoxType.PLAYER_TYPE), x: 1, y: 12 },
{ ...getBoxLayoutItemDefaults(BoxType.PLAYER_NFT_GALLERY), x: 2, y: 0 },
{ ...getBoxLayoutItemDefaults(BoxType.PLAYER_DAO_MEMBERSHIPS), x: 2, y: 10 },
];
export const gridDataMd = [
{ i: 'hero', x: 0, y: 0, w: 6, h: 4, static: true },
{ i: 'colors', x: 6, y: 0, w: 6, h: 2, minH: 2 },
{ i: 'skills', x: 6, y: 1, w: 6, h: 2, minH: 2 },
{ i: 'type', x: 0, y: 4, w: 6, h: 4 },
{ i: 'memberships', x: 6, y: 4, w: 6, h: 4 },
const gridDataMd: Layout[] = [
{ ...getBoxLayoutItemDefaults(BoxType.PLAYER_HERO), x: 0, y: -3 },
{
...getBoxLayoutItemDefaults(BoxType.PLAYER_COLOR_DISPOSITION),
x: 1,
y: 0,
},
{ ...getBoxLayoutItemDefaults(BoxType.PLAYER_SKILLS), x: 1, y: 5 },
{ ...getBoxLayoutItemDefaults(BoxType.PLAYER_TYPE), x: 1, y: 6 },
{ ...getBoxLayoutItemDefaults(BoxType.PLAYER_NFT_GALLERY), x: 0, y: 7 },
{ ...getBoxLayoutItemDefaults(BoxType.PLAYER_DAO_MEMBERSHIPS), x: 0, y: 16 },
];
export const gridDataSm = [
{ i: 'hero', x: 0, y: 4, w: 4, h: 3, static: true },
{ i: 'colors', x: 0, y: 0, w: 4, h: 2 },
{ i: 'skills', x: 0, y: 2, w: 4, h: 2 },
{ i: 'type', x: 0, y: 7, w: 4, h: 4 },
{ i: 'memberships', x: 0, y: 11, w: 4, h: 4 },
const gridDataSm: Layout[] = [
{ ...getBoxLayoutItemDefaults(BoxType.PLAYER_HERO), x: 0, y: 0 },
{
...getBoxLayoutItemDefaults(BoxType.PLAYER_COLOR_DISPOSITION),
x: 0,
y: 10,
},
{ ...getBoxLayoutItemDefaults(BoxType.PLAYER_SKILLS), x: 0, y: 15 },
{ ...getBoxLayoutItemDefaults(BoxType.PLAYER_TYPE), x: 0, y: 19 },
{ ...getBoxLayoutItemDefaults(BoxType.PLAYER_NFT_GALLERY), x: 0, y: 7 },
{ ...getBoxLayoutItemDefaults(BoxType.PLAYER_DAO_MEMBERSHIPS), x: 0, y: 16 },
];
export const initLayouts = {
lg: gridData,
export const initLayouts: Layouts = {
lg: gridDataLg,
md: gridDataMd,
sm: gridDataSm,
xs: gridDataSm,
};
export const gridConfig = {
wrapper: (editable: boolean): Record<string, unknown> => ({
'.gridItem': {
boxShadow: editable
? '0 0 10px rgba(0,0,0,0.4)'
? '0 0 10px rgba(0,0,0,0.6)'
: '0 0 0 rgba(0,0,0,0.4)',
borderTopRadius: 'lg',
height: 'unset',
bg: editable ? 'blackAlpha.600' : 'blackAlpha.300',
overflow: 'hidden',
borderRadius: 'lg',
transition: 'boxShadow 0.2s 0.3s ease',
p: {
fontSize: 'md',
pb: 2,
mr: 'auto',
},
ul: {
fontSize: 'sm',
pb: 2,
pl: 6,
},
'& > div': {
bg: editable ? 'blackAlpha.500' : 'blackAlpha.300',
backdropFilter: 'blur(10px)',
borderBottomRadius: 'lg',
overflow: 'hidden',
h: '100%',
transition: 'bg 0.2s 0.3s ease',
},
'.container': {
overflowY: 'auto',
overflowX: 'hidden',
height: '100%',
},
h2: {
fontFamily: 'exo2',
fontSize: 'lg',
fontWeight: '700',
textAlign: 'left',
textTransform: 'uppercase',
h: '100%',
overflow: 'hidden',
},
},
'.react-grid-placeholder': {
@@ -82,113 +140,18 @@ export const gridConfig = {
boxShadow: '0 0 0 solid rgba(0, 0, 0, 0.8)',
borderRadius: 'lg',
},
'.react-resizable-handle': {
width: '1rem',
height: '1rem',
background: 'none',
borderStyle: 'solid',
borderColor: 'pinkShadeOne',
borderWidth: '0 2px 2px 0',
borderRadius: '0 0 6px 0',
margin: '2px',
},
'.react-resizable-handle::after': {
border: 'none',
},
}),
memberships: {
'.player': {
transition: 'all 0.3s ease',
'&__score': {
fontWeight: '400',
},
'&:hover': {
boxShadow: '0 0 8px rgba(0,0,0,0.3)',
cursor: 'pointer',
},
},
'&.container': {
'&__xxs': {
'.player': {
px: 3,
py: 2,
fontSize: 'sm',
justifyContent: 'center',
opacity: 1,
'&__position, &__name, &__score': {
visibility: 'hidden',
maxW: 0,
maxH: 0,
mr: 0,
},
'&__avatar': {
mr: 0,
},
},
},
'&__xs': {
'.player': {
px: 3,
fontSize: 'sm',
},
},
},
},
skills: {
'&.container': {
'&__xxs': {
'.chakra-stack': {
flexFlow: 'column',
alignItems: 'flex-start',
p: {
mx: 0,
},
},
'.chakra-stat': {
'&__group': {
mt: 3,
mb: 0,
},
'&__label': {
fontSize: 'xs',
},
'&__number': {
fontSize: 'lg',
},
'&:nth-of-type(3n)': {
display: 'none',
},
},
'.infoLink': {
display: 'none',
},
},
'&__xs': {
'.chakra-stat': {
'&__label': {
fontSize: 'xs',
},
},
},
},
},
colors: {
'&.container': {
'&__xxs': {
'.chakra-stack': {
flexFlow: 'column wrap',
alignItems: 'flex-start',
p: {
mx: 0,
},
},
'.chakra-stat': {
flex: '0 1 100%',
'&__group': {
mt: 1,
},
'&__label': {
fontSize: 'xs',
},
'&:nth-of-type(3), &:last-of-type': {
display: 'none',
},
},
},
'&__xs': {
'.chakra-stat': {
'&__label': {
fontSize: 'xs',
},
},
},
},
},
};

View File

@@ -18,14 +18,14 @@ import { SetupPlayerType } from 'components/Setup/SetupPlayerType';
import { SetupSkills } from 'components/Setup/SetupSkills';
import React from 'react';
import { FaTimes } from 'react-icons/fa';
import { BOX_TYPE } from 'utils/boxTypes';
import { BoxType } from 'utils/boxTypes';
export type ProfileSectionProps = {
children?: React.ReactNode;
onRemoveClick?: () => void;
isOwnProfile?: boolean;
canEdit?: boolean;
boxType?: string;
boxType?: BoxType;
title?: string;
};
@@ -54,7 +54,10 @@ export const ProfileSection: React.FC<ProfileSectionProps> = ({
>
{title.toUpperCase()}
</Text>
{isOwnProfile ? (
{isOwnProfile &&
!canEdit &&
boxType &&
isBoxDataEditable(boxType) ? (
<IconButton
aria-label="Edit Profile Info"
size="lg"
@@ -74,12 +77,24 @@ export const ProfileSection: React.FC<ProfileSectionProps> = ({
isRound
/>
) : null}
{canEdit ? (
<FaTimes
color="blueLight"
opacity="0.4"
cursor="pointer"
{canEdit && boxType && boxType !== BoxType.PLAYER_HERO ? (
<IconButton
aria-label="Edit Profile Info"
size="lg"
background="transparent"
color="pinkShadeOne"
icon={<FaTimes />}
_hover={{ color: 'white' }}
onClick={onRemoveClick}
_focus={{
boxShadow: 'none',
backgroundColor: 'transparent',
}}
_active={{
transform: 'scale(0.8)',
backgroundColor: 'transparent',
}}
isRound
/>
) : null}
</HStack>
@@ -94,8 +109,20 @@ export const ProfileSection: React.FC<ProfileSectionProps> = ({
css={{ backdropFilter: 'blur(8px)' }}
w="100%"
h="100%"
pos="relative"
pointerEvents={canEdit ? 'none' : 'initial'}
>
{children}
{canEdit && (
<Box
w="100%"
h="100%"
bg="purpleTag50"
pos="absolute"
top="0"
left="0"
/>
)}
</Box>
{boxType && (
<Modal isOpen={isOpen} onClose={onClose}>
@@ -131,16 +158,23 @@ export const ProfileSection: React.FC<ProfileSectionProps> = ({
);
};
const isBoxDataEditable = (boxType: BoxType) =>
[
BoxType.PLAYER_TYPE,
BoxType.PLAYER_COLOR_DISPOSITION,
BoxType.PLAYER_SKILLS,
].includes(boxType);
const getEditSectionBox = (
boxType: string,
onClose: () => void,
): React.ReactNode => {
switch (boxType) {
case BOX_TYPE.PLAYER.TYPE:
case BoxType.PLAYER_TYPE:
return <SetupPlayerType isEdit onClose={onClose} />;
case BOX_TYPE.PLAYER.COLOR_DISPOSITION:
case BoxType.PLAYER_COLOR_DISPOSITION:
return <SetupPersonalityType isEdit onClose={onClose} />;
case BOX_TYPE.PLAYER.SKILLS:
case BoxType.PLAYER_SKILLS:
return <SetupSkills isEdit onClose={onClose} />;
default:
return <></>;

View File

@@ -11,7 +11,7 @@ import {
import Error from 'next/error';
import { useRouter } from 'next/router';
import React from 'react';
import { BOX_TYPE } from 'utils/boxTypes';
import { BoxType } from 'utils/boxTypes';
import { getGuildCoverImageFull } from 'utils/playerHelpers';
import { PageContainer } from '../../components/Container';
@@ -26,14 +26,14 @@ const GuildPage: React.FC<Props> = ({ guild }) => {
const router = useRouter();
// Hidden until implemented
// BOX_TYPE.GUILD.SKILLS,
// BOX_TYPE.GUILD.STATS,
// BOX_TYPE.GUILD.QUESTS,
// BOX_TYPE.GUILD.GALLERY,
// BoxType.GUILD_SKILLS,
// BoxType.GUILD_STATS,
// BoxType.GUILD_QUESTS,
// BoxType.GUILD_GALLERY,
const boxes = [
[BOX_TYPE.GUILD.PLAYERS],
[BOX_TYPE.GUILD.ANNOUNCEMENTS, BOX_TYPE.GUILD.LINKS],
[BoxType.GUILD_PLAYERS],
[BoxType.GUILD_ANNOUNCEMENTS, BoxType.GUILD_LINKS],
];
if (router.isFallback) {
@@ -46,11 +46,11 @@ const GuildPage: React.FC<Props> = ({ guild }) => {
const getBox = (name: string): React.ReactNode => {
switch (name) {
case BOX_TYPE.GUILD.PLAYERS:
case BoxType.GUILD_PLAYERS:
return <GuildPlayers guildId={guild.id} guildname={guild.guildname} />;
case BOX_TYPE.GUILD.LINKS:
case BoxType.GUILD_LINKS:
return <GuildLinks guild={guild} />;
case BOX_TYPE.GUILD.ANNOUNCEMENTS:
case BoxType.GUILD_ANNOUNCEMENTS:
return (
<ProfileSection title="Announcements">
<p>No announcements.</p>

View File

@@ -12,7 +12,7 @@ import {
import Error from 'next/error';
import { useRouter } from 'next/router';
import React, { useEffect, useState } from 'react';
import { BOX_TYPE } from 'utils/boxTypes';
import { BoxType } from 'utils/boxTypes';
import {
getPlayerCoverImageFull,
getPlayerDescription,
@@ -36,7 +36,7 @@ const PlayerPage: React.FC<Props> = ({ player }) => {
const router = useRouter();
const [boxAvailableList, setBoxAvailableList] = useState<string[]>([]);
const [canEdit] = useState(true);
const [canEdit] = useState(false);
const [, invalidateCache] = useInsertCacheInvalidationMutation();
const { user, fetching } = useUser();
const { connected } = useWeb3();
@@ -44,15 +44,11 @@ const PlayerPage: React.FC<Props> = ({ player }) => {
const [fakeData, setFakeData] = useState([
[],
[
BOX_TYPE.PLAYER.SKILLS,
BOX_TYPE.PLAYER.COLOR_DISPOSITION,
BOX_TYPE.PLAYER.TYPE,
],
[
// BOX_TYPE.PLAYER.ROLES,
BOX_TYPE.PLAYER.GALLERY,
BOX_TYPE.PLAYER.MEMBERSHIPS,
BoxType.PLAYER_SKILLS,
BoxType.PLAYER_COLOR_DISPOSITION,
BoxType.PLAYER_TYPE,
],
[BoxType.PLAYER_NFT_GALLERY, BoxType.PLAYER_DAO_MEMBERSHIPS],
]);
useEffect(() => {
@@ -84,7 +80,7 @@ const PlayerPage: React.FC<Props> = ({ player }) => {
const addBox = (column: number, name: string) => {
setBoxAvailableList(boxAvailableList.filter((box) => box !== name));
const updatedFakeData = [...fakeData];
updatedFakeData[column].push(name);
updatedFakeData[column].push(name as BoxType);
setFakeData(updatedFakeData);
};
@@ -100,7 +96,7 @@ const PlayerPage: React.FC<Props> = ({ player }) => {
const getBox = (column: number, name: string): React.ReactNode => {
const person = isOwnProfile ? user?.player : player;
switch (name) {
case BOX_TYPE.PLAYER.SKILLS:
case BoxType.PLAYER_SKILLS:
return (
<PlayerSkills
player={person}
@@ -108,21 +104,21 @@ const PlayerPage: React.FC<Props> = ({ player }) => {
onRemoveClick={() => removeBox(column, name)}
/>
);
case BOX_TYPE.PLAYER.GALLERY:
case BoxType.PLAYER_NFT_GALLERY:
return (
<PlayerGallery
player={person}
onRemoveClick={() => removeBox(column, name)}
/>
);
case BOX_TYPE.PLAYER.MEMBERSHIPS:
case BoxType.PLAYER_DAO_MEMBERSHIPS:
return (
<PlayerMemberships
player={person}
onRemoveClick={() => removeBox(column, name)}
/>
);
case BOX_TYPE.PLAYER.COLOR_DISPOSITION:
case BoxType.PLAYER_COLOR_DISPOSITION:
return (
<PlayerColorDisposition
player={person}
@@ -130,7 +126,7 @@ const PlayerPage: React.FC<Props> = ({ player }) => {
onRemoveClick={() => removeBox(column, name)}
/>
);
case BOX_TYPE.PLAYER.TYPE:
case BoxType.PLAYER_TYPE:
return (
<PlayerType
player={person}
@@ -138,16 +134,19 @@ const PlayerPage: React.FC<Props> = ({ player }) => {
onRemoveClick={() => removeBox(column, name)}
/>
);
case BOX_TYPE.PLAYER.ROLES:
case BoxType.PLAYER_ROLES:
return (
<PlayerRoles
player={person}
onRemoveClick={() => removeBox(column, name)}
/>
);
case BOX_TYPE.PLAYER.ACHIEVEMENTS:
case BoxType.PLAYER_ACHIEVEMENTS:
return (
<PlayerAchievements onRemoveClick={() => removeBox(column, name)} />
<PlayerAchievements
player={person}
onRemoveClick={() => removeBox(column, name)}
/>
);
default:
return <></>;
@@ -226,7 +225,7 @@ const PlayerPage: React.FC<Props> = ({ player }) => {
))}
{canEdit ? (
<PlayerAddSection
boxList={boxAvailableList}
boxList={boxAvailableList as BoxType[]}
setNewBox={(name) => addBox(0, name)}
mb={6}
display={{ base: 'none', md: 'flex' }}
@@ -256,7 +255,7 @@ const PlayerPage: React.FC<Props> = ({ player }) => {
))}
{canEdit ? (
<PlayerAddSection
boxList={boxAvailableList}
boxList={boxAvailableList as BoxType[]}
setNewBox={(name) => addBox(1, name)}
mb={6}
display={{ base: 'none', lg: 'flex' }}
@@ -274,7 +273,7 @@ const PlayerPage: React.FC<Props> = ({ player }) => {
))}
{canEdit ? (
<PlayerAddSection
boxList={boxAvailableList}
boxList={boxAvailableList as BoxType[]}
setNewBox={(name) => addBox(2, name)}
mb={6}
/>

View File

@@ -7,19 +7,16 @@ import {
DeleteIcon,
EditIcon,
Flex,
GridItem,
MetaButton,
ResponsiveText,
} from '@metafam/ds';
import { PageContainer } from 'components/Container';
import { gridConfig, initLayouts } from 'components/Player/Section/config';
// import { PlayerAchievements } from 'components/Player/Section/PlayerAchievements';
import { PlayerColorDisposition } from 'components/Player/Section/PlayerColorDisposition';
// import { PlayerGallery } from 'components/Player/Section/PlayerGallery';
import { PlayerHero } from 'components/Player/Section/PlayerHero';
import { PlayerMemberships } from 'components/Player/Section/PlayerMemberships';
// import { PlayerRoles } from 'components/Player/Section/PlayerRoles';
import { PlayerSkills } from 'components/Player/Section/PlayerSkills';
import { PlayerType } from 'components/Player/Section/PlayerType';
import {
getBoxLayoutItemDefaults,
gridConfig,
initLayouts,
} from 'components/Player/Section/config';
import { PlayerSection } from 'components/Player/Section/PlayerSection';
import { HeadComponent } from 'components/Seo';
import { useInsertCacheInvalidationMutation } from 'graphql/autogen/types';
import { getPlayer } from 'graphql/getPlayer';
@@ -30,8 +27,9 @@ import {
GetStaticPropsContext,
InferGetStaticPropsType,
} from 'next';
import { ReactElement, useEffect, useState } from 'react';
import { Layout, Layouts, Responsive, WidthProvider } from 'react-grid-layout';
import { ReactElement, useCallback, useEffect, useMemo, useState } from 'react';
import { Layouts, Responsive, WidthProvider } from 'react-grid-layout';
import { BoxType } from 'utils/boxTypes';
import {
getPlayerCoverImageFull,
getPlayerDescription,
@@ -53,8 +51,6 @@ export interface ContainerQueries {
const ResponsiveGridLayout = WidthProvider(Responsive);
export const originalLayouts = initLayouts;
type Props = InferGetStaticPropsType<typeof getStaticProps>;
const PlayerPage: React.FC<Props> = ({ player }): ReactElement => (
@@ -77,7 +73,8 @@ const PlayerPage: React.FC<Props> = ({ player }): ReactElement => (
w="100%"
h="100%"
minH="100vh"
p={[4, 8, 12]}
p="4"
pt="8"
direction="column"
align="center"
>
@@ -88,9 +85,64 @@ const PlayerPage: React.FC<Props> = ({ player }): ReactElement => (
export default PlayerPage;
type CurrentLayoutType = {
layout: Layout[];
layouts: Layouts;
const makeLayouts = (editable: boolean, layouts: Layouts) => {
const newLayouts: Layouts = {};
Object.keys(layouts).map((key) => {
newLayouts[key] = layouts[key].map((item) =>
item.i === 'hero' ? { ...item, isResizable: editable } : item,
);
return key;
});
return newLayouts;
};
const ALL_BOXES = [
BoxType.PLAYER_HERO,
BoxType.PLAYER_SKILLS,
BoxType.PLAYER_COLOR_DISPOSITION,
BoxType.PLAYER_TYPE,
BoxType.PLAYER_NFT_GALLERY,
BoxType.PLAYER_DAO_MEMBERSHIPS,
BoxType.PLAYER_ROLES,
];
const DEFAULT_BOXES = [
BoxType.PLAYER_HERO,
BoxType.PLAYER_SKILLS,
BoxType.PLAYER_COLOR_DISPOSITION,
BoxType.PLAYER_TYPE,
BoxType.PLAYER_NFT_GALLERY,
BoxType.PLAYER_DAO_MEMBERSHIPS,
];
const removeBoxFromLayouts = (
boxType: BoxType,
pastLayouts: Layouts,
): Layouts => {
const layouts = { ...pastLayouts };
Object.keys(layouts).map((key) => {
layouts[key] = layouts[key].filter(
(item) => (item.i as BoxType) !== boxType,
);
return key;
});
return layouts;
};
const addBoxToLayouts = (boxType: BoxType, pastLayouts: Layouts): Layouts => {
const layouts = { ...pastLayouts };
Object.keys(layouts).map((key) => {
const heroItem = layouts[key].find(
(item) => item.i === BoxType.PLAYER_HERO,
);
layouts[key].push({
...getBoxLayoutItemDefaults(boxType),
x: 0,
y: heroItem ? heroItem.y + heroItem.h : 0,
});
return key;
});
return layouts;
};
export const Grid: React.FC<Props> = ({ player }): ReactElement => {
@@ -109,18 +161,31 @@ export const Grid: React.FC<Props> = ({ player }): ReactElement => {
invalidateCache({ playerId: player.id });
}
}, [player, invalidateCache]);
const [gridLayouts, setGridLayouts] = useState(
JSON.parse(JSON.stringify(originalLayouts)), // TODO: persist in hasura
const [savedLayouts, setSavedLayouts] = useState<Layouts>(
JSON.parse(JSON.stringify(initLayouts)), // TODO: persist in hasura
);
const [currentLayouts, setCurrentLayouts] = useState<Layouts>(
JSON.parse(JSON.stringify(initLayouts)),
);
const [ownLayout, setOwnLayout] = useState(false);
const [changed, setChanged] = useState(false);
const [current, setCurrent] = useState<CurrentLayoutType>({
layout: [],
layouts: {},
});
const [editable, setEditable] = useState(false);
const toggleEditLayout = () => setEditable(!editable);
const toggleEditLayout = useCallback(() => {
if (editable) {
const layouts = removeBoxFromLayouts(
BoxType.PLAYER_ADD_BOX,
currentLayouts,
);
setCurrentLayouts(layouts);
setSavedLayouts(layouts);
} else {
const layouts = addBoxToLayouts(BoxType.PLAYER_ADD_BOX, currentLayouts);
setCurrentLayouts(layouts);
}
setEditable(!editable);
setChanged(false);
}, [editable, currentLayouts]);
const toggleScrollLock = () => {
if (typeof window !== 'undefined') {
@@ -130,91 +195,137 @@ export const Grid: React.FC<Props> = ({ player }): ReactElement => {
return null;
};
useEffect(() => {
function handleLayoutChange(layouts: Layouts) {
const parsedLayouts = JSON.parse(JSON.stringify(layouts));
// TODO: save parsedLayouts to hasura
setGridLayouts(parsedLayouts);
}
if (changed) handleLayoutChange(current.layouts);
}, [current, changed]);
const handleLayoutChange = useCallback((layouts: Layouts) => {
const parsedLayouts = JSON.parse(JSON.stringify(layouts));
setCurrentLayouts(parsedLayouts);
setChanged(true);
}, []);
function handleReset() {
setGridLayouts(JSON.parse(JSON.stringify(initLayouts)));
const handleReset = useCallback(() => {
const parsedLayouts = JSON.parse(JSON.stringify(savedLayouts));
const layouts = addBoxToLayouts(BoxType.PLAYER_ADD_BOX, parsedLayouts);
setCurrentLayouts(layouts);
setTimeout(() => {
setOwnLayout(false);
setChanged(false);
// resetLayouts();
}, 300);
}
}, [savedLayouts]);
const wrapperSX = useMemo(() => gridConfig.wrapper(editable), [editable]);
const displayLayouts = useMemo(() => makeLayouts(editable, currentLayouts), [
editable,
currentLayouts,
]);
const onRemoveBox = useCallback(
(boxType: BoxType): void => {
const layouts = removeBoxFromLayouts(boxType, currentLayouts);
setCurrentLayouts(layouts);
setChanged(true);
},
[currentLayouts],
);
const onAddBox = useCallback(
(boxType: BoxType): void => {
const layouts = addBoxToLayouts(boxType, currentLayouts);
setCurrentLayouts(layouts);
setChanged(true);
},
[currentLayouts],
);
const boxes = useMemo(() => {
const boxIds = new Set<BoxType>();
Object.keys(currentLayouts).map((key) => {
const layout = currentLayouts[key];
layout.forEach((item) => boxIds.add(item.i as BoxType));
return key;
});
const boxIdArray = Array.from(boxIds);
return boxIdArray.length > 0 ? boxIdArray : DEFAULT_BOXES;
}, [currentLayouts]);
const availableBoxList = useMemo(
() => ALL_BOXES.filter((box) => !boxes.includes(box)),
[boxes],
);
return (
<Box
className="gridWrapper"
width="100%"
height="100%"
sx={gridConfig.wrapper(editable)}
sx={wrapperSX}
maxW="96rem"
mb="12rem"
pt={isOwnProfile ? '0rem' : '10rem'}
>
<ButtonGroup
w="100%"
justifyContent={'end'}
variant="ghost"
zIndex={10}
isAttached
>
{(changed || ownLayout) && editable && (
{isOwnProfile && (
<ButtonGroup
w="100%"
px="2rem"
justifyContent={'end'}
variant="ghost"
zIndex={10}
isAttached
mb="7rem"
>
{changed && editable && (
<MetaButton
aria-label="Edit layout"
colorScheme="purple"
_hover={{ background: 'purple.600' }}
textTransform="uppercase"
px={12}
letterSpacing="0.1em"
size="lg"
fontSize="sm"
onClick={handleReset}
leftIcon={<DeleteIcon />}
>
Reset
</MetaButton>
)}
<MetaButton
aria-label="Edit layout"
colorScheme="purple"
borderColor="transparent"
background="rgba(17, 17, 17, 0.9)"
_hover={{ color: 'white', borderColor: 'transparent' }}
variant="outline"
textTransform="uppercase"
px={12}
letterSpacing="0.1em"
size="lg"
fontSize="sm"
bg="transparent"
color="purple.400"
onClick={handleReset}
leftIcon={<DeleteIcon />}
color={editable ? 'red.400' : 'pinkShadeOne'}
leftIcon={<EditIcon />}
transition="color 0.2s ease"
onClick={toggleEditLayout}
>
Reset
<ResponsiveText
content={{
base: editable ? 'Save' : 'Edit',
md: `${editable ? 'Save' : 'Edit'} layout`,
}}
/>
</MetaButton>
)}
<MetaButton
aria-label="Edit layout"
borderColor="transparent"
background="rgba(17, 17, 17, 0.9)"
_hover={{ color: 'white', borderColor: 'transparent' }}
variant="outline"
textTransform="uppercase"
px={12}
letterSpacing="0.1em"
size="lg"
fontSize="sm"
bg="transparent"
color={editable ? 'red.400' : 'pinkShadeOne'}
leftIcon={<EditIcon />}
transition="color 0.2s ease"
onClick={toggleEditLayout}
>
{editable ? 'Save' : 'Edit'} layout
</MetaButton>
</ButtonGroup>
</ButtonGroup>
)}
<ResponsiveGridLayout
className="grid"
onLayoutChange={(layout, layouts) => {
setCurrent({ layout, layouts });
setChanged(true);
onLayoutChange={(_layout, layouts) => {
handleLayoutChange(layouts);
}}
verticalCompact
layouts={gridLayouts}
breakpoints={{ xl: 1920, lg: 1180, md: 900, sm: 768, xs: 480, xxs: 0 }}
layouts={displayLayouts}
breakpoints={{ lg: 1180, md: 900, sm: 768, xxs: 0 }}
preventCollision={false}
cols={{ xl: 12, lg: 12, md: 12, sm: 4, xs: 4, xxs: 4 }}
rowHeight={135}
autoSize
// isBounded
cols={{ lg: 3, md: 2, sm: 1, xxs: 1 }}
rowHeight={32}
isDraggable={!!editable}
isResizable={!!editable}
onDragStart={toggleScrollLock}
@@ -223,55 +334,32 @@ export const Grid: React.FC<Props> = ({ player }): ReactElement => {
onResizeStop={toggleScrollLock}
transformScale={1}
margin={{
xl: [30, 30],
lg: [30, 30],
md: [30, 30],
sm: [30, 30],
xs: [30, 30],
xxs: [30, 30],
}}
containerPadding={{
xl: [30, 30],
lg: [30, 30],
md: [20, 20],
sm: [20, 20],
xs: [15, 15],
xxs: [15, 15],
}}
>
{/* <DashboardSection key="latest" id="latest" containerQuery={queryData}> */}
<Box key="hero" className="gridItem">
<GridItem>
<PlayerHero player={player} isOwnProfile={isOwnProfile} />
</GridItem>
</Box>
<Box key="colors" className="gridItem">
<GridItem>
<PlayerColorDisposition player={player} />
</GridItem>
</Box>
<Box key="skills" className="gridItem">
<GridItem>
<PlayerSkills player={player} />
</GridItem>
</Box>
<Box key="type" className="gridItem">
<GridItem>
<PlayerType player={player} />
</GridItem>
</Box>
<Box key="memberships" className="gridItem">
<GridItem>
<PlayerMemberships player={player} />
</GridItem>
</Box>
{/*
<Box key="gallery" className="gridItem">
<GridItem >
<PlayerGallery player={player} />
</GridItem>
</Box>
*/}
{boxes.map((item) => (
// item === BoxType.PLAYER_ADD_BOX && !editable ? null : (
<Flex key={item} className="gridItem">
<PlayerSection
boxType={item}
player={player}
isOwnProfile={isOwnProfile}
canEdit={editable}
removeBox={onRemoveBox}
availableBoxList={availableBoxList}
setNewBox={onAddBox}
/>
</Flex>
))}
</ResponsiveGridLayout>
</Box>
);

View File

@@ -1,20 +1,18 @@
export const BOX_TYPE = {
PLAYER: {
SKILLS: 'Skills',
GALLERY: 'Gallery',
MEMBERSHIPS: 'Memberships',
ACHIEVEMENTS: 'Achievements',
TYPE: 'Player Type',
COLOR_DISPOSITION: 'Color disposition',
ROLES: 'Roles',
},
GUILD: {
SKILLS: 'Skills',
GALLERY: 'Gallery',
ANNOUNCEMENTS: 'Announcements',
PLAYERS: 'Players',
QUESTS: 'Quests',
STATS: 'Stats',
LINKS: 'Links',
},
};
export enum BoxType {
PLAYER_HERO = 'player-hero',
PLAYER_SKILLS = 'player-skills',
PLAYER_NFT_GALLERY = 'player-nft-gallery',
PLAYER_DAO_MEMBERSHIPS = 'player-dao-memberships',
PLAYER_ACHIEVEMENTS = 'player-achievements',
PLAYER_TYPE = 'player-type',
PLAYER_COLOR_DISPOSITION = 'player-color-disposition',
PLAYER_ROLES = 'player-roles',
PLAYER_ADD_BOX = 'player-add-box',
GUILD_SKILLS = 'guild-skills',
GUILD_GALLERY = 'guild-gallery',
GUILD_ANNOUNCEMENTS = 'guild-announcements',
GUILD_PLAYERS = 'guild-players',
GUILD_QUESTS = 'quild-quests',
GUILD_STATS = 'guild-stats',
GUILD_LINKS = 'guild-links',
}