Add layout for overview panel in project details page (#3)

* Create layout for overview panel

* Populate project details in overview panel

* Add more types

* Fix typo

---------

Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
Nabarun Gogoi 2023-12-14 18:17:46 +05:30 committed by GitHub
parent 348ff92fa9
commit 5a17747be2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 209 additions and 42 deletions

View File

@ -0,0 +1,37 @@
[
{
"author": "Bob",
"authorAvatar": "^",
"createdAt": "2023-12-11T04:20:00",
"branch": "main",
"message": "Design integrate and tested"
},
{
"author": "Alice",
"authorAvatar": "^",
"createdAt": "2023-12-11T04:20:00",
"branch": "prod",
"message": "Fix lint errors"
},
{
"author": "Charlie",
"authorAvatar": "^",
"createdAt": "2023-12-11T04:20:00",
"branch": "main",
"message": "Sidebar changed"
},
{
"author": "Roy",
"authorAvatar": "^",
"createdAt": "2023-12-11T04:20:00",
"branch": "staging",
"message": "Add style to the page"
},
{
"author": "Brad",
"authorAvatar": "^",
"createdAt": "2023-12-11T04:20:00",
"branch": "dev",
"message": "404 not found"
}
]

View File

@ -4,9 +4,13 @@
"icon": "^", "icon": "^",
"title": "iglotools", "title": "iglotools",
"domain": "iglotools.com", "domain": "iglotools.com",
"createdAt": "2023-12-07T04:20:00",
"createdBy": "Bob",
"deployment": "iglotools.snowball.com",
"source": "feature/add-remote-control",
"latestCommit": { "latestCommit": {
"message": "Subscription added", "message": "Subscription added",
"time": "2023-12-11T04:20:00", "createdAt": "2023-12-11T04:20:00",
"branch": "main" "branch": "main"
} }
}, },
@ -15,9 +19,13 @@
"icon": "^", "icon": "^",
"title": "snowball-starter-kit", "title": "snowball-starter-kit",
"domain": "snowball-starter-kit.com", "domain": "snowball-starter-kit.com",
"createdAt": "2023-12-04T04:20:00",
"createdBy": "Erin",
"deployment": "snowball-starter-kit.com",
"source": "prod/add-docker-compose",
"latestCommit": { "latestCommit": {
"message": "404 added", "message": "404 added",
"time": "2023-12-11T04:20:00", "createdAt": "2023-12-11T04:20:00",
"branch": "staging" "branch": "staging"
} }
}, },
@ -26,9 +34,13 @@
"icon": "^", "icon": "^",
"title": "passkeys-demo", "title": "passkeys-demo",
"domain": "passkeys-demo.com", "domain": "passkeys-demo.com",
"createdAt": "2023-12-01T04:20:00",
"createdBy": "Charlie",
"deployment": "passkeys-demo.com",
"source": "dev/style-page",
"latestCommit": { "latestCommit": {
"message": "Design system integrated", "message": "Design system integrated",
"time": "2023-12-11T04:20:00", "createdAt": "2023-12-01T04:20:00",
"branch": "main" "branch": "main"
} }
}, },
@ -37,9 +49,13 @@
"icon": "^", "icon": "^",
"title": "watcher-tool", "title": "watcher-tool",
"domain": "azimuth-watcher.com", "domain": "azimuth-watcher.com",
"createdAt": "2023-12-11T04:20:00",
"createdBy": "Alice",
"deployment": "azimuth-watcher.com",
"source": "prod/fix-error",
"latestCommit": { "latestCommit": {
"message": "Listen for subscription", "message": "Listen for subscription",
"time": "2023-12-10T04:20:00", "createdAt": "2023-12-09T04:20:00",
"branch": "prod" "branch": "prod"
} }
} }

View File

