Create congratulations bot (#5404)

- Created congratulations bot :
<img width="939" alt="Screenshot 2024-05-14 at 12 47 13"
src="https://github.com/twentyhq/twenty/assets/102751374/5138515f-fe4d-4c6d-9c7a-0240accbfca9">

- Modified OG image

- Added png extension to OG image route

To be noted: The bot will not work until the new API route is not
deployed. Please check OG image with Cloudflare cache.

---------

Co-authored-by: Ady Beraud <a.beraud96@gmail.com>
This commit is contained in:
Ady Beraud
2024-05-21 23:56:25 +03:00
committed by GitHub
parent 3deda2f29a
commit 5ad59b5845
17 changed files with 277 additions and 73 deletions

View File

@ -2,7 +2,7 @@ import { format } from 'date-fns';
import { ImageResponse } from 'next/og';
import {
bottomBackgroundImage,
backgroundImage,
container,
contributorInfo,
contributorInfoBox,
@ -15,8 +15,7 @@ import {
profileInfoContainer,
profileUsernameHeader,
styledContributorAvatar,
topBackgroundImage,
} from '@/app/api/contributors/og-image/[slug]/style';
} from '@/app/api/contributors/[slug]/og.png/style';
import { getContributorActivity } from '@/app/contributors/utils/get-contributor-activity';
const GABARITO_FONT_CDN_URL =
@ -33,8 +32,10 @@ const getGabarito = async () => {
export async function GET(request: Request) {
try {
const url = request.url;
const username = url.split('/')?.pop() || '';
const splitUrl = url.split('/');
const usernameIndex =
splitUrl.findIndex((part) => part === 'contributors') + 1;
const username = splitUrl[usernameIndex];
const contributorActivity = await getContributorActivity(username);
if (contributorActivity) {
@ -45,11 +46,11 @@ export async function GET(request: Request) {
activeDays,
contributorAvatar,
} = contributorActivity;
return await new ImageResponse(
const imageResponse = await new ImageResponse(
(
<div style={container}>
<div style={topBackgroundImage}></div>
<div style={bottomBackgroundImage}></div>
<div style={backgroundImage}></div>
<div style={profileContainer}>
<img src={contributorAvatar} style={styledContributorAvatar} />
<div style={profileInfoContainer}>
@ -59,8 +60,8 @@ export async function GET(request: Request) {
</h2>
</div>
<svg
width="96"
height="96"
width="134"
height="134"
viewBox="0 0 136 136"
fill="none"
xmlns="http://www.w3.org/2000/svg"
@ -122,6 +123,7 @@ export async function GET(request: Request) {
],
},
);
return imageResponse;
}
} catch (error) {
return new Response(`error: ${error}`, {

View File

@ -14,42 +14,36 @@ export const container: CSSProperties = {
fontFamily: 'Gabarito',
};
export const topBackgroundImage: CSSProperties = {
backgroundImage: `url(${BACKGROUND_IMAGE_URL})`,
export const backgroundImage: CSSProperties = {
position: 'absolute',
zIndex: '-1',
width: '1300px',
height: '250px',
transform: 'rotate(-11deg)',
opacity: '0.2',
top: '-100',
left: '-25',
};
export const bottomBackgroundImage: CSSProperties = {
backgroundImage: `url(${BACKGROUND_IMAGE_URL})`,
position: 'absolute',
zIndex: '-1',
width: '1300px',
height: '250px',
transform: 'rotate(-11deg)',
opacity: '0.2',
bottom: '-120',
right: '-40',
width: '1250px',
height: '850px',
transform: 'rotate(-7deg)',
opacity: '0.8',
backgroundImage: `
linear-gradient(
158.4deg,
rgba(255, 255, 255, 0.8) 30.69%,
#FFFFFF 35.12%,
rgba(255, 255, 255, 0.8) 60.27%,
rgba(255, 255, 255, 0.64) 38.88%
),
url(${BACKGROUND_IMAGE_URL})`,
};
export const profileContainer: CSSProperties = {
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
width: '780px',
margin: '0px 0px 40px',
width: '970px',
height: '134px',
margin: '0px 0px 55px',
};
export const styledContributorAvatar = {
display: 'flex',
width: '96px',
height: '96px',
width: '134px',
height: '134px',
margin: '0px',
border: '3px solid #141414',
borderRadius: '16px',
@ -65,7 +59,7 @@ export const profileInfoContainer: CSSProperties = {
export const profileUsernameHeader: CSSProperties = {
margin: '0px',
fontSize: '28px',
fontSize: '39px',
fontWeight: '700',
color: '#141414',
fontFamily: 'Gabarito',
@ -74,7 +68,7 @@ export const profileUsernameHeader: CSSProperties = {
export const profileContributionHeader: CSSProperties = {
margin: '0px',
color: '#818181',
fontSize: '20px',
fontSize: '27px',
fontWeight: '400',
};
@ -84,8 +78,8 @@ export const contributorInfoContainer: CSSProperties = {
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-around',
width: '780px',
height: '149px',
width: '970px',
height: '209px',
backgroundColor: '#F1F1F1',
};
@ -110,14 +104,14 @@ export const contributorInfoTitle = {
color: '#B3B3B3',
margin: '0px',
fontWeight: '500',
fontSize: '24px',
fontSize: '33px',
};
export const contributorInfoStats = {
color: '#474747',
margin: '0px',
fontWeight: '700',
fontSize: '40px',
fontSize: '55px',
};
export const infoSeparator: CSSProperties = {
@ -125,6 +119,6 @@ export const infoSeparator: CSSProperties = {
right: 0,
display: 'flex',
width: '2px',
height: '85px',
height: '120px',
backgroundColor: '#141414',
};

View File

@ -0,0 +1,26 @@
import { getContributorActivity } from '@/app/contributors/utils/get-contributor-activity';
import { executePartialSync } from '@/github/execute-partial-sync';
export const dynamic = 'force-dynamic';
export async function GET(request: Request) {
try {
const url = request.url;
const username = url.split('/')?.pop() || '';
await executePartialSync();
const contributorActivity = await getContributorActivity(username);
if (contributorActivity) {
const mergedPRsCount = contributorActivity.mergedPRsCount;
const rank = contributorActivity.rank;
return Response.json({ mergedPRsCount, rank });
}
} catch (error: any) {
return new Response(`Contributor stats error: ${error?.message}`, {
status: 500,
});
}
}