Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: create colony cards for landing page #3425

Open
wants to merge 3 commits into
base: feat/landing-page
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions src/components/frame/LandingPage/ColonyCard.tsx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given we have multiple scenarios for the ColonyCard, namely the loading state, creating a colony and active colony, we should definitely create multiple instances of the ColonyCard and use them accordingly: LoadingColonyCard, CreateColonyCard and ActiveColonyCard - the last two could instantiate a BaseColonyCard which could have the following implementation

interface BaseColonyCardProps extends PropsWithChildren {
  isClickable?: boolean
}

const BaseColonyCard: FC<BaseColonyCardProps> = ({ children, isClickable }) => {

  return (
    <div
      className={clsx(
        'flex h-[4.5rem] items-center gap-[.875rem] rounded border px-5 py-4 transition-colors duration-normal hover:border-gray-900',
        {
          'cursor-pointer': isClickable,
        },
      )}
    >
      {children}
    </div>
  )
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { Plus } from '@phosphor-icons/react';
import clsx from 'clsx';
import React from 'react';

import LoadingSkeleton from '~common/LoadingSkeleton/LoadingSkeleton.tsx';
import { formatText } from '~utils/intl.ts';
import Button from '~v5/shared/Button/Button.tsx';

export interface ColonyCardProps {
colonyName?: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all of the conditional rendering we're doing with skeletons and handling the create new colony function is putting way too many things into this component.
I would recommend the following steps to make this more sustainable:

  1. Create 2 new components, a ColonyCard and CreateNewColonyCard
  2. Instead of having all the props optional because the app may be loading, I would recommend creating a file structure something like this:
  • ColonyCardHandler is a component which gets the colony and the loading state, if the app is loading it renders ColonyCardSkeleton, if we have all the necessary data, we render ColonyCard with all the props sent in defined and not nullable
  • then the same for CreateColonyCard (can this one even be impacted by anything loading?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bassgeta Ok, I will add ColonyCardHandler when I start creating logic for Landing page

colonyAvatar?: string;
membersCount?: number;
invitationsRemaining?: number;
loading?: boolean;
onCreate?: () => void;
}

const displayName = 'frame.LandingPage';

export const ColonyCard = ({
colonyName,
colonyAvatar,
invitationsRemaining,
membersCount = 0,
loading,
onCreate,
}: ColonyCardProps) => {
return (
<div
className={clsx(
'flex h-[4.5rem] items-center gap-[.875rem] rounded border px-5 py-4 transition-colors duration-normal',
{
'cursor-pointer': colonyName && !loading,
'hover:border-gray-900': !loading,
},
)}
>
<div className="flex h-8 w-8 items-center justify-center">
<LoadingSkeleton isLoading={loading} className="h-8 w-8 rounded-full">
{colonyName && colonyAvatar ? (
<img
src={colonyAvatar}
alt="Colony avatar"
className="w-8 rounded-full"
/>
) : (
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-gray-100">
<Plus size={18} className="text-gray-900 " />
</div>
)}
</LoadingSkeleton>
</div>
{loading ? (
<div className="flex flex-col gap-1">
<LoadingSkeleton isLoading className="h-5 w-[7.5rem] rounded" />
<LoadingSkeleton
isLoading
className="h-[.6875rem] w-[4.25rem] rounded"
/>
</div>
) : (
<div className="flex w-full items-center justify-between">
{colonyName ? (
<p className="text-md font-medium">{colonyName}</p>
) : (
<div className="flex flex-col gap-1">
<div className="flex">
<span className="rounded bg-blue-100 px-[.1875rem] py-[.1563rem] text-2xs font-extrabold text-blue-400">
{formatText(
{
id: 'landingPage.card.remaining',
},
{ remaining: invitationsRemaining },
).toUpperCase()}
</span>
</div>
<p className="text-md font-medium">
{formatText({
id: 'landingPage.card.createColony',
})}
</p>
</div>
)}

{colonyName ? (
<p className="text-xs font-normal">
{formatText(
{
id: 'landingPage.card.members',
},
{ members: membersCount.toLocaleString('en-US') },
)}
</p>
) : (
<Button icon={Plus} onClick={onCreate}>
Create
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please extract this into a MessageDescriptor and then use here formatText(MSG.createColony)

</Button>
)}
</div>
)}
</div>
);
};

ColonyCard.displayName = displayName;

export default ColonyCard;
3 changes: 3 additions & 0 deletions src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@
"home": "Home",
"wallet": "Wallet",
"colonyWelcome": "Welcome to Colony",
"landingPage.card.members": "{members} Members",
"landingPage.card.createColony": "Create a new colony",
"landingPage.card.remaining": "{remaining} invitations remaining",
"domain.all": "All Teams",
"domain.root": "Root",
"role.disabled": "Disabled",
Expand Down
72 changes: 72 additions & 0 deletions src/stories/common/ColonyCard.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { type Meta, type StoryObj } from '@storybook/react';
import React from 'react';

import ColonyCard from '~frame/LandingPage/ColonyCard.tsx';

const meta: Meta<typeof ColonyCard> = {
title: 'Common/Colony Card',
component: ColonyCard,
decorators: [
(Story) => (
<div className="mx-auto max-w-[41.75rem]">
<Story />
</div>
),
],
argTypes: {
colonyName: {
name: 'Colony name',
control: {
type: 'text',
},
},
colonyAvatar: {
name: 'Colony avatar',
control: {
type: 'text',
},
},
membersCount: {
name: 'Members count',
control: {
type: 'number',
},
},
invitationsRemaining: {
name: 'Invitations remaining',
control: {
type: 'number',
},
},
loading: {
name: 'Loading',
control: {
type: 'boolean',
},
},
},
};

export default meta;
type Story = StoryObj<typeof ColonyCard>;

export const ActiveColony: Story = {
args: {
colonyName: 'Beta colony',
colonyAvatar: 'https://picsum.photos/200',
membersCount: 1520,
invitationsRemaining: 2,
},
};

export const CreateColony: Story = {
args: {
invitationsRemaining: 3,
},
};

export const Loading: Story = {
args: {
loading: true,
},
};
1 change: 1 addition & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ module.exports = {
inter: ['Inter', 'sans-serif'],
},
fontSize: {
'2xs': ['.5rem', 1.5],
xs: ['0.625rem', 1.6],
sm: ['0.75rem', 1.5],
md: ['0.875rem', '1.25rem'],
Expand Down
Loading