-
Notifications
You must be signed in to change notification settings - Fork 558
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6025 from gitbutlerapp/sc-review-og-cards
OG graph data for reviews
- Loading branch information
Showing
7 changed files
with
522 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
94 changes: 94 additions & 0 deletions
94
apps/web/src/routes/[ownerSlug]/[projectSlug]/reviews/[branchId]/og/+server.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import Card from './Card.svelte'; | ||
import { HttpClient } from '@gitbutler/shared/network/httpClient'; | ||
import { gravatarUrlFromEmail } from '@gitbutler/ui/avatar/gravatar'; | ||
import { Resvg } from '@resvg/resvg-js'; | ||
import satori from 'satori'; | ||
import { html as satoriHtml } from 'satori-html'; | ||
import { render } from 'svelte/server'; | ||
import { readable } from 'svelte/store'; | ||
import { readFileSync } from 'fs'; | ||
import path from 'path'; | ||
import type { RequestHandler } from './$types'; | ||
import type { ApiBranch } from '@gitbutler/shared/branches/types'; | ||
import type { ApiUser } from '@gitbutler/shared/users/types'; | ||
import { env } from '$env/dynamic/public'; | ||
|
||
// Load the font data | ||
const fontFilePath = path.resolve('src/lib/fonts/NotoSans-Regular.ttf'); | ||
const fontData = readFileSync(fontFilePath); | ||
|
||
// eslint-disable-next-line func-style | ||
export const GET: RequestHandler = async ({ params }) => { | ||
const httpClient = new HttpClient(fetch, env.PUBLIC_APP_HOST, readable(undefined)); | ||
|
||
let branch: ApiBranch; | ||
let date: string; | ||
|
||
try { | ||
branch = await httpClient.get<ApiBranch>( | ||
`patch_stack/${params.ownerSlug}/${params.projectSlug}/branch/${params.branchId}` | ||
); | ||
const dateString = branch.created_at; | ||
const dateObj = new Date(dateString); | ||
// format date as Jun 30, 2021 | ||
date = dateObj.toLocaleDateString('en-US', { | ||
year: 'numeric', | ||
month: 'short', | ||
day: 'numeric' | ||
}); | ||
} catch (e) { | ||
console.error(e); | ||
return new Response(); | ||
} | ||
|
||
let user: ApiUser | undefined; | ||
try { | ||
user = await httpClient.get<ApiUser>(`user/${branch.owner_login}`); | ||
} catch (_) { | ||
/* empty */ | ||
} | ||
|
||
const slug = params.ownerSlug + '/' + params.projectSlug; | ||
const title = branch.title || 'unknown'; | ||
const picture = | ||
user?.picture || (await gravatarUrlFromEmail(user?.email || '[email protected]')); | ||
|
||
const commit_titles = branch.patches.map((patch) => patch.title || '') || []; | ||
const commits = branch.stack_size || 1; | ||
const files = branch.patches.reduce((acc, patch) => acc + patch.statistics.file_count, 0); | ||
const additions = branch.patches.reduce( | ||
(acc, patch) => acc + (patch.statistics.lines - patch.statistics.deletions), | ||
0 | ||
); | ||
const subtractions = branch.patches.reduce((acc, patch) => acc + patch.statistics.deletions, 0); | ||
|
||
const { body } = render(Card, { | ||
props: { title, slug, picture, date, commit_titles, commits, files, additions, subtractions } | ||
}); | ||
|
||
// Convert HTML string to VDOM | ||
const vdom = satoriHtml(body); | ||
|
||
// Generate the SVG using Satori | ||
// @ts-expect-error The satori-html library is fine | ||
const svg = await satori(vdom, { | ||
width: 1200, | ||
height: 630, | ||
fonts: [ | ||
{ | ||
name: 'Noto Sans', | ||
data: fontData, | ||
weight: 400, | ||
style: 'normal' | ||
} | ||
] | ||
}); | ||
|
||
// Render the SVG to PNG using Resvg | ||
const resvg = new Resvg(svg); | ||
const pngData = resvg.render(); | ||
|
||
return new Response(pngData.asPng(), { | ||
headers: { 'Content-Type': 'image/png' } | ||
}); | ||
}; |
85 changes: 85 additions & 0 deletions
85
apps/web/src/routes/[ownerSlug]/[projectSlug]/reviews/[branchId]/og/Card.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
<script lang="ts"> | ||
type Props = { | ||
title: string; | ||
slug: string; | ||
picture: string; | ||
date: string; | ||
commits: number; | ||
files: number; | ||
additions: number; | ||
subtractions: number; | ||
commit_titles: string[]; | ||
}; | ||
let { | ||
title, | ||
slug, | ||
picture, | ||
date, | ||
commit_titles, | ||
commits, | ||
files, | ||
additions, | ||
subtractions | ||
}: Props = $props(); | ||
// limit commit_titles to 3 max | ||
commit_titles = commit_titles.slice(0, 3); | ||
</script> | ||
|
||
<div | ||
style="display: flex; flex-direction: column; height: 100%; width: 100%; justify-content: space-between; letter-spacing: -0.02em; font-weight: 700; background: white; padding: 35px; background-image: linear-gradient(to bottom, #f1f1f1, #dbf4ff);" | ||
> | ||
<div style="display: flex; flex-direction: row; justify-content: space-between;"> | ||
<div style="display: flex; flex-direction: column;"> | ||
<div style="display: flex; gap: 12px; margin-bottom: 10px;"> | ||
<svg | ||
xmlns="http://www.w3.org/2000/svg" | ||
style="margin-top: 10px; margin-right: 10px" | ||
width="40" | ||
height="40" | ||
viewBox="0 0 23 24" | ||
fill="none" | ||
> | ||
<path d="M0 24V0L11.4819 10.5091L23 0V24L11.4819 13.5273L0 24Z" fill="black"></path> | ||
</svg> | ||
<div style="font-weight: 100; font-size: 40px; color: #666; padding-bottom: 10px;"> | ||
{slug} | ||
</div> | ||
</div> | ||
<div | ||
style="display: flex; color: #000000; font-size: 60px; width: 800px; height: 180px; overflow: hidden; text-overflow: ellipsis; padding-bottom: 10px;" | ||
> | ||
{title} | ||
</div> | ||
</div> | ||
<div style="display: flex;"> | ||
<img style="border-radius: 50%;" width="250px" height="250px" alt="avatar" src={picture} /> | ||
</div> | ||
</div> | ||
<div style="display: flex; flex-direction: column;"> | ||
{#each commit_titles as commit_title} | ||
<div | ||
style="display: flex; color: #666; font-size: 30px; font-weight: 100; padding: 10px; margin-right: 10px;" | ||
> | ||
- {commit_title.substring(0, 70)} | ||
</div> | ||
{/each} | ||
</div> | ||
<div | ||
style="display: flex; align-items: center; justify-content: space-between; color: #57606a; font-size: 40px; font-weight: 100;" | ||
> | ||
<div style="display: flex; gap: 50px;"> | ||
<span style="color: #333;">{date}</span> | ||
{#if commits > 1} | ||
<span>{commits} commits</span> | ||
{:else} | ||
<span>{commits} commit</span> | ||
{/if} | ||
<span style="color: #888;">{files} files</span> | ||
</div> | ||
<div style="display: flex; font-size: 60px; gap: 25px; font-weight: 800;"> | ||
<span style="color: #28a745;">+{additions}</span> | ||
<span style="color: #d73a49;">-{subtractions}</span> | ||
</div> | ||
</div> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.