diff --git a/packages/frontend/src/components/projects/project/overview/Activity/Activity.tsx b/packages/frontend/src/components/projects/project/overview/Activity/Activity.tsx new file mode 100644 index 00000000..040683b9 --- /dev/null +++ b/packages/frontend/src/components/projects/project/overview/Activity/Activity.tsx @@ -0,0 +1,28 @@ +import React from 'react'; + +import { GitCommitWithBranch } from 'types'; +import { Heading } from 'components/shared/Heading'; +import ActivityCard from './ActivityCard'; +import { Button } from 'components/shared/Button'; + +export const Activity = ({ + activities, +}: { + activities: GitCommitWithBranch[]; +}) => { + return ( +
+
+ Activity + +
+
+ {activities.map((activity, index) => { + return ; + })} +
+
+ ); +}; diff --git a/packages/frontend/src/components/projects/project/ActivityCard.tsx b/packages/frontend/src/components/projects/project/overview/Activity/ActivityCard.tsx similarity index 95% rename from packages/frontend/src/components/projects/project/ActivityCard.tsx rename to packages/frontend/src/components/projects/project/overview/Activity/ActivityCard.tsx index 3f3cc55e..6d86ecd5 100644 --- a/packages/frontend/src/components/projects/project/ActivityCard.tsx +++ b/packages/frontend/src/components/projects/project/overview/Activity/ActivityCard.tsx @@ -1,11 +1,11 @@ import React from 'react'; import { Link } from 'react-router-dom'; -import { GitCommitWithBranch } from '../../../types'; +import { GitCommitWithBranch } from '../../../../../types'; import { Avatar } from 'components/shared/Avatar'; import { Button } from 'components/shared/Button'; import { ArrowRightCircleFilledIcon, - BranchIcon, + BranchStrokeIcon, } from 'components/shared/CustomIcon'; import { formatDistance } from 'date-fns'; import { getInitials } from 'utils/geInitials'; @@ -50,7 +50,7 @@ const ActivityCard = ({ activity }: ActivityCardProps) => {
- +
) => { + const styledIcon = cloneElement({ + element: icon, + className: 'w-4 h-4', + }); + + return ( +
+
+ {styledIcon} + {label} +
+
{children}
+
+ ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/BranchStrokeIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/BranchStrokeIcon.tsx new file mode 100644 index 00000000..e8b95175 --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/BranchStrokeIcon.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const BranchStrokeIcon = (props: CustomIconProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/CalendarDaysIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/CalendarDaysIcon.tsx new file mode 100644 index 00000000..2528559e --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/CalendarDaysIcon.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const CalendarDaysIcon = (props: CustomIconProps) => { + return ( + + + + + + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/CursorBoxIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/CursorBoxIcon.tsx new file mode 100644 index 00000000..df7889cc --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/CursorBoxIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const CursorBoxIcon = (props: CustomIconProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/GithubStrokeIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/GithubStrokeIcon.tsx new file mode 100644 index 00000000..74d259ba --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/GithubStrokeIcon.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const GithubStrokeIcon = (props: CustomIconProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/LinkIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/LinkIcon.tsx new file mode 100644 index 00000000..2f0aa923 --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/LinkIcon.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const LinkIcon = (props: CustomIconProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/StorageIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/StorageIcon.tsx new file mode 100644 index 00000000..38a651f1 --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/StorageIcon.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const StorageIcon = (props: CustomIconProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/index.ts b/packages/frontend/src/components/shared/CustomIcon/index.ts index 754404be..b9965188 100644 --- a/packages/frontend/src/components/shared/CustomIcon/index.ts +++ b/packages/frontend/src/components/shared/CustomIcon/index.ts @@ -36,6 +36,11 @@ export * from './WarningDiamondIcon'; export * from './ArrowRightCircleIcon'; export * from './ClockOutlineIcon'; export * from './ArrowRightCircleFilledIcon'; +export * from './GithubStrokeIcon'; +export * from './BranchStrokeIcon'; +export * from './StorageIcon'; +export * from './LinkIcon'; +export * from './CursorBoxIcon'; // Templates export * from './templates'; diff --git a/packages/frontend/src/components/shared/Tabs/Tabs.theme.ts b/packages/frontend/src/components/shared/Tabs/Tabs.theme.ts index 3f9ef417..81a32589 100644 --- a/packages/frontend/src/components/shared/Tabs/Tabs.theme.ts +++ b/packages/frontend/src/components/shared/Tabs/Tabs.theme.ts @@ -8,7 +8,6 @@ export const tabsTheme = tv({ triggerWrapper: [ // Horizontal – default 'px-1', - 'pb-5', 'cursor-default', 'select-none', 'text-elements-low-em', @@ -55,9 +54,13 @@ export const tabsTheme = tv({ 'outline-none', 'leading-none', 'tracking-[-0.006em]', + 'text-sm', 'rounded-md', // Horizontal – default 'data-[orientation=horizontal]:focus-ring', + 'data-[orientation=horizontal]:h-10', + // select direct child of data-[orientation=horizontal] + '[&[data-orientation=horizontal]_>_*]:h-full', // Vertical 'data-[orientation=vertical]:gap-2', 'data-[orientation=vertical]:justify-start', diff --git a/packages/frontend/src/components/shared/Tag/Tag.theme.ts b/packages/frontend/src/components/shared/Tag/Tag.theme.ts index 086b59b3..a027185d 100644 --- a/packages/frontend/src/components/shared/Tag/Tag.theme.ts +++ b/packages/frontend/src/components/shared/Tag/Tag.theme.ts @@ -5,25 +5,25 @@ export const tagTheme = tv( { slots: { wrapper: ['flex', 'gap-1.5', 'rounded-lg', 'border'], - icon: ['h-4', 'w-4'], + icon: [], label: ['font-inter', 'text-xs'], }, variants: { type: { attention: { - icon: ['text-elements-warning'], + wrapper: ['text-elements-warning'], }, negative: { - icon: ['text-elements-danger'], + wrapper: ['text-elements-danger'], }, positive: { - icon: ['text-elements-success'], + wrapper: ['text-elements-success'], }, emphasized: { - icon: ['text-elements-on-secondary'], + wrapper: ['text-elements-on-secondary'], }, neutral: { - icon: ['text-elements-mid-em'], + wrapper: ['text-elements-mid-em'], }, }, style: { @@ -36,9 +36,11 @@ export const tagTheme = tv( size: { sm: { wrapper: ['px-2', 'py-2'], + icon: ['h-4', 'w-4'], }, xs: { - wrapper: ['px-2', 'py-1.5'], + wrapper: ['px-2', 'py-1'], + icon: ['h-3', 'w-3'], }, }, }, diff --git a/packages/frontend/src/components/shared/Tag/Tag.tsx b/packages/frontend/src/components/shared/Tag/Tag.tsx index 086d3515..8be34c85 100644 --- a/packages/frontend/src/components/shared/Tag/Tag.tsx +++ b/packages/frontend/src/components/shared/Tag/Tag.tsx @@ -27,6 +27,8 @@ export const Tag = ({ type = 'attention', style = 'default', size = 'sm', + className, + ...props }: TagProps) => { const { wrapper: wrapperCls, @@ -51,7 +53,7 @@ export const Tag = ({ }, [cloneIcon, iconCls, rightIcon]); return ( -
+
{renderLeftIcon}

{children}

{renderRightIcon} diff --git a/packages/frontend/src/pages/org-slug/projects/Id.tsx b/packages/frontend/src/pages/org-slug/projects/Id.tsx index 37ce9719..8b164852 100644 --- a/packages/frontend/src/pages/org-slug/projects/Id.tsx +++ b/packages/frontend/src/pages/org-slug/projects/Id.tsx @@ -8,18 +8,13 @@ import { } from 'react-router-dom'; import { Project as ProjectType } from 'gql-client'; -import { - Button, - Tab, - Tabs, - TabsBody, - TabsHeader, - Typography, -} from '@material-tailwind/react'; - -import HorizontalLine from '../../../components/HorizontalLine'; import { useGQLClient } from '../../../context/GQLClientContext'; import { useOctokit } from '../../../context/OctokitContext'; +import { Button } from 'components/shared/Button'; +import { ChevronLeft } from 'components/shared/CustomIcon'; +import { WavyBorder } from 'components/shared/WavyBorder'; +import { Heading } from 'components/shared/Heading'; +import { Tabs } from 'components/shared/Tabs'; const Id = () => { const { id } = useParams(); @@ -69,96 +64,61 @@ const Id = () => {
{project ? ( <> -
- - - {project?.name} - - +
+
- - + variant="tertiary" + className="rounded-full h-11 w-11 p-0" + aria-label="Go back" + leftIcon={} + onClick={() => navigate(-1)} + /> + + {project?.name} + +
+
+ + + + +
- -
- - - - - Overview - - - - - Deployments - - - - - Database - - - - - Integrations - - - - - Settings - - - - + +
+ + + + Overview + + + Deployments + + + Database + + + Integrations + + + Settings + + + {/* Not wrapping in Tab.Content because we are using Outlet */} +
- +
) : ( -

Project not found

+
+ + Project not found. + +
)}
); diff --git a/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx b/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx index 21f281c1..81cdbe16 100644 --- a/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx +++ b/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx @@ -1,18 +1,30 @@ import React, { useEffect, useState } from 'react'; import { Domain, DomainStatus } from 'gql-client'; -import { useNavigate, useOutletContext } from 'react-router-dom'; +import { Link, useNavigate, useOutletContext } from 'react-router-dom'; import { RequestError } from 'octokit'; -import { Typography, Chip, Avatar, Tooltip } from '@material-tailwind/react'; - -import ActivityCard from '../../../../components/projects/project/ActivityCard'; -import { relativeTimeMs } from '../../../../utils/time'; 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'; +import { Avatar } from 'components/shared/Avatar'; +import { getInitials } from 'utils/geInitials'; +import { + BranchStrokeIcon, + CheckRoundFilledIcon, + ClockIcon, + CursorBoxIcon, + GithubStrokeIcon, + GlobeIcon, + LinkIcon, + StorageIcon, +} from 'components/shared/CustomIcon'; +import { Tag } from 'components/shared/Tag'; +import { Activity } from 'components/projects/project/overview/Activity'; +import { OverviewInfo } from 'components/projects/project/overview/OverviewInfo'; +import { CalendarDaysIcon } from 'components/shared/CustomIcon/CalendarDaysIcon'; +import { relativeTimeMs } from 'utils/time'; const COMMITS_PER_PAGE = 4; @@ -103,92 +115,109 @@ const OverviewTabPanel = () => { }, [project]); return ( -
+
-
+
-
- {project.name} - +
+ + {project.name} + + {project.subDomain} - +
-
-
^ Domain
+ }> {liveDomain ? ( - + }> + Connected + ) : ( -
- +
+ }> + Not connected +
)} -
+
{project.deployments.length !== 0 ? ( <> -
-

^ Source

-

^ {project.deployments[0]?.branch}

-
-
-

^ Deployment

-

{liveDomain?.name}

-
-
-

^ Created

-

- {relativeTimeMs(project.deployments[0].createdAt)} by ^{' '} - - {formatAddress(project.deployments[0].createdBy.name ?? '')} - -

-
+ {/* SOURCE */} + }> +
+ + + {project.deployments[0]?.branch} + +
+
+ + {/* DATABASE */} + }> +
+ + + {/* // TODO: add db name + dbname + */} + + + +
+
+ + {/* DEPLOYMENT */} + }> +
+ + + {liveDomain?.name}{' '} + + + +
+
+ + {/* DEPLOYMENT DATE */} + }> +
+ {relativeTimeMs(project.deployments[0].createdAt)} + by + + {project.deployments[0]?.createdBy?.name} +
+
) : ( -
No current deployment found
+

+ No current deployment found. +

)}
-
-
- Activity - -
-
- {activities.map((activity, index) => { - return ( - - ); - })} -
-
+
); }; diff --git a/packages/frontend/src/utils/cloneElement.tsx b/packages/frontend/src/utils/cloneElement.tsx new file mode 100644 index 00000000..202f9e45 --- /dev/null +++ b/packages/frontend/src/utils/cloneElement.tsx @@ -0,0 +1,43 @@ +import React, { + ReactElement, + isValidElement, + Children, + cloneElement as reactCloneElement, + HTMLProps, + ReactNode, +} from 'react'; +import { ClassProp } from 'tailwind-variants'; +import { cn } from './classnames'; + +interface cloneElement extends HTMLProps { + element: ReactNode; + themeStyle?: (props: ClassProp) => string; +} + +export const cloneElement = ({ + element, + themeStyle, + className, + ...props +}: cloneElement) => { + if (isValidElement(element)) { + return ( + <> + {Children.map(element, (child) => { + const originalClassName = (child.props as HTMLProps) + ?.className; + + return reactCloneElement(child as ReactElement, { + className: themeStyle + ? themeStyle({ + className: cn(originalClassName, className), // overriding icon classNames + }) + : originalClassName, + ...props, + }); + })} + + ); + } + return <>; +};