feat(ui): make ui prod-ready@@ -1,5 +1,5 @@
{
- "_generatedAtUnix": 1778610831056,
+ "_generatedAtUnix": 1778632838233,
"_hashAlgorithm": "sha1",
"_version": 2,
"assets": {
@@ -58,7 +58,7 @@
"pathSourceMap": "./public/.islands/RepositoryCreateForm.bundle.js.map"
},
"RepositoryFilesDiffsList": {
- "hash": "9ce62604a45279c7f72a745076a8cdb6a24e8ca4",
+ "hash": "a0909e0f0bdded0880457bbb0dc78de25fbfda76",
"pathSource": "./app/islands/RepositoryFilesDiffsList.tsx",
"pathBundle": "./public/.islands/RepositoryFilesDiffsList.bundle.js",
"pathSourceMap": "./public/.islands/RepositoryFilesDiffsList.bundle.js.map"
@@ -70,7 +70,7 @@
"pathSourceMap": "./public/.islands/RepositoryForkForm.bundle.js.map"
},
"RepositoryHero": {
- "hash": "921b889a0f6a0f33e554def62c54a95096e7cc6f",
+ "hash": "b9728d9a21834f12046d8ead42aeb7b51dfc619b",
"pathSource": "./app/islands/RepositoryHero.tsx",
"pathBundle": "./public/.islands/RepositoryHero.bundle.js",
"pathSourceMap": "./public/.islands/RepositoryHero.bundle.js.map"
@@ -88,13 +88,13 @@
"pathSourceMap": "./public/.islands/RepositoryPullRequestCreateForm.bundle.js.map"
},
"RepositoryTreeView": {
- "hash": "6774ee402778e12236e8501a4a49339f68b34edb",
+ "hash": "0a66e97cc87e2e449fff4e938a4eb3a0e4d7589b",
"pathSource": "./app/islands/RepositoryTreeView.tsx",
"pathBundle": "./public/.islands/RepositoryTreeView.bundle.js",
"pathSourceMap": "./public/.islands/RepositoryTreeView.bundle.js.map"
},
"SSHKeyItem": {
- "hash": "ee31649cf2c982c83452e871d1e61836fef95ae5",
+ "hash": "38e32ae581341246ab4379f701dcba9a74d7cf71",
"pathSource": "./app/islands/SSHKeyItem.tsx",
"pathBundle": "./public/.islands/SSHKeyItem.bundle.js",
"pathSourceMap": "./public/.islands/SSHKeyItem.bundle.js.map"
@@ -122,11 +122,11 @@
"pathSource": "./app/views/organization/OrganizationDetailsView.tsx"
},
"RepositoryBrowserView": {
- "hash": "b5248afb14d96e71f7350f187c10328c56891765",
+ "hash": "8ad5b2c67b6a65a04c2976cba9079ec2f0da1eee",
"pathSource": "./app/views/repository/RepositoryBrowserView.tsx"
},
"RepositoryCommitsLogView": {
- "hash": "672d52245a43e68f6ded72e39c4c2fc9ab1bf897",
+ "hash": "fee84b81eded32f58b010fa66941d9df1860fa8b",
"pathSource": "./app/views/repository/RepositoryCommitsLogView.tsx"
},
"RepositoryCompareView": {
@@ -138,7 +138,7 @@
"pathSource": "./app/views/repository/RepositoryCreateView.tsx"
},
"RepositoryDetailsView": {
- "hash": "da0ebcac2dd17cb279732b4654d507c3d7568bca",
+ "hash": "63df2df0c5ed9838505df2c351aece6e198d17bb",
"pathSource": "./app/views/repository/RepositoryDetailsView.tsx"
},
"RepositoryExploreView": {
@@ -146,23 +146,23 @@
"pathSource": "./app/views/repository/RepositoryExploreView.tsx"
},
"RepositoryForkView": {
- "hash": "ae3d083cc6ea0e4fec0dbc719e8916ca3045f987",
+ "hash": "6c4f238f98aace40dfa8eeff9749d3841349f8e0",
"pathSource": "./app/views/repository/RepositoryForkView.tsx"
},
"RepositoryShowObjectView": {
- "hash": "d7207fa7763a330998b1f92c9d38168d82c4cc6b",
+ "hash": "057fe75366d6705671a24bac56d201581ac54567",
"pathSource": "./app/views/repository/RepositoryShowObjectView.tsx"
},
"RepositoryPullRequestCreateView": {
- "hash": "447d38c5a6c5e1e88caa4fbcbe897f2d7ba0a3f1",
+ "hash": "f5c39bf5a0ea9ec03a1a684293c7a1f595176c0b",
"pathSource": "./app/views/repositoryPullRequests/RepositoryPullRequestCreateView.tsx"
},
"RepositoryPullRequestDetailsView": {
- "hash": "bec2821c1c5cebc708479c41d53a57b10f3a67d9",
+ "hash": "9664f6328191169ea5926e23fd63da11be4163c6",
"pathSource": "./app/views/repositoryPullRequests/RepositoryPullRequestDetailsView.tsx"
},
"RepositoryPullRequestsView": {
- "hash": "403b3c7ba81523e900b7bc746ef805c533ba330a",
+ "hash": "d9764b3bbb660c5a2c9f09606970d4264e218ffc",
"pathSource": "./app/views/repositoryPullRequests/RepositoryPullRequestsView.tsx"
},
"SettingsKeyAddView": {
@@ -31,6 +31,7 @@ const baseButtonCss = css<ButtonProps>`
min-width: 120px;
padding: 8px 16px;
+ gap: 8px;
background-color: ${Colors.PRIMARY_01};
border: none; /* 1px solid ${Colors.WHITE_01}; */
@@ -1,8 +1,11 @@
-import Color from "color";
+// 3rd-party
import styled, { css } from "styled-components";
+// app
+import { Color, NamedColors } from "../utils/style";
+import { WithThemeSchemeProp } from "../types";
-export const Chip = styled.div<{ color?: string }>`
- ${({ color = undefined }) => css`
+export const Chip = styled.div<WithThemeSchemeProp & { color?: string }>`
+ ${({ themeScheme, color = undefined }) => css`
display: flex;
flex-flow: row nowrap;
align-items: center;
@@ -15,7 +18,9 @@ export const Chip = styled.div<{ color?: string }>`
font-weight: bold;
text-transform: uppercase;
- color: ${color ? Color(color).alpha(1).toString() : "black"};
+ color: ${color
+ ? Color(color).alpha(1).toString()
+ : NamedColors.TEXT_DEFAULT[themeScheme]};
background-color: ${color
? Color(color).alpha(0.3).toString()
: "rgba(0, 0, 0, 0.3)"};
@@ -4,8 +4,7 @@ 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 { Colors, NamedColors } from "../utils/style";
import {
type RepositoryCountersDTO,
type CommonViewProps,
@@ -13,7 +12,17 @@ import {
} from "../types";
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,
@@ -78,7 +87,7 @@ export const DrawerPrimary = ({
</StyledLogoArea>
</StyledDrawerHeader>
<StyledDrawerContent>
- <StyledDrawerListHeader>
+ <StyledDrawerListHeader style={{ margin: 0 }}>
<a href={buildRouteLink(AppRoute.ORGANIZATION_DETAILS, { orgSlug })}>
@{orgSlug}
</a>
@@ -92,6 +101,64 @@ export const DrawerPrimary = ({
<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,
+ }}
+ >
+ {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,
+ }}
+ >
+ {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,
+ }}
+ >
+ {counters.forks || "0"}
+ </Chip>
+ </Grid.Row>
+ </Grid.Row>
+ </StyledDrawerListHeader>
<StyledDrawerList>
<StyledDrawerListItem
themeScheme={themeScheme}
@@ -108,6 +175,19 @@ export const DrawerPrimary = ({
}
>
<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}
@@ -120,23 +200,23 @@ export const DrawerPrimary = ({
}
>
<span>Pull Requests</span>
- <Chip>{counters.pulls || 0}</Chip>
+ <Chip themeScheme={themeScheme}>{counters.pulls || 0}</Chip>
</StyledDrawerListItem>
<StyledDrawerListItem themeScheme={themeScheme} disabled>
<span>Tests & Coverage</span>
- <Chip>{counters.tests || 0}</Chip>
+ <Chip themeScheme={themeScheme}>{counters.tests || 0}</Chip>
</StyledDrawerListItem>
<StyledDrawerListItem themeScheme={themeScheme} disabled>
<span>Builds</span>
- <Chip>{counters.builds || 0}</Chip>
+ <Chip themeScheme={themeScheme}>{counters.builds || 0}</Chip>
</StyledDrawerListItem>
<StyledDrawerListItem themeScheme={themeScheme} disabled>
<span>Issues</span>
- <Chip>{counters.issues || 0}</Chip>
+ <Chip themeScheme={themeScheme}>{counters.issues || 0}</Chip>
</StyledDrawerListItem>
<StyledDrawerListItem themeScheme={themeScheme} disabled>
<span>API Reference</span>
- <Chip>{counters.apiRefSymbols || 0}</Chip>
+ <Chip themeScheme={themeScheme}>{counters.apiRefSymbols || 0}</Chip>
</StyledDrawerListItem>
</StyledDrawerList>
<StyledDrawerListHeader></StyledDrawerListHeader>
@@ -146,15 +226,28 @@ export const DrawerPrimary = ({
<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>{counters.helpCenterNotifs}</Chip>
+ <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>
@@ -12,6 +12,11 @@ import {
} from "../types";
import { buildRouteLink } from "../utils/shared";
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,
@@ -60,7 +65,8 @@ export const DrawerSettings = ({
</StyledDrawerHeader>
<StyledDrawerContent>
<StyledDrawerListHeader>
- <div
+ <img
+ src={commonProps.currentUserAvatarUri || ""}
style={{
width: 20,
height: 20,
@@ -89,6 +95,7 @@ export const DrawerSettings = ({
}
>
<span>My Account</span>
+ <UserIcon color={NamedColors.TEXT_DEFAULT[themeScheme]} size={20} />
</StyledDrawerListItem>
<StyledDrawerListItem
themeScheme={themeScheme}
@@ -101,7 +108,10 @@ export const DrawerSettings = ({
}
>
<span>SSH Keys</span>
- <Chip>{counters.sshKeys || 0}</Chip>
+ <Chip themeScheme={themeScheme} style={{ marginRight: 8 }}>
+ {counters.sshKeys || 0}
+ </Chip>
+ <KeyIcon color={NamedColors.TEXT_DEFAULT[themeScheme]} size={24} />
</StyledDrawerListItem>
</StyledDrawerList>
<StyledDrawerListHeader></StyledDrawerListHeader>
@@ -111,18 +121,30 @@ export const DrawerSettings = ({
<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>{counters.helpCenterNotifs}</Chip>
+ <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>
@@ -58,7 +58,7 @@ const LayoutComponent: FC<LayoutProps & WithThemeSchemeProp> = (props) => {
}
html {
/* so anchor are not hidden behind sticky header */
- scroll-padding-top: ${HEADER_HEIGHT + 16}px;
+ scroll-padding-top: ${HEADER_HEIGHT + 64}px;
}
body {
overflow-x: hidden;
@@ -181,8 +181,8 @@ const StyledPageHeaderWrapper = styled.div<WithThemeSchemeProp>`
top: 0;
z-index: 11000;
- gap: 20px;
- padding: 0 20px;
+ gap: 8px;
+ padding: 0 16px;
backdrop-filter: blur(8px);
@@ -7,7 +7,12 @@ import { AppRoute } from "../routes.defs";
import { Const } from "../const";
import { NamedColors } from "../utils/style";
import { buildRouteLink } from "../utils/shared";
+// app components
import { PageWrapper } from "./PageWrapper";
+import { BurgerMenuIcon } from "./icons/BurgerMenuIcon";
+import { MoonIcon } from "./icons/MoonIcon";
+import { SunIcon } from "./icons/SunIcon";
+import { PlusIcon } from "./icons/PlusIcon";
interface PageHeaderProps extends CommonProps {
forceShowLogo?: boolean;
@@ -51,6 +56,7 @@ export const PageHeader: VFC<PageHeaderProps & WithThemeSchemeProp> = ({
<PageHeaderAvatar
aria-label={commonProps.currentUserUsername || "ghost"}
themeScheme={themeScheme}
+ src={commonProps.currentUserAvatarUri || ""}
/>
</a>
</>
@@ -77,12 +83,15 @@ export const PageHeader: VFC<PageHeaderProps & WithThemeSchemeProp> = ({
return (
<StyledPageHeader themeScheme={themeScheme}>
- <PageWrapper>
+ <PageWrapper style={{ gap: 12 }}>
<StyledBurgerMenu
themeScheme={themeScheme}
onClick={toggleDrawerPrimary}
>
- ☰
+ <BurgerMenuIcon
+ color={NamedColors.TEXT_DEFAULT[themeScheme]}
+ size={24}
+ />
</StyledBurgerMenu>
<StyledLogoArea themeScheme={themeScheme} forceShowLogo={forceShowLogo}>
<a href={"/"}>
@@ -127,20 +136,35 @@ export const PageHeader: VFC<PageHeaderProps & WithThemeSchemeProp> = ({
{commonProps.authenticated && (
<a
aria-label={"Create a new Repository"}
+ title={"New Repository"}
href={buildRouteLink(AppRoute.REPOSITORY_CREATE, null)}
>
- (+) Repo
+ <PlusIcon
+ color={NamedColors.TEXT_DEFAULT[themeScheme]}
+ size={24}
+ />
</a>
)}
<a
- aria-label={`Switch to ${invertThemeScheme} theme`}
data-smooth-scroll={"disabled"}
+ aria-label={`Switch to ${invertThemeScheme} theme`}
+ title={`Switch to ${invertThemeScheme} theme`}
href={buildRouteLink(AppRoute.THEME_SET_SCHEME_ACTION, {
themeScheme: invertThemeScheme,
})}
- title={`Click to enable ${invertThemeScheme} mode`}
>
- {`${themeScheme === "light" ? "Dark" : "Light"}`}
+ {themeScheme === "light" ? (
+ <MoonIcon
+ color={NamedColors.TEXT_DEFAULT[themeScheme]}
+ size={24}
+ />
+ ) : (
+ <SunIcon
+ color={NamedColors.TEXT_DEFAULT[themeScheme]}
+ color2={NamedColors.BRAND_LINE[themeScheme]}
+ size={24}
+ />
+ )}
</a>
{pageHeaderActions}
</StyledActionsArea>
@@ -151,6 +175,10 @@ export const PageHeader: VFC<PageHeaderProps & WithThemeSchemeProp> = ({
const StyledBurgerMenu = styled.button<WithThemeSchemeProp>`
${({ themeScheme }) => css`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
/* above mobile size */
@media only screen and (min-width: 768px) {
& {
@@ -158,16 +186,33 @@ const StyledBurgerMenu = styled.button<WithThemeSchemeProp>`
}
}
- width: 40px;
- height: 40px;
+ width: 44px;
+ min-width: 44px;
+ max-width: 44px;
+ height: 44px;
+ min-height: 44px;
+ max-height: 44px;
+
+ padding-top: -2px;
+
+ font-size: 20px;
+ font-weight: thin;
+ color: ${NamedColors.TEXT_MUTED[themeScheme]};
+ background: ${NamedColors.HEADER_NAV_PILL[themeScheme]};
border-image: none;
border: none;
- border-radius: 20px;
- background: ${NamedColors.CARD_OVERLAY[themeScheme]};
- font-size: 24px;
- font-weight: thin;
- padding-top: -2px;
- /*color: red;*/
+ border-radius: 22px;
+ cursor: pointer;
+
+ &.active,
+ &:hover {
+ color: ${NamedColors.TEXT_DEFAULT[themeScheme]};
+ background: ${NamedColors.CARD[themeScheme]};
+ }
+
+ &:active {
+ font-size: 22px;
+ }
`}
`;
@@ -183,7 +228,7 @@ const StyledPageHeader = styled.header<WithThemeSchemeProp>`
/* above mobile size */
@media only screen and (min-width: 768px) {
& > ${PageWrapper} {
- padding: 0 16px;
+ padding: 0 8px;
}
}
@@ -263,7 +308,7 @@ const StyledPageHeaderNav = styled.nav<WithThemeSchemeProp>`
${({ themeScheme }) => css`
border-radius: 20px;
- background-color: ${NamedColors.CARD_OVERLAY[themeScheme]};
+ background-color: ${NamedColors.HEADER_NAV_PILL[themeScheme]};
`};
@media only screen and (max-width: 768px) {
@@ -0,0 +1,28 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const BackIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"arrow_left_or_back"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ d="M20.3284 11.0001V13.0001L7.50011 13.0001L10.7426 16.2426L9.32842 17.6568L3.67157 12L9.32842 6.34314L10.7426 7.75735L7.49988 11.0001L20.3284 11.0001Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,38 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const BugIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"bug"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ d="M10 11C10 10.4477 10.4477 10 11 10H13C13.5523 10 14 10.4477 14 11C14 11.5523 13.5523 12 13 12H11C10.4477 12 10 11.5523 10 11Z"
+ fill={color}
+ />
+ <path
+ d="M11 14C10.4477 14 10 14.4477 10 15C10 15.5523 10.4477 16 11 16H13C13.5523 16 14 15.5523 14 15C14 14.4477 13.5523 14 13 14H11Z"
+ fill={color}
+ />
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M9.09447 4.74918C8.41606 4.03243 8 3.0648 8 2H10C10 3.10457 10.8954 4 12 4C13.1046 4 14 3.10457 14 2H16C16 3.0648 15.5839 4.03243 14.9055 4.74918C16.1782 5.45491 17.1673 6.6099 17.6586 8H19C19.5523 8 20 8.44772 20 9C20 9.55229 19.5523 10 19 10H18V12H19C19.5523 12 20 12.4477 20 13C20 13.5523 19.5523 14 19 14H18V16H19C19.5523 16 20 16.4477 20 17C20 17.5523 19.5523 18 19 18H17.6586C16.8349 20.3304 14.6124 22 12 22C9.38756 22 7.16508 20.3304 6.34141 18H5C4.44772 18 4 17.5523 4 17C4 16.4477 4.44772 16 5 16H6V14H5C4.44772 14 4 13.5523 4 13C4 12.4477 4.44772 12 5 12H6V10H5C4.44772 10 4 9.55229 4 9C4 8.44772 4.44772 8 5 8H6.34141C6.83274 6.6099 7.82181 5.45491 9.09447 4.74918ZM8 16V10C8 7.79086 9.79086 6 12 6C14.2091 6 16 7.79086 16 10V16C16 18.2091 14.2091 20 12 20C9.79086 20 8 18.2091 8 16Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,36 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const BurgerMenuIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"burger_menu"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ d="M7 6C5.34315 6 4 7.34315 4 9H20C20 7.34315 18.6569 6 17 6H7Z"
+ fill={color}
+ />
+ <path
+ d="M7 18C5.34315 18 4 16.6569 4 15H20C20 16.6569 18.6569 18 17 18H7Z"
+ fill={color}
+ />
+ <path
+ d="M3 11C2.44772 11 2 11.4477 2 12C2 12.5523 2.44772 13 3 13H21C21.5523 13 22 12.5523 22 12C22 11.4477 21.5523 11 21 11H3Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -6,15 +6,18 @@ export const ChevronRightIcon: VFC<IconProps> = ({
size = 24,
color = "currentColor",
}) => {
+ const sizeProps = {
+ width: size + 1,
+ height: size,
+ viewBox: "0 0 25 24",
+ };
return (
- <div aria-label={"chevron_right"} aria-roledescription={"icon"}>
- <svg
- width={`${size + 1}`}
- height={`${size}`}
- viewBox="0 0 25 24"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- >
+ <div
+ aria-label={"chevron_right"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M9.25671 16.59L13.8367 12L9.25671 7.41L10.6667 6L16.6667 12L10.6667 18L9.25671 16.59Z"
fill={color}
@@ -0,0 +1,38 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const ClipboardIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"clipboard"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ d="M8 11C7.44772 11 7 11.4477 7 12C7 12.5523 7.44772 13 8 13H15.9595C16.5118 13 16.9595 12.5523 16.9595 12C16.9595 11.4477 16.5118 11 15.9595 11H8Z"
+ fill={color}
+ />
+ <path
+ d="M8.04053 15.0665C7.48824 15.0665 7.04053 15.5142 7.04053 16.0665C7.04053 16.6188 7.48824 17.0665 8.04053 17.0665H16C16.5523 17.0665 17 16.6188 17 16.0665C17 15.5142 16.5523 15.0665 16 15.0665H8.04053Z"
+ fill={color}
+ />
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M5 3C3.89543 3 3 3.89543 3 5V19C3 20.1046 3.89543 21 5 21H19C20.1046 21 21 20.1046 21 19V5C21 3.89543 20.1046 3 19 3H5ZM7 5H5L5 19H19V5H17V6C17 7.65685 15.6569 9 14 9H10C8.34315 9 7 7.65685 7 6V5ZM9 5V6C9 6.55228 9.44772 7 10 7H14C14.5523 7 15 6.55228 15 6V5H9Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,36 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const CodeIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"code"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ d="M13.325 3.05011L8.66741 20.4323L10.5993 20.9499L15.2568 3.56775L13.325 3.05011Z"
+ fill={color}
+ />
+ <path
+ d="M7.61197 18.3608L8.97136 16.9124L8.97086 16.8933L3.87657 12.1121L8.66699 7.00798L7.20868 5.63928L1.04956 12.2017L7.61197 18.3608Z"
+ fill={color}
+ />
+ <path
+ d="M16.388 18.3608L15.0286 16.9124L15.0291 16.8933L20.1234 12.1121L15.333 7.00798L16.7913 5.63928L22.9504 12.2017L16.388 18.3608Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,32 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const CommentIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"comment"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M17 9H7V7H17V9Z" fill={color} />
+ <path d="M7 13H17V11H7V13Z" fill={color} />
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M2 18V2H22V18H16V22H14C11.7909 22 10 20.2091 10 18H2ZM12 16V18C12 19.1046 12.8954 20 14 20V16H20V4H4V16H12Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,30 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const CrownIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"crown"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M2.5 6.09143L7.21997 10.8114L12.0005 6.03088L16.7811 10.8114L21.5 6.09245V14.9691C21.5 16.626 20.1569 17.9691 18.5 17.9691H5.5C3.84314 17.9691 2.5 16.626 2.5 14.9691V6.09143ZM19.5 10.9087V14.9691C19.5 15.5214 19.0523 15.9691 18.5 15.9691H5.5C4.94771 15.9691 4.5 15.5214 4.5 14.9691V10.9077L7.21997 13.6277L12.0005 8.84717L16.7811 13.6277L19.5 10.9087Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,32 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const DownloadIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"download"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ d="M11 5C11 4.44772 11.4477 4 12 4C12.5523 4 13 4.44772 13 5V12.1578L16.2428 8.91501L17.657 10.3292L12.0001 15.9861L6.34326 10.3292L7.75748 8.91501L11 12.1575V5Z"
+ fill={color}
+ />
+ <path
+ d="M4 14H6V18H18V14H20V18C20 19.1046 19.1046 20 18 20H6C4.89543 20 4 19.1046 4 18V14Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,30 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const FileIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"file"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M3 5C3 3.34315 4.34315 2 6 2H14C17.866 2 21 5.13401 21 9V19C21 20.6569 19.6569 22 18 22H6C4.34315 22 3 20.6569 3 19V5ZM13 4H6C5.44772 4 5 4.44772 5 5V19C5 19.5523 5.44772 20 6 20H18C18.5523 20 19 19.5523 19 19V9H13V4ZM18.584 7C17.9413 5.52906 16.6113 4.4271 15 4.10002V7H18.584Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,30 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const FolderIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"folder"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M4 1.5C2.89543 1.5 2 2.39543 2 3.5V4.5C2 4.55666 2.00236 4.61278 2.00698 4.66825C0.838141 5.07811 0 6.19118 0 7.5V19.5C0 21.1569 1.34315 22.5 3 22.5H21C22.6569 22.5 24 21.1569 24 19.5V7.5C24 5.84315 22.6569 4.5 21 4.5H11.874C11.4299 2.77477 9.86384 1.5 8 1.5H4ZM9.73244 4.5C9.38663 3.9022 8.74028 3.5 8 3.5H4V4.5H9.73244ZM3 6.5C2.44772 6.5 2 6.94772 2 7.5V19.5C2 20.0523 2.44772 20.5 3 20.5H21C21.5523 20.5 22 20.0523 22 19.5V7.5C22 6.94772 21.5523 6.5 21 6.5H3Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,28 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const GitBranchIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"git_branch"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ d="M9 3C7.89543 3 7 3.89543 7 5C7 5.74028 7.4022 6.38663 8 6.73244V17.2676C7.4022 17.6134 7 18.2597 7 19C7 20.1046 7.89543 21 9 21C9.74028 21 10.3866 20.5978 10.7324 20H11.9585C14.1676 20 15.9585 18.2091 15.9585 16V14.7324C16.5563 14.3866 16.9585 13.7403 16.9585 13C16.9585 11.8954 16.0631 11 14.9585 11C13.8539 11 12.9585 11.8954 12.9585 13C12.9585 13.7403 13.3607 14.3866 13.9585 14.7324V16C13.9585 17.1046 13.0631 18 11.9585 18H10.7324C10.5568 17.6964 10.3036 17.4432 10 17.2676V6.73244C10.5978 6.38663 11 5.74028 11 5C11 3.89543 10.1046 3 9 3Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,30 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const GitCommmitIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"git_commit"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M11 4C11 3.44772 11.4477 3 12 3C12.5523 3 13 3.44772 13 4V9.17071C14.1652 9.58254 15 10.6938 15 12C15 13.3062 14.1652 14.4175 13 14.8293V20C13 20.5523 12.5523 21 12 21C11.4477 21 11 20.5523 11 20V14.8293C9.83481 14.4175 9 13.3062 9 12C9 10.6938 9.83481 9.58254 11 9.17071V4ZM12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,28 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const GitForkIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"git_fork"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ d="M7 5C7 3.89543 7.89543 3 9 3C10.1046 3 11 3.89543 11 5C11 5.74028 10.5978 6.38663 10 6.73244V14.0396H11.7915C12.8961 14.0396 13.7915 13.1441 13.7915 12.0396V10.7838C13.1823 10.4411 12.7708 9.78837 12.7708 9.03955C12.7708 7.93498 13.6662 7.03955 14.7708 7.03955C15.8753 7.03955 16.7708 7.93498 16.7708 9.03955C16.7708 9.77123 16.3778 10.4111 15.7915 10.7598V12.0396C15.7915 14.2487 14.0006 16.0396 11.7915 16.0396H10V17.2676C10.5978 17.6134 11 18.2597 11 19C11 20.1046 10.1046 21 9 21C7.89543 21 7 20.1046 7 19C7 18.2597 7.4022 17.6134 8 17.2676V6.73244C7.4022 6.38663 7 5.74028 7 5Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,28 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const GitPullIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"git_pull"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ d="M7 5C7 3.89543 7.89543 3 9 3C10.1046 3 11 3.89543 11 5C11 5.34168 10.9143 5.66336 10.7633 5.9447H11.3438C13.5529 5.9447 15.3438 7.73556 15.3438 9.9447V11.2244C15.9301 11.5731 16.323 12.213 16.323 12.9447C16.323 14.0493 15.4276 14.9447 14.323 14.9447C13.2184 14.9447 12.323 14.0493 12.323 12.9447C12.323 12.1959 12.7345 11.5432 13.3438 11.2004V9.9447C13.3438 8.84013 12.4483 7.9447 11.3438 7.9447H10V17.2676C10.5978 17.6134 11 18.2597 11 19C11 20.1046 10.1046 21 9 21C7.89543 21 7 20.1046 7 19C7 18.2597 7.4022 17.6134 8 17.2676V6.73244C7.4022 6.38663 7 5.74028 7 5Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,30 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const KeyIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"key"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M6 8C4.34315 8 3 9.34315 3 11V13C3 14.6569 4.34315 16 6 16C7.65685 16 9 14.6569 9 13H15V15H17V13H18V15H20V11H9C9 9.34315 7.65685 8 6 8ZM7 13V11C7 10.4477 6.55228 10 6 10C5.44772 10 5 10.4477 5 11V13C5 13.5523 5.44772 14 6 14C6.55228 14 7 13.5523 7 13Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,42 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const LikeIcon: VFC<IconProps & { fill?: boolean }> = ({
+ size = 24,
+ color = "currentColor",
+ fill = false,
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"like"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ {fill ? (
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d={
+ "M12.0122 5.57169L10.9252 4.48469C8.77734 2.33681 5.29493 2.33681 3.14705 4.48469C0.999162 6.63258 0.999162 10.115 3.14705 12.2629L11.9859 21.1017L12.014 21.1262L20.8528 12.2874C23.0007 10.1395 23.0007 6.65711 20.8528 4.50923C18.705 2.36134 15.2226 2.36134 13.0747 4.50923L12.0122 5.57169Z"
+ }
+ fill={color}
+ />
+ ) : (
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M12.0122 5.57169L10.9252 4.48469C8.77734 2.33681 5.29493 2.33681 3.14705 4.48469C0.999162 6.63258 0.999162 10.115 3.14705 12.2629L11.9859 21.1017L11.9877 21.0999L12.014 21.1262L20.8528 12.2874C23.0007 10.1395 23.0007 6.65711 20.8528 4.50923C18.705 2.36134 15.2226 2.36134 13.0747 4.50923L12.0122 5.57169ZM11.9877 18.2715L16.9239 13.3352L18.3747 11.9342L18.3762 11.9356L19.4386 10.8732C20.8055 9.50635 20.8055 7.29028 19.4386 5.92344C18.0718 4.55661 15.8557 4.55661 14.4889 5.92344L12.0133 8.39904L12.006 8.3918L12.005 8.39287L9.51101 5.89891C8.14417 4.53207 5.92809 4.53207 4.56126 5.89891C3.19442 7.26574 3.19442 9.48182 4.56126 10.8487L7.10068 13.3881L7.10248 13.3863L11.9877 18.2715Z"
+ fill={color}
+ />
+ )}
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,32 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const LogOutIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"log_out"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ d="M8.51428 20H4.51428C3.40971 20 2.51428 19.1046 2.51428 18V6C2.51428 4.89543 3.40971 4 4.51428 4H8.51428V6H4.51428V18H8.51428V20Z"
+ fill={color}
+ />
+ <path
+ d="M13.8418 17.385L15.262 15.9768L11.3428 12.0242L20.4857 12.0242C21.038 12.0242 21.4857 11.5765 21.4857 11.0242C21.4857 10.4719 21.038 10.0242 20.4857 10.0242L11.3236 10.0242L15.304 6.0774L13.8958 4.6572L7.5049 10.9941L13.8418 17.385Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,28 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const MinusIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"minus"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ d="M4 12C4 11.4477 4.44772 11 5 11H19C19.5523 11 20 11.4477 20 12C20 12.5523 19.5523 13 19 13H5C4.44772 13 4 12.5523 4 12Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,30 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const MoonIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"moon_or_dark_mode"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M12.2256 2.00253C9.59172 1.94346 6.93894 2.9189 4.92893 4.92891C1.02369 8.83415 1.02369 15.1658 4.92893 19.071C8.83418 22.9763 15.1658 22.9763 19.0711 19.071C21.0811 17.061 22.0565 14.4082 21.9975 11.7743C21.9796 10.9772 21.8669 10.1818 21.6595 9.40643C21.0933 9.9488 20.5078 10.4276 19.9163 10.8425C18.5649 11.7906 17.1826 12.4053 15.9301 12.6837C14.0241 13.1072 12.7156 12.7156 12 12C11.2844 11.2844 10.8928 9.97588 11.3163 8.0699C11.5947 6.81738 12.2094 5.43511 13.1575 4.08368C13.5724 3.49221 14.0512 2.90664 14.5935 2.34046C13.8182 2.13305 13.0228 2.02041 12.2256 2.00253ZM17.6569 17.6568C18.9081 16.4056 19.6582 14.8431 19.9072 13.2186C16.3611 15.2643 12.638 15.4664 10.5858 13.4142C8.53361 11.362 8.73568 7.63895 10.7814 4.09281C9.1569 4.34184 7.59434 5.09193 6.34315 6.34313C3.21895 9.46732 3.21895 14.5326 6.34315 17.6568C9.46734 20.781 14.5327 20.781 17.6569 17.6568Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,42 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const MoreHorizIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"more_horizontal"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M5 15C6.65685 15 8 13.6569 8 12C8 10.3431 6.65685 9 5 9C3.34315 9 2 10.3431 2 12C2 13.6569 3.34315 15 5 15ZM5 13C5.55228 13 6 12.5523 6 12C6 11.4477 5.55228 11 5 11C4.44772 11 4 11.4477 4 12C4 12.5523 4.44772 13 5 13Z"
+ fill={color}
+ />
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15ZM12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13Z"
+ fill={color}
+ />
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M22 12C22 13.6569 20.6569 15 19 15C17.3431 15 16 13.6569 16 12C16 10.3431 17.3431 9 19 9C20.6569 9 22 10.3431 22 12ZM20 12C20 12.5523 19.5523 13 19 13C18.4477 13 18 12.5523 18 12C18 11.4477 18.4477 11 19 11C19.5523 11 20 11.4477 20 12Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,30 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const MoreVertIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"more_vertical"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M12 5C12.5523 5 13 4.55228 13 4C13 3.44772 12.5523 3 12 3C11.4477 3 11 3.44772 11 4C11 4.55228 11.4477 5 12 5ZM12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13ZM12 21C12.5523 21 13 20.5523 13 20C13 19.4477 12.5523 19 12 19C11.4477 19 11 19.4477 11 20C11 20.5523 11.4477 21 12 21ZM15 4C15 5.65685 13.6569 7 12 7C10.3431 7 9 5.65685 9 4C9 2.34315 10.3431 1 12 1C13.6569 1 15 2.34315 15 4ZM15 12C15 13.6569 13.6569 15 12 15C10.3431 15 9 13.6569 9 12C9 10.3431 10.3431 9 12 9C13.6569 9 15 10.3431 15 12ZM12 23C13.6569 23 15 21.6569 15 20C15 18.3431 13.6569 17 12 17C10.3431 17 9 18.3431 9 20C9 21.6569 10.3431 23 12 23Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,43 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const PasswordIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"password"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ d="M6 12C6 12.5523 5.55228 13 5 13C4.44772 13 4 12.5523 4 12C4 11.4477 4.44772 11 5 11C5.55228 11 6 11.4477 6 12Z"
+ fill={color}
+ />
+ <path
+ d="M9 13C9.55228 13 10 12.5523 10 12C10 11.4477 9.55228 11 9 11C8.44771 11 8 11.4477 8 12C8 12.5523 8.44771 13 9 13Z"
+ fill={color}
+ />
+ <path
+ d="M14 12C14 12.5523 13.5523 13 13 13C12.4477 13 12 12.5523 12 12C12 11.4477 12.4477 11 13 11C13.5523 11 14 11.4477 14 12Z"
+ fill={color}
+ />
+ <path d="M20 11H16V13H20V11Z" fill={color} />
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M2 6C0.895431 6 0 6.89543 0 8V16C0 17.1046 0.89543 18 2 18H22C23.1046 18 24 17.1046 24 16V8C24 6.89543 23.1046 6 22 6H2ZM22 8H2L2 16H22V8Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,28 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const PlusIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"plus"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ d="M12 4C11.4477 4 11 4.44772 11 5V11H5C4.44772 11 4 11.4477 4 12C4 12.5523 4.44772 13 5 13H11V19C11 19.5523 11.4477 20 12 20C12.5523 20 13 19.5523 13 19V13H19C19.5523 13 20 12.5523 20 12C20 11.4477 19.5523 11 19 11H13V5C13 4.44772 12.5523 4 12 4Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,30 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const SearchIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"search"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M18.319 14.4326C20.7628 11.2941 20.542 6.75347 17.6569 3.86829C14.5327 0.744098 9.46734 0.744098 6.34315 3.86829C3.21895 6.99249 3.21895 12.0578 6.34315 15.182C9.22833 18.0672 13.769 18.2879 16.9075 15.8442C16.921 15.8595 16.9351 15.8745 16.9497 15.8891L21.1924 20.1317C21.5829 20.5223 22.2161 20.5223 22.6066 20.1317C22.9971 19.7412 22.9971 19.1081 22.6066 18.7175L18.364 14.4749C18.3493 14.4603 18.3343 14.4462 18.319 14.4326ZM16.2426 5.28251C18.5858 7.62565 18.5858 11.4246 16.2426 13.7678C13.8995 16.1109 10.1005 16.1109 7.75736 13.7678C5.41421 11.4246 5.41421 7.62565 7.75736 5.28251C10.1005 2.93936 13.8995 2.93936 16.2426 5.28251Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,36 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const SettingsIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"settings"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M7 3C8.86384 3 10.4299 4.27477 10.874 6H19V8H10.874C10.4299 9.72523 8.86384 11 7 11C4.79086 11 3 9.20914 3 7C3 4.79086 4.79086 3 7 3ZM7 9C8.10457 9 9 8.10457 9 7C9 5.89543 8.10457 5 7 5C5.89543 5 5 5.89543 5 7C5 8.10457 5.89543 9 7 9Z"
+ fill={color}
+ />
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M17 20C15.1362 20 13.5701 18.7252 13.126 17H5V15H13.126C13.5701 13.2748 15.1362 12 17 12C19.2091 12 21 13.7909 21 16C21 18.2091 19.2091 20 17 20ZM17 18C18.1046 18 19 17.1046 19 16C19 14.8954 18.1046 14 17 14C15.8954 14 15 14.8954 15 16C15 17.1046 15.8954 18 17 18Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,37 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const SunIcon: VFC<IconProps & { color2?: string }> = ({
+ size = 24,
+ color = "currentColor",
+ color2 = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"sun_or_light_mode"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16ZM12 18C15.3137 18 18 15.3137 18 12C18 8.68629 15.3137 6 12 6C8.68629 6 6 8.68629 6 12C6 15.3137 8.68629 18 12 18Z"
+ fill={color}
+ />
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M11 0H13V4.06189C12.6724 4.02104 12.3387 4 12 4C11.6613 4 11.3276 4.02104 11 4.06189V0ZM7.0943 5.68018L4.22173 2.80761L2.80752 4.22183L5.6801 7.09441C6.09071 6.56618 6.56608 6.0908 7.0943 5.68018ZM4.06189 11H0V13H4.06189C4.02104 12.6724 4 12.3387 4 12C4 11.6613 4.02104 11.3276 4.06189 11ZM5.6801 16.9056L2.80751 19.7782L4.22173 21.1924L7.0943 18.3198C6.56608 17.9092 6.09071 17.4338 5.6801 16.9056ZM11 19.9381V24H13V19.9381C12.6724 19.979 12.3387 20 12 20C11.6613 20 11.3276 19.979 11 19.9381ZM16.9056 18.3199L19.7781 21.1924L21.1923 19.7782L18.3198 16.9057C17.9092 17.4339 17.4338 17.9093 16.9056 18.3199ZM19.9381 13H24V11H19.9381C19.979 11.3276 20 11.6613 20 12C20 12.3387 19.979 12.6724 19.9381 13ZM18.3198 7.0943L21.1923 4.22183L19.7781 2.80762L16.9056 5.6801C17.4338 6.09071 17.9092 6.56608 18.3198 7.0943Z"
+ fill={color2 || color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,30 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const SupportIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"support"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M12.2607 21.9966C12.174 21.9988 12.0871 22 12 22C11.9128 22 11.8259 21.9988 11.7393 21.9966C7.68318 21.8928 4.22762 19.3738 2.7573 15.8242C1.74192 13.3674 1.7476 10.588 2.77433 8.13481C3.27688 6.93672 4.00599 5.85718 4.90808 4.94979L4.94983 4.90804C5.85259 4.01056 6.92574 3.28429 8.1165 2.78202C10.5894 1.74123 13.3958 1.73933 15.87 2.77633C17.0688 3.27993 18.1488 4.01042 19.0562 4.91407L19.0859 4.94373C19.9989 5.86054 20.7351 6.95351 21.2392 8.16721C21.7279 9.34662 21.9812 10.6006 21.999 11.8573C21.9997 11.9047 22 11.9523 22 12C22 12.0506 21.9996 12.1012 21.9989 12.1516C21.9376 16.2743 19.3814 19.7925 15.7731 21.2637C14.6481 21.7213 13.4566 21.9656 12.2607 21.9966ZM14.0322 15.4464L16.906 18.3202C14.0281 20.5599 9.97192 20.5599 7.09402 18.3202L9.96779 15.4464C11.2175 16.1845 12.7825 16.1845 14.0322 15.4464ZM8.55358 14.0322L5.67981 16.906C3.44007 14.0281 3.44007 9.97192 5.67981 7.09402L8.55358 9.96779C7.81548 11.2175 7.81548 12.7825 8.55358 14.0322ZM10.0824 12.5694C10.0773 12.5523 10.0725 12.5351 10.0679 12.5179C9.97738 12.179 9.97738 11.821 10.0679 11.4821C10.1556 11.1537 10.3282 10.8434 10.5858 10.5858C10.8299 10.3417 11.1213 10.1739 11.4306 10.0824C11.4477 10.0773 11.4649 10.0725 11.4821 10.0679C11.821 9.97738 12.179 9.97737 12.5179 10.0679C12.8463 10.1556 13.1566 10.3282 13.4142 10.5858C13.6583 10.8299 13.8261 11.1213 13.9176 11.4306C13.9227 11.4477 13.9275 11.4649 13.9321 11.4821C14.0226 11.821 14.0226 12.179 13.9321 12.5179C13.8444 12.8462 13.6718 13.1566 13.4142 13.4142C13.1701 13.6583 12.8787 13.8261 12.5694 13.9176C12.5523 13.9227 12.5351 13.9275 12.5179 13.9321C12.179 14.0226 11.821 14.0226 11.4821 13.9321C11.1538 13.8444 10.8434 13.6718 10.5858 13.4142C10.3417 13.1701 10.1739 12.8787 10.0824 12.5694ZM14.0322 8.55357C12.7825 7.81548 11.2175 7.81548 9.96779 8.55357L7.09402 5.6798C9.97192 3.44007 14.0281 3.44007 16.906 5.6798L14.0322 8.55357ZM18.3202 16.906C20.5599 14.0281 20.5599 9.97192 18.3202 7.09402L15.4464 9.96779C16.1845 11.2175 16.1845 12.7825 15.4464 14.0322L18.3202 16.906Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,28 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const TimesIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"times_or_close"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ d="M6.2253 4.81108C5.83477 4.42056 5.20161 4.42056 4.81108 4.81108C4.42056 5.20161 4.42056 5.83477 4.81108 6.2253L10.5858 12L4.81114 17.7747C4.42062 18.1652 4.42062 18.7984 4.81114 19.1889C5.20167 19.5794 5.83483 19.5794 6.22535 19.1889L12 13.4142L17.7747 19.1889C18.1652 19.5794 18.7984 19.5794 19.1889 19.1889C19.5794 18.7984 19.5794 18.1652 19.1889 17.7747L13.4142 12L19.189 6.2253C19.5795 5.83477 19.5795 5.20161 19.189 4.81108C18.7985 4.42056 18.1653 4.42056 17.7748 4.81108L12 10.5858L6.2253 4.81108Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,32 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const TrashIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"trash"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M17 5V4C17 2.89543 16.1046 2 15 2H9C7.89543 2 7 2.89543 7 4V5H4C3.44772 5 3 5.44772 3 6C3 6.55228 3.44772 7 4 7H5V18C5 19.6569 6.34315 21 8 21H16C17.6569 21 19 19.6569 19 18V7H20C20.5523 7 21 6.55228 21 6C21 5.44772 20.5523 5 20 5H17ZM15 4H9V5H15V4ZM17 7H7V18C7 18.5523 7.44772 19 8 19H16C16.5523 19 17 18.5523 17 18V7Z"
+ fill={color}
+ />
+ <path d="M9 9H11V17H9V9Z" fill={color} />
+ <path d="M13 9H15V17H13V9Z" fill={color} />
+ </svg>
+ </div>
+ );
+};
@@ -0,0 +1,34 @@
+import React, { VFC } from "react";
+
+import type { IconProps } from "./types";
+
+export const UserIcon: VFC<IconProps> = ({
+ size = 24,
+ color = "currentColor",
+}) => {
+ const sizeProps = {
+ width: size,
+ height: size,
+ viewBox: "0 0 24 24",
+ };
+ return (
+ <div
+ aria-label={"user"}
+ aria-roledescription={"icon"}
+ style={{ width: sizeProps.width, height: sizeProps.height }}
+ >
+ <svg {...sizeProps} fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M16 7C16 9.20914 14.2091 11 12 11C9.79086 11 8 9.20914 8 7C8 4.79086 9.79086 3 12 3C14.2091 3 16 4.79086 16 7ZM14 7C14 8.10457 13.1046 9 12 9C10.8954 9 10 8.10457 10 7C10 5.89543 10.8954 5 12 5C13.1046 5 14 5.89543 14 7Z"
+ fill={color}
+ />
+ <path
+ d="M16 15C16 14.4477 15.5523 14 15 14H9C8.44772 14 8 14.4477 8 15V21H6V15C6 13.3431 7.34315 12 9 12H15C16.6569 12 18 13.3431 18 15V21H16V15Z"
+ fill={color}
+ />
+ </svg>
+ </div>
+ );
+};
@@ -1 +1,2 @@
+export { BurgerMenuIcon } from "./BurgerMenuIcon";
export { ChevronRightIcon } from "./ChevronRightIcon";
@@ -52,7 +52,11 @@ const getRepositoryPullRequestsView: ReqHandler<
}
}
- const pullRequests = await prService.getPullRequestsInRepository(repo);
+ const pullRequests = await prService.getPullRequestsInRepository(
+ repo,
+ undefined,
+ (request.query as any)?.filter ?? "open",
+ );
const reqHandler = reply.makeRequestHandler(request, reply);
return reqHandler<RepositoryPullRequestsViewProps>(
@@ -61,7 +65,8 @@ const getRepositoryPullRequestsView: ReqHandler<
parentOrg,
pullRequests,
repo,
- }
+ pullRequestsFilter: (request.query as any)?.filter ?? "open",
+ },
);
};
@@ -49,7 +49,9 @@ const RepositoryFilesDiffsList: ReactIsland<
<Grid.Col fluid nowrap>
<Grid.Row fluid nowrap gap={12} alignItems={"center"}>
{diff.from === "/dev/null" ? (
- <Chip color={"rgb(43, 176, 90)"}>new file</Chip>
+ <Chip themeScheme={themeScheme} color={"rgb(43, 176, 90)"}>
+ new file
+ </Chip>
) : diff.to !== "/dev/null" ? (
<strong>{diff.from}</strong>
) : null}
@@ -60,7 +62,12 @@ const RepositoryFilesDiffsList: ReactIsland<
)}
{diff.to === "/dev/null" ? (
<>
- <Chip color={"rgb(215, 44, 44)"}>file deleted</Chip>
+ <Chip
+ themeScheme={themeScheme}
+ color={"rgb(215, 44, 44)"}
+ >
+ file deleted
+ </Chip>
<strong>{diff.from}</strong>
</>
) : (
@@ -91,7 +98,7 @@ const RepositoryFilesDiffsList: ReactIsland<
repoSlug,
currentRef: commitHash,
"*": diff.to === "/dev/null" ? diff.from : diff.to,
- }
+ },
)}
>
View file (current ref)
@@ -104,7 +111,7 @@ const RepositoryFilesDiffsList: ReactIsland<
repoSlug,
currentRef: Const.PRIMARY_BRANCH_REF,
"*": diff.to === "/dev/null" ? diff.from : diff.to,
- }
+ },
)}
style={{ marginLeft: 16 }}
>
@@ -2,6 +2,7 @@
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
@@ -11,10 +12,13 @@ import type {
} from "../types";
import { buildRouteLink } from "../utils/shared";
import { ButtonAnchor } from "../components/Button.styled";
-import { AppRoute } from "../routes.defs";
+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 { NamedColors } from "../utils/style";
+// import { theme } from "../theme";
export interface RepositoryHeroProps {
parentOrg: Organization;
@@ -26,7 +30,7 @@ export interface RepositoryHeroProps {
showForkButton?: boolean;
showNewButton?: boolean;
newButtonUrl?: string;
- newButtonText?: string;
+ newButtonText?: string | JSX.Element;
}
const RepositoryHero: ReactIsland<
@@ -55,10 +59,21 @@ const RepositoryHero: ReactIsland<
}}
>
<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 }}
+ style={{ minWidth: 300, marginBottom: 12, marginLeft: 12 }}
>
<h2 style={{ margin: 0, fontSize: isMobile ? 20 : 20 }}>
<a
@@ -133,15 +148,14 @@ const RepositoryHero: ReactIsland<
alignItems={"center"}
gap={8}
>
- Fork
+ <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,
}}
>
@@ -160,3 +174,42 @@ const RepositoryHero: ReactIsland<
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;
+ }
+ `}
+`;
@@ -12,10 +12,14 @@ import type {
import { buildRouteLink } from "../utils/shared";
import { AppRoute } from "../routes.defs";
import { Const } from "../const";
+import { NamedColors } from "../utils/style";
+// app components
import { Grid } from "../components/Grid";
import { TextEllipsis } from "../components/TextEllipsis.styled";
-import { NamedColors } from "../utils/style";
import { Select } from "../components/TextInput.styled";
+import { FolderIcon } from "../components/icons/FolderIcon";
+import { FileIcon } from "../components/icons/FileIcon";
+import { GitCommmitIcon } from "../components/icons/GitCommitIcon";
// app islands
// import RepositoryCommitSummaryLine from "./RepositoryCommitSummaryLine";
@@ -116,6 +120,15 @@ const RepositoryTreeView: ReactIsland<
"*": currentPath === "/" ? "" : currentPath,
},
);
+ window.location.replace(
+ buildRouteLink(AppRoute.REPOSITORY_BROWSER_WITH_PATH, {
+ orgSlug: orgSlug,
+ repoSlug: repoSlug,
+ currentRef: e.currentTarget.value,
+ "*": currentPath === "/" ? "" : currentPath,
+ }),
+ );
+ window.location.reload();
}}
style={{
height: 32,
@@ -179,6 +192,10 @@ const RepositoryTreeView: ReactIsland<
)}
</Grid.Row>
<Grid.Row nowrap alignItems={"center"}>
+ <GitCommmitIcon
+ color={NamedColors.TEXT_DEFAULT[themeScheme]}
+ size={24}
+ />
<a
style={{ minWidth: "max-content" }}
href={buildRouteLink(AppRoute.REPOSITORY_COMMITS_LOG, {
@@ -226,7 +243,18 @@ const RepositoryTreeView: ReactIsland<
href={fileLink.href}
title={fileLink.text}
>
- <span>
+ {fileLink.text.endsWith("/") ? (
+ <FolderIcon
+ color={NamedColors.TEXT_MUTED[themeScheme]}
+ size={16}
+ />
+ ) : (
+ <FileIcon
+ color={NamedColors.TEXT_MUTED[themeScheme]}
+ size={16}
+ />
+ )}
+ <span style={{ marginLeft: 8 }}>
<TextEllipsis>{fileLink.text}</TextEllipsis>
</span>
</StyledTreeViewListItemAnchor>
@@ -266,13 +294,13 @@ const StyledTreeViewListItem = styled.li<WithThemeSchemeProp>`
justify-content: flex-start;
align-items: center;
- height: 32px;
+ height: 40px;
width: 100%;
padding: 0 8px;
${({ themeScheme }) => css`
- border-bottom: 1px solid ${NamedColors.BORDER_DEFAULT[themeScheme]};
+ border-bottom: 1px solid ${NamedColors.CARD_ALPHA_01[themeScheme]};
&:hover {
background-color: ${NamedColors.CARD_OVERLAY[themeScheme]};
@@ -7,6 +7,8 @@ import { UserSSHKey } from "@prisma/client";
import type { WithThemeSchemeProp } from "../types";
import { Card } from "../components/Card.styled";
import { Grid } from "../components/Grid";
+import { KeyIcon } from "../components/icons/KeyIcon";
+import { NamedColors } from "../utils/style";
// import Code from "./Code";
@@ -29,8 +31,16 @@ const SSHKeyItem: ReactIsland<SSHKeyItemProps & WithThemeSchemeProp> = ({
alignItems="center"
onClick={() => setShow((prev) => !prev)}
>
- <div>{name}</div>
- <div>{new Date(createdAt).toDateString()}</div>
+ <Grid.Row fluid nowrap gap={8} alignItems={"center"}>
+ <KeyIcon color={NamedColors.TEXT_DEFAULT[themeScheme]} size={24} />
+ <div>{name}</div>
+ </Grid.Row>
+ <Grid.Col nowrap gap={4}>
+ <div style={{ whiteSpace: "nowrap" }}>Added on:</div>
+ <div style={{ whiteSpace: "nowrap" }}>
+ {new Date(createdAt).toLocaleDateString()}
+ </div>
+ </Grid.Col>
</Grid.Row>
{show && (
<code
@@ -1,7 +1,7 @@
// 1st-party
import type { ServiceMethodFactory } from "@ethicdevs/react-monolith";
// generated via script[generate:prisma]
-import type { PullRequest, Repository } from "@prisma/client";
+import { PullRequest, PullRequestState, Repository } from "@prisma/client";
// service
import type {
PullRequestSelectOrIncludes,
@@ -10,14 +10,30 @@ import type {
const getPullRequestsInRepository: ServiceMethodFactory<
PullRequestServiceDeps,
- [Repository, PullRequestSelectOrIncludes | undefined],
+ [
+ Repository,
+ PullRequestSelectOrIncludes | undefined,
+ "all" | "open" | "merged" | "closed" | undefined,
+ ],
Promise<PullRequest[]>
> = ({ request }) => {
- return async (repository, selectOrIncludes) => {
+ return async (repository, selectOrIncludes, filter = "open") => {
const pullRequestsInRepository = await request.prisma.pullRequest.findMany({
...(selectOrIncludes || {}),
where: {
targetRepositoryId: repository.id,
+ AND:
+ filter != null && filter !== "all"
+ ? {
+ state: {
+ equals: {
+ open: PullRequestState.OPEN,
+ merged: PullRequestState.CLOSE_MERGED,
+ closed: PullRequestState.CLOSE_DENIED,
+ }[filter],
+ },
+ }
+ : undefined,
},
});
@@ -50,6 +50,7 @@ export interface PullRequestServiceAPI extends ServiceApiContract {
getPullRequestsInRepository(
repository: Repository,
selectOrIncludes?: PullRequestSelectOrIncludes,
+ filter?: "all" | "open" | "merged" | "closed",
): Promise<PullRequest[]>;
createPullRequest(dto: CreatePullRequestDTO): Promise<PullRequest>;
mergePullRequest(dto: MergePullRequestDTO): Promise<MergePullRequestResult>;
@@ -52,6 +52,34 @@ const makeGetRepositoryCounters: ServiceMethodFactory<
})
: 0;
+ // retrieve merged pulls count in repository (PRs targeting this repo)
+ const mergedPulls =
+ orgSlug != null && repoSlug != null
+ ? await request.prisma.pullRequest.count({
+ where: {
+ targetRepository: {
+ organization: { slug: orgSlug },
+ slug: repoSlug,
+ },
+ state: "CLOSE_MERGED",
+ },
+ })
+ : 0;
+
+ // retrieve closed pulls count in repository (PRs targeting this repo)
+ const closedPulls =
+ orgSlug != null && repoSlug != null
+ ? await request.prisma.pullRequest.count({
+ where: {
+ targetRepository: {
+ organization: { slug: orgSlug },
+ slug: repoSlug,
+ },
+ state: "CLOSE_DENIED",
+ },
+ })
+ : 0;
+
// retrieve current user ssh keyrs count
const sshKeys =
username != null
@@ -65,14 +93,33 @@ const makeGetRepositoryCounters: ServiceMethodFactory<
})
: 0;
+ const forks =
+ orgSlug != null && repoSlug != null
+ ? await request.prisma.repository.count({
+ where: {
+ isFork: true,
+ forkedFromRepo: {
+ organization: {
+ slug: orgSlug,
+ },
+ slug: repoSlug,
+ },
+ },
+ })
+ : 0;
+
// for now provide pulls and zeros
const counters: RepositoryCountersDTO = {
files: 0,
- forks: 0,
+ forks: forks,
branches: 0,
tags: 0,
commits: 0,
- pulls: openPulls,
+ pulls: openPulls, // we only show open pulls, not total here
+ pullsOpen: openPulls,
+ pullsMerged: mergedPulls,
+ pullsClosed: closedPulls,
+ pullsTotal: openPulls + mergedPulls + closedPulls,
tests: 0,
builds: 0,
issues: 0,
@@ -90,11 +137,16 @@ const makeGetRepositoryCounters: ServiceMethodFactory<
const DEFAULT_COUNTERS: RepositoryCountersDTO = {
files: 0,
+ watchers: 0,
+ likes: 0,
forks: 0,
branches: 0,
tags: 0,
commits: 0,
pulls: 0,
+ pullsOpen: 0,
+ pullsMerged: 0,
+ pullsClosed: 0,
tests: 0,
builds: 0,
issues: 0,
@@ -0,0 +1,18 @@
+import { DefaultTheme } from "styled-components";
+import { createStyledContainerQueries } from "styled-container-queries";
+
+import { breakpoints } from "./utils/style";
+
+const containerTheme = createStyledContainerQueries(breakpoints);
+
+const styledTheme: DefaultTheme = {
+ // This is where we would register styled theme
+ // so we can use it in css via theme.property.
+};
+
+const theme = {
+ ...containerTheme,
+ ...styledTheme,
+};
+
+export { theme };
@@ -210,10 +210,16 @@ export type RepositoryWithParentAndForkedFromRepos =
export interface RepositoryCountersDTO {
files?: number;
forks?: number;
+ likes?: number;
+ watchers?: number;
branches?: number;
tags?: number;
commits?: number;
pulls?: number;
+ pullsOpen?: number;
+ pullsMerged?: number;
+ pullsClosed?: number;
+ pullsTotal?: number;
tests?: number;
builds?: number;
issues?: number;
@@ -1,12 +1,7 @@
import React from "react";
import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect";
-const breakpoints = {
- sm: "768px",
- md: "1024px",
- lg: "1280px",
- xl: "1640px",
-} as const;
+import { breakpoints } from "../style";
type Breakpoints = keyof typeof breakpoints;
@@ -1,10 +1,13 @@
const Colors = {
+ BLACK_TRANSPARENT: "rgba(0, 0, 0, 0.0)",
+ WHITE_TRANSPARENT: "rgba(255, 255, 255, 0.0)",
PRIMARY_01: "#1B8F97",
GRAY_LIGHT_01: "#EDEDED",
GRAY_LIGHT_02: "#9D9D9D",
GRAY_LIGHT_03: "#DDDDDD",
GRAY_LIGHT_04: "#6C6C6C",
GRAY_LIGHT_05: "#EEEEEE",
+ GRAY_LIGHT_05_ALPHA_01: "rgb(238 238 238 / 52%)",
GRAY_LIGHT_06: "#656565",
GRAY_LIGHT_07: "#D5D5D5",
GRAY_LIGHT_08: "#D8D8D8",
@@ -35,11 +35,15 @@ const NamedColors = {
},
CARD_OVERLAY: {
dark: Colors.GRAY_DARK_05,
- light: Colors.GRAY_LIGHT_05,
+ light: Colors.GRAY_LIGHT_05_ALPHA_01,
},
HEADER: {
light: Colors.WHITE_ALPHA_01,
- dark: Colors.GRAY_DARK_05_ALPHA_01,
+ dark: Colors.GRAY_DARK_05,
+ },
+ HEADER_NAV_PILL: {
+ light: Colors.WHITE_ALPHA_01,
+ dark: Colors.BLACK_TRANSPARENT,
},
INPUT: {
light: Colors.WHITE_01,
@@ -0,0 +1,6 @@
+export const breakpoints = {
+ sm: "768px",
+ md: "1024px",
+ lg: "1280px",
+ xl: "1640px",
+} as const;
@@ -0,0 +1,519 @@
+//@ts-nocheck
+
+const colorString = require("color-string");
+const convert = require("color-convert");
+
+const skippedModels = [
+ // To be honest, I don't really feel like keyword belongs in color convert, but eh.
+ "keyword",
+
+ // Gray conflicts with some method names, and has its own method defined.
+ "gray",
+
+ // Shouldn't really be in color-convert either...
+ "hex",
+];
+
+const hashedModelKeys = {};
+for (const model of Object.keys(convert)) {
+ hashedModelKeys[[...convert[model].labels].sort().join("")] = model;
+}
+
+const limiters = {};
+
+function Color(object, model) {
+ if (!(this instanceof Color)) {
+ return new Color(object, model);
+ }
+
+ if (model && model in skippedModels) {
+ model = null;
+ }
+
+ if (model && !(model in convert)) {
+ throw new Error("Unknown model: " + model);
+ }
+
+ let i;
+ let channels;
+
+ if (object == null) {
+ // eslint-disable-line no-eq-null,eqeqeq
+ this.model = "rgb";
+ this.color = [0, 0, 0];
+ this.valpha = 1;
+ } else if (object instanceof Color) {
+ this.model = object.model;
+ this.color = [...object.color];
+ this.valpha = object.valpha;
+ } else if (typeof object === "string") {
+ const result = colorString.get(object);
+ if (result === null) {
+ throw new Error("Unable to parse color from string: " + object);
+ }
+
+ this.model = result.model;
+ channels = convert[this.model].channels;
+ this.color = result.value.slice(0, channels);
+ this.valpha =
+ typeof result.value[channels] === "number" ? result.value[channels] : 1;
+ } else if (object.length > 0) {
+ this.model = model || "rgb";
+ channels = convert[this.model].channels;
+ const newArray = Array.prototype.slice.call(object, 0, channels);
+ this.color = zeroArray(newArray, channels);
+ this.valpha = typeof object[channels] === "number" ? object[channels] : 1;
+ } else if (typeof object === "number") {
+ // This is always RGB - can be converted later on.
+ this.model = "rgb";
+ this.color = [(object >> 16) & 0xff, (object >> 8) & 0xff, object & 0xff];
+ this.valpha = 1;
+ } else {
+ this.valpha = 1;
+
+ const keys = Object.keys(object);
+ if ("alpha" in object) {
+ keys.splice(keys.indexOf("alpha"), 1);
+ this.valpha = typeof object.alpha === "number" ? object.alpha : 0;
+ }
+
+ const hashedKeys = keys.sort().join("");
+ if (!(hashedKeys in hashedModelKeys)) {
+ throw new Error(
+ "Unable to parse color from object: " + JSON.stringify(object),
+ );
+ }
+
+ this.model = hashedModelKeys[hashedKeys];
+
+ const { labels } = convert[this.model];
+ const color = [];
+ for (i = 0; i < labels.length; i++) {
+ color.push(object[labels[i]]);
+ }
+
+ this.color = zeroArray(color);
+ }
+
+ // Perform limitations (clamping, etc.)
+ if (limiters[this.model]) {
+ channels = convert[this.model].channels;
+ for (i = 0; i < channels; i++) {
+ const limit = limiters[this.model][i];
+ if (limit) {
+ this.color[i] = limit(this.color[i]);
+ }
+ }
+ }
+
+ this.valpha = Math.max(0, Math.min(1, this.valpha));
+
+ if (Object.freeze) {
+ Object.freeze(this);
+ }
+}
+
+Color.prototype = {
+ toString() {
+ return this.string();
+ },
+
+ toJSON() {
+ return this[this.model]();
+ },
+
+ string(places) {
+ let self = this.model in colorString.to ? this : this.rgb();
+ self = self.round(typeof places === "number" ? places : 1);
+ const args = self.valpha === 1 ? self.color : [...self.color, this.valpha];
+ return colorString.to[self.model](args);
+ },
+
+ percentString(places) {
+ const self = this.rgb().round(typeof places === "number" ? places : 1);
+ const args = self.valpha === 1 ? self.color : [...self.color, this.valpha];
+ return colorString.to.rgb.percent(args);
+ },
+
+ array() {
+ return this.valpha === 1 ? [...this.color] : [...this.color, this.valpha];
+ },
+
+ object() {
+ const result = {};
+ const { channels } = convert[this.model];
+ const { labels } = convert[this.model];
+
+ for (let i = 0; i < channels; i++) {
+ result[labels[i]] = this.color[i];
+ }
+
+ if (this.valpha !== 1) {
+ result.alpha = this.valpha;
+ }
+
+ return result;
+ },
+
+ unitArray() {
+ const rgb = this.rgb().color;
+ rgb[0] /= 255;
+ rgb[1] /= 255;
+ rgb[2] /= 255;
+
+ if (this.valpha !== 1) {
+ rgb.push(this.valpha);
+ }
+
+ return rgb;
+ },
+
+ unitObject() {
+ const rgb = this.rgb().object();
+ rgb.r /= 255;
+ rgb.g /= 255;
+ rgb.b /= 255;
+
+ if (this.valpha !== 1) {
+ rgb.alpha = this.valpha;
+ }
+
+ return rgb;
+ },
+
+ round(places) {
+ places = Math.max(places || 0, 0);
+ return new Color(
+ [...this.color.map(roundToPlace(places)), this.valpha],
+ this.model,
+ );
+ },
+
+ alpha(value) {
+ if (value !== undefined) {
+ return new Color(
+ [...this.color, Math.max(0, Math.min(1, value))],
+ this.model,
+ );
+ }
+
+ return this.valpha;
+ },
+
+ // Rgb
+ red: getset("rgb", 0, maxfn(255)),
+ green: getset("rgb", 1, maxfn(255)),
+ blue: getset("rgb", 2, maxfn(255)),
+
+ hue: getset(
+ ["hsl", "hsv", "hsl", "hwb", "hcg"],
+ 0,
+ (value) => ((value % 360) + 360) % 360,
+ ),
+
+ saturationl: getset("hsl", 1, maxfn(100)),
+ lightness: getset("hsl", 2, maxfn(100)),
+
+ saturationv: getset("hsv", 1, maxfn(100)),
+ value: getset("hsv", 2, maxfn(100)),
+
+ chroma: getset("hcg", 1, maxfn(100)),
+ gray: getset("hcg", 2, maxfn(100)),
+
+ white: getset("hwb", 1, maxfn(100)),
+ wblack: getset("hwb", 2, maxfn(100)),
+
+ cyan: getset("cmyk", 0, maxfn(100)),
+ magenta: getset("cmyk", 1, maxfn(100)),
+ yellow: getset("cmyk", 2, maxfn(100)),
+ black: getset("cmyk", 3, maxfn(100)),
+
+ x: getset("xyz", 0, maxfn(95.047)),
+ y: getset("xyz", 1, maxfn(100)),
+ z: getset("xyz", 2, maxfn(108.833)),
+
+ l: getset("lab", 0, maxfn(100)),
+ a: getset("lab", 1),
+ b: getset("lab", 2),
+
+ keyword(value) {
+ if (value !== undefined) {
+ return new Color(value);
+ }
+
+ return convert[this.model].keyword(this.color);
+ },
+
+ hex(value) {
+ if (value !== undefined) {
+ return new Color(value);
+ }
+
+ return colorString.to.hex(this.rgb().round().color);
+ },
+
+ hexa(value) {
+ if (value !== undefined) {
+ return new Color(value);
+ }
+
+ const rgbArray = this.rgb().round().color;
+
+ let alphaHex = Math.round(this.valpha * 255)
+ .toString(16)
+ .toUpperCase();
+ if (alphaHex.length === 1) {
+ alphaHex = "0" + alphaHex;
+ }
+
+ return colorString.to.hex(rgbArray) + alphaHex;
+ },
+
+ rgbNumber() {
+ const rgb = this.rgb().color;
+ return ((rgb[0] & 0xff) << 16) | ((rgb[1] & 0xff) << 8) | (rgb[2] & 0xff);
+ },
+
+ luminosity() {
+ // http://www.w3.org/TR/WCAG20/#relativeluminancedef
+ const rgb = this.rgb().color;
+
+ const lum = [];
+ for (const [i, element] of rgb.entries()) {
+ const chan = element / 255;
+ lum[i] = chan <= 0.04045 ? chan / 12.92 : ((chan + 0.055) / 1.055) ** 2.4;
+ }
+
+ return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];
+ },
+
+ contrast(color2) {
+ // http://www.w3.org/TR/WCAG20/#contrast-ratiodef
+ const lum1 = this.luminosity();
+ const lum2 = color2.luminosity();
+
+ if (lum1 > lum2) {
+ return (lum1 + 0.05) / (lum2 + 0.05);
+ }
+
+ return (lum2 + 0.05) / (lum1 + 0.05);
+ },
+
+ level(color2) {
+ // https://www.w3.org/TR/WCAG/#contrast-enhanced
+ const contrastRatio = this.contrast(color2);
+ if (contrastRatio >= 7) {
+ return "AAA";
+ }
+
+ return contrastRatio >= 4.5 ? "AA" : "";
+ },
+
+ isDark() {
+ // YIQ equation from http://24ways.org/2010/calculating-color-contrast
+ const rgb = this.rgb().color;
+ const yiq = (rgb[0] * 2126 + rgb[1] * 7152 + rgb[2] * 722) / 10000;
+ return yiq < 128;
+ },
+
+ isLight() {
+ return !this.isDark();
+ },
+
+ negate() {
+ const rgb = this.rgb();
+ for (let i = 0; i < 3; i++) {
+ rgb.color[i] = 255 - rgb.color[i];
+ }
+
+ return rgb;
+ },
+
+ lighten(ratio) {
+ const hsl = this.hsl();
+ hsl.color[2] += hsl.color[2] * ratio;
+ return hsl;
+ },
+
+ darken(ratio) {
+ const hsl = this.hsl();
+ hsl.color[2] -= hsl.color[2] * ratio;
+ return hsl;
+ },
+
+ saturate(ratio) {
+ const hsl = this.hsl();
+ hsl.color[1] += hsl.color[1] * ratio;
+ return hsl;
+ },
+
+ desaturate(ratio) {
+ const hsl = this.hsl();
+ hsl.color[1] -= hsl.color[1] * ratio;
+ return hsl;
+ },
+
+ whiten(ratio) {
+ const hwb = this.hwb();
+ hwb.color[1] += hwb.color[1] * ratio;
+ return hwb;
+ },
+
+ blacken(ratio) {
+ const hwb = this.hwb();
+ hwb.color[2] += hwb.color[2] * ratio;
+ return hwb;
+ },
+
+ grayscale() {
+ // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
+ const rgb = this.rgb().color;
+ const value = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;
+ return Color.rgb(value, value, value);
+ },
+
+ fade(ratio) {
+ return this.alpha(this.valpha - this.valpha * ratio);
+ },
+
+ opaquer(ratio) {
+ return this.alpha(this.valpha + this.valpha * ratio);
+ },
+
+ rotate(degrees) {
+ const hsl = this.hsl();
+ let hue = hsl.color[0];
+ hue = (hue + degrees) % 360;
+ hue = hue < 0 ? 360 + hue : hue;
+ hsl.color[0] = hue;
+ return hsl;
+ },
+
+ mix(mixinColor, weight) {
+ // Ported from sass implementation in C
+ // https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209
+ if (!mixinColor || !mixinColor.rgb) {
+ throw new Error(
+ 'Argument to "mix" was not a Color instance, but rather an instance of ' +
+ typeof mixinColor,
+ );
+ }
+
+ const color1 = mixinColor.rgb();
+ const color2 = this.rgb();
+ const p = weight === undefined ? 0.5 : weight;
+
+ const w = 2 * p - 1;
+ const a = color1.alpha() - color2.alpha();
+
+ const w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2;
+ const w2 = 1 - w1;
+
+ return Color.rgb(
+ w1 * color1.red() + w2 * color2.red(),
+ w1 * color1.green() + w2 * color2.green(),
+ w1 * color1.blue() + w2 * color2.blue(),
+ color1.alpha() * p + color2.alpha() * (1 - p),
+ );
+ },
+};
+
+// Model conversion methods and static constructors
+for (const model of Object.keys(convert)) {
+ if (skippedModels.includes(model)) {
+ continue;
+ }
+
+ const { channels } = convert[model];
+
+ // Conversion methods
+ Color.prototype[model] = function (...args) {
+ if (this.model === model) {
+ return new Color(this);
+ }
+
+ if (args.length > 0) {
+ return new Color(args, model);
+ }
+
+ return new Color(
+ [...assertArray(convert[this.model][model].raw(this.color)), this.valpha],
+ model,
+ );
+ };
+
+ // 'static' construction methods
+ Color[model] = function (...args) {
+ let color = args[0];
+ if (typeof color === "number") {
+ color = zeroArray(args, channels);
+ }
+
+ return new Color(color, model);
+ };
+}
+
+function roundTo(number, places) {
+ return Number(number.toFixed(places));
+}
+
+function roundToPlace(places) {
+ return function (number) {
+ return roundTo(number, places);
+ };
+}
+
+function getset(model, channel, modifier) {
+ model = Array.isArray(model) ? model : [model];
+
+ for (const m of model) {
+ (limiters[m] || (limiters[m] = []))[channel] = modifier;
+ }
+
+ model = model[0];
+
+ return function (value) {
+ let result;
+
+ if (value !== undefined) {
+ if (modifier) {
+ value = modifier(value);
+ }
+
+ result = this[model]();
+ result.color[channel] = value;
+ return result;
+ }
+
+ result = this[model]().color[channel];
+ if (modifier) {
+ result = modifier(result);
+ }
+
+ return result;
+ };
+}
+
+function maxfn(max) {
+ return function (v) {
+ return Math.max(0, Math.min(max, v));
+ };
+}
+
+function assertArray(value) {
+ return Array.isArray(value) ? value : [value];
+}
+
+function zeroArray(array, length) {
+ for (let i = 0; i < length; i++) {
+ if (typeof array[i] !== "number") {
+ array[i] = 0;
+ }
+ }
+
+ return array;
+}
+
+module.exports = Color;
+
+export default Color as (obj: string, model?: string) => Color;
@@ -1,2 +1,4 @@
export { default as Colors } from "./Colors";
export { default as NamedColors } from "./NamedColors";
+export { breakpoints } from "./breakpoints";
+export { default as Color } from "./color-utils";
@@ -75,7 +75,7 @@ const RepositoryBrowserView: ReactView<RepositoryBrowserViewProps> = ({
repo={repo}
/>
</IslandWrapper>
- <Grid.Col fluid style={{ marginTop: 32 }}>
+ <Grid.Col fluid style={{ marginTop: 16 }}>
{lastCommit && (
<Card
data-islandid={`${RepositoryCommitSummaryLine.name}$$0`}
@@ -99,7 +99,7 @@ const RepositoryBrowserView: ReactView<RepositoryBrowserViewProps> = ({
backgroundColor:
NamedColors.CARD_ALPHA_01[commonProps.themeScheme],
position: "sticky",
- top: 80,
+ top: 70,
zIndex: 9000,
borderRadius: 8,
}}
@@ -61,7 +61,7 @@ const RepositoryCommitsLogView: ReactView<RepositoryCommitsLogViewProps> = ({
data-islandid={`${RepositoryCommitSummaryLine.name}$$${idx}`}
style={{
width: "100%",
- marginTop: idx >= 1 ? 4 : 32,
+ marginTop: idx >= 1 ? 4 : 16,
padding: 8,
}}
themeScheme={commonProps.themeScheme}
@@ -86,7 +86,7 @@ const RepositoryDetailsView: ReactView<RepositoryDetailsViewProps> = ({
<style
dangerouslySetInnerHTML={{
__html: `
- @media only screen and (max-width: 768px) {
+ @media only screen and (max-width: 1143px) {
.mobile-column {
flex-flow: column nowrap;
}
@@ -107,7 +107,7 @@ const RepositoryDetailsView: ReactView<RepositoryDetailsViewProps> = ({
<Grid.Row
nowrap
fluid
- style={{ marginTop: 32 }}
+ style={{ marginTop: 16 }}
gap={16}
className={"mobile-column mobile-full-width"}
>
@@ -140,7 +140,7 @@ const RepositoryDetailsView: ReactView<RepositoryDetailsViewProps> = ({
width: "100%",
padding: 8,
position: "sticky",
- top: 80,
+ top: 70,
zIndex: 9000,
borderRadius: 8,
}}
@@ -194,7 +194,7 @@ const RepositoryDetailsView: ReactView<RepositoryDetailsViewProps> = ({
width: "100%",
maxWidth: 768,
position: "sticky",
- top: 80,
+ top: 70,
zIndex: 9000,
}}
>
@@ -53,7 +53,7 @@ const RepositoryForkView: ReactView<RepositoryForkViewProps> = ({
showForkButton={false}
/>
</IslandWrapper>
- <div style={{ height: 32 }} />
+ <div style={{ height: 16 }} />
{errorMessage && (
<div className={"error_message"}>
<p>{errorMessage}</p>
@@ -70,18 +70,17 @@ const RepositoryShowObjectView: ReactView<RepositoryShowObjectViewProps> = ({
separator={"~"}
/>
</IslandWrapper>
-
<Card
data-islandid={`${RepositoryCommitSummaryLine.name}$$0`}
style={{
width: "100%",
- marginTop: 32,
+ marginTop: 16,
padding: 8,
gap: 8,
backdropFilter: "blur(8px)",
backgroundColor: NamedColors.CARD_ALPHA_01[commonProps.themeScheme],
position: "sticky",
- top: 80,
+ top: 70,
zIndex: 9000,
borderRadius: 8,
}}
@@ -48,7 +48,7 @@ const RepositoryPullRequestCreateView: ReactView<
</IslandWrapper>
<IslandWrapper
data-islandid={`${RepositoryPullRequestCreateForm.name}$$0`}
- style={{ marginTop: 24 }}
+ style={{ marginTop: 16 }}
>
<RepositoryPullRequestCreateForm
parentOrgSlug={parentOrg.slug}
@@ -101,7 +101,7 @@ const RepositoryPullRequestDetailsView: ReactView<
// onCloseButtonClick
/>
</IslandWrapper>
- <Grid.Col fluid style={{ marginTop: 24 }}>
+ <Grid.Col fluid style={{ marginTop: 16 }}>
<Grid.Col key={pr.id} fluid>
<Grid.Row fluid alignItems="center" gap={16}>
<h1 style={{ margin: 0, marginTop: 8 }}>{pr.summary}</h1>
@@ -7,12 +7,18 @@ import type { Organization, PullRequest } from "@prisma/client";
// app
import type { CommonProps, RepositoryWithForkedFromRepo } from "../../types";
import { AppRoute } from "../../routes.defs";
-import { Grid, IslandWrapper, Layout, PageWrapper } from "../../components";
+import { Card } from "../../components/Card.styled";
+import { Chip } from "../../components/Chip";
+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";
// app islands
+import { IslandWrapper } from "../../components/IslandWrapper.styled";
import RepositoryHero from "../../islands/RepositoryHero";
-type PullRequestsFilter = "opened" | "closed" | "merged" | "all" | "search";
+type PullRequestsFilter = "all" | "open" | "closed" | "merged" | "search";
export interface RepositoryPullRequestsViewProps extends CommonProps {
parentOrg: Organization;
@@ -28,7 +34,7 @@ const RepositoryPullRequestsView: ReactView<
parentOrg,
pullRequests,
repo,
- pullRequestsFilter = "all",
+ pullRequestsFilter = "open",
}) => {
return (
<Layout
@@ -49,6 +55,15 @@ const RepositoryPullRequestsView: ReactView<
showForkButton={false}
showNewButton
newButtonText={"New Pull Request"}
+ // newButtonText={
+ // <>
+ // <span>New Pull Request</span>
+ // <GitPullIcon
+ // color={Colors.WHITE_01}
+ // size={24}
+ // />
+ // </>
+ // }
newButtonUrl={buildRouteLink(
AppRoute.REPOSITORY_PULL_REQUEST_CREATE,
{
@@ -58,11 +73,22 @@ const RepositoryPullRequestsView: ReactView<
)}
/>
</IslandWrapper>
- <Grid.Col fluid style={{ marginTop: 16 }}>
- <Grid.Row fluid alignItems={"center"} gap={12}>
+ <Grid.Col
+ fluid
+ style={{
+ padding: "12px 0",
+ borderBottom: `1px solid ${NamedColors.BORDER_DEFAULT[commonProps.themeScheme]}`,
+ }}
+ >
+ <Grid.Row
+ fluid
+ alignItems={"center"}
+ gap={12}
+ style={{ padding: "0 8px" }}
+ >
<a
style={{
- fontWeight: "bold",
+ fontWeight: pullRequestsFilter === "all" ? "bold" : "normal",
textDecoration:
pullRequestsFilter === "all" ? "underline" : "none",
}}
@@ -70,23 +96,33 @@ const RepositoryPullRequestsView: ReactView<
"all" as PullRequestsFilter
}`}
>
- All
+ <Grid.Row nowrap gap={8} alignItems={"center"}>
+ <span>All</span>
+ <Chip themeScheme={commonProps.themeScheme}>
+ {commonProps.layoutCounters!.pullsTotal}
+ </Chip>
+ </Grid.Row>
</a>
<a
style={{
- fontWeight: "normal",
+ fontWeight: pullRequestsFilter === "open" ? "bold" : "normal",
textDecoration:
- pullRequestsFilter === "opened" ? "underline" : "none",
+ pullRequestsFilter === "open" ? "underline" : "none",
}}
href={`/${parentOrg.slug}/${repo.slug}/pulls?filter=${
- "opened" as PullRequestsFilter
+ "open" as PullRequestsFilter
}`}
>
- Opened
+ <Grid.Row nowrap gap={8} alignItems={"center"}>
+ <span>Open</span>
+ <Chip themeScheme={commonProps.themeScheme}>
+ {commonProps.layoutCounters!.pullsOpen}
+ </Chip>
+ </Grid.Row>
</a>
<a
style={{
- fontWeight: "normal",
+ fontWeight: pullRequestsFilter === "merged" ? "bold" : "normal",
textDecoration:
pullRequestsFilter === "merged" ? "underline" : "none",
}}
@@ -94,11 +130,16 @@ const RepositoryPullRequestsView: ReactView<
"merged" as PullRequestsFilter
}`}
>
- Merged
+ <Grid.Row nowrap gap={8} alignItems={"center"}>
+ <span>Merged</span>
+ <Chip themeScheme={commonProps.themeScheme}>
+ {commonProps.layoutCounters!.pullsMerged}
+ </Chip>
+ </Grid.Row>
</a>
<a
style={{
- fontWeight: "normal",
+ fontWeight: pullRequestsFilter === "closed" ? "bold" : "normal",
textDecoration:
pullRequestsFilter === "closed" ? "underline" : "none",
}}
@@ -106,68 +147,85 @@ const RepositoryPullRequestsView: ReactView<
"closed" as PullRequestsFilter
}`}
>
- Closed
+ <Grid.Row nowrap gap={8} alignItems={"center"}>
+ <span>Closed</span>
+ <Chip themeScheme={commonProps.themeScheme}>
+ {commonProps.layoutCounters!.pullsClosed}
+ </Chip>
+ </Grid.Row>
</a>
</Grid.Row>
</Grid.Col>
<Grid.Col fluid style={{ marginTop: 8 }}>
{pullRequests != null && pullRequests.length >= 1 ? (
pullRequests.map((pr, idx) => (
- <Grid.Col
+ <Card
key={pr.id}
- fluid
- style={{ marginTop: idx === 0 ? 0 : 16 }}
+ themeScheme={commonProps.themeScheme}
+ style={{ width: "100%" }}
>
- <a
- href={buildRouteLink(
- AppRoute.REPOSITORY_PULL_REQUEST_DETAILS,
- {
- orgSlug: parentOrg.slug,
- repoSlug: repo.slug,
- pullUid: pr.uid,
- },
- )}
- >
- #{pr.uid} - {pr.summary} [{pr.state}]
- </a>
- <span style={{ opacity: 0.67 }}>
- wants to merge <code>{pr.sourceBranch}</code> into{" "}
- <code>{pr.targetBranch}</code>
- </span>
- <Grid.Row
+ <Grid.Col
+ key={pr.id}
fluid
- alignItems={"center"}
- style={{ opacity: 0.67, marginTop: 4 }}
+ style={{ marginTop: idx === 0 ? 0 : 16 }}
>
- {new Date(pr.createdAt).getTime() <=
- new Date(pr.updatedAt).getTime() && (
- <span>
- opened on {new Date(pr.createdAt).toLocaleString()}
- </span>
- )}
- {((pr.closedAt == null &&
- new Date(pr.updatedAt).getTime() >
- new Date(pr.createdAt).getTime()) ||
- (pr.closedAt != null &&
- new Date(pr.updatedAt).getTime() <
- new Date(pr.closedAt).getTime())) && (
- <span>
- updated on {new Date(pr.updatedAt).toLocaleString()}
- </span>
- )}
- {pr.closedAt != null && (
- <span>
- closed on
- {new Date(pr.closedAt).toLocaleString()}
- </span>
- )}
- </Grid.Row>
- </Grid.Col>
+ <a
+ href={buildRouteLink(
+ AppRoute.REPOSITORY_PULL_REQUEST_DETAILS,
+ {
+ orgSlug: parentOrg.slug,
+ repoSlug: repo.slug,
+ pullUid: pr.uid,
+ },
+ )}
+ >
+ #{pr.uid} - {pr.summary} [{pr.state}]
+ </a>
+ <span style={{ opacity: 0.67 }}>
+ wants to merge <code>{pr.sourceBranch}</code> into{" "}
+ <code>{pr.targetBranch}</code>
+ </span>
+ <Grid.Row
+ fluid
+ alignItems={"center"}
+ style={{ opacity: 0.67, marginTop: 4 }}
+ >
+ {new Date(pr.createdAt).getTime() <=
+ new Date(pr.updatedAt).getTime() && (
+ <span>
+ opened on {new Date(pr.createdAt).toLocaleString()}
+ </span>
+ )}
+ {((pr.closedAt == null &&
+ new Date(pr.updatedAt).getTime() >
+ new Date(pr.createdAt).getTime()) ||
+ (pr.closedAt != null &&
+ new Date(pr.updatedAt).getTime() <
+ new Date(pr.closedAt).getTime())) && (
+ <span>
+ updated on {new Date(pr.updatedAt).toLocaleString()}
+ </span>
+ )}
+ {pr.closedAt != null && (
+ <span>
+ closed on
+ {new Date(pr.closedAt).toLocaleString()}
+ </span>
+ )}
+ </Grid.Row>
+ </Grid.Col>
+ </Card>
))
) : (
- <div>
- <h1>No Pull Request Yet</h1>
- <p>
+ <Grid.Col
+ fluid
+ nowrap
+ justifyContent={"center"}
+ alignItems={"center"}
+ style={{ minHeight: "70vh" }}
+ >
+ <h1 style={{ margin: 0 }}>No Pull Request Yet</h1>
+ <p style={{ maxWidth: "62%", textAlign: "center" }}>
<span>Be the change you want to see, </span>
<a
href={buildRouteLink(
@@ -182,7 +240,7 @@ const RepositoryPullRequestsView: ReactView<
</a>
<span> to this repository 🚀.</span>
</p>
- </div>
+ </Grid.Col>
)}
</Grid.Col>
</PageWrapper>
@@ -62,7 +62,8 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-is": "^17.0.2",
- "styled-components": "^5.3.5"
+ "styled-components": "^5.3.5",
+ "styled-container-queries": "^1.0.0"
},
"devDependencies": {
"@babel/core": "^7.0.0-0",
@@ -4841,6 +4841,11 @@ styled-components@>=5.3.5, styled-components@^5.3.5:
shallowequal "^1.1.0"
supports-color "^5.5.0"
+styled-container-queries@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/styled-container-queries/-/styled-container-queries-1.0.0.tgz#b1a0ec16d1d89d6bc4fd8eead57171d4f1afe530"
+ integrity sha512-Rxvb0brymST4qqf0ckW+kAJuuyPuXOr4uRvNnJ5tbqNwOoSpmvpWj5KcJlV9mNs2xq8hozRD1s9lx3+Azwl4Dg==
+
supports-color@^5.3.0, supports-color@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"