GitFOSS
.ts
TypeScript
(application/typescript)
// 3rd-party
import React from "react";
import styled, { css } from "styled-components";
// import Color from "color";
// app
import { Const } from "../const";
import { Chip } from "./Chip";
import { NamedColors } from "../utils/style";
import {
  type RepositoryCountersDTO,
  type CommonViewProps,
  type WithThemeSchemeProp,
} from "../types";
import { buildRouteLink } from "../utils/shared";
import { AppRoute } from "../routes.defs";
import { TextEllipsis } from "./TextEllipsis.styled";

export const DrawerPrimary = ({
  visible = false,
  commonProps,
  themeScheme,
  orgSlug,
  repoSlug,
  currentRef = Const.DEFAULT_HEAD_REF,
  path = "/",
  counters = {
    pulls: 0,
    tests: 0,
    builds: 0,
    issues: 0,
    apiRefSymbols: 0,
  },
}: WithThemeSchemeProp & {
  visible: boolean;
  commonProps: CommonViewProps;
  orgSlug: string;
  repoSlug: string;
  currentRef?: string;
  path?: string;
  counters?: RepositoryCountersDTO;
}) => {
  const pathRepo = buildRouteLink(AppRoute.REPOSITORY_DETAILS, {
    orgSlug: orgSlug,
    repoSlug: repoSlug,
  });

  const pathRepoTrailing = buildRouteLink(
    AppRoute.REPOSITORY_DETAILS_WITH_TRAILING_SLASH,
    {
      orgSlug: orgSlug,
      repoSlug: repoSlug,
    },
  );

  const pathFiles = buildRouteLink(AppRoute.REPOSITORY_BROWSER, {
    orgSlug: orgSlug,
    repoSlug: repoSlug,
    currentRef: currentRef,
    "*": path,
  });

  const pathPulls = buildRouteLink(AppRoute.REPOSITORY_PULL_REQUESTS, {
    orgSlug: orgSlug,
    repoSlug: repoSlug,
  });

  if (visible === false) {
    return null;
  }

  return (
    <StyledDrawerPrimary themeScheme={themeScheme}>
      <StyledDrawerHeader>
        <StyledLogoArea themeScheme={themeScheme}>
          <a href={"/"}>
            <h1>{Const.APP_NAME}</h1>
          </a>
        </StyledLogoArea>
      </StyledDrawerHeader>
      <StyledDrawerContent>
        <StyledDrawerListHeader>
          <a href={buildRouteLink(AppRoute.ORGANIZATION_DETAILS, { orgSlug })}>
            @{orgSlug}
          </a>
          <span>{" / "}</span>
          <a
            href={buildRouteLink(AppRoute.REPOSITORY_DETAILS, {
              orgSlug,
              repoSlug,
            })}
          >
            <TextEllipsis>{repoSlug}</TextEllipsis>
          </a>
        </StyledDrawerListHeader>
        <StyledDrawerList>
          <StyledDrawerListItem
            themeScheme={themeScheme}
            href={pathFiles}
            className={
              (commonProps.path!.startsWith(pathFiles) ||
                [pathFiles, pathRepo, pathRepoTrailing].some(
                  (p) =>
                    commonProps.path === p || commonProps.path!.startsWith(p),
                )) &&
              commonProps.path!.startsWith(pathPulls) === false
                ? "active"
                : undefined
            }
          >
            <span>Files</span>
          </StyledDrawerListItem>
          <StyledDrawerListItem
            themeScheme={themeScheme}
            href={pathPulls}
            className={
              commonProps.path! === pathPulls ||
              commonProps.path!.startsWith(pathPulls)
                ? "active"
                : undefined
            }
          >
            <span>Pull Requests</span>
            <Chip>{counters.pulls || 0}</Chip>
          </StyledDrawerListItem>
          <StyledDrawerListItem themeScheme={themeScheme} disabled>
            <span>Tests & Coverage</span>
            <Chip>{counters.tests || 0}</Chip>
          </StyledDrawerListItem>
          <StyledDrawerListItem themeScheme={themeScheme} disabled>
            <span>Builds</span>
            <Chip>{counters.builds || 0}</Chip>
          </StyledDrawerListItem>
          <StyledDrawerListItem themeScheme={themeScheme} disabled>
            <span>Issues</span>
            <Chip>{counters.issues || 0}</Chip>
          </StyledDrawerListItem>
          <StyledDrawerListItem themeScheme={themeScheme} disabled>
            <span>API Reference</span>
            <Chip>{counters.apiRefSymbols || 0}</Chip>
          </StyledDrawerListItem>
        </StyledDrawerList>
        <StyledDrawerListHeader></StyledDrawerListHeader>
        <StyledDrawerList></StyledDrawerList>
      </StyledDrawerContent>
      <StyledDrawerFooter>
        <StyledDrawerList>
          <StyledDrawerListItem themeScheme={themeScheme} disabled>
            <span>Feedback</span>
          </StyledDrawerListItem>
          <StyledDrawerListItem themeScheme={themeScheme} disabled>
            <span>Help Center</span>
            {counters.helpCenterNotifs! > 0 && (
              <Chip>{counters.helpCenterNotifs}</Chip>
            )}
          </StyledDrawerListItem>
          <StyledDrawerListItem themeScheme={themeScheme} disabled>
            <span>Settings</span>
          </StyledDrawerListItem>
        </StyledDrawerList>
      </StyledDrawerFooter>
    </StyledDrawerPrimary>
  );
};