@ -0,0 +1,33 @@
import React from 'react';
import { relativeTime } from '../utils/time';
interface ActivityDetails {
author: string;
authorAvatar: string;
createdAt: string;
branch: string;
message: string;
}
interface ActivityCardProps {
activity: ActivityDetails;
}
const ActivityCard = ({ activity }: ActivityCardProps) => {
return (
<div className="flex hover:bg-gray-200 rounded mt-1">
<div className="w-4">{activity.authorAvatar}</div>
<div className="grow text-sm text-gray-500">
<p className="text-black">{activity.author}</p>
<p className="text-xs">
{relativeTime(activity.createdAt)} ^ {activity.branch}
</p>
<p>{activity.message}</p>
</div>
</div>
);
};
export default ActivityCard;

View File

@ -0,0 +1,57 @@
import React from 'react';
import ActivityCard from './ActivityCard';
import activityDetails from '../assets/activities.json';
import { ProjectDetails } from '../types/project';
import { relativeTime } from '../utils/time';
interface OverviewProps {
project: ProjectDetails;
}
const Overview = ({ project }: OverviewProps) => (
<div className="grid grid-cols-5">
<div className="col-span-3 p-2">
<div className="flex items-center gap-2 p-2 ">
<div>^</div>
<div className="grow">
<p className="text-sm text-gray-700">{project.title}</p>
<p className="text-sm text-gray-400">{project.domain}</p>
</div>
</div>
<div className="flex justify-between p-2 text-sm">
<p>Domain</p>
<button>Set up</button>
</div>
<div className="flex justify-between p-2 text-sm">
<p>Source</p>
<p>{project.source}</p>
</div>
<div className="flex justify-between p-2 text-sm">
<p>deployment</p>
<p>{project.deployment}</p>
</div>
<div className="flex justify-between p-2 text-sm">
<p>Created</p>
<p>
{relativeTime(project.createdAt)} by {project.createdBy}
</p>
</div>
</div>
<div className="col-span-2 p-2">
<div className="flex justify-between">
<p>Activity</p>
<button className="text-xs bg-gray-300 rounded-full p-2">
See all
</button>
</div>
<div className="p-2">
{activityDetails.map((activity, key) => {
return <ActivityCard activity={activity} key={key} />;
})}
</div>
</div>
</div>
);
export default Overview;

View File

