chore(ui): small design adjustments
+ 282
- 58
app/components/Chip.ts
@@ -17,12 +17,13 @@ export const Chip = styled.div<WithThemeSchemeProp & { color?: string }>`
 
     font-weight: bold;
     text-transform: uppercase;
+    text-decoration: none !important;
 
     color: ${color
-      ? Color(color).alpha(1).toString()
+      ? Color(color).alpha(1).lightness(0.3).toString()
       : NamedColors.TEXT_DEFAULT[themeScheme]};
     background-color: ${color
-      ? Color(color).alpha(0.3).toString()
+      ? Color(color).alpha(0.2).toString()
       : "rgba(0, 0, 0, 0.3)"};
     border-radius: 8px;
   `};

app/components/DrawerPrimary.tsx
@@ -10,6 +10,7 @@ import {
   type CommonViewProps,
   type WithThemeSchemeProp,
 } from "../types";
+import { useMediaQuery } from "../utils/hooks/useMediaQuery";
 import { buildRouteLink } from "../utils/shared";
 import { AppRoute } from "../routes.defs";
 // app components

...
@@ -73,12 +74,17 @@ export const DrawerPrimary = ({
     repoSlug: repoSlug,
   });
 
+  // const isMobile = useMediaQuery("sm");
+  // if (isMobile === false) {
+  //   visible = true;
+  // }
+
   if (visible === false) {
     return null;
   }
 
   return (
-    <StyledDrawerPrimary themeScheme={themeScheme}>
+    <StyledDrawerPrimary id="drawer" themeScheme={themeScheme}>
       <StyledDrawerHeader>
         <StyledLogoArea themeScheme={themeScheme}>
           <a href={"/"}>

...
@@ -122,6 +128,7 @@ export const DrawerPrimary = ({
                   padding: "2px 6px",
                   backgroundColor: "rgba(0,0,0,0.1)",
                   fontSize: 11,
+                  color: NamedColors.TEXT_MUTED[themeScheme],
                 }}
               >
                 {counters.watchers || "0"}

...
@@ -137,6 +144,7 @@ export const DrawerPrimary = ({
                   padding: "2px 6px",
                   backgroundColor: "rgba(0,0,0,0.1)",
                   fontSize: 11,
+                  color: NamedColors.TEXT_MUTED[themeScheme],
                 }}
               >
                 {counters.likes || "0"}

...
@@ -152,6 +160,7 @@ export const DrawerPrimary = ({
                   padding: "2px 6px",
                   backgroundColor: "rgba(0,0,0,0.1)",
                   fontSize: 11,
+                  color: NamedColors.TEXT_MUTED[themeScheme],
                 }}
               >
                 {counters.forks || "0"}

...
@@ -173,6 +182,7 @@ export const DrawerPrimary = ({
                 ? "active"
                 : undefined
             }
+            style={{ paddingRight: 16 }}
           >
             <span>Files</span>
             <FolderIcon

...
@@ -276,8 +286,22 @@ const StyledDrawerPrimary = styled.aside<
     background: ${NamedColors.HEADER[themeScheme]};
     border-right: 1px solid ${NamedColors.BORDER_DEFAULT[themeScheme]};
 
-    @media only screen and (max-width: 768px) {
+    @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;
+      }
     }
   `};
 `;

app/components/DrawerSettings.tsx
@@ -11,6 +11,7 @@ import {
   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";

...
@@ -48,6 +49,11 @@ export const DrawerSettings = ({
     { encodeURIComponent: false },
   );
 
+  // const isMobile = useMediaQuery("sm");
+  // if (isMobile === false) {
+  //   visible = true;
+  // }
+
   if (visible === false) {
     return null;
   }

...
@@ -55,7 +61,7 @@ export const DrawerSettings = ({
   console.log("counters:", counters);
 
   return (
-    <StyledDrawerSettings themeScheme={themeScheme}>
+    <StyledDrawerSettings id="drawer" themeScheme={themeScheme}>
       <StyledDrawerHeader>
         <StyledLogoArea themeScheme={themeScheme}>
           <a href={"/"}>

...
@@ -173,8 +179,22 @@ const StyledDrawerSettings = styled.aside<
     background: ${NamedColors.HEADER[themeScheme]};
     border-right: 1px solid ${NamedColors.BORDER_DEFAULT[themeScheme]};
 
-    @media only screen and (max-width: 768px) {
+    @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;
+      }
     }
   `};
 `;

app/components/Layout.tsx
@@ -17,7 +17,7 @@ const BRANDLINE_HEIGHT = 4;
 const HEADER_HEIGHT = 64;
 
 // Default Layout implementation.
-// (dataloading happens through HOC at export level lower in file)
+// (dataloading happens in request context and pass through common props)
 const LayoutComponent: FC<LayoutProps & WithThemeSchemeProp> = (props) => {
   const {
     appVersion,

...
@@ -93,26 +93,30 @@ const LayoutComponent: FC<LayoutProps & WithThemeSchemeProp> = (props) => {
           <InstantRouterIndicator />
         </div>
         <StyledPageWrapper>
-          <DrawerPrimary
-            commonProps={props as any}
-            themeScheme={themeScheme}
-            visible={drawerPrimaryOpen}
-            counters={layoutCounters}
-            orgSlug={orgSlug}
-            repoSlug={repoSlug}
-            currentRef={currentRef}
-            path={path}
-          />
-          <DrawerSettings
-            commonProps={props as any}
-            themeScheme={themeScheme}
-            visible={drawerSettingsOpen}
-            counters={layoutCounters}
-            username={username!}
-          />
+          {showDrawerPrimary && (
+            <DrawerPrimary
+              commonProps={props as any}
+              themeScheme={themeScheme}
+              visible={drawerPrimaryOpen}
+              counters={layoutCounters}
+              orgSlug={orgSlug}
+              repoSlug={repoSlug}
+              currentRef={currentRef}
+              path={path}
+            />
+          )}
+          {showDrawerSettings && (
+            <DrawerSettings
+              commonProps={props as any}
+              themeScheme={themeScheme}
+              visible={drawerSettingsOpen}
+              counters={layoutCounters}
+              username={username!}
+            />
+          )}
           <StyledChildrenWrapper
             {...sharedProps}
-            showDrawerPrimary={drawerPrimaryOpen}
+            showDrawerPrimary={drawerPrimaryOpen || drawerSettingsOpen}
           >
             <StyledPageHeaderWrapper {...sharedProps}>
               <PageHeader

app/components/PageHeader.tsx
+ 16
- 12
@@ -24,19 +24,19 @@ export const PageHeader: VFC<PageHeaderProps & WithThemeSchemeProp> = ({
   commonProps,
   themeScheme,
   forceShowLogo = true,
-  setDrawerPrimaryOpen = undefined,
-  setDrawerSettingsOpen = undefined,
+  // setDrawerPrimaryOpen = undefined,
+  // setDrawerSettingsOpen = undefined,
 }) => {
   const invertThemeScheme = themeScheme === "light" ? "dark" : "light";
 
-  const toggleDrawerPrimary = () => {
-    if (setDrawerPrimaryOpen) {
-      setDrawerPrimaryOpen((prev) => !prev);
-    }
-    if (setDrawerSettingsOpen) {
-      setDrawerSettingsOpen((prev) => !prev);
-    }
-  };
+  // const toggleDrawerPrimary = () => {
+  //   if (setDrawerPrimaryOpen) {
+  //     setDrawerPrimaryOpen((prev) => !prev);
+  //   }
+  //   if (setDrawerSettingsOpen) {
+  //     setDrawerSettingsOpen((prev) => !prev);
+  //   }
+  // };
 
   const pageHeaderActions = useMemo(() => {
     if (commonProps.authenticated) {

...
@@ -86,7 +86,8 @@ export const PageHeader: VFC<PageHeaderProps & WithThemeSchemeProp> = ({
       <PageWrapper style={{ gap: 12 }}>
         <StyledBurgerMenu
           themeScheme={themeScheme}
-          onClick={toggleDrawerPrimary}
+          // onClick={toggleDrawerPrimary}
+          href="#drawer"
         >
           <BurgerMenuIcon
             color={NamedColors.TEXT_DEFAULT[themeScheme]}

...
@@ -102,6 +103,7 @@ export const PageHeader: VFC<PageHeaderProps & WithThemeSchemeProp> = ({
           <a
             aria-label={"Explore Repositories"}
             href={buildRouteLink(AppRoute.REPOSITORY_EXPLORE, null)}
+            style={{ minWidth: 88 }}
             className={
               commonProps.path ===
               buildRouteLink(AppRoute.REPOSITORY_EXPLORE, null)

...
@@ -174,12 +176,14 @@ export const PageHeader: VFC<PageHeaderProps & WithThemeSchemeProp> = ({
   );
 };
 
-const StyledBurgerMenu = styled.button<WithThemeSchemeProp>`
+const StyledBurgerMenu = styled.a<WithThemeSchemeProp>`
   ${({ themeScheme }) => css`
     display: flex;
     justify-content: center;
     align-items: center;
 
+    text-decoration: none;
+
     /* above mobile size */
     @media only screen and (min-width: 768px) {
       & {

app/islands/RepositoryTreeView.tsx
@@ -193,8 +193,8 @@ const RepositoryTreeView: ReactIsland<
           </Grid.Row>
           <Grid.Row nowrap alignItems={"center"}>
             <GitCommmitIcon
-              color={NamedColors.TEXT_DEFAULT[themeScheme]}
-              size={24}
+              color={NamedColors.TEXT_MUTED[themeScheme]}
+              size={20}
             />
             <a
               style={{ minWidth: "max-content" }}

app/utils/style/Colors.ts
@@ -29,6 +29,7 @@ const Colors = {
   PURPLE_01: "#23014D",
   CYAN_01: "#1B8F97",
   RED_01: "red",
+  GREEN_01: "green",
 };
 
 export default Colors;

new file
app/utils/style/color-utils.d.ts
@@ -0,0 +1,134 @@
+type ColorParam =
+  | Color
+  | string
+  | ArrayLike<number>
+  | number
+  | { [key: string]: any };
+
+interface Color<T extends ColorParam = ColorParam> {
+  toString(): string;
+  toJSON(): Color<T>;
+  string(places?: number): string;
+  percentString(places?: number): string;
+  array(): number[];
+  object(): { alpha?: number | undefined } & { [key: string]: number };
+  unitArray(): number[];
+  unitObject(): { r: number; g: number; b: number; alpha?: number | undefined };
+  round(places?: number): Color;
+  alpha(): number;
+  alpha(val: number): Color;
+  red(): number;
+  red(val: number): Color;
+  green(): number;
+  green(val: number): Color;
+  blue(): number;
+  blue(val: number): Color;
+  hue(): number;
+  hue(val: number): Color;
+  saturationl(): number;
+  saturationl(val: number): Color;
+  lightness(): number;
+  lightness(val: number): Color;
+  saturationv(): number;
+  saturationv(val: number): Color;
+  value(): number;
+  value(val: number): Color;
+  chroma(): number;
+  chroma(val: number): Color;
+  gray(): number;
+  gray(val: number): Color;
+  white(): number;
+  white(val: number): Color;
+  wblack(): number;
+  wblack(val: number): Color;
+  cyan(): number;
+  cyan(val: number): Color;
+  magenta(): number;
+  magenta(val: number): Color;
+  yellow(): number;
+  yellow(val: number): Color;
+  black(): number;
+  black(val: number): Color;
+  x(): number;
+  x(val: number): Color;
+  y(): number;
+  y(val: number): Color;
+  z(): number;
+  z(val: number): Color;
+  l(): number;
+  l(val: number): Color;
+  a(): number;
+  a(val: number): Color;
+  b(): number;
+  b(val: number): Color;
+  keyword(): string;
+  keyword<V extends string>(val: V): Color<V>;
+  hex(): string;
+  hex<V extends string>(val: V): Color<V>;
+  hexa(): string;
+  hexa<V extends string>(val: V): Color<V>;
+  rgbNumber(): number;
+  luminosity(): number;
+  contrast(color2: Color): number;
+  level(color2: Color): "AAA" | "AA" | "";
+  isDark(): boolean;
+  isLight(): boolean;
+  negate(): Color;
+  lighten(ratio: number): Color;
+  darken(ratio: number): Color;
+  saturate(ratio: number): Color;
+  desaturate(ratio: number): Color;
+  whiten(ratio: number): Color;
+  blacken(ratio: number): Color;
+  grayscale(): Color;
+  fade(ratio: number): Color;
+  opaquer(ratio: number): Color;
+  rotate(degrees: number): Color;
+  mix(mixinColor: Color, weight?: number): Color;
+
+  rgb(...args: number[]): Color;
+  hsl(...args: number[]): Color;
+  hsv(...args: number[]): Color;
+  hwb(...args: number[]): Color;
+  cmyk(...args: number[]): Color;
+  xyz(...args: number[]): Color;
+  lab(...args: number[]): Color;
+  lch(...args: number[]): Color;
+  ansi16(...args: number[]): Color;
+  ansi256(...args: number[]): Color;
+  hcg(...args: number[]): Color;
+  apple(...args: number[]): Color;
+}
+
+interface ColorConstructor {
+  <T extends ColorParam>(obj?: T, model?: string): Color<T>;
+  new <T extends ColorParam>(obj?: T, model?: string): Color<T>;
+  rgb(...val: number[]): Color;
+  rgb(color: ColorParam): Color;
+  hsl(...val: number[]): Color;
+  hsl(color: ColorParam): Color;
+  hsv(...val: number[]): Color;
+  hsv(color: ColorParam): Color;
+  hwb(...val: number[]): Color;
+  hwb(color: ColorParam): Color;
+  cmyk(...val: number[]): Color;
+  cmyk(color: ColorParam): Color;
+  xyz(...val: number[]): Color;
+  xyz(color: ColorParam): Color;
+  lab(...val: number[]): Color;
+  lab(color: ColorParam): Color;
+  lch(...val: number[]): Color;
+  lch(color: ColorParam): Color;
+  ansi16(...val: number[]): Color;
+  ansi16(color: ColorParam): Color;
+  ansi256(...val: number[]): Color;
+  ansi256(color: ColorParam): Color;
+  hcg(...val: number[]): Color;
+  hcg(color: ColorParam): Color;
+  apple(...val: number[]): Color;
+  apple(color: ColorParam): Color;
+}
+
+declare const Color: ColorConstructor;
+
+export = Color;

app/views/repositoryPullRequests/RepositoryPullRequestsView.tsx
@@ -13,7 +13,7 @@ import { Grid } from "../../components/Grid";
 import { Layout } from "../../components/Layout";
 import { PageWrapper } from "../../components/PageWrapper";
 import { buildRouteLink } from "../../utils/shared";
-import { NamedColors } from "../../utils/style";
+import { Colors, NamedColors } from "../../utils/style";
 // app islands
 import { IslandWrapper } from "../../components/IslandWrapper.styled";
 import RepositoryHero from "../../islands/RepositoryHero";

...
@@ -158,18 +158,15 @@ const RepositoryPullRequestsView: ReactView<
         </Grid.Col>
         <Grid.Col fluid gap={4} style={{ marginTop: 12 }}>
           {pullRequests != null && pullRequests.length >= 1 ? (
-            pullRequests.map((pr, idx) => (
+            pullRequests.map((pr) => (
               <Card
                 key={pr.id}
                 themeScheme={commonProps.themeScheme}
-                style={{ width: "100%" }}
+                style={{ width: "100%", padding: 8 }}
               >
-                <Grid.Col
-                  key={pr.id}
-                  fluid
-                  style={{ marginTop: idx === 0 ? 0 : 16 }}
-                >
+                <Grid.Col fluid>
                   <a
+                    style={{ width: "100%" }}
                     href={buildRouteLink(
                       AppRoute.REPOSITORY_PULL_REQUEST_DETAILS,
                       {

...
@@ -179,21 +176,61 @@ const RepositoryPullRequestsView: ReactView<
                       },
                     )}
                   >
-                    #{pr.uid} - {pr.summary} [{pr.state}]
+                    <Grid.Row fluid alignItems={"center"} gap={4}>
+                      <span>#{pr.uid}</span>
+                      <span>&bull;</span>
+                      <span style={{ flex: 1 }}>{pr.summary}</span>
+                      <Chip
+                        themeScheme={commonProps.themeScheme}
+                        color={
+                          {
+                            OPEN: Colors.PRIMARY_01,
+                            CLOSE_MERGED: Colors.GREEN_01,
+                            CLOSE_DENIED: Colors.RED_01,
+                          }[pr.state]
+                        }
+                      >
+                        {
+                          {
+                            OPEN: "Open",
+                            CLOSE_MERGED: "Merged",
+                            CLOSE_DENIED: "Closed",
+                          }[pr.state]
+                        }
+                      </Chip>
+                    </Grid.Row>
                   </a>
-                  <span style={{ opacity: 0.67 }}>
-                    wants to merge <code>{pr.sourceBranch}</code> into{" "}
-                    <code>{pr.targetBranch}</code>
-                  </span>
                   <Grid.Row
                     fluid
+                    nowrap
+                    gap={8}
                     alignItems={"center"}
+                    style={{ opacity: 0.67 }}
+                  >
+                    wants to merge{" "}
+                    <Chip
+                      themeScheme={commonProps.themeScheme}
+                      style={{ textTransform: "none" }}
+                    >
+                      <code>{pr.sourceBranch}</code>
+                    </Chip>
+                    into{" "}
+                    <Chip
+                      themeScheme={commonProps.themeScheme}
+                      style={{ textTransform: "none" }}
+                    >
+                      <code>{pr.targetBranch}</code>
+                    </Chip>
+                  </Grid.Row>
+                  <Grid.Col
+                    fluid
+                    gap={4}
                     style={{ opacity: 0.67, marginTop: 4 }}
                   >
                     {new Date(pr.createdAt).getTime() <=
                       new Date(pr.updatedAt).getTime() && (
                       <span>
-                        opened on {new Date(pr.createdAt).toLocaleString()}
+                        {`opened on ${new Date(pr.createdAt).toLocaleString()}`}
                       </span>
                     )}
                     {((pr.closedAt == null &&

...
@@ -203,16 +240,15 @@ const RepositoryPullRequestsView: ReactView<
                         new Date(pr.updatedAt).getTime() <
                           new Date(pr.closedAt).getTime())) && (
                       <span>
-                        updated on {new Date(pr.updatedAt).toLocaleString()}
+                        {`updated on ${new Date(pr.updatedAt).toLocaleString()}`}
                       </span>
                     )}
                     {pr.closedAt != null && (
                       <span>
-                        closed on
-                        {new Date(pr.closedAt).toLocaleString()}
+                        {`closed on ${new Date(pr.closedAt).toLocaleString()}`}
                       </span>
                     )}
-                  </Grid.Row>
+                  </Grid.Col>
                 </Grid.Col>
               </Card>
             ))

app/views/settings/SettingsView.tsx
@@ -45,7 +45,7 @@ const SettingsView: ReactView<SettingsViewProps> = ({
           />
         </IslandWrapper>
         <Grid.Col fluid nowrap gap={24} style={{ marginTop: 16 }}>
-          <Grid.Col fluid nowrap gap={12}>
+          <Grid.Col fluid nowrap gap={4}>
             {sshKeys.map((key, idx) => (
               <IslandWrapper
                 key={key.id}