const StyledDrawerPrimary = styled.aside<
  WithThemeSchemeProp & { color?: string }
>`
  ${({ themeScheme }) => css`
    min-width: 300px;
    max-width: 320px;
    height: 100vh;

    display: flex;
    flex-flow: column nowrap;
    align-items: center;
    justify-content: center;

    position: sticky;
    top: 0;
    left: 0;
    bottom: 0;

    background: ${NamedColors.HEADER[themeScheme]};
    border-right: 1px solid ${NamedColors.BORDER_DEFAULT[themeScheme]};

    @media only screen and (max-width: 768px) {
      display: none;
    }
  `};
`;

const StyledDrawerHeader = styled.header`
  width: 100%;
  height: 64px;

  display: flex;
  justify-content: center;
  align-items: center;
`;

const StyledLogoArea = styled.div<WithThemeSchemeProp>`
  @media only screen and (max-width: 768px) {
    & > a > h1 {
      font-size: 22px;
    }
  }

  & > a {
    display: flex;
    flex-flow: row nowrap;
    justify-content: flex-start;
    align-items: center;

    ${({ themeScheme }) => css`
      color: ${NamedColors.TEXT_DEFAULT[themeScheme]};
    `};

    h1 {
      margin: 0;
    }
  }
`;

const StyledDrawerContent = styled.main`
  width: 100%;
  max-width: 100%;
  min-width: 100%;
  height: 100%;

  flex: 1;

  padding: 12px;
  overflow-y: auto;
`;

const StyledDrawerListHeader = styled.section`
  width: 100%;
  min-height: 40px;

  display: flex;
  flex-flow: row wrap;
  justify-content: center;
  align-items: center;

  font-weight: bold;

  margin-bottom: 12px;

  & > span {
    margin: 0 4px;
  }
`;

const StyledDrawerList = styled.section`
  width: 100%;

  display: flex;
  flex-flow: column nowrap;
  justify-content: flex-start;
  align-items: center;

  gap: 2px;
`;

const StyledDrawerListItem = styled.a<
  WithThemeSchemeProp & { disabled?: boolean }
>`
  ${({ disabled, themeScheme }) => css`
    width: 100%;
    height: 40px;

    display: flex;
    flex-flow: row nowrap;
    justify-content: flex-start;
    align-items: center;

    padding: 0 12px;

    font-weight: normal;
    font-size: 14px;
    color: ${NamedColors.TEXT_DEFAULT[themeScheme]};
    border-radius: 20px;
    text-decoration: none;

    & > span:nth-child(1) {
      flex: 1;
    }

    & > ${Chip} {
      color: ${NamedColors.TEXT_MUTED[themeScheme]};
      background-color: ${NamedColors.CARD_OVERLAY[themeScheme]};
    }

    ${(disabled == null || disabled === false) &&
    css`
      &.active,
      &:not(:disabled):hover {
        color: ${NamedColors.TEXT_DEFAULT[themeScheme]};
        background-color: ${NamedColors.CARD[themeScheme]};
        font-weight: bold;
        font-family: monospace;
      }
    `};

    &:hover {
      text-decoration: none;
    }

    &:disabled {
      color: ${NamedColors.TEXT_MUTED[themeScheme]};
    }

    ${disabled &&
    css`
      color: ${NamedColors.TEXT_MUTED[themeScheme]};

      & > ${Chip} {
        color: ${NamedColors.TEXT_MUTED[themeScheme]};
        opacity: 0.3;
      }
    `}
  `}
`;

const StyledDrawerFooter = styled.footer`
  width: 100%;
  height: 128px;

  display: flex;
  justify-content: flex-start;
  align-items: center;

  margin: 16px 0;
  padding: 0 12px;
`;