feat(drawer): make them mobile first@@ -1 +0,0 @@
-Branch B\n
@@ -1,5 +1,5 @@
{
- "_generatedAtUnix": 1778731850286,
+ "_generatedAtUnix": 1778816347541,
"_hashAlgorithm": "sha1",
"_version": 2,
"assets": {
@@ -102,7 +102,7 @@
},
"views": {
"HomeView": {
- "hash": "02d7348a7966d0bab30badacd77703cec1446515",
+ "hash": "9af14ca668298d8cf3ddd309fe29ab8bc93be7b7",
"pathSource": "./app/views/HomeView.tsx"
},
"InternalErrorView": {
@@ -170,7 +170,7 @@
"pathSource": "./app/views/repository/RepositoryForkView.tsx"
},
"RepositoryShowObjectView": {
- "hash": "057fe75366d6705671a24bac56d201581ac54567",
+ "hash": "3c5578449f0a838f9a8b679ec2360a212f5a4e4c",
"pathSource": "./app/views/repository/RepositoryShowObjectView.tsx"
},
"RepositoryPullRequestCreateView": {
@@ -1,7 +1,8 @@
// 3rd-party
-import styled, { css } from "styled-components";
+import { css } from "styled-components";
+import styledContainerQuery from "styled-container-query";
// app
-import { Colors } from "../utils/style";
+import { breakpoints, Colors } from "../utils/style";
type ButtonProps = {
disabled?: boolean;
@@ -50,6 +51,15 @@ const baseButtonCss = css<ButtonProps>`
padding-top 140ms ease-in-out 0s,
transform 140ms ease-in-out 0s;
+ &:container(max-width: 119px) {
+ font-size: 11px;
+ background: red !important;
+ }
+ &:container(min-width: 120px) {
+ font-size: 18px;
+ background: green !important;
+ }
+
&:not(:disabled) {
cursor: pointer;
}
@@ -78,13 +88,17 @@ const baseButtonCss = css<ButtonProps>`
}
${({ disabled }) => disabled && disabledButtonCss};
+
+ // @media only screen and (max-width: ${breakpoints.sm}) {
+ // font-size: 11px;
+ // }
`;
-export const Button = styled.button<ButtonProps>`
+export const Button = styledContainerQuery.button<ButtonProps>`
${baseButtonCss};
`;
-export const ButtonAnchor = styled.a<ButtonProps>`
+export const ButtonAnchor = styledContainerQuery.a<ButtonProps>`
${baseButtonCss};
text-decoration: none;
&:hover {
@@ -89,111 +89,101 @@ export const DrawerPrimary = ({
}
return (
- <StyledDrawerPrimary id="drawer" themeScheme={themeScheme}>
- <StyledDrawerHeader>
- <StyledLogoArea themeScheme={themeScheme}>
- <a href={"/"}>
- <h1>{Const.APP_NAME}</h1>
- </a>
- </StyledLogoArea>
- </StyledDrawerHeader>
- <StyledDrawerContent>
- <StyledDrawerListHeader style={{ margin: 0 }}>
- <a href={buildRouteLink(AppRoute.ORGANIZATION_DETAILS, { orgSlug })}>
- @{orgSlug}
- </a>
- <span>{" / "}</span>
- <a
- href={buildRouteLink(AppRoute.REPOSITORY_DETAILS, {
- orgSlug,
- repoSlug,
- })}
- >
- <TextEllipsis>{repoSlug}</TextEllipsis>
- </a>
- </StyledDrawerListHeader>
- <StyledDrawerListHeader style={{ height: 32 }}>
- <Grid.Row
- fluid
- nowrap
- gap={8}
- justifyContent={"center"}
- alignItems={"center"}
- >
- <Grid.Row nowrap gap={4} alignItems={"center"}>
- <GitPullIcon
- color={NamedColors.TEXT_MUTED[themeScheme]}
- size={16}
- />
- <span style={{ fontSize: 11 }}>Watchers</span>
- <Chip
- themeScheme={themeScheme}
- color={NamedColors.TEXT_MUTED[themeScheme]}
- style={{
- padding: "2px 6px",
- backgroundColor: "rgba(0,0,0,0.1)",
- fontSize: 11,
- color: NamedColors.TEXT_MUTED[themeScheme],
- }}
- >
- {counters.watchers || "0"}
- </Chip>
- </Grid.Row>
- <Grid.Row nowrap gap={4} alignItems={"center"}>
- <LikeIcon color={NamedColors.TEXT_MUTED[themeScheme]} size={16} />
- <span style={{ fontSize: 11 }}>Likes</span>
- <Chip
- themeScheme={themeScheme}
- color={NamedColors.TEXT_MUTED[themeScheme]}
- style={{
- padding: "2px 6px",
- backgroundColor: "rgba(0,0,0,0.1)",
- fontSize: 11,
- color: NamedColors.TEXT_MUTED[themeScheme],
- }}
- >
- {counters.likes || "0"}
- </Chip>
- </Grid.Row>
- <Grid.Row nowrap gap={4} alignItems={"center"}>
- <GitForkIcon color={Colors.WHITE_01} size={16} />
- <span style={{ fontSize: 11 }}>Forks</span>
- <Chip
- themeScheme={themeScheme}
- color={NamedColors.TEXT_MUTED[themeScheme]}
- style={{
- padding: "2px 6px",
- backgroundColor: "rgba(0,0,0,0.1)",
- fontSize: 11,
- color: NamedColors.TEXT_MUTED[themeScheme],
- }}
- >
- {counters.forks || "0"}
- </Chip>
+ <>
+ <StyledDrawerPrimary id="drawer" themeScheme={themeScheme}>
+ <StyledDrawerHeader>
+ <StyledLogoArea themeScheme={themeScheme}>
+ <a href={"/"}>
+ <h1>{Const.APP_NAME}</h1>
+ </a>
+ </StyledLogoArea>
+ </StyledDrawerHeader>
+ <StyledDrawerContent>
+ <StyledDrawerListHeader style={{ margin: 0 }}>
+ <a
+ href={buildRouteLink(AppRoute.ORGANIZATION_DETAILS, { orgSlug })}
+ >
+ @{orgSlug}
+ </a>
+ <span>{" / "}</span>
+ <a
+ href={buildRouteLink(AppRoute.REPOSITORY_DETAILS, {
+ orgSlug,
+ repoSlug,
+ })}
+ >
+ <TextEllipsis>{repoSlug}</TextEllipsis>
+ </a>
+ </StyledDrawerListHeader>
+ <StyledDrawerListHeader style={{ height: 32 }}>
+ <Grid.Row
+ fluid
+ nowrap
+ gap={8}
+ justifyContent={"center"}
+ alignItems={"center"}
+ >
+ <Grid.Row nowrap gap={4} alignItems={"center"}>
+ <GitPullIcon
+ color={NamedColors.TEXT_MUTED[themeScheme]}
+ size={16}
+ />
+ <span style={{ fontSize: 11 }}>Watchers</span>
+ <Chip
+ themeScheme={themeScheme}
+ color={NamedColors.TEXT_MUTED[themeScheme]}
+ style={{
+ padding: "2px 6px",
+ backgroundColor: "rgba(0,0,0,0.1)",
+ fontSize: 11,
+ color: NamedColors.TEXT_MUTED[themeScheme],
+ }}
+ >
+ {counters.watchers || "0"}
+ </Chip>
+ </Grid.Row>
+ <Grid.Row nowrap gap={4} alignItems={"center"}>
+ <LikeIcon
+ color={NamedColors.TEXT_MUTED[themeScheme]}
+ size={16}
+ />
+ <span style={{ fontSize: 11 }}>Likes</span>
+ <Chip
+ themeScheme={themeScheme}
+ color={NamedColors.TEXT_MUTED[themeScheme]}
+ style={{
+ padding: "2px 6px",
+ backgroundColor: "rgba(0,0,0,0.1)",
+ fontSize: 11,
+ color: NamedColors.TEXT_MUTED[themeScheme],
+ }}
+ >
+ {counters.likes || "0"}
+ </Chip>
+ </Grid.Row>
+ <Grid.Row nowrap gap={4} alignItems={"center"}>
+ <GitForkIcon color={Colors.WHITE_01} size={16} />
+ <span style={{ fontSize: 11 }}>Forks</span>
+ <Chip
+ themeScheme={themeScheme}
+ color={NamedColors.TEXT_MUTED[themeScheme]}
+ style={{
+ padding: "2px 6px",
+ backgroundColor: "rgba(0,0,0,0.1)",
+ fontSize: 11,
+ color: NamedColors.TEXT_MUTED[themeScheme],
+ }}
+ >
+ {counters.forks || "0"}
+ </Chip>
+ </Grid.Row>
</Grid.Row>
- </Grid.Row>
- </StyledDrawerListHeader>
- <StyledDrawerList>
- <StyledDrawerListItem
- themeScheme={themeScheme}
- href={pathFiles}
- className={
- ((!commonProps.path!.startsWith(pathPipelines) === false &&
- commonProps.path!.startsWith(pathFiles)) ||
- [pathFiles, pathRepo, pathRepoTrailing].some(
- (p) =>
- commonProps.path === p || commonProps.path!.startsWith(p),
- )) &&
- commonProps.path!.startsWith(pathPulls) === false &&
- commonProps.path!.startsWith(pathPipelines) === false
- ? "active"
- : undefined
- }
- style={{ paddingRight: 16 }}
- >
- <span>Files</span>
- <FolderIcon
- color={
+ </StyledDrawerListHeader>
+ <StyledDrawerList>
+ <StyledDrawerListItem
+ themeScheme={themeScheme}
+ href={pathFiles}
+ className={
((!commonProps.path!.startsWith(pathPipelines) === false &&
commonProps.path!.startsWith(pathFiles)) ||
[pathFiles, pathRepo, pathRepoTrailing].some(
@@ -202,87 +192,128 @@ export const DrawerPrimary = ({
)) &&
commonProps.path!.startsWith(pathPulls) === false &&
commonProps.path!.startsWith(pathPipelines) === false
- ? NamedColors.TEXT_DEFAULT[themeScheme]
- : NamedColors.TEXT_MUTED[themeScheme]
+ ? "active"
+ : undefined
+ }
+ style={{ paddingRight: 16 }}
+ >
+ <span>Files</span>
+ <FolderIcon
+ color={
+ ((!commonProps.path!.startsWith(pathPipelines) === false &&
+ commonProps.path!.startsWith(pathFiles)) ||
+ [pathFiles, pathRepo, pathRepoTrailing].some(
+ (p) =>
+ commonProps.path === p ||
+ commonProps.path!.startsWith(p),
+ )) &&
+ commonProps.path!.startsWith(pathPulls) === false &&
+ commonProps.path!.startsWith(pathPipelines) === false
+ ? NamedColors.TEXT_DEFAULT[themeScheme]
+ : NamedColors.TEXT_MUTED[themeScheme]
+ }
+ size={16}
+ />
+ </StyledDrawerListItem>
+ <StyledDrawerListItem
+ themeScheme={themeScheme}
+ href={pathPulls}
+ className={
+ commonProps.path! === pathPulls ||
+ commonProps.path!.startsWith(pathPulls)
+ ? "active"
+ : undefined
}
- size={16}
- />
- </StyledDrawerListItem>
- <StyledDrawerListItem
- themeScheme={themeScheme}
- href={pathPulls}
- className={
- commonProps.path! === pathPulls ||
- commonProps.path!.startsWith(pathPulls)
- ? "active"
- : undefined
- }
- >
- <span>Pull Requests</span>
- <Chip themeScheme={themeScheme}>{counters.pulls || 0}</Chip>
- </StyledDrawerListItem>
- <StyledDrawerListItem
- themeScheme={themeScheme}
- href={pathPipelines}
- className={
- commonProps.path! === pathPipelines ||
- commonProps.path!.startsWith(pathPipelines)
- ? "active"
- : undefined
- }
- >
- <span>Pipelines</span>
- <Chip themeScheme={themeScheme}>{counters.builds || 0}</Chip>
- </StyledDrawerListItem>
- <StyledDrawerListItem themeScheme={themeScheme} disabled>
- <span>Tests & Coverage</span>
- <Chip themeScheme={themeScheme}>{counters.tests || 0}</Chip>
- </StyledDrawerListItem>
- <StyledDrawerListItem themeScheme={themeScheme} disabled>
- <span>Issues</span>
- <Chip themeScheme={themeScheme}>{counters.issues || 0}</Chip>
- </StyledDrawerListItem>
- <StyledDrawerListItem themeScheme={themeScheme} disabled>
- <span>API Reference</span>
- <Chip themeScheme={themeScheme}>{counters.apiRefSymbols || 0}</Chip>
- </StyledDrawerListItem>
- </StyledDrawerList>
- <StyledDrawerListHeader></StyledDrawerListHeader>
- <StyledDrawerList></StyledDrawerList>
- </StyledDrawerContent>
- <StyledDrawerFooter>
- <StyledDrawerList>
- <StyledDrawerListItem themeScheme={themeScheme} disabled>
- <span>Feedback</span>
- <CommentIcon
- color={NamedColors.TEXT_MUTED[themeScheme]}
- size={20}
- />
- </StyledDrawerListItem>
- <StyledDrawerListItem themeScheme={themeScheme} disabled>
- <span>Help Center</span>
- <span style={{ flex: 1 }}></span>
- {counters.helpCenterNotifs! > 0 && (
- <Chip themeScheme={themeScheme}>{counters.helpCenterNotifs}</Chip>
- )}
- <SupportIcon
- color={NamedColors.TEXT_MUTED[themeScheme]}
- size={20}
- />
- </StyledDrawerListItem>
- <StyledDrawerListItem themeScheme={themeScheme} disabled>
- <span>Settings</span>
- <SettingsIcon
- color={NamedColors.TEXT_MUTED[themeScheme]}
- size={20}
- />
- </StyledDrawerListItem>
- </StyledDrawerList>
- </StyledDrawerFooter>
- </StyledDrawerPrimary>
+ >
+ <span>Pull Requests</span>
+ <Chip themeScheme={themeScheme}>{counters.pulls || 0}</Chip>
+ </StyledDrawerListItem>
+ <StyledDrawerListItem
+ themeScheme={themeScheme}
+ href={pathPipelines}
+ className={
+ commonProps.path! === pathPipelines ||
+ commonProps.path!.startsWith(pathPipelines)
+ ? "active"
+ : undefined
+ }
+ >
+ <span>Pipelines</span>
+ <Chip themeScheme={themeScheme}>{counters.builds || 0}</Chip>
+ </StyledDrawerListItem>
+ <StyledDrawerListItem themeScheme={themeScheme} disabled>
+ <span>Tests & Coverage</span>
+ <Chip themeScheme={themeScheme}>{counters.tests || 0}</Chip>
+ </StyledDrawerListItem>
+ <StyledDrawerListItem themeScheme={themeScheme} disabled>
+ <span>Issues</span>
+ <Chip themeScheme={themeScheme}>{counters.issues || 0}</Chip>
+ </StyledDrawerListItem>
+ <StyledDrawerListItem themeScheme={themeScheme} disabled>
+ <span>API Reference</span>
+ <Chip themeScheme={themeScheme}>
+ {counters.apiRefSymbols || 0}
+ </Chip>
+ </StyledDrawerListItem>
+ </StyledDrawerList>
+ <StyledDrawerListHeader></StyledDrawerListHeader>
+ <StyledDrawerList></StyledDrawerList>
+ </StyledDrawerContent>
+ <StyledDrawerFooter>
+ <StyledDrawerList>
+ <StyledDrawerListItem themeScheme={themeScheme} disabled>
+ <span>Feedback</span>
+ <CommentIcon
+ color={NamedColors.TEXT_MUTED[themeScheme]}
+ size={20}
+ />
+ </StyledDrawerListItem>
+ <StyledDrawerListItem themeScheme={themeScheme} disabled>
+ <span>Help Center</span>
+ <span style={{ flex: 1 }}></span>
+ {counters.helpCenterNotifs! > 0 && (
+ <Chip themeScheme={themeScheme}>
+ {counters.helpCenterNotifs}
+ </Chip>
+ )}
+ <SupportIcon
+ color={NamedColors.TEXT_MUTED[themeScheme]}
+ size={20}
+ />
+ </StyledDrawerListItem>
+ <StyledDrawerListItem themeScheme={themeScheme} disabled>
+ <span>Settings</span>
+ <SettingsIcon
+ color={NamedColors.TEXT_MUTED[themeScheme]}
+ size={20}
+ />
+ </StyledDrawerListItem>
+ </StyledDrawerList>
+ </StyledDrawerFooter>
+ </StyledDrawerPrimary>
+ <StyledDrawerOverlay href="#?"></StyledDrawerOverlay>
+ </>
);
};
+const StyledDrawerOverlay = styled.a`
+ display: none;
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ width: 100vw;
+ height: 100vh;
+ z-index: 21000;
+ pointer-events: none;
+ user-select: none;
+ background: rgba(0, 0, 0, 0.4);
+ filter: blur(8px);
+ opacity: 0;
+ transition: opacity 140ms ease-in-out 140ms;
+`;
+
const StyledDrawerPrimary = styled.aside<
WithThemeSchemeProp & { color?: string }
>`
@@ -304,21 +335,30 @@ const StyledDrawerPrimary = styled.aside<
background: ${NamedColors.HEADER[themeScheme]};
border-right: 1px solid ${NamedColors.BORDER_DEFAULT[themeScheme]};
- @media only screen and (max-width: 386px) {
- display: none;
-
- position: absolute;
- top: 0;
- left: 0;
- bottom: 0;
- z-index: 1000;
- width: 85vw;
- max-width: 320px;
- transform: translateX(-100%);
+ transition: transform 140ms cubic-bezier(0, 0, 0.2, 1);
+
+ @media only screen and (max-width: 768px) {
+ & {
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ z-index: 10000;
+ width: 85vw;
+ max-width: 320px;
+ transition: transform 140ms cubic-bezier(0, 0, 0.2, 1);
+ transform: translateX(-100%);
+ }
&:target {
transform: translateX(0);
- transition: transform 0.3s ease-in-out;
+ }
+
+ &:target ~ ${StyledDrawerOverlay} {
+ display: flex;
+ pointer-events: auto;
+ opacity: 1;
+ z-index: 8000;
}
}
`};
@@ -61,103 +61,132 @@ export const DrawerSettings = ({
console.log("counters:", counters);
return (
- <StyledDrawerSettings id="drawer" themeScheme={themeScheme}>
- <StyledDrawerHeader>
- <StyledLogoArea themeScheme={themeScheme}>
- <a href={"/"}>
- <h1>{Const.APP_NAME}</h1>
- </a>
- </StyledLogoArea>
- </StyledDrawerHeader>
- <StyledDrawerContent>
- <StyledDrawerListHeader>
- <img
- src={commonProps.currentUserAvatarUri || ""}
- style={{
- width: 20,
- height: 20,
- background: "red",
- borderRadius: 16,
- marginRight: 8,
- }}
- />
- <a
- href={buildRouteLink(
- AppRoute.USER_DETAILS,
- { username },
- { encodeURIComponent: false },
- )}
- >
- @{username}
- </a>
- </StyledDrawerListHeader>
- <StyledDrawerList>
- <StyledDrawerListItem
- themeScheme={themeScheme}
- href={pathMyAccount}
- className={
- // commonProps.path!.startsWith(pathMyAccount) ||
- commonProps.path! === pathMyAccount ? "active" : undefined
- }
- >
- <span>My Account</span>
- <UserIcon color={NamedColors.TEXT_DEFAULT[themeScheme]} size={20} />
- </StyledDrawerListItem>
- <StyledDrawerListItem
- themeScheme={themeScheme}
- href={pathSSHKeys}
- className={
- commonProps.path! === pathSSHKeys ||
- commonProps.path!.startsWith(pathSSHKeys)
- ? "active"
- : undefined
- }
- >
- <span>SSH Keys</span>
- <Chip themeScheme={themeScheme} style={{ marginRight: 8 }}>
- {counters.sshKeys || 0}
- </Chip>
- <KeyIcon color={NamedColors.TEXT_DEFAULT[themeScheme]} size={24} />
- </StyledDrawerListItem>
- </StyledDrawerList>
- <StyledDrawerListHeader></StyledDrawerListHeader>
- <StyledDrawerList></StyledDrawerList>
- </StyledDrawerContent>
- <StyledDrawerFooter>
- <StyledDrawerList>
- <StyledDrawerListItem themeScheme={themeScheme} disabled>
- <span>Feedback</span>
- <CommentIcon
- color={NamedColors.TEXT_MUTED[themeScheme]}
- size={20}
+ <>
+ <StyledDrawerSettings id="drawer" themeScheme={themeScheme}>
+ <StyledDrawerHeader>
+ <StyledLogoArea themeScheme={themeScheme}>
+ <a href={"/"}>
+ <h1>{Const.APP_NAME}</h1>
+ </a>
+ </StyledLogoArea>
+ </StyledDrawerHeader>
+ <StyledDrawerContent>
+ <StyledDrawerListHeader>
+ <img
+ src={commonProps.currentUserAvatarUri || ""}
+ style={{
+ width: 20,
+ height: 20,
+ background: "red",
+ borderRadius: 16,
+ marginRight: 8,
+ }}
/>
- </StyledDrawerListItem>
- <StyledDrawerListItem themeScheme={themeScheme} disabled>
- <span>Help Center</span>
- {counters.helpCenterNotifs! > 0 && (
- <Chip themeScheme={themeScheme}>{counters.helpCenterNotifs}</Chip>
- )}
- <SupportIcon
- color={NamedColors.TEXT_MUTED[themeScheme]}
- size={20}
- />
- </StyledDrawerListItem>
- <StyledDrawerListItem
- themeScheme={themeScheme}
- href={buildRouteLink(AppRoute.AUTH_LOGOUT_ACTION, null)}
- >
- <span>Logout</span>
- <LogOutIcon
- color={NamedColors.TEXT_DEFAULT[themeScheme]}
- size={20}
- />
- </StyledDrawerListItem>
- </StyledDrawerList>
- </StyledDrawerFooter>
- </StyledDrawerSettings>
+ <a
+ href={buildRouteLink(
+ AppRoute.USER_DETAILS,
+ { username },
+ { encodeURIComponent: false },
+ )}
+ >
+ @{username}
+ </a>
+ </StyledDrawerListHeader>
+ <StyledDrawerList>
+ <StyledDrawerListItem
+ themeScheme={themeScheme}
+ href={pathMyAccount}
+ className={
+ // commonProps.path!.startsWith(pathMyAccount) ||
+ commonProps.path! === pathMyAccount ? "active" : undefined
+ }
+ >
+ <span>My Account</span>
+ <UserIcon
+ color={NamedColors.TEXT_DEFAULT[themeScheme]}
+ size={20}
+ />
+ </StyledDrawerListItem>
+ <StyledDrawerListItem
+ themeScheme={themeScheme}
+ href={pathSSHKeys}
+ className={
+ commonProps.path! === pathSSHKeys ||
+ commonProps.path!.startsWith(pathSSHKeys)
+ ? "active"
+ : undefined
+ }
+ >
+ <span>SSH Keys</span>
+ <Chip themeScheme={themeScheme} style={{ marginRight: 8 }}>
+ {counters.sshKeys || 0}
+ </Chip>
+ <KeyIcon
+ color={NamedColors.TEXT_DEFAULT[themeScheme]}
+ size={24}
+ />
+ </StyledDrawerListItem>
+ </StyledDrawerList>
+ <StyledDrawerListHeader></StyledDrawerListHeader>
+ <StyledDrawerList></StyledDrawerList>
+ </StyledDrawerContent>
+ <StyledDrawerFooter>
+ <StyledDrawerList>
+ <StyledDrawerListItem themeScheme={themeScheme} disabled>
+ <span>Feedback</span>
+ <CommentIcon
+ color={NamedColors.TEXT_MUTED[themeScheme]}
+ size={20}
+ />
+ </StyledDrawerListItem>
+ <StyledDrawerListItem themeScheme={themeScheme} disabled>
+ <span>Help Center</span>
+ {counters.helpCenterNotifs! > 0 && (
+ <Chip themeScheme={themeScheme}>
+ {counters.helpCenterNotifs}
+ </Chip>
+ )}
+ <SupportIcon
+ color={NamedColors.TEXT_MUTED[themeScheme]}
+ size={20}
+ />
+ </StyledDrawerListItem>
+ <StyledDrawerListItem
+ themeScheme={themeScheme}
+ href={buildRouteLink(AppRoute.AUTH_LOGOUT_ACTION, null)}
+ >
+ <span>Logout</span>
+ <LogOutIcon
+ color={NamedColors.TEXT_DEFAULT[themeScheme]}
+ size={20}
+ />
+ </StyledDrawerListItem>
+ </StyledDrawerList>
+ </StyledDrawerFooter>
+ </StyledDrawerSettings>
+ <StyledDrawerOverlay href="#?"></StyledDrawerOverlay>
+ </>
);
};
+const StyledDrawerOverlay = styled.a`
+ display: none;
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ width: 100vw;
+ height: 100vh;
+ z-index: 21000;
+ pointer-events: none;
+ user-select: none;
+ background: rgba(0, 0, 0, 0.4);
+ filter: blur(8px);
+ opacity: 0;
+ transition: opacity 140ms ease-in-out 140ms;
+`;
+
const StyledDrawerSettings = styled.aside<
WithThemeSchemeProp & { color?: string }
>`
@@ -179,21 +208,30 @@ const StyledDrawerSettings = styled.aside<
background: ${NamedColors.HEADER[themeScheme]};
border-right: 1px solid ${NamedColors.BORDER_DEFAULT[themeScheme]};
- @media only screen and (max-width: 386px) {
- display: none;
-
- position: absolute;
- top: 0;
- left: 0;
- bottom: 0;
- z-index: 1000;
- width: 85vw;
- max-width: 320px;
- transform: translateX(-100%);
+ transition: transform 140ms cubic-bezier(0, 0, 0.2, 1);
+
+ @media only screen and (max-width: 768px) {
+ & {
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ z-index: 10000;
+ width: 85vw;
+ max-width: 320px;
+ transition: transform 140ms cubic-bezier(0, 0, 0.2, 1);
+ transform: translateX(-100%);
+ }
- &.target {
+ &:target {
transform: translateX(0);
- transition: transform 0.3s ease-in-out;
+ }
+
+ &:target ~ ${StyledDrawerOverlay} {
+ display: flex;
+ pointer-events: auto;
+ opacity: 1;
+ z-index: 8000;
}
}
`};
@@ -122,6 +122,7 @@ const LayoutComponent: FC<LayoutProps & WithThemeSchemeProp> = (props) => {
<PageHeader
commonProps={props as any}
themeScheme={themeScheme}
+ showBurgerMenu={showDrawerPrimary || showDrawerSettings}
forceShowLogo={
showDrawerPrimary !== true && showDrawerSettings !== true
}
@@ -16,6 +16,7 @@ import { PlusIcon } from "./icons/PlusIcon";
interface PageHeaderProps extends CommonProps {
forceShowLogo?: boolean;
+ showBurgerMenu?: boolean;
setDrawerPrimaryOpen?: (predicate: (prev: boolean) => boolean) => void;
setDrawerSettingsOpen?: (predicate: (prev: boolean) => boolean) => void;
}
@@ -24,6 +25,7 @@ export const PageHeader: VFC<PageHeaderProps & WithThemeSchemeProp> = ({
commonProps,
themeScheme,
forceShowLogo = true,
+ showBurgerMenu = false,
// setDrawerPrimaryOpen = undefined,
// setDrawerSettingsOpen = undefined,
}) => {
@@ -84,16 +86,18 @@ export const PageHeader: VFC<PageHeaderProps & WithThemeSchemeProp> = ({
return (
<StyledPageHeader themeScheme={themeScheme}>
<PageWrapper style={{ gap: 12 }}>
- <StyledBurgerMenu
- themeScheme={themeScheme}
- // onClick={toggleDrawerPrimary}
- href="#drawer"
- >
- <BurgerMenuIcon
- color={NamedColors.TEXT_DEFAULT[themeScheme]}
- size={24}
- />
- </StyledBurgerMenu>
+ {showBurgerMenu && (
+ <StyledBurgerMenu
+ themeScheme={themeScheme}
+ // onClick={toggleDrawerPrimary}
+ href="#drawer"
+ >
+ <BurgerMenuIcon
+ color={NamedColors.TEXT_DEFAULT[themeScheme]}
+ size={24}
+ />
+ </StyledBurgerMenu>
+ )}
<StyledLogoArea themeScheme={themeScheme} forceShowLogo={forceShowLogo}>
<a href={"/"}>
<h1>{Const.APP_NAME}</h1>
@@ -231,7 +231,7 @@ const HomeView: ReactView<HomeViewProps> = (props) => {
.feature-section {
display: flex;
width: 100%;
- min-height: 80vh;
+ min-height: 90vh;
flex-direction: row;
align-items: center;
gap: 48px;
@@ -63,7 +63,8 @@
"react-dom": "^17.0.2",
"react-is": "^17.0.2",
"styled-components": "^5.3.5",
- "styled-container-queries": "^1.0.0"
+ "styled-container-queries": "^1.0.0",
+ "styled-container-query": "^1.3.5"
},
"devDependencies": {
"@babel/core": "^7.0.0-0",
@@ -1,6 +1,6 @@
stages:
- - name: hello
- image: alpine:3.18
+ - name: hello-android
+ image: webcuisine/gitlab-ci-react-native-android:latest
workdir: ./.workdir/:/home/node/
env:
FOO: "$HOME"
@@ -14,8 +14,8 @@ struct Command
cached : Array(String)
shell : String
workdir : String
- artifacts_to_set : Hash(String, String) # was Stash
- artifacts_to_get : Hash(String, String) # was UnStash
+ artifacts_to_set : Hash(String, String) # was stash
+ artifacts_to_get : Hash(String, String) # was unstash
def initialize(
@image : String,
@@ -0,0 +1,302 @@
+# Event bus with graceful shutdown, wildcard topic matching
+# serialization helpers, and error handling
+require "json"
+require "mutex"
+
+# Payload type alias
+alias Payload = JSON::Any
+
+struct Event
+ getter topic : String
+ getter payload : Payload
+ getter timestamp : Time = Time.local
+
+ def initialize(topic : String, payload : Payload)
+ @topic = topic
+ @payload = payload
+ @timestamp = Time.local
+ end
+
+ # Serialization helper -> JSON string
+ def to_json : String
+ JSON.build do |j|
+ j.object do
+ j.field "topic", topic
+ j.field "payload", payload_to_json(payload)
+ j.field "timestamp", timestamp.to_unix.to_i
+ end
+ end
+ end
+
+ # Parse from JSON string (expects same shape)
+ def self.from_json(json_str : String) : Event
+ parsed = JSON.parse(json_str).as_h
+ topic = parsed["topic"].as_s
+ payload = json_to_payload(parsed["payload"])
+ Event.new(topic, payload)
+ end
+
+ private def payload_to_json(p)
+ case p
+ when String, Int32, Float32, Bool, Nil
+ p
+ when JSON::Any
+ p
+ when Array
+ p.as_a.map(&.payload_to_json)
+ when Hash
+ h = {} of String => JSON::Any
+ p.as_h.each { |k, v| h[k] = payload_to_json(v) }
+ h
+ else
+ raise "Unsupported payload type: #{p.class}"
+ end
+ end
+
+ private def self.json_to_payload(j) : Payload
+ j
+ # JSON::Any -> convert to allowed Payload structures
+ # case j
+ # when JSON::Any
+ # case j
+ # when j.is_a?(String) then j.as_s
+ # when j.is_a?(Int) then j.as_i
+ # when j.is_a?(Float) then j.as_f32
+ # when j.is_a?(Bool) then j.as_bool
+ # when j.is_a?(Nil) then nil
+ # when j.is_a?(Array)
+ # j.as_a.map { |el| json_to_payload(el).as(JSON::Any) }
+ # when j.is_a?(Hash)
+ # res = {} of String => Payload
+ # j.as_h.each { |k, v| res[k] = json_to_payload(v).as(JSON::Any) }
+ # res
+ # else
+ # raise "Unsupported JSON::Any variant"
+ # end
+ # else
+ # # primitive Crystal types (if already converted)
+ # j
+ # end
+ end
+end
+
+# Simple wildcard matcher:
+# - "*" matches any single topic exactly "*"
+# Pattern matchers:
+# - "#" as multi-level wildcard (matches any suffix, e.g., "user.#" matches "user.login", "user.signup.confirm")
+# - "+" as single-level wildcard (matches exactly one token between dots, e.g., "user.+.created")
+module TopicMatcher
+ def self.matches?(pattern : String, topic : String) : Bool
+ return true if pattern == "*"
+ pat_tokens = pattern.split(".")
+ t_tokens = topic.split(".")
+
+ i = 0
+ j = 0
+ while i < pat_tokens.size && j < t_tokens.size
+ pt = pat_tokens[i]
+ if pt == "#"
+ return true
+ elsif pt == "+"
+ i += 1
+ j += 1
+ next
+ elsif pt == t_tokens[j]
+ i += 1
+ j += 1
+ next
+ else
+ return false
+ end
+ end
+
+ # consume remaining pattern tokens: if only trailing "#" remain, match
+ while i < pat_tokens.size
+ return true if pat_tokens[i] == "#"
+ break
+ end
+
+ i == pat_tokens.size && j == t_tokens.size
+ end
+end
+
+class Subscriber
+ getter patterns : Array(String)
+ getter ch : Channel(Event)
+ getter id : Int32
+
+ def initialize(id : Int32, patterns : Array(String), buffer = 10)
+ @id = id
+ @patterns = patterns
+ @ch = Channel(Event).new(buffer)
+ end
+
+ def matches?(topic : String) : Bool
+ @patterns.any? { |pat| TopicMatcher.matches?(pat, topic) }
+ end
+end
+
+class EventBus
+ @dispatcher_fiber : Fiber
+
+ def initialize
+ @inbox = Channel(Event).new
+ @subs = [] of Subscriber
+ @mutex = Mutex.new
+ @closing = false
+ @next_sub_id = 1_i32
+ @dispatcher_fiber = spawn run
+ end
+
+ def publish(event : Event)
+ raise "EventBus is shutting down, cannot publish" if @closing
+ @inbox.send(event)
+ end
+
+ # subscribe accepts a pattern string (or array of patterns) using + and # like MQTT
+ # block handler runs in a spawned fiber; errors from handler are caught and forwarded to error_handler if set
+ def subscribe(patterns : String | Array(String), buffer = 10, &handler : Proc(Event, Nil))
+ pattern_list = patterns.is_a?(String) ? [patterns] : patterns
+ @mutex.synchronize do
+ raise "EventBus is shutting down" if @closing
+ end
+ id = @next_sub_id
+ @next_sub_id += 1
+ sub = Subscriber.new(id, pattern_list, buffer)
+ @mutex.synchronize { @subs << sub }
+
+ spawn do
+ begin
+ loop do
+ e = sub.ch.receive
+ begin
+ handler.call(e)
+ rescue ex
+ # send to configured error handler if available, else print
+ if @error_handler
+ begin
+ @error_handler.not_nil!.call(sub, e, ex)
+ rescue err2
+ STDERR.puts "Subscriber error handler failed: #{err2.message}"
+ end
+ else
+ STDERR.puts "Subscriber ##{sub.id} handler error: #{ex.message}"
+ end
+ end
+ end
+ rescue Channel::ClosedError
+ # exit
+ end
+ end
+
+ sub
+ end
+
+ # Allows setting a centralized error handler: Proc(Subscriber, Event, Exception)
+ def set_error_handler(&block : Proc(Subscriber, Event, Exception, Nil))
+ @error_handler = block
+ end
+
+ def unsubscribe(sub : Subscriber)
+ @mutex.synchronize do
+ @subs.delete(sub)
+ end
+ sub.ch.close
+ end
+
+ # Graceful shutdown:
+ # - stop accepting new publishes
+ # - close inbox so dispatcher drains
+ # - wait for dispatcher to finish dispatching
+ # - close all subscriber channels (so subscriber handler fibers exit)
+ def shutdown(timeout_seconds = 5_f32)
+ @mutex.synchronize do
+ return if @closing
+ @closing = true
+ end
+
+ begin
+ @inbox.close
+ rescue
+ end
+
+ # wait for dispatcher fiber to finish (simple busy-wait with timeout)
+ started = Time.local
+ while @dispatcher_fiber.dead? == false
+ break if (Time.local - started).seconds > timeout_seconds
+ sleep(0.01.seconds)
+ end
+
+ # close subscribers
+ @mutex.synchronize do
+ @subs.each { |s| s.ch.close rescue nil }
+ @subs.clear
+ end
+ end
+
+ private def run
+ loop do
+ e = @inbox.receive
+ @mutex.synchronize do
+ # dispatch to matching subscribers
+ @subs.each do |sub|
+ if sub.matches?(e.topic)
+ # non-blocking dispatch: send in spawned fiber, ignore if closed
+ spawn { sub.ch.send(e) rescue nil }
+ end
+ end
+ end
+ end
+ rescue Channel::ClosedError
+ # inbox closed -> exit dispatcher
+ end
+end
+
+# ---------------- Example usage ----------------
+bus = EventBus.new
+
+# Set centralized error handler
+bus.set_error_handler do |sub, event, ex|
+ STDERR.puts "Error in subscriber ##{sub.id} handling #{event.topic}: #{ex.class} - #{ex.message}"
+end
+
+# Subscribe with MQTT-style patterns
+all = bus.subscribe("*") do |e|
+ puts "[*] #{e.topic}: #{e.payload.inspect}"
+end
+user_any = bus.subscribe("user.#") do |e|
+ puts "[user.#] #{e.topic}: #{e.payload.inspect}"
+end
+login_specific = bus.subscribe("user.login") do |e|
+ puts "[user.login] #{e.payload.inspect}"
+end
+single_level = bus.subscribe("order.+.created") do |e|
+ puts "[order.+.created] got #{e.topic}"
+end
+
+# Publish a variety of events (using typed payloads)
+bus.publish Event.new("user.signup", JSON.parse(%({"email": "alice@example.com"})))
+bus.publish Event.new("user.signup.confirm", JSON.parse(%({"email": "alice@example.com"})))
+bus.publish Event.new("user.login", JSON.parse(%({"id": 123, "method": "oauth"})))
+bus.publish Event.new("order.us.created", JSON.parse(%({"order_id": "o-1", "total": 42})))
+bus.publish Event.new("order.eu.created", JSON.parse(%({"order_id": "o-2", "total": 55})))
+
+# Demonstrate serialization helpers
+# e = Event.new("meta", JSON.parse(%({"k":"v","n":1})))
+# json_str = e.to_json
+# puts "Serialized event: #{json_str}"
+# parsed = Event.from_json(json_str)
+# puts "Parsed event topic: #{parsed.topic}, payload: #{parsed.payload.inspect}"
+
+# Trigger an error in a handler to show central error handling
+bus.subscribe("bad.handler") do |ev|
+ raise "boom for #{ev.topic}"
+end
+
+bus.publish Event.new("bad.handler", JSON.parse(%(null)))
+
+sleep(0.1.seconds)
+
+# Graceful shutdown
+bus.shutdown(2.0)
+puts "Shutdown complete."
@@ -1,5 +1,6 @@
todo:
+- [ ] add pipelines feature (wip: ci-runner: done, ui: wip api: wip)
- [x] make http git push work
- [x] make ssh git push work
- [ ] make ssh git push work every times
@@ -0,0 +1,184 @@
+declare module "styled-container-query" {
+ import * as React from "react";
+ import styledComponents from "styled-components";
+
+ export type ContainerQueryRule = {
+ minWidth?: string;
+ maxWidth?: string;
+ minHeight?: string;
+ maxHeight?: string;
+ };
+
+ export type ContainerQueryRules = {
+ [className: string]: ContainerQueryRule;
+ };
+
+ export function matchQueries(
+ rules: ContainerQueryRules,
+ size: { width?: number | null; height?: number | null },
+ ): string[];
+
+ export function withQueryContainer<P = any>(
+ StyledComponent: React.ComponentType<P>,
+ rules: ContainerQueryRules,
+ ): React.ForwardRefExoticComponent<
+ React.PropsWithoutRef<
+ P & { children?: React.ReactNode; query?: ContainerQueryRules }
+ > &
+ React.RefAttributes<any>
+ >;
+
+ export function unitToPx(
+ element: Element | null,
+ value: string,
+ prop: "width" | "height" | string,
+ ): number;
+
+ export interface StyledContainerQuery {
+ <Props = any>(
+ component: React.ComponentType<Props> | string,
+ ): styledComponents.ThemedStyledFunction<any, any, {}, never>;
+
+ a: any;
+ abbr: any;
+ address: any;
+ area: any;
+ article: any;
+ aside: any;
+ audio: any;
+ b: any;
+ base: any;
+ bdi: any;
+ bdo: any;
+ big: any;
+ blockquote: any;
+ body: any;
+ br: any;
+ button: any;
+ canvas: any;
+ caption: any;
+ cite: any;
+ code: any;
+ col: any;
+ colgroup: any;
+ data: any;
+ datalist: any;
+ dd: any;
+ del: any;
+ details: any;
+ dfn: any;
+ dialog: any;
+ div: any;
+ dl: any;
+ dt: any;
+ em: any;
+ embed: any;
+ fieldset: any;
+ figcaption: any;
+ figure: any;
+ footer: any;
+ form: any;
+ h1: any;
+ h2: any;
+ h3: any;
+ h4: any;
+ h5: any;
+ h6: any;
+ head: any;
+ header: any;
+ hgroup: any;
+ hr: any;
+ html: any;
+ i: any;
+ iframe: any;
+ img: any;
+ input: any;
+ ins: any;
+ kbd: any;
+ keygen: any;
+ label: any;
+ legend: any;
+ li: any;
+ link: any;
+ main: any;
+ map: any;
+ mark: any;
+ marquee: any;
+ menu: any;
+ menuitem: any;
+ meta: any;
+ meter: any;
+ nav: any;
+ noscript: any;
+ object: any;
+ ol: any;
+ optgroup: any;
+ option: any;
+ output: any;
+ p: any;
+ param: any;
+ picture: any;
+ pre: any;
+ progress: any;
+ q: any;
+ rp: any;
+ rt: any;
+ ruby: any;
+ s: any;
+ samp: any;
+ script: any;
+ section: any;
+ select: any;
+ small: any;
+ source: any;
+ span: any;
+ strong: any;
+ style: any;
+ sub: any;
+ summary: any;
+ sup: any;
+ table: any;
+ tbody: any;
+ td: any;
+ textarea: any;
+ tfoot: any;
+ th: any;
+ thead: any;
+ time: any;
+ title: any;
+ tr: any;
+ track: any;
+ u: any;
+ ul: any;
+ var: any;
+ video: any;
+ wbr: any;
+ circle: any;
+ clipPath: any;
+ defs: any;
+ ellipse: any;
+ foreignObject: any;
+ g: any;
+ image: any;
+ line: any;
+ linearGradient: any;
+ marker: any;
+ mask: any;
+ path: any;
+ pattern: any;
+ polygon: any;
+ polyline: any;
+ radialGradient: any;
+ rect: any;
+ stop: any;
+ svg: any;
+ text: any;
+ tspan: any;
+
+ [element: string]: any;
+ }
+
+ const styledContainerQuery: StyledContainerQuery;
+ export { styledContainerQuery as styledCQ };
+ export default styledContainerQuery;
+}
@@ -1537,6 +1537,11 @@ classifier@~0.1.0:
redis ">=0.7.0"
underscore ">=1.1.0"
+classnames@^2.2.6:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b"
+ integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==
+
cliui@^7.0.2:
version "7.0.4"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
@@ -2643,7 +2648,7 @@ himalaya@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/himalaya/-/himalaya-1.1.0.tgz#31724ae9d35714cd7c6f4be94888953f3604606a"
-hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0:
+hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
dependencies:
@@ -4440,6 +4445,11 @@ require-from-string@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
+resize-observer@^1.0.0:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/resize-observer/-/resize-observer-1.0.4.tgz#48beb64602ce408ebd1a433784d64ef76f38d321"
+ integrity sha512-AQ2MdkWTng9d6JtjHvljiQR949qdae91pjSNugGGeOFzKIuLHvoZIYhUTjePla5hCFDwQHrnkciAIzjzdsTZew==
+
resolve-cwd@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
@@ -4630,6 +4640,11 @@ shell-quote@^1.6.1:
version "1.7.3"
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123"
+shorthash@0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/shorthash/-/shorthash-0.0.2.tgz#59b268eecbde59038b30da202bcfbddeb2c4a4eb"
+ integrity sha512-L/QRElsfTaCCzA7AJPXuin6/jgWjgmTfjdaXucQ5PauPypmqAZ7t4GueaCv+Jti0M8S2Iv1C/ryD+aWY/KUGCA==
+
side-channel@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
@@ -4846,6 +4861,16 @@ styled-container-queries@^1.0.0:
resolved "https://registry.yarnpkg.com/styled-container-queries/-/styled-container-queries-1.0.0.tgz#b1a0ec16d1d89d6bc4fd8eead57171d4f1afe530"
integrity sha512-Rxvb0brymST4qqf0ckW+kAJuuyPuXOr4uRvNnJ5tbqNwOoSpmvpWj5KcJlV9mNs2xq8hozRD1s9lx3+Azwl4Dg==
+styled-container-query@^1.3.5:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/styled-container-query/-/styled-container-query-1.3.5.tgz#15ab590d32e20f879bcb9e8d882da65da7ab22a9"
+ integrity sha512-YzL4+CC+OZqkS94xZkxz2MsP6JjsJi2VKYC4JnhzWinWAJ0Mnj8Gmuw71mixg40D4BOOrXXXmt8AekyXSo10cg==
+ dependencies:
+ classnames "^2.2.6"
+ hoist-non-react-statics "^3.3.2"
+ resize-observer "^1.0.0"
+ shorthash "0.0.2"
+
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"
feat(drawer): make them mobile first@@ -1 +0,0 @@
-Branch B\n
@@ -1,5 +1,5 @@
{
- "_generatedAtUnix": 1778731850286,
+ "_generatedAtUnix": 1778816347541,
"_hashAlgorithm": "sha1",
"_version": 2,
"assets": {
@@ -102,7 +102,7 @@
},
"views": {
"HomeView": {
- "hash": "02d7348a7966d0bab30badacd77703cec1446515",
+ "hash": "9af14ca668298d8cf3ddd309fe29ab8bc93be7b7",
"pathSource": "./app/views/HomeView.tsx"
},
"InternalErrorView": {
@@ -170,7 +170,7 @@
"pathSource": "./app/views/repository/RepositoryForkView.tsx"
},
"RepositoryShowObjectView": {
- "hash": "057fe75366d6705671a24bac56d201581ac54567",
+ "hash": "3c5578449f0a838f9a8b679ec2360a212f5a4e4c",
"pathSource": "./app/views/repository/RepositoryShowObjectView.tsx"
},
"RepositoryPullRequestCreateView": {
@@ -1,7 +1,8 @@
// 3rd-party
-import styled, { css } from "styled-components";
+import { css } from "styled-components";
+import styledContainerQuery from "styled-container-query";
// app
-import { Colors } from "../utils/style";
+import { breakpoints, Colors } from "../utils/style";
type ButtonProps = {
disabled?: boolean;
@@ -50,6 +51,15 @@ const baseButtonCss = css<ButtonProps>`
padding-top 140ms ease-in-out 0s,
transform 140ms ease-in-out 0s;
+ &:container(max-width: 119px) {
+ font-size: 11px;
+ background: red !important;
+ }
+ &:container(min-width: 120px) {
+ font-size: 18px;
+ background: green !important;
+ }
+
&:not(:disabled) {
cursor: pointer;
}
@@ -78,13 +88,17 @@ const baseButtonCss = css<ButtonProps>`
}
${({ disabled }) => disabled && disabledButtonCss};
+
+ // @media only screen and (max-width: ${breakpoints.sm}) {
+ // font-size: 11px;
+ // }
`;
-export const Button = styled.button<ButtonProps>`
+export const Button = styledContainerQuery.button<ButtonProps>`
${baseButtonCss};
`;
-export const ButtonAnchor = styled.a<ButtonProps>`
+export const ButtonAnchor = styledContainerQuery.a<ButtonProps>`
${baseButtonCss};
text-decoration: none;
&:hover {
@@ -89,111 +89,101 @@ export const DrawerPrimary = ({
}
return (
- <StyledDrawerPrimary id="drawer" themeScheme={themeScheme}>
- <StyledDrawerHeader>
- <StyledLogoArea themeScheme={themeScheme}>
- <a href={"/"}>
- <h1>{Const.APP_NAME}</h1>
- </a>
- </StyledLogoArea>
- </StyledDrawerHeader>
- <StyledDrawerContent>
- <StyledDrawerListHeader style={{ margin: 0 }}>
- <a href={buildRouteLink(AppRoute.ORGANIZATION_DETAILS, { orgSlug })}>
- @{orgSlug}
- </a>
- <span>{" / "}</span>
- <a
- href={buildRouteLink(AppRoute.REPOSITORY_DETAILS, {
- orgSlug,
- repoSlug,
- })}
- >
- <TextEllipsis>{repoSlug}</TextEllipsis>
- </a>
- </StyledDrawerListHeader>
- <StyledDrawerListHeader style={{ height: 32 }}>
- <Grid.Row
- fluid
- nowrap
- gap={8}
- justifyContent={"center"}
- alignItems={"center"}
- >
- <Grid.Row nowrap gap={4} alignItems={"center"}>
- <GitPullIcon
- color={NamedColors.TEXT_MUTED[themeScheme]}
- size={16}
- />
- <span style={{ fontSize: 11 }}>Watchers</span>
- <Chip
- themeScheme={themeScheme}
- color={NamedColors.TEXT_MUTED[themeScheme]}
- style={{
- padding: "2px 6px",
- backgroundColor: "rgba(0,0,0,0.1)",
- fontSize: 11,
- color: NamedColors.TEXT_MUTED[themeScheme],
- }}
- >
- {counters.watchers || "0"}
- </Chip>
- </Grid.Row>
- <Grid.Row nowrap gap={4} alignItems={"center"}>
- <LikeIcon color={NamedColors.TEXT_MUTED[themeScheme]} size={16} />
- <span style={{ fontSize: 11 }}>Likes</span>
- <Chip
- themeScheme={themeScheme}
- color={NamedColors.TEXT_MUTED[themeScheme]}
- style={{
- padding: "2px 6px",
- backgroundColor: "rgba(0,0,0,0.1)",
- fontSize: 11,
- color: NamedColors.TEXT_MUTED[themeScheme],
- }}
- >
- {counters.likes || "0"}
- </Chip>
- </Grid.Row>
- <Grid.Row nowrap gap={4} alignItems={"center"}>
- <GitForkIcon color={Colors.WHITE_01} size={16} />
- <span style={{ fontSize: 11 }}>Forks</span>
- <Chip
- themeScheme={themeScheme}
- color={NamedColors.TEXT_MUTED[themeScheme]}
- style={{
- padding: "2px 6px",
- backgroundColor: "rgba(0,0,0,0.1)",
- fontSize: 11,
- color: NamedColors.TEXT_MUTED[themeScheme],
- }}
- >
- {counters.forks || "0"}
- </Chip>
+ <>
+ <StyledDrawerPrimary id="drawer" themeScheme={themeScheme}>
+ <StyledDrawerHeader>
+ <StyledLogoArea themeScheme={themeScheme}>
+ <a href={"/"}>
+ <h1>{Const.APP_NAME}</h1>
+ </a>
+ </StyledLogoArea>
+ </StyledDrawerHeader>
+ <StyledDrawerContent>
+ <StyledDrawerListHeader style={{ margin: 0 }}>
+ <a
+ href={buildRouteLink(AppRoute.ORGANIZATION_DETAILS, { orgSlug })}
+ >
+ @{orgSlug}
+ </a>
+ <span>{" / "}</span>
+ <a
+ href={buildRouteLink(AppRoute.REPOSITORY_DETAILS, {
+ orgSlug,
+ repoSlug,
+ })}
+ >
+ <TextEllipsis>{repoSlug}</TextEllipsis>
+ </a>
+ </StyledDrawerListHeader>
+ <StyledDrawerListHeader style={{ height: 32 }}>
+ <Grid.Row
+ fluid
+ nowrap
+ gap={8}
+ justifyContent={"center"}
+ alignItems={"center"}
+ >
+ <Grid.Row nowrap gap={4} alignItems={"center"}>
+ <GitPullIcon
+ color={NamedColors.TEXT_MUTED[themeScheme]}
+ size={16}
+ />
+ <span style={{ fontSize: 11 }}>Watchers</span>
+ <Chip
+ themeScheme={themeScheme}
+ color={NamedColors.TEXT_MUTED[themeScheme]}
+ style={{
+ padding: "2px 6px",
+ backgroundColor: "rgba(0,0,0,0.1)",
+ fontSize: 11,
+ color: NamedColors.TEXT_MUTED[themeScheme],
+ }}
+ >
+ {counters.watchers || "0"}
+ </Chip>
+ </Grid.Row>
+ <Grid.Row nowrap gap={4} alignItems={"center"}>
+ <LikeIcon
+ color={NamedColors.TEXT_MUTED[themeScheme]}
+ size={16}
+ />
+ <span style={{ fontSize: 11 }}>Likes</span>
+ <Chip
+ themeScheme={themeScheme}
+ color={NamedColors.TEXT_MUTED[themeScheme]}
+ style={{
+ padding: "2px 6px",
+ backgroundColor: "rgba(0,0,0,0.1)",
+ fontSize: 11,
+ color: NamedColors.TEXT_MUTED[themeScheme],
+ }}
+ >
+ {counters.likes || "0"}
+ </Chip>
+ </Grid.Row>
+ <Grid.Row nowrap gap={4} alignItems={"center"}>
+ <GitForkIcon color={Colors.WHITE_01} size={16} />
+ <span style={{ fontSize: 11 }}>Forks</span>
+ <Chip
+ themeScheme={themeScheme}
+ color={NamedColors.TEXT_MUTED[themeScheme]}
+ style={{
+ padding: "2px 6px",
+ backgroundColor: "rgba(0,0,0,0.1)",
+ fontSize: 11,
+ color: NamedColors.TEXT_MUTED[themeScheme],
+ }}
+ >
+ {counters.forks || "0"}
+ </Chip>
+ </Grid.Row>
</Grid.Row>
- </Grid.Row>
- </StyledDrawerListHeader>
- <StyledDrawerList>
- <StyledDrawerListItem
- themeScheme={themeScheme}
- href={pathFiles}
- className={
- ((!commonProps.path!.startsWith(pathPipelines) === false &&
- commonProps.path!.startsWith(pathFiles)) ||
- [pathFiles, pathRepo, pathRepoTrailing].some(
- (p) =>
- commonProps.path === p || commonProps.path!.startsWith(p),
- )) &&
- commonProps.path!.startsWith(pathPulls) === false &&
- commonProps.path!.startsWith(pathPipelines) === false
- ? "active"
- : undefined
- }
- style={{ paddingRight: 16 }}
- >
- <span>Files</span>
- <FolderIcon
- color={
+ </StyledDrawerListHeader>
+ <StyledDrawerList>
+ <StyledDrawerListItem
+ themeScheme={themeScheme}
+ href={pathFiles}
+ className={
((!commonProps.path!.startsWith(pathPipelines) === false &&
commonProps.path!.startsWith(pathFiles)) ||
[pathFiles, pathRepo, pathRepoTrailing].some(