.ts
TypeScript
(application/typescript)
// 3rd-party
import React from "react";
import styled, { css } from "styled-components";
// 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 { useMediaQuery } from "../utils/hooks/useMediaQuery";
import { AppRoute } from "../routes.defs";
import { KeyIcon } from "./icons/KeyIcon";
import { SupportIcon } from "./icons/SupportIcon";
import { LogOutIcon } from "./icons/LogOutIcon";
import { UserIcon } from "./icons/UserIcon";
import { CommentIcon } from "./icons/CommentIcon";

export const DrawerSettings = ({
  visible = false,
  commonProps,
  themeScheme,
  username,
  counters = {
    sshKeys: 0,
  },
}: WithThemeSchemeProp & {
  visible: boolean;
  commonProps: CommonViewProps;
  username: string;
  counters?: RepositoryCountersDTO;
}) => {
  const pathMyAccount = buildRouteLink(
    AppRoute.USER_DETAILS,
    {
      username: username,
    },
    { encodeURIComponent: false },
  );

  const pathSSHKeys = buildRouteLink(
    AppRoute.SETTINGS_KEYS,
    {
      username: username,
    },
    { encodeURIComponent: false },
  );

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

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

  console.log("counters:", counters);

  return (
    <>
      <StyledDrawerSettings id="drawer" themeScheme={themeScheme}>
        <StyledDrawerHeader>
          <StyledLogoArea themeScheme={themeScheme}>
            <a href={"/"}>
              <h1>{Const.APP_NAME}</h1>
            </a>
          </StyledLogoArea>
        </StyledDrawerHeader>
        <StyledDrawerContent>
          <StyledDrawerListHeader>
            <img
              src={commonProps.currentUserAvatarUri || ""}
              style={{
                width: 20,
                height: 20,
                background: "red",
                borderRadius: 16,
                marginRight: 8,
              }}
            />
            <a
              href={buildRouteLink(
                AppRoute.USER_DETAILS,
                { username },
                { encodeURIComponent: false },
              )}
            >
              @{username}
            </a>
          </StyledDrawerListHeader>
          <StyledDrawerList>
            <StyledDrawerListItem
              themeScheme={themeScheme}
              href={pathMyAccount}
              className={
                // commonProps.path!.startsWith(pathMyAccount) ||
                commonProps.path! === pathMyAccount ? "active" : undefined
              }
            >
              <span>Repositories</span>
              <UserIcon
                color={NamedColors.TEXT_DEFAULT[themeScheme]}
                size={20}
              />
            </StyledDrawerListItem>
            <StyledDrawerListItem
              themeScheme={themeScheme}
              href={pathSSHKeys}
              className={
                commonProps.path! === pathSSHKeys ||
                commonProps.path!.startsWith(pathSSHKeys)
                  ? "active"
                  : undefined
              }
            >
              <span>SSH Keys</span>
              <Chip themeScheme={themeScheme} style={{ marginRight: 8 }}>
                {counters.sshKeys || 0}
              </Chip>
              <KeyIcon
                color={NamedColors.TEXT_DEFAULT[themeScheme]}
                size={24}
              />
            </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>
              {counters.helpCenterNotifs! > 0 && (
                <Chip themeScheme={themeScheme}>
                  {counters.helpCenterNotifs}
                </Chip>
              )}
              <SupportIcon
                color={NamedColors.TEXT_MUTED[themeScheme]}
                size={20}
              />
            </StyledDrawerListItem>
            <StyledDrawerListItem
              themeScheme={themeScheme}
              href={buildRouteLink(AppRoute.AUTH_LOGOUT_ACTION, null)}
            >
              <span>Logout</span>
              <LogOutIcon
                color={NamedColors.TEXT_DEFAULT[themeScheme]}
                size={20}
              />
            </StyledDrawerListItem>
          </StyledDrawerList>
        </StyledDrawerFooter>
      </StyledDrawerSettings>
      <StyledDrawerOverlay href="#?"></StyledDrawerOverlay>
    </>
  );
};

const StyledDrawerOverlay = styled.a`
  display: none;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  width: 100vw;
  height: 100vh;
  z-index: 21000;
  pointer-events: none;
  user-select: none;
  background: rgba(0, 0, 0, 0.4);
  backdrop-filter: blur(3px);
  opacity: 0;
  transition: opacity 140ms ease-in-out 140ms;
`;

const StyledDrawerSettings = 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.DRAWER[themeScheme]};
    backdrop-filter: blur(8px);
    border-right: 1px solid ${NamedColors.BORDER_DEFAULT[themeScheme]};

    transition: transform 140ms cubic-bezier(0, 0, 0.2, 1);

    @media only screen and (max-width: 768px) {
      & {
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        z-index: 12000;
        width: 85vw;
        max-width: 320px;
        transition: transform 140ms cubic-bezier(0, 0, 0.2, 1);
        transform: translateX(-100%);
      }

      &:target {
        transform: translateX(0);
      }

      &:target ~ ${StyledDrawerOverlay} {
        display: flex;
        pointer-events: auto;
        opacity: 1;
        z-index: 9999;
      }
    }
  `};
`;

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