diff options
Diffstat (limited to 'src/components')
| -rw-r--r-- | src/components/ProjectSummary/ProjectSummary.module.scss | 73 | ||||
| -rw-r--r-- | src/components/ProjectSummary/ProjectSummary.tsx | 122 |
2 files changed, 195 insertions, 0 deletions
diff --git a/src/components/ProjectSummary/ProjectSummary.module.scss b/src/components/ProjectSummary/ProjectSummary.module.scss new file mode 100644 index 0000000..cf1e77f --- /dev/null +++ b/src/components/ProjectSummary/ProjectSummary.module.scss @@ -0,0 +1,73 @@ +@use "@styles/abstracts/functions" as fun; + +.wrapper { + margin-bottom: var(--spacing-md); + padding: var(--spacing-sm) var(--spacing-md) var(--spacing-md); + border: fun.convert-px(1) solid var(--color-border); +} + +.cover { + height: fun.convert-px(150); + position: relative; +} + +.info { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(20ch, 1fr)); + align-items: start; + justify-content: left; + column-gap: var(--spacing-md); + margin: var(--spacing-md) 0 0; +} + +.inline-data { + display: inline-block; + margin-top: fun.convert-px(3); + + &:not(:last-of-type) { + margin-right: var(--spacing-xs); + } +} + +.techno { + padding: 0 var(--spacing-2xs); + border: fun.convert-px(1) solid var(--color-primary-darker); +} + +.repo { + display: block; + width: 3em; + height: 3em; + background: none; + box-shadow: fun.convert-px(1) fun.convert-px(1) fun.convert-px(1) + var(--color-shadow), + fun.convert-px(1) fun.convert-px(2) fun.convert-px(2) fun.convert-px(-1) + var(--color-shadow), + fun.convert-px(3) fun.convert-px(4) fun.convert-px(4) fun.convert-px(-3) + var(--color-shadow), + 0 0 0 0 var(--color-shadow); + transition: all 0.3s linear 0s; + + &:hover, + &:focus { + box-shadow: fun.convert-px(1) fun.convert-px(1) fun.convert-px(1) + var(--color-shadow), + fun.convert-px(1) fun.convert-px(1) fun.convert-px(2) fun.convert-px(-1) + var(--color-shadow-light), + fun.convert-px(3) fun.convert-px(3) fun.convert-px(4) fun.convert-px(-4) + var(--color-shadow-light), + fun.convert-px(6) fun.convert-px(6) fun.convert-px(10) fun.convert-px(-3) + var(--color-shadow); + transform: scale(1.15); + } + + &:focus { + outline: var(--color-primary) dashed fun.convert-px(2); + } + + &:active { + box-shadow: 0 0 0 0 var(--color-shadow); + outline: none; + transform: scale(0.9); + } +} diff --git a/src/components/ProjectSummary/ProjectSummary.tsx b/src/components/ProjectSummary/ProjectSummary.tsx new file mode 100644 index 0000000..0d00f06 --- /dev/null +++ b/src/components/ProjectSummary/ProjectSummary.tsx @@ -0,0 +1,122 @@ +import GithubIcon from '@assets/images/social-media/github.svg'; +import GitlabIcon from '@assets/images/social-media/gitlab.svg'; +import { t } from '@lingui/macro'; +import { getRepoData } from '@services/repos/github'; +import { ProjectMeta } from '@ts/types/app'; +import { RepoData } from '@ts/types/github'; +import { slugify } from '@utils/helpers/slugify'; +import Image from 'next/image'; +import { useRouter } from 'next/router'; +import { useEffect, useState } from 'react'; +import styles from './ProjectSummary.module.scss'; + +const ProjectSummary = ({ + slug, + title, + cover, + meta, +}: { + slug: string; + title: string; + cover: string; + meta: ProjectMeta; +}) => { + const { license, repos, technologies } = meta; + const [data, setData] = useState<RepoData>(); + const { locale } = useRouter(); + const githubUser = process.env.NEXT_PUBLIC_GITHUB_USER; + + useEffect(() => { + getRepoData(slug) + .then((repoData) => setData(repoData)) + .catch((e) => console.error(e)); + }, [slug]); + + const getFormattedDate = (date: string) => { + const dateOptions: Intl.DateTimeFormatOptions = { + day: 'numeric', + month: 'long', + year: 'numeric', + }; + + return new Date(date).toLocaleDateString(locale, dateOptions); + }; + + return ( + <div className={styles.wrapper}> + <div className={styles.cover}> + <Image + src={cover} + alt={t`${title} preview`} + layout="fill" + objectFit="contain" + /> + </div> + <dl className={styles.info}> + {data && ( + <div className={styles.info__item}> + <dt>{t`Created on`}</dt> + <dd>{t`${getFormattedDate(data.created_at)}`}</dd> + </div> + )} + {data && ( + <div className={styles.info__item}> + <dt>{t`Last updated on`}</dt> + <dd>{t`${getFormattedDate(data.updated_at)}`}</dd> + </div> + )} + <div className={styles.info__item}> + <dt>{t`License`}</dt> + <dd>{license}</dd> + </div> + {technologies && ( + <div className={styles.info__item}> + <dt>{t`Technologies`}</dt> + {technologies.map((techno) => ( + <dd + key={slugify(techno)} + className={`${styles.techno} ${styles['inline-data']}`} + > + {techno} + </dd> + ))} + </div> + )} + {repos && ( + <div className={styles.info__item}> + <dt>{t`Repositories`}</dt> + {repos.github && ( + <dd className={styles['inline-data']}> + <a href={repos.github} className={styles.repo}> + <GithubIcon /> + <span className="screen-reader-text">Github</span> + </a> + </dd> + )} + {repos.gitlab && ( + <dd className={styles['inline-data']}> + <a href={repos.gitlab} className={styles.repo}> + <GitlabIcon /> + <span className="screen-reader-text">Gitlab</span> + </a> + </dd> + )} + </div> + )} + {data && ( + <div> + <dt>{t`Popularity`}</dt> + <dd> + ⭐ + <a href={`https://github.com/${githubUser}/${slug}/stargazers`}> + {t`${data.stargazers_count} stars on Github`} + </a> + </dd> + </div> + )} + </dl> + </div> + ); +}; + +export default ProjectSummary; |
