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 { Colors, NamedColors } from "../utils/style";
import {
  type RepositoryCountersDTO,
  type CommonViewProps,
  type WithThemeSchemeProp,
} from "../types";
// import { useMediaQuery } from "../utils/hooks/useMediaQuery";
import { buildRouteLink } from "../utils/shared";
import { AppRoute } from "../routes.defs";
// app components
import { Chip } from "./Chip";
import { TextEllipsis } from "./TextEllipsis.styled";
import { SupportIcon } from "./icons/SupportIcon";
import { SettingsIcon } from "./icons/SettingsIcon";
import { FolderIcon } from "./icons/FolderIcon";
import { CommentIcon } from "./icons/CommentIcon";
import { Grid } from "./Grid";
import { GitForkIcon } from "./icons/GitForkIcon";
import { GitPullIcon } from "./icons/GitPullIcon";
import { LikeIcon } from "./icons/LikeIcon";

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,
  });

  const pathPipelines = buildRouteLink(AppRoute.REPOSITORY_PIPELINES, {
    orgSlug: orgSlug,
    repoSlug: repoSlug,
  });

  // const isMobile = useMediaQuery("sm");
  // if (isMobile === false) {
  //   visible = true;
  // }

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

  return (
    <StyledDrawerPrimary id="drawer" themeScheme={themeScheme}>
      <StyledDrawerHeader>
        <StyledLogoArea themeScheme={themeScheme}>
          <a href={"/"}>
            <h1>{Const.APP_NAME}</h1>
          </a>
        </StyledLogoArea>
      </StyledDrawerHeader>
      <StyledDrawerContent>
        <StyledDrawerListHeader style={{ margin: 0 }}>
          <a href={buildRouteLink(AppRoute.ORGANIZATION_DETAILS, { orgSlug })}>
            @{orgSlug}
          </a>
          <span>{" / "}</span>
          <a
            href={buildRouteLink(AppRoute.REPOSITORY_DETAILS, {
              orgSlug,
              repoSlug,
            })}
          >
            <TextEllipsis>{repoSlug}</TextEllipsis>
          </a>
        </StyledDrawerListHeader>
        <StyledDrawerListHeader style={{ height: 32 }}>
          <Grid.Row
            fluid
            nowrap
            gap={8}
            justifyContent={"center"}
            alignItems={"center"}
          >
            <Grid.Row nowrap gap={4} alignItems={"center"}>
              <GitPullIcon
                color={NamedColors.TEXT_MUTED[themeScheme]}
                size={16}
              />
              <span style={{ fontSize: 11 }}>Watchers</span>
              <Chip
                themeScheme={themeScheme}
                color={NamedColors.TEXT_MUTED[themeScheme]}
                style={{
                  padding: "2px 6px",
                  backgroundColor: "rgba(0,0,0,0.1)",
                  fontSize: 11,
                  color: NamedColors.TEXT_MUTED[themeScheme],
                }}
              >
                {counters.watchers || "0"}
              </Chip>
            </Grid.Row>
            <Grid.Row nowrap gap={4} alignItems={"center"}>
              <LikeIcon color={NamedColors.TEXT_MUTED[themeScheme]} size={16} />
              <span style={{ fontSize: 11 }}>Likes</span>
              <Chip
                themeScheme={themeScheme}
                color={NamedColors.TEXT_MUTED[themeScheme]}
                style={{
                  padding: "2px 6px",
                  backgroundColor: "rgba(0,0,0,0.1)",
                  fontSize: 11,
                  color: NamedColors.TEXT_MUTED[themeScheme],
                }}
              >
                {counters.likes || "0"}
              </Chip>
            </Grid.Row>
            <Grid.Row nowrap gap={4} alignItems={"center"}>
              <GitForkIcon color={Colors.WHITE_01} size={16} />
              <span style={{ fontSize: 11 }}>Forks</span>
              <Chip
                themeScheme={themeScheme}
                color={NamedColors.TEXT_MUTED[themeScheme]}
                style={{
                  padding: "2px 6px",
                  backgroundColor: "rgba(0,0,0,0.1)",
                  fontSize: 11,
                  color: NamedColors.TEXT_MUTED[themeScheme],
                }}
              >
                {counters.forks || "0"}
              </Chip>
            </Grid.Row>
          </Grid.Row>
        </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
            }
            style={{ paddingRight: 16 }}
          >
            <span>Files</span>
            <FolderIcon
              color={
                (commonProps.path!.startsWith(pathFiles) ||
                  [pathFiles, pathRepo, pathRepoTrailing].some(
                    (p) =>
                      commonProps.path === p || commonProps.path!.startsWith(p),
                  )) &&
                commonProps.path!.startsWith(pathPulls) === false
                  ? NamedColors.TEXT_DEFAULT[themeScheme]
                  : NamedColors.TEXT_MUTED[themeScheme]
              }
              size={16}
            />
          </StyledDrawerListItem>
          <StyledDrawerListItem
            themeScheme={themeScheme}
            href={pathPulls}
            className={
              commonProps.path! === pathPulls ||
              commonProps.path!.startsWith(pathPulls)
                ? "active"
                : undefined
            }
          >
            <span>Pull Requests</span>
            <Chip themeScheme={themeScheme}>{counters.pulls || 0}</Chip>
          </StyledDrawerListItem>
          <StyledDrawerListItem
            themeScheme={themeScheme}
            href={pathPipelines}
            className={
              commonProps.path! === pathPipelines ||
              commonProps.path!.startsWith(pathPipelines)
                ? "active"
                : undefined
            }
          >
            <span>Pipelines</span>
            <Chip themeScheme={themeScheme}>{counters.builds || 0}</Chip>
          </StyledDrawerListItem>
          <StyledDrawerListItem themeScheme={themeScheme} disabled>
            <span>Tests & Coverage</span>
            <Chip themeScheme={themeScheme}>{counters.tests || 0}</Chip>
          </StyledDrawerListItem>
          <StyledDrawerListItem themeScheme={themeScheme} disabled>
            <span>Issues</span>
            <Chip themeScheme={themeScheme}>{counters.issues || 0}</Chip>
          </StyledDrawerListItem>
          <StyledDrawerListItem themeScheme={themeScheme} disabled>
            <span>API Reference</span>
            <Chip themeScheme={themeScheme}>{counters.apiRefSymbols || 0}</Chip>
          </StyledDrawerListItem>
        </StyledDrawerList>
        <StyledDrawerListHeader></StyledDrawerListHeader>
        <StyledDrawerList></StyledDrawerList>
      </StyledDrawerContent>
      <StyledDrawerFooter>
        <StyledDrawerList>
          <StyledDrawerListItem themeScheme={themeScheme} disabled>
            <span>Feedback</span>
            <CommentIcon
              color={NamedColors.TEXT_MUTED[themeScheme]}
              size={20}
            />
          </StyledDrawerListItem>
          <StyledDrawerListItem themeScheme={themeScheme} disabled>
            <span>Help Center</span>
            <span style={{ flex: 1 }}></span>
            {counters.helpCenterNotifs! > 0 && (
              <Chip themeScheme={themeScheme}>{counters.helpCenterNotifs}</Chip>
            )}
            <SupportIcon
              color={NamedColors.TEXT_MUTED[themeScheme]}
              size={20}
            />
          </StyledDrawerListItem>
          <StyledDrawerListItem themeScheme={themeScheme} disabled>
            <span>Settings</span>
            <SettingsIcon
              color={NamedColors.TEXT_MUTED[themeScheme]}
              size={20}
            />
          </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: 386px) {
      display: none;

      position: absolute;
      top: 0;
      left: 0;
      bottom: 0;
      z-index: 1000;
      width: 85vw;
      max-width: 320px;
      transform: translateX(-100%);

      &:target {
        transform: translateX(0);
        transition: transform 0.3s ease-in-out;
      }
    }
  `};
`;

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;
`;

GitFOSS • v0.2.0 (#421408f) • MIT License