Skip to content

Commit

Permalink
Merge pull request #6025 from gitbutlerapp/sc-review-og-cards
Browse files Browse the repository at this point in the history
OG graph data for reviews
  • Loading branch information
schacon authored Jan 22, 2025
2 parents e4ce232 + fed1453 commit 80cff10
Show file tree
Hide file tree
Showing 7 changed files with 522 additions and 4 deletions.
10 changes: 7 additions & 3 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,20 @@
"@types/node": "^22.3.0",
"svelte": "catalog:svelte",
"svelte-check": "catalog:svelte",
"vite": "catalog:",
"svelte-french-toast": "^1.2.0"
"svelte-french-toast": "^1.2.0",
"vite": "catalog:"
},
"dependencies": {
"@ethercorps/sveltekit-og": "^3.0.0",
"@fontsource-variable/spline-sans-mono": "^5.1.0",
"@resvg/resvg-js": "^2.6.2",
"@sentry/sveltekit": "^8.48.0",
"@tryghost/content-api": "^1.11.21",
"@types/tryghost__content-api": "^1.3.17",
"dayjs": "^1.11.13",
"highlight.js": "^11.10.0",
"marked": "^10.0.0"
"marked": "^10.0.0",
"satori": "^0.12.1",
"satori-html": "^0.3.2"
}
}
Binary file added apps/web/src/lib/fonts/NotoSans-Regular.ttf
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import relativeTime from 'dayjs/plugin/relativeTime';
import type { Branch } from '@gitbutler/shared/branches/types';
import { goto } from '$app/navigation';
import { PUBLIC_APP_HOST } from '$env/static/public';
dayjs.extend(relativeTime);
Expand Down Expand Up @@ -106,7 +107,6 @@
}
function copyLocation() {
console.log('hi');
copyToClipboard(location.href);
}
</script>
Expand All @@ -117,6 +117,16 @@
{/if}
{/snippet}

<svelte:head>
<title>Review: {data.ownerSlug}/{data.projectSlug}</title>
<meta property="og:title" content="GitButler Review: {data.ownerSlug}/{data.projectSlug}" />
<meta property="og:description" content="GitButler code review" />
<meta
property="og:image"
content="{PUBLIC_APP_HOST}/{data.ownerSlug}/{data.projectSlug}/reviews/{data.branchId}/og"
/>
</svelte:head>

<h2>Review page: {data.ownerSlug}/{data.projectSlug} {data.branchId}</h2>

<Loading loadable={and([branchUuid?.current, branch?.current])}>
Expand Down
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' }
});
};
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>
1 change: 1 addition & 0 deletions packages/shared/src/lib/branches/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ export type ApiBranch = {
branch_stack_id?: string;
branch_stack_order?: number;
permissions: ApiPermissions;
owner_login?: string;
};

export type Branch = {
Expand Down
Loading

0 comments on commit 80cff10

Please sign in to comment.