@ -1,19 +1,11 @@
import React from 'react'; import React from 'react';
import { DateTime } from 'luxon';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
interface projectDetails { import { relativeTime } from '../utils/time';
icon: string; import { ProjectDetails } from '../types/project';
title: string;
domain: string;
id: number;
latestCommit: {
[key: string]: string;
};
}
interface ProjectCardProps { interface ProjectCardProps {
project: projectDetails; project: ProjectDetails;
} }
const ProjectCard: React.FC<ProjectCardProps> = ({ project }) => { const ProjectCard: React.FC<ProjectCardProps> = ({ project }) => {
@ -32,7 +24,7 @@ const ProjectCard: React.FC<ProjectCardProps> = ({ project }) => {
<div className="border-slate-200 border-t-2 border-solid p-4 text-gray-500 text-xs"> <div className="border-slate-200 border-t-2 border-solid p-4 text-gray-500 text-xs">
<p>{project.latestCommit.message}</p> <p>{project.latestCommit.message}</p>
<p> <p>
{DateTime.fromISO(project.latestCommit.time).toRelative()} on{' '} {relativeTime(project.latestCommit.createdAt)} on{' '}
{project.latestCommit.branch} {project.latestCommit.branch}
</p> </p>
</div> </div>

View File

@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { DateTime } from 'luxon';
import { relativeTime } from '../utils/time';
interface RepositoryDetails { interface RepositoryDetails {
title: string; title: string;
@ -16,7 +17,7 @@ const ProjectRepoCard: React.FC<ProjectRepoCardProps> = ({ repository }) => {
<div>^</div> <div>^</div>
<div className="grow"> <div className="grow">
<p>{repository.title}</p> <p>{repository.title}</p>
<p>{DateTime.fromISO(repository.updatedTime).toRelative()}</p> <p>{relativeTime(repository.updatedTime)}</p>
</div> </div>
</div> </div>
); );

View File

@ -1,14 +1,13 @@
import React from 'react'; import React from 'react';
import { Tab, Tabs, TabList, TabPanel } from 'react-tabs'; import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
const Overview = () => ( import Overview from './Overview';
<div> import { ProjectDetails } from '../types/project';
Content of overview tab
<p className="block"> interface ProjectTabsProps {
Lorem Ipsum is simply dummy text of the printing and typesetting industry. project: ProjectDetails;
</p> }
</div>
);
const Deployments = () => ( const Deployments = () => (
<div> <div>
Content of deployments tab Content of deployments tab
@ -44,7 +43,7 @@ const Settings = () => (
</div> </div>
); );
const ProjectTab = () => { const ProjectTabs = ({ project }: ProjectTabsProps) => {
return ( return (
<Tabs <Tabs
selectedTabClassName={ selectedTabClassName={
@ -59,7 +58,7 @@ const ProjectTab = () => {
<Tab className={'p-2 cursor-pointer'}>Settings</Tab> <Tab className={'p-2 cursor-pointer'}>Settings</Tab>
</TabList> </TabList>
<TabPanel> <TabPanel>
<Overview /> <Overview project={project} />
</TabPanel> </TabPanel>
<TabPanel> <TabPanel>
<Deployments /> <Deployments />
@ -77,4 +76,4 @@ const ProjectTab = () => {
); );
}; };
export default ProjectTab; export default ProjectTabs;

View File

@ -6,7 +6,7 @@ import TemplateCard from '../../components/TemplateCard';
import RepositoryList from '../../components/RepositoryList'; import RepositoryList from '../../components/RepositoryList';
import ConnectAccount from '../../components/ConnectAccount'; import ConnectAccount from '../../components/ConnectAccount';
const isGitAuth = true; const IS_GIT_AUTH = true;
const CreateProject = () => { const CreateProject = () => {
return ( return (
@ -31,7 +31,7 @@ const CreateProject = () => {
})} })}
</div> </div>
<h5 className="mt-4 ml-4">Import a repository</h5> <h5 className="mt-4 ml-4">Import a repository</h5>
{isGitAuth ? <RepositoryList /> : <ConnectAccount />} {IS_GIT_AUTH ? <RepositoryList /> : <ConnectAccount />}
</div> </div>
); );
}; };

View File

@ -3,7 +3,7 @@ import { useNavigate, useParams } from 'react-router-dom';
import HorizontalLine from '../../components/HorizontalLine'; import HorizontalLine from '../../components/HorizontalLine';
import projects from '../../assets/projects.json'; import projects from '../../assets/projects.json';
import ProjectTab from '../../components/Tab'; import ProjectTabs from '../../components/Tab';
const getProject = (id: number) => { const getProject = (id: number) => {
return projects.find((project) => { return projects.find((project) => {
@ -18,16 +18,22 @@ const Project = () => {
return ( return (
<div className="bg-white rounded-3xl h-full"> <div className="bg-white rounded-3xl h-full">
<div className="flex p-4 gap-4"> {project ? (
<button onClick={() => navigate(-1)}>{'<'}</button> <>
<h3 className="grow">{project?.title} </h3> <div className="flex p-4 gap-4">
<button>Open Repo</button> <button onClick={() => navigate(-1)}>{'<'}</button>
<button>Go to app</button> <h3 className="grow">{project?.title} </h3>
</div> <button>Open Repo</button>
<HorizontalLine /> <button>Go to app</button>
<div className="p-4"> </div>
<ProjectTab /> <HorizontalLine />
</div> <div className="p-4">
<ProjectTabs project={project} />
</div>
</>
) : (
<h4>Project not found</h4>
)}
</div> </div>
); );
}; };

View File

@ -0,0 +1,15 @@
export interface ProjectDetails {
icon: string;
title: string;
domain: string;
id: number;
createdAt: string;
createdBy: string;
deployment: string;
source: string;
latestCommit: {
message: string;
createdAt: string;
branch: string;
};
}

View File

@ -0,0 +1,11 @@
import { DateTime } from 'luxon';
/**
* Converts an ISO 8601 formatted time to a human-readable relative time with respect to the current time.
*
* @param {string} time - The input time in ISO 8601 format.
* @returns {string} - A human-readable relative time string.
*/
export const relativeTime = (time: string) => {
return DateTime.fromISO(time).toRelative();
};