Merge branch 'main' of https://github.com/snowball-tools/snowballtools-base into ayungavis/T-4910-create-project-template-card

This commit is contained in:
Wahyu Kurniawan 2024-02-28 14:57:34 +07:00
commit 6dbfdafe2a
No known key found for this signature in database
GPG Key ID: 040A1549143A8E33
10 changed files with 228 additions and 91 deletions

View File

@ -7,7 +7,12 @@ import {
GitIcon,
EllipsesIcon,
SnowballIcon,
GithubIcon,
GitTeaIcon,
} from 'components/shared/CustomIcon';
import { useToast } from 'components/shared/Toast';
import { IconWithFrame } from 'components/shared/IconWithFrame';
import { Heading } from 'components/shared/Heading';
const SCOPES = 'repo user';
const GITHUB_OAUTH_URL = `https://github.com/login/oauth/authorize?client_id=${
@ -23,36 +28,44 @@ const ConnectAccount: React.FC<ConnectAccountInterface> = ({
}: ConnectAccountInterface) => {
const client = useGQLClient();
const { toast, dismiss } = useToast();
const handleCode = async (code: string) => {
// Pass code to backend and get access token
const {
authenticateGitHub: { token },
} = await client.authenticateGitHub(code);
onToken(token);
toast({
onDismiss: dismiss,
id: 'connected-to-github',
title: 'The Git account is connected.',
variant: 'success',
});
};
// TODO: Use correct height
return (
<div className="bg-gray-100 flex flex-col p-4 gap-7 justify-center items-center text-center text-sm h-full rounded-2xl">
<div className="w-52 h-16 justify-center items-center gap-4 inline-flex">
<div className="w-16 h-16 bg-blue-100 rounded-2xl shadow-inner border border-sky-950 border-opacity-10 justify-center items-center gap-2.5 inline-flex">
<GitIcon />
</div>
<div className="flex flex-col items-center max-w-[420px]">
{/** Icons */}
<div className="w-52 h-16 justify-center items-center gap-4 inline-flex mb-7">
<IconWithFrame icon={<GitIcon />} />
<EllipsesIcon className="items-center gap-1.5 flex" />
<div className="w-16 h-16 bg-blue-400 rounded-2xl shadow-inner border border-sky-950 border-opacity-10 justify-center items-center gap-2.5 flex">
<SnowballIcon />
<IconWithFrame className="bg-blue-400" icon={<SnowballIcon />} />
</div>
</div>
<div>
<div className="text-center text-slate-900 text-xl font-medium leading-7">
{/** Text */}
<div className="flex flex-col gap-1.5 mb-6">
<Heading className="text-xl font-medium">
Connect to your Git account
</Heading>
<p className="text-center text-elements-mid-em">
Once connected, you can import a repository from your account or
start with one of our templates.
</p>
</div>
<div className="text-center text-slate-600 text-base font-normal leading-normal">
Once connected, you can import a repository from your account or start
with one of our templates.
</div>
</div>
<div className="mt-2 flex gap-3">
{/** CTA Buttons */}
<div className="flex flex-col w-full sm:w-auto sm:flex-row gap-2 sm:gap-3">
<OauthPopup
url={GITHUB_OAUTH_URL}
onCode={handleCode}
@ -61,9 +74,22 @@ const ConnectAccount: React.FC<ConnectAccountInterface> = ({
width={1000}
height={1000}
>
<Button>Connect to GitHub</Button>
<Button
className="w-full sm:w-auto"
leftIcon={<GithubIcon />}
variant="tertiary"
>
Connect to GitHub
</Button>
</OauthPopup>
<Button>Connect to Gitea</Button>
<Button
className="w-full sm:w-auto"
leftIcon={<GitTeaIcon />}
variant="tertiary"
>
Connect to GitTea
</Button>
</div>
</div>
{/* TODO: Add ConnectAccountTabPanel */}

View File

@ -1,45 +1,85 @@
import React from 'react';
import { Typography, IconButton, Avatar } from '@material-tailwind/react';
import { relativeTimeISO } from '../../../utils/time';
import { Link } from 'react-router-dom';
import { GitCommitWithBranch } from '../../../types';
import { Avatar } from 'components/shared/Avatar';
import { Button } from 'components/shared/Button';
import {
ArrowRightCircleFilledIcon,
BranchIcon,
} from 'components/shared/CustomIcon';
import { formatDistance } from 'date-fns';
import { getInitials } from 'utils/geInitials';
interface ActivityCardProps {
activity: GitCommitWithBranch;
}
const ActivityCard = ({ activity }: ActivityCardProps) => {
const formattedDate = formatDistance(
new Date(activity.commit.author!.date!),
new Date(),
{
addSuffix: true,
},
);
return (
<div className="group flex gap-2 hover:bg-gray-200 rounded mt-1">
<div className="w-8">
<>
<Link
to={activity.html_url}
target="_blank"
className="p-3 gap-2 focus-within:ring-2 focus-within:ring-controls-primary/40 focus:outline-none rounded-xl transition-colors hover:bg-base-bg-alternate flex group"
>
<div>
<Avatar
src={activity.author?.avatar_url}
variant="rounded"
size="sm"
placeholder={''}
type="orange"
size={36}
initials={getInitials(activity.commit.author?.name ?? '')}
imageSrc={activity.author?.avatar_url}
/>
</div>
<div className="grow">
<Typography placeholder={''}>{activity.commit.author?.name}</Typography>
<Typography variant="small" color="gray" placeholder={''}>
{relativeTimeISO(activity.commit.author!.date!)} ^{' '}
{activity.branch.name}
</Typography>
<Typography variant="small" color="gray" placeholder={''}>
{activity.commit.message}
</Typography>
<div className="flex-1">
<span className="text-elements-high-em text-sm font-medium tracking-tight">
{activity.commit.author?.name}
</span>
<span className="text-elements-low-em text-xs flex items-center gap-2">
<span title={formattedDate} className="whitespace-nowrap">
{formattedDate}
</span>
{/* Dot */}
<span className="w-0.5 h-0.5 rounded-full bg-border-interactive-hovered"></span>
<span className="flex justify-center items-center gap-1.5">
<div>
<BranchIcon />
</div>
<div className="mr-2 self-center hidden group-hover:block">
<IconButton
size="sm"
className="rounded-full bg-gray-600"
placeholder={''}
<span
title={activity.branch.name}
// pseudo to increase hover area
className="before:absolute relative before:h-5 before:-top-4 before:inset-x-0"
>
{'>'}
</IconButton>
</div>
<span className="line-clamp-1">{activity.branch.name}</span>
</span>
</span>
</span>
<p
title={activity.commit.message}
className="text-sm line-clamp-4 tracking-tight text-elements-mid-em mt-2"
>
{activity.commit.message}
</p>
</div>
<Button
aria-label="Go to commit"
variant="unstyled"
tabIndex={-1}
className="p-0 text-elements-low-em group-focus-within:opacity-100 group-hover:opacity-100 opacity-0 transition-all"
leftIcon={<ArrowRightCircleFilledIcon className="w-5 h-5" />}
/>
</Link>
{/* Separator calc => 100% - 36px (avatar) - 12px (padding-left) - 8px (gap)
*/}
<div className="pt-2 mb-2 ml-auto h-1 w-[calc(100%-36px-12px-8px)] border-b border-border-separator last:border-b-transparent"></div>
</>
);
};

View File

@ -14,6 +14,8 @@ export const buttonTheme = tv(
'whitespace-nowrap',
'focus-ring',
'disabled:cursor-not-allowed',
'transition-colors',
'duration-150',
],
variants: {
size: {
@ -61,14 +63,13 @@ export const buttonTheme = tv(
tertiary: [
'text-elements-on-tertiary',
'border',
'border-border-interactive/10',
'border-border-interactive',
'bg-controls-tertiary',
'shadow-button',
'hover:bg-controls-tertiary-hovered',
'hover:border-border-interactive-hovered',
'hover:border-border-interactive-hovered/[0.14]',
'focus-visible:bg-controls-tertiary-hovered',
'focus-visible:border-border-interactive-hovered',
'focus-visible:border-border-interactive-hovered/[0.14]',
'disabled:text-elements-on-disabled',
'disabled:bg-controls-disabled',
'disabled:border-transparent',
@ -81,10 +82,8 @@ export const buttonTheme = tv(
'bg-transparent',
'hover:bg-controls-tertiary-hovered',
'hover:border-border-interactive-hovered',
'hover:border-border-interactive-hovered/[0.14]',
'focus-visible:bg-controls-tertiary-hovered',
'focus-visible:border-border-interactive-hovered',
'focus-visible:border-border-interactive-hovered/[0.14]',
'disabled:text-elements-on-disabled',
'disabled:bg-controls-disabled',
'disabled:border-transparent',
@ -109,10 +108,8 @@ export const buttonTheme = tv(
'bg-transparent',
'hover:bg-controls-tertiary-hovered',
'hover:border-border-interactive-hovered',
'hover:border-border-interactive-hovered/[0.14]',
'focus-visible:bg-controls-tertiary-hovered',
'focus-visible:border-border-interactive-hovered',
'focus-visible:border-border-interactive-hovered/[0.14]',
'disabled:text-elements-on-disabled',
'disabled:bg-controls-disabled',
'disabled:border-transparent',

View File

@ -0,0 +1,21 @@
import React from 'react';
import { CustomIcon, CustomIconProps } from './CustomIcon';
export const ArrowRightCircleFilledIcon = (props: CustomIconProps) => {
return (
<CustomIcon
{...props}
fill="none"
height="32"
viewBox="0 0 32 32"
width="32"
>
<path
clipRule="evenodd"
d="M29.3334 16C29.3334 8.63619 23.3638 2.66666 16 2.66666C8.63622 2.66666 2.66669 8.63619 2.66669 16C2.66669 23.3638 8.63622 29.3333 16 29.3333C23.3638 29.3333 29.3334 23.3638 29.3334 16ZM18.1144 17.3333L16.3905 19.0572C15.8698 19.5779 15.8698 20.4221 16.3905 20.9428C16.9112 21.4635 17.7555 21.4635 18.2762 20.9428L21.3334 17.8856C22.3748 16.8442 22.3748 15.1558 21.3334 14.1144L18.2762 11.0572C17.7555 10.5365 16.9112 10.5365 16.3905 11.0572C15.8698 11.5779 15.8698 12.4221 16.3905 12.9428L18.1144 14.6667H10.6667C9.93031 14.6667 9.33335 15.2636 9.33335 16C9.33335 16.7364 9.93031 17.3333 10.6667 17.3333H18.1144Z"
fill="currentColor"
fillRule="evenodd"
/>
</CustomIcon>
);
};

View File

@ -0,0 +1,27 @@
import React from 'react';
import { CustomIcon, CustomIconProps } from './CustomIcon';
export const GitTeaIcon: React.FC<CustomIconProps> = (props) => {
return (
<CustomIcon
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
{...props}
>
<path
d="M12.372 15.1312L8.40635 13.225C8.01573 13.0375 7.84698 12.5625 8.0376 12.1687L9.94385 8.20308C10.1314 7.81245 10.6064 7.6437 11.0001 7.83433C11.5376 8.0937 11.847 8.24058 11.847 8.24058L11.8439 4.82808L12.3657 4.82495L12.3689 8.48433C12.3689 8.48433 14.1626 9.24058 14.9657 9.73745C15.0814 9.80933 15.2845 9.94995 15.3689 10.1875C15.4345 10.3781 15.4314 10.5968 15.3376 10.7906L13.4314 14.7562C13.2376 15.1531 12.7626 15.3218 12.372 15.1312Z"
fill="white"
/>
<path
d="M19.4595 4.68123C19.3314 4.5531 19.1595 4.55623 19.1595 4.55623C19.1595 4.55623 15.497 4.76248 13.6001 4.80623C13.1845 4.8156 12.772 4.82498 12.3626 4.8281C12.3626 6.04998 12.3626 7.27185 12.3626 8.4906C12.1907 8.40935 12.0157 8.32498 11.8439 8.24373C11.8439 7.10623 11.8407 4.83123 11.8407 4.83123C10.9345 4.84373 9.05324 4.76248 9.05324 4.76248C9.05324 4.76248 4.63449 4.5406 4.15324 4.49685C3.84699 4.4781 3.45011 4.43123 2.93449 4.54373C2.66261 4.59998 1.88761 4.77498 1.25324 5.38435C-0.153014 6.63748 0.206361 8.63123 0.250111 8.93123C0.303236 9.29685 0.465736 10.3125 1.24074 11.1969C2.67199 12.95 5.75324 12.9094 5.75324 12.9094C5.75324 12.9094 6.13136 13.8125 6.70949 14.6437C7.49074 15.6781 8.29386 16.4844 9.07511 16.5812C11.0439 16.5812 14.9782 16.5781 14.9782 16.5781C14.9782 16.5781 15.3532 16.5812 15.8626 16.2562C16.3001 15.9906 16.6907 15.525 16.6907 15.525C16.6907 15.525 17.0939 15.0937 17.6564 14.1094C17.8282 13.8062 17.972 13.5125 18.097 13.2344C18.097 13.2344 19.822 9.57498 19.822 6.01248C19.7876 4.93435 19.522 4.74373 19.4595 4.68123ZM3.92511 11.0594C3.11574 10.7937 2.77199 10.475 2.77199 10.475C2.77199 10.475 2.17511 10.0562 1.87511 9.23123C1.35949 7.84998 1.83136 7.00623 1.83136 7.00623C1.83136 7.00623 2.09386 6.3031 3.03449 6.06873C3.46574 5.9531 4.00324 5.97185 4.00324 5.97185C4.00324 5.97185 4.22511 7.8281 4.49386 8.9156C4.71886 9.8281 5.26886 11.3437 5.26886 11.3437C5.26886 11.3437 4.45324 11.2469 3.92511 11.0594ZM13.3095 14.4219C13.3095 14.4219 13.1189 14.875 12.697 14.9031C12.5157 14.9156 12.3751 14.8656 12.3751 14.8656C12.3751 14.8656 12.3657 14.8625 12.2095 14.8L8.68136 13.0812C8.68136 13.0812 8.34074 12.9031 8.28136 12.5937C8.21261 12.3406 8.36574 12.0281 8.36574 12.0281L10.0626 8.53123C10.0626 8.53123 10.2126 8.2281 10.4439 8.12498C10.4626 8.1156 10.5157 8.09373 10.5845 8.0781C10.8376 8.01248 11.147 8.1656 11.147 8.1656L14.6064 9.84373C14.6064 9.84373 15.0001 10.0219 15.0845 10.35C15.1439 10.5812 15.0689 10.7875 15.0282 10.8875C14.8314 11.3687 13.3095 14.4219 13.3095 14.4219Z"
fill="#609926"
/>
<path
d="M10.2126 11.8781C9.95632 11.8813 9.73132 12.0594 9.67195 12.3094C9.61257 12.5594 9.73445 12.8187 9.95632 12.9344C10.1969 13.0594 10.5032 12.9906 10.6657 12.7656C10.8251 12.5437 10.8001 12.2375 10.6094 12.0437L11.3594 10.5094C11.4063 10.5125 11.4751 10.5156 11.5532 10.4937C11.6813 10.4656 11.7751 10.3813 11.7751 10.3813C11.9063 10.4375 12.0438 10.5 12.1876 10.5719C12.3376 10.6469 12.4782 10.725 12.6063 10.8C12.6344 10.8156 12.6626 10.8344 12.6938 10.8594C12.7438 10.9 12.8001 10.9562 12.8407 11.0312C12.9001 11.2031 12.7813 11.4969 12.7813 11.4969C12.7094 11.7344 12.2063 12.7656 12.2063 12.7656C11.9532 12.7594 11.7282 12.9219 11.6532 13.1562C11.5719 13.4094 11.6876 13.6969 11.9313 13.8219C12.1751 13.9469 12.4751 13.875 12.6344 13.6562C12.7907 13.4437 12.7782 13.1469 12.6001 12.95C12.6594 12.8344 12.7157 12.7188 12.7751 12.5969C12.9313 12.2719 13.1969 11.6469 13.1969 11.6469C13.2251 11.5938 13.3751 11.325 13.2813 10.9812C13.2032 10.625 12.8876 10.4594 12.8876 10.4594C12.5063 10.2125 11.9751 9.98438 11.9751 9.98438C11.9751 9.98438 11.9751 9.85625 11.9407 9.7625C11.9063 9.66562 11.8532 9.60313 11.8188 9.56563C11.9657 9.2625 12.1126 8.9625 12.2594 8.65938C12.1313 8.59688 12.0063 8.53437 11.8782 8.46875C11.7282 8.775 11.5751 9.08438 11.4251 9.39062C11.2157 9.3875 11.0219 9.5 10.9219 9.68437C10.8157 9.88125 10.8376 10.125 10.9813 10.3031C10.7251 10.8281 10.4688 11.3531 10.2126 11.8781Z"
fill="#609926"
/>
</CustomIcon>
);
};

View File

@ -23,6 +23,7 @@ export * from './EllipsesIcon';
export * from './SnowballIcon';
export * from './NotificationBellIcon';
export * from './GithubIcon';
export * from './GitTeaIcon';
export * from './LockIcon';
export * from './PencilIcon';
export * from './CheckRadioIcon';
@ -34,6 +35,7 @@ export * from './HorizontalDotIcon';
export * from './WarningDiamondIcon';
export * from './ArrowRightCircleIcon';
export * from './ClockOutlineIcon';
export * from './ArrowRightCircleFilledIcon';
// Templates
export * from './templates';

View File

@ -0,0 +1,32 @@
import React, { ComponentPropsWithoutRef, ReactNode } from 'react';
import { cn } from 'utils/classnames';
interface IconWithFrameProps extends ComponentPropsWithoutRef<'div'> {
icon: ReactNode;
hasHighlight?: boolean;
}
export const IconWithFrame = ({
icon,
className,
hasHighlight = true,
...props
}: IconWithFrameProps) => {
return (
<div
className={cn(
'relative justify-center items-center gap-2.5 inline-flex',
'w-16 h-16 rounded-2xl shadow-inner',
'border border-b-[3px] border-border-interactive border-opacity-10',
'bg-controls-secondary',
className,
)}
{...props}
>
{hasHighlight && (
<div className="bottom-0 absolute w-[37px] h-px bg-gradient-to-r from-gray-0/0 via-gray-0/50 to-gray-0/0" />
)}
{icon}
</div>
);
};

View File

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

View File

@ -1,15 +1,9 @@
import React, { useEffect, useState } from 'react';
import { Domain, DomainStatus } from 'gql-client';
import { Link, useNavigate, useOutletContext } from 'react-router-dom';
import { useNavigate, useOutletContext } from 'react-router-dom';
import { RequestError } from 'octokit';
import {
Typography,
Button,
Chip,
Avatar,
Tooltip,
} from '@material-tailwind/react';
import { Typography, Chip, Avatar, Tooltip } from '@material-tailwind/react';
import ActivityCard from '../../../../components/projects/project/ActivityCard';
import { relativeTimeMs } from '../../../../utils/time';
@ -17,6 +11,8 @@ import { useOctokit } from '../../../../context/OctokitContext';
import { GitCommitWithBranch, OutletContextType } from '../../../../types';
import { useGQLClient } from '../../../../context/GQLClientContext';
import { formatAddress } from '../../../../utils/format';
import { Button } from 'components/shared/Button';
import { Heading } from 'components/shared/Heading';
const COMMITS_PER_PAGE = 4;
@ -107,9 +103,9 @@ const OverviewTabPanel = () => {
}, [project]);
return (
<div className="grid grid-cols-5">
<div className="col-span-3 p-2">
<div className="flex items-center gap-2 p-2 ">
<div className="grid grid-cols-5 gap-[72px] mt-7">
<div className="col-span-3">
<div className="flex items-center gap-2">
<Avatar
src={project.icon || '/gray.png'}
variant="rounded"
@ -143,12 +139,11 @@ const OverviewTabPanel = () => {
/>
<Button
className="normal-case rounded-full"
color="blue"
variant="primary"
size="sm"
onClick={() => {
navigate('settings/domains');
}}
placeholder={''}
>
Setup
</Button>
@ -179,21 +174,17 @@ const OverviewTabPanel = () => {
<div>No current deployment found</div>
)}
</div>
<div className="col-span-2 p-2">
<div className="flex justify-between">
<Typography variant="h6" placeholder={''}>
Activity
</Typography>
<button className="text-xs bg-gray-300 rounded-full p-2">
<div className="col-span-2 mr-1">
<div className="flex items-center justify-between">
<Heading className="text-lg leading-6 font-medium">Activity</Heading>
<Button variant="tertiary" size="sm">
See all
</button>
</Button>
</div>
<div className="p-2">
<div className="mt-5">
{activities.map((activity, index) => {
return (
<Link to={activity.html_url} target="_blank" key={index}>
<ActivityCard activity={activity} />
</Link>
<ActivityCard activity={activity} key={`activity-${index}`} />
);
})}
</div>

View File

@ -152,7 +152,7 @@ export default withMT({
},
boxShadow: {
button:
'inset 0px 0px 4px rgba(255, 255, 255, 0.25), inset 0px -2px 0px rgba(0, 0, 0, 0.04)',
'0px -2px 0px 0px rgba(0, 0, 0, 0.04) inset, 0px 0px 4px 0px rgba(255, 255, 255, 0.25) inset',
dropdown:
'0px 3px 20px rgba(8, 47, 86, 0.1), 0px 0px 4px rgba(8, 47, 86, 0.14)',
field: '0px 1px 2px rgba(0, 0, 0, 0.04)',