Website UI design (#4829)
**Fixed different issues** : - Multiple CSS fixes: font-size, colors, margins, z-index ... - Fixed hover on contributor avatars - Added link to contributors in footer - Made the year in the footer dynamic (2023 --> 2024) - Added name of contributor in "Thank you" section of Contributor page - Added footer in small screens - Made Activity Log Responsive - Fixed bug in "saving issues to DB", title was null everywhere. I needed to implement an "upsert" behaviour to update the existing database on init **To be noted :** There is the following bug on production happening on mobile when you refresh a second time : <img width="1440" alt="Screenshot 2024-04-05 at 01 30 58" src="https://github.com/twentyhq/twenty/assets/102751374/b935b07a-63dc-463d-8dcb-070ad4ef6db0"> It seems to be related to the following issue on mdx : [https://github.com/hashicorp/next-mdx-remote/issues/350](https://github.com/hashicorp/next-mdx-remote/issues/350) I added the following code that fixed this bug for me in development (this needs to be tested in production) : ``` const serialized = await serialize(content, { mdxOptions: { development: process.env.NODE_ENV === 'development', } }) ``` --------- Co-authored-by: Ady Beraud <a.beraud96@gmail.com>
This commit is contained in:
@ -1,10 +1,20 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { ResponsiveTimeRange } from '@nivo/calendar';
|
import styled from '@emotion/styled';
|
||||||
|
import { TimeRange } from '@nivo/calendar';
|
||||||
|
|
||||||
import { CardContainer } from '@/app/_components/contributors/CardContainer';
|
import { CardContainer } from '@/app/_components/contributors/CardContainer';
|
||||||
import { Title } from '@/app/_components/contributors/Title';
|
import { Title } from '@/app/_components/contributors/Title';
|
||||||
|
|
||||||
|
const CalendarContentContainer = styled.div`
|
||||||
|
@media (max-width: 890px) {
|
||||||
|
overflow-x: auto;
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export const ActivityLog = ({
|
export const ActivityLog = ({
|
||||||
data,
|
data,
|
||||||
}: {
|
}: {
|
||||||
@ -16,17 +26,20 @@ export const ActivityLog = ({
|
|||||||
return (
|
return (
|
||||||
<CardContainer>
|
<CardContainer>
|
||||||
<Title>Activity</Title>
|
<Title>Activity</Title>
|
||||||
<div style={{ width: '100%', height: '214px' }}>
|
<CalendarContentContainer>
|
||||||
<ResponsiveTimeRange
|
<TimeRange
|
||||||
|
height={150}
|
||||||
|
width={725}
|
||||||
data={data}
|
data={data}
|
||||||
emptyColor="#F4EFFF"
|
emptyColor="#F4EFFF"
|
||||||
colors={['#E9DFFF', '#B28FFE', '#915FFD']}
|
colors={['#E9DFFF', '#B28FFE', '#915FFD']}
|
||||||
dayBorderWidth={2}
|
weekdayTicks={[]}
|
||||||
dayBorderColor="#ffffff"
|
weekdayLegendOffset={0}
|
||||||
|
dayBorderWidth={0}
|
||||||
dayRadius={4}
|
dayRadius={4}
|
||||||
daySpacing={2}
|
daySpacing={4}
|
||||||
/>
|
/>
|
||||||
</div>
|
</CalendarContentContainer>
|
||||||
</CardContainer>
|
</CardContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -52,6 +52,8 @@ const AvatarItem = styled.div`
|
|||||||
transition:
|
transition:
|
||||||
opacity 0.3s ease,
|
opacity 0.3s ease,
|
||||||
visibility 0.3s;
|
visibility 0.3s;
|
||||||
|
border-bottom-left-radius: 8px;
|
||||||
|
border-bottom-right-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover .username {
|
&:hover .username {
|
||||||
|
|||||||
@ -11,7 +11,6 @@ export const CardContainer = styled.div`
|
|||||||
background-color: #fafafa;
|
background-color: #fafafa;
|
||||||
|
|
||||||
@media (max-width: 810px) {
|
@media (max-width: 810px) {
|
||||||
gap: 16px;
|
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -9,11 +9,11 @@ const Container = styled.div`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 898px;
|
max-width: 898px;
|
||||||
padding: 40px;
|
padding: 40px;
|
||||||
|
|
||||||
gap: 40px;
|
gap: 40px;
|
||||||
@media (max-width: 809px) {
|
@media (max-width: 809px) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 40px 24px 40px 24px;
|
padding: 40px 24px 40px 24px;
|
||||||
|
gap: 24px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -4,13 +4,19 @@ import styled from '@emotion/styled';
|
|||||||
|
|
||||||
const Title = styled.h2`
|
const Title = styled.h2`
|
||||||
font-size: 56px;
|
font-size: 56px;
|
||||||
font-weight: 600;
|
font-weight: bold;
|
||||||
color: #b3b3b3;
|
color: #b3b3b3;
|
||||||
margin-bottom: 0px;
|
margin-bottom: 32px;
|
||||||
margin-top: 64px;
|
margin-top: 64px;
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
justify-items: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
@media (max-width: 810px) {
|
@media (max-width: 810px) {
|
||||||
font-size: 28px;
|
font-size: 32px;
|
||||||
|
margin-bottom: 22px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -18,7 +24,8 @@ export const Header = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title>
|
<Title>
|
||||||
Our amazing <br /> <span style={{ color: 'black' }}>Contributors</span>
|
Our amazing <br />
|
||||||
|
<span style={{ color: '#141414' }}>Contributors</span>
|
||||||
</Title>
|
</Title>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -10,6 +10,10 @@ const ProfileContainer = styled.div`
|
|||||||
gap: 32px;
|
gap: 32px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Avatar = styled.div`
|
const Avatar = styled.div`
|
||||||
@ -33,6 +37,10 @@ const Details = styled.div`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
|
|
||||||
|
@media (max-width: 810px) {
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.username {
|
.username {
|
||||||
font-size: 40px;
|
font-size: 40px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
@ -42,7 +50,7 @@ const Details = styled.div`
|
|||||||
gap: 12px;
|
gap: 12px;
|
||||||
|
|
||||||
@media (max-width: 810px) {
|
@media (max-width: 810px) {
|
||||||
font-size: 24px;
|
font-size: 32px;
|
||||||
line-height: 28.8px;
|
line-height: 28.8px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { CardContainer } from '@/app/_components/contributors/CardContainer';
|
import { CardContainer } from '@/app/_components/contributors/CardContainer';
|
||||||
|
import { Theme } from '@/app/_components/ui/theme/theme';
|
||||||
|
|
||||||
const Container = styled(CardContainer)`
|
const Container = styled(CardContainer)`
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@ -21,8 +22,8 @@ const Container = styled(CardContainer)`
|
|||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
color: #b3b3b3;
|
color: ${Theme.text.color.quarternary};
|
||||||
margin: 0;
|
margin: 8px;
|
||||||
|
|
||||||
@media (max-width: 810px) {
|
@media (max-width: 810px) {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
@ -32,7 +33,7 @@ const Container = styled(CardContainer)`
|
|||||||
.value {
|
.value {
|
||||||
font-size: 56px;
|
font-size: 56px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #474747;
|
color: ${Theme.text.color.secondary};
|
||||||
|
|
||||||
@media (max-width: 810px) {
|
@media (max-width: 810px) {
|
||||||
font-size: 32px;
|
font-size: 32px;
|
||||||
@ -72,7 +73,7 @@ export const ProfileInfo = ({
|
|||||||
</div>
|
</div>
|
||||||
<div className="separator"></div>
|
<div className="separator"></div>
|
||||||
<div className="item">
|
<div className="item">
|
||||||
<p className="title">Rank</p>
|
<p className="title">Ranking</p>
|
||||||
<span className="value">{rank}%</span>
|
<span className="value">{rank}%</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="separator"></div>
|
<div className="separator"></div>
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import styled from '@emotion/styled';
|
|||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
|
|
||||||
import { PullRequestIcon } from '@/app/_components/ui/icons/SvgIcons';
|
import { PullRequestIcon } from '@/app/_components/ui/icons/SvgIcons';
|
||||||
|
import { Theme } from '@/app/_components/ui/theme/theme';
|
||||||
import { formatIntoRelativeDate } from '@/shared-utils/formatIntoRelativeDate';
|
import { formatIntoRelativeDate } from '@/shared-utils/formatIntoRelativeDate';
|
||||||
|
|
||||||
const StyledTooltip = styled(Tooltip)``;
|
const StyledTooltip = styled(Tooltip)``;
|
||||||
@ -15,7 +16,7 @@ const Item = styled.div`
|
|||||||
const StyledTitle = styled.a`
|
const StyledTitle = styled.a`
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: #474747;
|
color: ${Theme.text.color.secondary};
|
||||||
margin: 0;
|
margin: 0;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
@ -27,6 +28,7 @@ const StyledTitle = styled.a`
|
|||||||
const StyledPrLink = styled.a`
|
const StyledPrLink = styled.a`
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
color: ${Theme.text.color.quarternary} !important;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
@ -38,7 +40,8 @@ const StyledDescription = styled.div`
|
|||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
line-height: 28px;
|
line-height: 28px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #b3b3b3;
|
color: ${Theme.text.color.quarternary};
|
||||||
|
margin-top: 4px;
|
||||||
|
|
||||||
@media (max-width: 810px) {
|
@media (max-width: 810px) {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
|
|||||||
@ -10,6 +10,7 @@ const List = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
`;
|
`;
|
||||||
interface PullRequestsProps {
|
interface PullRequestsProps {
|
||||||
list: {
|
list: {
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import { CardContainer } from '@/app/_components/contributors/CardContainer';
|
|||||||
import { HeartIcon } from '@/app/_components/ui/icons/SvgIcons';
|
import { HeartIcon } from '@/app/_components/ui/icons/SvgIcons';
|
||||||
|
|
||||||
const StyledTitle = styled.div`
|
const StyledTitle = styled.div`
|
||||||
display: flex;
|
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
@ -18,20 +17,21 @@ const StyledTitle = styled.div`
|
|||||||
|
|
||||||
const StyledHeartIcon = styled(HeartIcon)`
|
const StyledHeartIcon = styled(HeartIcon)`
|
||||||
@media (max-width: 810px) {
|
@media (max-width: 810px) {
|
||||||
|
display: inline-block !important;
|
||||||
width: 16px !important;
|
width: 16px !important;
|
||||||
height: 16px !important;
|
height: 16px !important;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
interface ThankYouProps {
|
interface ThankYouProps {
|
||||||
authorId: string;
|
username: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ThankYou = ({ authorId }: ThankYouProps) => {
|
export const ThankYou = ({ username }: ThankYouProps) => {
|
||||||
return (
|
return (
|
||||||
<CardContainer>
|
<CardContainer>
|
||||||
<StyledTitle>
|
<StyledTitle>
|
||||||
Thank you @{authorId} <StyledHeartIcon color="#333333" size="18px" />
|
Thank you @{username} <StyledHeartIcon color="#333333" size="18px" />
|
||||||
</StyledTitle>
|
</StyledTitle>
|
||||||
</CardContainer>
|
</CardContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -11,7 +11,7 @@ const Container = styled.div`
|
|||||||
gap: 26px;
|
gap: 26px;
|
||||||
@media (max-width: 809px) {
|
@media (max-width: 809px) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0px 12px 0px 12px;
|
padding: 0px 12px 40px 12px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -9,17 +9,17 @@ const StyledLineContainer = styled.div`
|
|||||||
|
|
||||||
@media (max-width: 810px) {
|
@media (max-width: 810px) {
|
||||||
width: auto;
|
width: auto;
|
||||||
margin: 24px 0;
|
|
||||||
display: block;
|
display: block;
|
||||||
|
margin: 24px 0px 64px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledLine = styled.div`
|
const StyledLine = styled.div`
|
||||||
height: 1px;
|
height: 1px;
|
||||||
background-color: #d9d9d9;
|
background-color: #d9d9d9;
|
||||||
margin-bottom: 48px;
|
margin-bottom: 80px;
|
||||||
margin-left: 148px;
|
margin-left: 148px;
|
||||||
margin-top: 48px;
|
margin-top: 40px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
@media (max-width: 810px) {
|
@media (max-width: 810px) {
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { compileMDX } from 'next-mdx-remote/rsc';
|
|||||||
import remarkBehead from 'remark-behead';
|
import remarkBehead from 'remark-behead';
|
||||||
import gfm from 'remark-gfm';
|
import gfm from 'remark-gfm';
|
||||||
|
|
||||||
|
import { Theme } from '@/app/_components/ui/theme/theme';
|
||||||
import { ReleaseNote } from '@/app/releases/api/route';
|
import { ReleaseNote } from '@/app/releases/api/route';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
@ -16,7 +17,6 @@ const StyledContainer = styled.div`
|
|||||||
|
|
||||||
@media (max-width: 810px) {
|
@media (max-width: 810px) {
|
||||||
width: auto;
|
width: auto;
|
||||||
margin: 24px 0;
|
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@ -35,17 +35,19 @@ const StyledVersion = styled.div`
|
|||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
flex-flow: row;
|
flex-flow: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledRelease = styled.span`
|
const StyledRelease = styled.span`
|
||||||
color: #141414;
|
color: ${Theme.text.color.quarternary};
|
||||||
|
line-height: 140%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledDate = styled.span`
|
const StyledDate = styled.span`
|
||||||
color: #474747;
|
color: ${Theme.text.color.secondary};
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
font-size: ${Theme.font.size.sm};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StlyedContent = styled.div`
|
const StlyedContent = styled.div`
|
||||||
@ -54,16 +56,20 @@ const StlyedContent = styled.div`
|
|||||||
gap: 64px;
|
gap: 64px;
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
color: #141414;
|
color: ${Theme.text.color.primary};
|
||||||
|
font-weight: 700;
|
||||||
font-size: 40px;
|
font-size: 40px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
color: #474747;
|
color: ${Theme.text.color.secondary};
|
||||||
|
font-family: ${Theme.font.family};
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 28.8px;
|
line-height: 28.8px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
margin: 40px 0px;
|
||||||
|
text-align: justify;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
@ -73,16 +79,16 @@ const StlyedContent = styled.div`
|
|||||||
@media (max-width: 810px) {
|
@media (max-width: 810px) {
|
||||||
h3 {
|
h3 {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
margin: 24px 0 40px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const gabarito = Gabarito({
|
const gabarito = Gabarito({
|
||||||
weight: ['400', '500'],
|
weight: ['400', '500', '600', '700'],
|
||||||
subsets: ['latin'],
|
subsets: ['latin'],
|
||||||
display: 'swap',
|
display: 'swap',
|
||||||
adjustFontFallback: false,
|
adjustFontFallback: false,
|
||||||
|
variable: '--font-gabarito',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const Release = async ({ release }: { release: ReleaseNote }) => {
|
export const Release = async ({ release }: { release: ReleaseNote }) => {
|
||||||
@ -92,6 +98,7 @@ export const Release = async ({ release }: { release: ReleaseNote }) => {
|
|||||||
source: release.content,
|
source: release.content,
|
||||||
options: {
|
options: {
|
||||||
mdxOptions: {
|
mdxOptions: {
|
||||||
|
development: process.env.NODE_ENV === 'development',
|
||||||
remarkPlugins: [gfm, [remarkBehead, { depth: 2 }]],
|
remarkPlugins: [gfm, [remarkBehead, { depth: 2 }]],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -139,7 +139,9 @@ export const PullRequestIcon = ({ size = 'S', color = 'rgb(179,179,179)' }) => {
|
|||||||
export const HeartIcon = ({ size = 'S', color = 'rgb(179,179,179)' }) => {
|
export const HeartIcon = ({ size = 'S', color = 'rgb(179,179,179)' }) => {
|
||||||
const dimension = getSize(size);
|
const dimension = getSize(size);
|
||||||
return (
|
return (
|
||||||
<div style={{ width: dimension, height: dimension }}>
|
<span
|
||||||
|
style={{ width: dimension, height: dimension, display: 'inline-block' }}
|
||||||
|
>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 20" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 20" fill="none">
|
||||||
<path
|
<path
|
||||||
d="M18.513 10.572L11.013 18L3.513 10.572C3.0183 10.0906 2.62864 9.51201 2.36854 8.87263C2.10845 8.23325 1.98356 7.54694 2.00173 6.85693C2.01991 6.16691 2.18076 5.48813 2.47415 4.86333C2.76755 4.23853 3.18713 3.68125 3.70648 3.22657C4.22583 2.7719 4.8337 2.42968 5.49181 2.22147C6.14991 2.01327 6.844 1.94358 7.53036 2.0168C8.21673 2.09001 8.8805 2.30455 9.47987 2.6469C10.0792 2.98925 10.6012 3.45199 11.013 4.00599C11.4265 3.45602 11.9491 2.99731 12.5481 2.6586C13.1471 2.31988 13.8095 2.10844 14.4939 2.03751C15.1784 1.96658 15.8701 2.03769 16.5258 2.24639C17.1815 2.45508 17.787 2.79687 18.3045 3.25036C18.8221 3.70385 19.2404 4.25928 19.5334 4.88189C19.8264 5.50449 19.9877 6.18088 20.0073 6.8687C20.0269 7.55653 19.9043 8.24099 19.6471 8.87924C19.39 9.5175 19.0039 10.0958 18.513 10.578"
|
d="M18.513 10.572L11.013 18L3.513 10.572C3.0183 10.0906 2.62864 9.51201 2.36854 8.87263C2.10845 8.23325 1.98356 7.54694 2.00173 6.85693C2.01991 6.16691 2.18076 5.48813 2.47415 4.86333C2.76755 4.23853 3.18713 3.68125 3.70648 3.22657C4.22583 2.7719 4.8337 2.42968 5.49181 2.22147C6.14991 2.01327 6.844 1.94358 7.53036 2.0168C8.21673 2.09001 8.8805 2.30455 9.47987 2.6469C10.0792 2.98925 10.6012 3.45199 11.013 4.00599C11.4265 3.45602 11.9491 2.99731 12.5481 2.6586C13.1471 2.31988 13.8095 2.10844 14.4939 2.03751C15.1784 1.96658 15.8701 2.03769 16.5258 2.24639C17.1815 2.45508 17.787 2.79687 18.3045 3.25036C18.8221 3.70385 19.2404 4.25928 19.5334 4.88189C19.8264 5.50449 19.9877 6.18088 20.0073 6.8687C20.0269 7.55653 19.9043 8.24099 19.6471 8.87924C19.39 9.5175 19.0039 10.0958 18.513 10.578"
|
||||||
@ -149,7 +151,7 @@ export const HeartIcon = ({ size = 'S', color = 'rgb(179,179,179)' }) => {
|
|||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -30,7 +30,7 @@ const ExternalLinkItem = styled.a`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const ActivePage = styled.span`
|
const ActivePage = styled.span`
|
||||||
color: ${Theme.text.color.secondary};
|
color: ${Theme.text.color.primary};
|
||||||
font-weight: ${Theme.font.weight.medium};
|
font-weight: ${Theme.font.weight.medium};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ const Container = styled.div`
|
|||||||
padding: 0px 96px 0px 96px;
|
padding: 0px 96px 0px 96px;
|
||||||
@media (max-width: 809px) {
|
@media (max-width: 809px) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0px 12px 0px 12px;
|
padding: 0px 24px 0px 24px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ const FooterContainer = styled.div`
|
|||||||
color: rgb(129, 129, 129);
|
color: rgb(129, 129, 129);
|
||||||
gap: 32px;
|
gap: 32px;
|
||||||
@media (max-width: 809px) {
|
@media (max-width: 809px) {
|
||||||
display: none;
|
padding: 36px 24px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -28,6 +28,9 @@ const LeftSideFooter = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
|
@media (max-width: 809px) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const RightSideFooter = styled.div`
|
const RightSideFooter = styled.div`
|
||||||
@ -35,6 +38,10 @@ const RightSideFooter = styled.div`
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 48px;
|
gap: 48px;
|
||||||
height: 146px;
|
height: 146px;
|
||||||
|
@media (max-width: 809px) {
|
||||||
|
flex-direction: column;
|
||||||
|
height: fit-content;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const RightSideFooterColumn = styled.div`
|
const RightSideFooterColumn = styled.div`
|
||||||
@ -96,6 +103,9 @@ export const FooterDesktop = () => {
|
|||||||
</RightSideFooterColumn>
|
</RightSideFooterColumn>
|
||||||
<RightSideFooterColumn>
|
<RightSideFooterColumn>
|
||||||
<RightSideFooterColumnTitle>Other</RightSideFooterColumnTitle>
|
<RightSideFooterColumnTitle>Other</RightSideFooterColumnTitle>
|
||||||
|
<RightSideFooterLink href="/contributors">
|
||||||
|
Contributors
|
||||||
|
</RightSideFooterLink>
|
||||||
<RightSideFooterLink href="/oss-friends">
|
<RightSideFooterLink href="/oss-friends">
|
||||||
OSS Friends
|
OSS Friends
|
||||||
</RightSideFooterLink>
|
</RightSideFooterLink>
|
||||||
@ -120,7 +130,7 @@ export const FooterDesktop = () => {
|
|||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<span style={{ fontFamily: 'Inter, sans-serif' }}>©</span>
|
<span style={{ fontFamily: 'Inter, sans-serif' }}>©</span>
|
||||||
2023 Twenty PBC
|
{new Date().getFullYear()} Twenty PBC
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@ -119,22 +119,26 @@ export const LinkNextToCTA = styled.a`
|
|||||||
export const HamburgerContainer = styled.div`
|
export const HamburgerContainer = styled.div`
|
||||||
height: 44px;
|
height: 44px;
|
||||||
width: 44px;
|
width: 44px;
|
||||||
cursor: pointer;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
input {
|
input {
|
||||||
|
cursor: pointer;
|
||||||
height: 44px;
|
height: 44px;
|
||||||
width: 44px;
|
width: 44px;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#line1 {
|
#line1 {
|
||||||
transition: transform 0.5s;
|
transition: transform 0.5s;
|
||||||
transition-timing-function: ease-in-out;
|
transition-timing-function: ease-in-out;
|
||||||
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#line2 {
|
#line2 {
|
||||||
transition: transform 0.5s;
|
transition: transform 0.5s;
|
||||||
transition-timing-function: ease-in-out;
|
transition-timing-function: ease-in-out;
|
||||||
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#menu-input:checked ~ #line1 {
|
#menu-input:checked ~ #line1 {
|
||||||
@ -154,6 +158,7 @@ export const HamburgerLine1 = styled.div`
|
|||||||
width: 20px;
|
width: 20px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background-color: rgb(179, 179, 179);
|
background-color: rgb(179, 179, 179);
|
||||||
|
z-index: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const HamburgerLine2 = styled.div`
|
export const HamburgerLine2 = styled.div`
|
||||||
@ -164,6 +169,7 @@ export const HamburgerLine2 = styled.div`
|
|||||||
width: 20px;
|
width: 20px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background-color: rgb(179, 179, 179);
|
background-color: rgb(179, 179, 179);
|
||||||
|
z-index: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const NavOpen = styled.div`
|
export const NavOpen = styled.div`
|
||||||
|
|||||||
@ -29,7 +29,7 @@ export interface Directory {
|
|||||||
async function getFiles(
|
async function getFiles(
|
||||||
filePath: string,
|
filePath: string,
|
||||||
basePath: string,
|
basePath: string,
|
||||||
position: number = 0,
|
position = 0,
|
||||||
): Promise<Directory> {
|
): Promise<Directory> {
|
||||||
const entries = fs.readdirSync(filePath, { withFileTypes: true });
|
const entries = fs.readdirSync(filePath, { withFileTypes: true });
|
||||||
|
|
||||||
@ -99,13 +99,14 @@ async function parseFrontMatterAndCategory(
|
|||||||
return parsedDirectory;
|
return parsedDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function compileMDXFile(filePath: string, addToc: boolean = true) {
|
export async function compileMDXFile(filePath: string, addToc = true) {
|
||||||
const fileContent = fs.readFileSync(filePath, 'utf8');
|
const fileContent = fs.readFileSync(filePath, 'utf8');
|
||||||
const compiled = await compileMDX<{ title: string; position?: number }>({
|
const compiled = await compileMDX<{ title: string; position?: number }>({
|
||||||
source: fileContent,
|
source: fileContent,
|
||||||
options: {
|
options: {
|
||||||
parseFrontmatter: true,
|
parseFrontmatter: true,
|
||||||
mdxOptions: {
|
mdxOptions: {
|
||||||
|
development: process.env.NODE_ENV === 'development',
|
||||||
remarkPlugins: [gfm],
|
remarkPlugins: [gfm],
|
||||||
rehypePlugins: [rehypeSlug, ...(addToc ? [toc] : [])],
|
rehypePlugins: [rehypeSlug, ...(addToc ? [toc] : [])],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -127,7 +127,7 @@ export default async function ({ params }: { params: { slug: string } }) {
|
|||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ThankYou authorId={contributor.login} />
|
<ThankYou username={contributor.id} />
|
||||||
</ContentContainer>
|
</ContentContainer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -15,6 +15,7 @@ export async function savePRsToDB(
|
|||||||
if (pr.author == null) {
|
if (pr.author == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
await insertMany(
|
await insertMany(
|
||||||
userModel,
|
userModel,
|
||||||
[
|
[
|
||||||
@ -43,7 +44,7 @@ export async function savePRsToDB(
|
|||||||
authorId: pr.author.login,
|
authorId: pr.author.login,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
{ onConflictKey: 'id' },
|
{ onConflictKey: 'id', onConflictUpdateObject: { title: pr.title } },
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const label of pr.labels.nodes) {
|
for (const label of pr.labels.nodes) {
|
||||||
|
|||||||
@ -47,9 +47,7 @@ const Contributors = async () => {
|
|||||||
<Background />
|
<Background />
|
||||||
<ContentContainer>
|
<ContentContainer>
|
||||||
<Header />
|
<Header />
|
||||||
<div>
|
<AvatarGrid users={fitlerContributors as Contributor[]} />
|
||||||
<AvatarGrid users={fitlerContributors as Contributor[]} />
|
|
||||||
</div>
|
|
||||||
</ContentContainer>
|
</ContentContainer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -76,10 +76,25 @@ const findAll = (model: SQLiteTableWithColumns<any>) => {
|
|||||||
const insertMany = async (
|
const insertMany = async (
|
||||||
model: SQLiteTableWithColumns<any>,
|
model: SQLiteTableWithColumns<any>,
|
||||||
data: any,
|
data: any,
|
||||||
options?: { onConflictKey?: string },
|
options?: {
|
||||||
|
onConflictKey?: string;
|
||||||
|
onConflictUpdateObject?: any;
|
||||||
|
},
|
||||||
) => {
|
) => {
|
||||||
if (isSqliteDriver) {
|
if (isSqliteDriver) {
|
||||||
const query = sqliteDb.insert(model).values(data);
|
const query = sqliteDb.insert(model).values(data);
|
||||||
|
|
||||||
|
if (options?.onConflictUpdateObject) {
|
||||||
|
if (options?.onConflictKey) {
|
||||||
|
return query
|
||||||
|
.onConflictDoUpdate({
|
||||||
|
target: [model[options.onConflictKey]],
|
||||||
|
set: options.onConflictUpdateObject,
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (options?.onConflictKey) {
|
if (options?.onConflictKey) {
|
||||||
return query
|
return query
|
||||||
.onConflictDoNothing({
|
.onConflictDoNothing({
|
||||||
@ -87,10 +102,23 @@ const insertMany = async (
|
|||||||
})
|
})
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
return query.execute();
|
return query.execute();
|
||||||
}
|
}
|
||||||
if (isPgDriver) {
|
if (isPgDriver) {
|
||||||
const query = pgDb.insert(model).values(data);
|
const query = pgDb.insert(model).values(data);
|
||||||
|
|
||||||
|
if (options?.onConflictUpdateObject) {
|
||||||
|
if (options?.onConflictKey) {
|
||||||
|
return query
|
||||||
|
.onConflictDoUpdate({
|
||||||
|
target: [model[options.onConflictKey]],
|
||||||
|
set: options.onConflictUpdateObject,
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (options?.onConflictKey) {
|
if (options?.onConflictKey) {
|
||||||
return query
|
return query
|
||||||
.onConflictDoNothing({
|
.onConflictDoNothing({
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export const pgUsers = pgTable('users', {
|
|||||||
|
|
||||||
export const pgPullRequests = pgTable('pullRequests', {
|
export const pgPullRequests = pgTable('pullRequests', {
|
||||||
id: text('id').primaryKey(),
|
id: text('id').primaryKey(),
|
||||||
name: text('title'),
|
title: text('title'),
|
||||||
body: text('body'),
|
body: text('body'),
|
||||||
url: text('url'),
|
url: text('url'),
|
||||||
createdAt: text('createdAt'),
|
createdAt: text('createdAt'),
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export const sqlLiteUsers = sqliteTable('users', {
|
|||||||
|
|
||||||
export const sqlLitePullRequests = sqliteTable('pullRequests', {
|
export const sqlLitePullRequests = sqliteTable('pullRequests', {
|
||||||
id: text('id').primaryKey(),
|
id: text('id').primaryKey(),
|
||||||
name: text('title'),
|
title: text('title'),
|
||||||
body: text('body'),
|
body: text('body'),
|
||||||
url: text('url'),
|
url: text('url'),
|
||||||
createdAt: text('createdAt'),
|
createdAt: text('createdAt'),
|
||||||
|
|||||||
Reference in New Issue
Block a user