.ts
TypeScript
(application/typescript)
// 1st-party
import type { ReactIsland } from "@ethicdevs/react-monolith";
// 3rd-party
import React from "react";
import styled, { css } from "styled-components";
// generated via script[generate:prisma]
import type { Organization, Repository } from "@prisma/client";
// app
import type {
  RepositoryForkedFromRepoMeta,
  WithThemeSchemeProp,
} from "../types";
import { buildRouteLink } from "../utils/shared";
import { ButtonAnchor } from "../components/Button.styled";
import { BackIcon } from "../components/icons/BackIcon";
import { GitForkIcon } from "../components/icons/GitForkIcon";
import { Grid } from "../components/Grid";
import { AppRoute } from "../routes.defs";
import { Colors, NamedColors } from "../utils/style";
import { useMediaQuery } from "../utils/hooks/useMediaQuery";
// import { theme } from "../theme";

export interface RepositoryHeroProps {
  parentOrg: Organization;
  repo: Repository;
  forkedFromRepo?: RepositoryForkedFromRepoMeta | null;
  forksCount?: number;
  path?: string;
  separator?: string;
  showForkButton?: boolean;
  showNewButton?: boolean;
  newButtonUrl?: string;
  newButtonText?: string | JSX.Element;
}

const RepositoryHero: ReactIsland<
  RepositoryHeroProps & WithThemeSchemeProp
> = ({
  themeScheme,
  parentOrg,
  repo,
  forkedFromRepo = null,
  forksCount = 0,
  path = undefined,
  // separator = "∙",
  showForkButton = true,
  showNewButton = false,
  newButtonUrl = undefined,
  newButtonText = "New Repository",
}) => {
  const isMobile = useMediaQuery("sm");

  return (
    <Grid.Col
      fluid
      gap={16}
      style={{
        borderBottom: `1px solid ${NamedColors.BORDER_DEFAULT[themeScheme]}`,
      }}
    >
      <Grid.Row fluid nowrap alignItems={"flex-start"}>
        <StyledActionIconButtonAnchor
          themeScheme={themeScheme}
          onClick={
            typeof window !== "undefined"
              ? () => window.history.back()
              : undefined
          }
          visible
        >
          <BackIcon color={NamedColors.TEXT_DEFAULT[themeScheme]} size={24} />
        </StyledActionIconButtonAnchor>
        <Grid.Col
          nowrap
          flex={"1 0 300px"}
          style={{ minWidth: 300, marginBottom: 12, marginLeft: 12 }}
        >
          <h2 style={{ margin: 0, fontSize: isMobile ? 20 : 20 }}>
            <a
              style={{ whiteSpace: "nowrap" }}
              href={buildRouteLink(AppRoute.ORGANIZATION_DETAILS, {
                orgSlug: parentOrg.slug,
              })}
            >
              {parentOrg.displayName || parentOrg.slug}
            </a>
            {" / "}
            <a
              style={{ whiteSpace: "nowrap" }}
              href={buildRouteLink(AppRoute.REPOSITORY_DETAILS, {
                orgSlug: parentOrg.slug,
                repoSlug: repo.slug,
              })}
            >
              {repo.displayName || repo.slug}
            </a>
          </h2>
          <div style={{ flex: 1 }}>
            <h3
              style={{
                whiteSpace: "nowrap",
                margin: 0,
                marginTop: 4,
                fontSize: 16,
                fontWeight: "700",
                fontFamily: "monospace",
              }}
            >
              {path || "Files"}
            </h3>
          </div>
          <div style={{ flex: 1 }}>
            {repo.isFork && forkedFromRepo != null && (
              <h5 style={{ margin: 0, marginTop: 8 }}>
                <span>Forked From</span>
                {" ∙ "}
                <a
                  href={buildRouteLink(AppRoute.ORGANIZATION_DETAILS, {
                    orgSlug: forkedFromRepo.organization.slug,
                  })}
                >
                  {forkedFromRepo.organization.displayName ||
                    forkedFromRepo.organization.slug}
                </a>
                {" / "}
                <a
                  href={buildRouteLink(AppRoute.REPOSITORY_DETAILS, {
                    orgSlug: forkedFromRepo.organization.slug,
                    repoSlug: forkedFromRepo.slug,
                  })}
                >
                  {forkedFromRepo.displayName || forkedFromRepo.slug}
                </a>
              </h5>
            )}
          </div>
        </Grid.Col>
        {showForkButton && (
          <ButtonAnchor
            href={buildRouteLink(AppRoute.REPOSITORY_FORK, {
              orgSlug: parentOrg.slug,
              repoSlug: repo.slug,
            })}
          >
            <Grid.Row
              nowrap
              justifyContent={"center"}
              alignItems={"center"}
              gap={8}
            >
              <GitForkIcon color={Colors.WHITE_01} size={24} />
              <span>Fork</span>
              <span
                style={{
                  padding: "2px 6px",
                  minWidth: 20,
                  background: "rgba(0,0,0,0.1)",
                  borderRadius: 8,
                  fontSize: 12,
                }}
              >
                {forksCount}
              </span>
            </Grid.Row>
          </ButtonAnchor>
        )}
        {showNewButton && (
          <ButtonAnchor href={newButtonUrl}>{newButtonText}</ButtonAnchor>
        )}
      </Grid.Row>
    </Grid.Col>
  );
};

RepositoryHero.displayName = "RepositoryHero";
export default RepositoryHero;

const StyledActionIconButtonAnchor = styled.button<
  WithThemeSchemeProp & { visible?: boolean }
>`
  ${({ themeScheme, visible = true }) => css`
    display: ${visible ? "flex" : "none"};

    justify-content: center;
    align-items: center;

    width: 44px;
    min-width: 44px;
    max-width: 44px;
    height: 44px;
    min-height: 44px;
    max-height: 44px;

    padding-top: -2px;

    font-size: 14px;
    font-weight: thin;
    color: ${NamedColors.TEXT_MUTED[themeScheme]};
    background: ${NamedColors.CARD_OVERLAY[themeScheme]};
    border-image: none;
    border: none;
    border-radius: 22px;
    cursor: pointer;

    &.active,
    &:hover {
      color: ${NamedColors.TEXT_DEFAULT[themeScheme]};
      background: ${NamedColors.CARD[themeScheme]};
    }

    &:active {
      font-size: 22px;
    }
  `}
`;