This repository has been archived by the owner on Aug 13, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Highlight Cards UI Generation (frontend-only) (#36)
* feat: get highlight data function * feat: setup highlight testing * feat: data interfaces * refractor: split card codes * feat: highlight cards code structure * refractor: template shared folder * refractor: card footer component * refractor: separate o ut card style setup * feat: highlights UI complete * lint
- Loading branch information
1 parent
58c00b5
commit 138a847
Showing
19 changed files
with
293 additions
and
53 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
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
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,11 @@ | ||
import { Module } from "@nestjs/common"; | ||
import { HttpModule } from "@nestjs/axios"; | ||
import { GithubModule } from "../../github/github.module"; | ||
import { S3FileStorageModule } from "../../s3-file-storage/s3-file-storage.module"; | ||
import { HighlightCardService } from "../highlight-card/highlight-card.service"; | ||
|
||
@Module({ | ||
imports: [HttpModule, GithubModule, S3FileStorageModule], | ||
providers: [HighlightCardService], | ||
}) | ||
export class HighlightCardModule {} |
113 changes: 113 additions & 0 deletions
113
src/social-card/highlight-card/highlight-card.service.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,113 @@ | ||
import { Injectable, Logger } from "@nestjs/common"; | ||
import { HttpService } from "@nestjs/axios"; | ||
import { Resvg } from "@resvg/resvg-js"; | ||
import { Repository, Language } from "@octokit/graphql-schema"; | ||
import fs from "node:fs/promises"; | ||
|
||
import { GithubService } from "../../github/github.service"; | ||
import { S3FileStorageService } from "../../s3-file-storage/s3-file-storage.service"; | ||
import userLangs from "../templates/shared/user-langs"; | ||
import userProfileRepos from "../templates/shared/user-repos"; | ||
import tailwindConfig from "../templates/tailwind.config"; | ||
import { firstValueFrom } from "rxjs"; | ||
import highlightCardTemplate from "../templates/highlight-card.template"; | ||
|
||
interface HighlightCardData { | ||
title: string, | ||
body: string, | ||
reactions: number, | ||
avatarUrl: string, | ||
repos: Repository[], | ||
langTotal: number, | ||
langs: (Language & { | ||
size: number, | ||
})[], | ||
} | ||
|
||
@Injectable() | ||
export class HighlightCardService { | ||
private readonly logger = new Logger(this.constructor.name); | ||
|
||
constructor ( | ||
private readonly httpService: HttpService, | ||
private readonly githubService: GithubService, | ||
private readonly s3FileStorageService: S3FileStorageService, | ||
) {} | ||
|
||
private async getHighlightData (highlightId: number): Promise<HighlightCardData> { | ||
const langs: Record<string, Language & { | ||
size: number, | ||
}> = {}; | ||
const today = (new Date); | ||
const today30daysAgo = new Date((new Date).setDate(today.getDate() - 30)); | ||
|
||
const highlightReq = await firstValueFrom(this.httpService.get<DbHighlight>(`https://api.opensauced.pizza/v1/user/highlights/${highlightId}`)); | ||
const { login, title, highlight: body } = highlightReq.data; | ||
|
||
const reactionsReq = await firstValueFrom(this.httpService.get<DbReaction[]>(`https://api.opensauced.pizza/v1/highlights/${highlightId}/reactions`)); | ||
const reactions = reactionsReq.data.reduce<number>( (acc, curr) => acc + Number(curr.reaction_count), 0); | ||
|
||
const user = await this.githubService.getUser(login); | ||
const langRepos = user.repositories.nodes?.filter(repo => new Date(String(repo?.pushedAt)) > today30daysAgo) as Repository[]; | ||
let langTotal = 0; | ||
|
||
langRepos.forEach(repo => { | ||
repo.languages?.edges?.forEach(edge => { | ||
if (edge?.node.id) { | ||
langTotal += edge.size; | ||
|
||
if (!Object.keys(langs).includes(edge.node.id)) { | ||
langs[edge.node.id] = { | ||
...edge.node, | ||
size: edge.size, | ||
}; | ||
} else { | ||
langs[edge.node.id].size += edge.size; | ||
} | ||
} | ||
}); | ||
}); | ||
|
||
return { | ||
title, | ||
body, | ||
reactions, | ||
avatarUrl: `${String(user.avatarUrl)}&size=150`, | ||
langs: Array.from(Object.values(langs)).sort((a, b) => b.size - a.size), | ||
langTotal, | ||
repos: user.topRepositories.nodes?.filter(repo => !repo?.isPrivate && repo?.owner.login !== login) as Repository[], | ||
}; | ||
} | ||
|
||
// public only to be used in local scripts. Not for controller direct use. | ||
async generateCardBuffer (highlightId: number, highlightData?: HighlightCardData) { | ||
const { html } = await import("satori-html"); | ||
const satori = (await import("satori")).default; | ||
|
||
const { title, body, reactions, avatarUrl, repos, langs, langTotal } = highlightData ? highlightData : await this.getHighlightData(highlightId); | ||
|
||
const template = html(highlightCardTemplate(avatarUrl, title, body, userLangs(langs, langTotal), userProfileRepos(repos, 2), reactions)); | ||
|
||
const interArrayBuffer = await fs.readFile("node_modules/@fontsource/inter/files/inter-all-400-normal.woff"); | ||
|
||
const svg = await satori(template, { | ||
width: 1200, | ||
height: 627, | ||
fonts: [ | ||
{ | ||
name: "Inter", | ||
data: interArrayBuffer, | ||
weight: 400, | ||
style: "normal", | ||
}, | ||
], | ||
tailwindConfig, | ||
}); | ||
|
||
const resvg = new Resvg(svg, { background: "rgba(238, 235, 230, .9)" }); | ||
|
||
const pngData = resvg.render(); | ||
|
||
return { png: pngData.asPng(), svg }; | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
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,30 @@ | ||
import cardFooter from "./shared/card-footer"; | ||
import cardStyleSetup from "./shared/card-style-setup"; | ||
|
||
const highlightCardTemplate = (avatarUrl: string, title: string, body: string, langs: string, repos: string, reactions: number): string => ` | ||
${cardStyleSetup} | ||
<div tw="flex-col justify-between w-1200px h-627px bg-white rounded-2xl p-32px pt-48px"> | ||
<div style="gap: 16px;"> | ||
<div tw="p-2.5 pt-5" style="gap: 10px;"> | ||
<img tw="w-132px h-132px border border-sauced-orange rounded-full" src="${avatarUrl}"/> | ||
</div> | ||
<div tw="w-906px flex-col flex-nowrap" style="gap: -10px;"> | ||
<h1 tw="font-medium text-72px leading-72px text-zinc-900 tracking-tight" style="width: 926px;"> | ||
${title} | ||
</h1> | ||
<p tw="font-normal text-48px text-light-slate-11 tracking-tight"> | ||
${body.length > 108 ? `${body.slice(0, 108)}...` : body} | ||
</p> | ||
</div> | ||
<div> | ||
<img tw="w-46px h-46px border border-white rounded" src="https://github.com/open-sauced/assets/d9a0d5a317036084aa3f5f4e20cdfbe58dc37377/svgs/slice-Orange-Gradient.svg"/> | ||
</div> | ||
</div> | ||
${cardFooter(langs, repos, reactions)} | ||
</div>`; | ||
|
||
export default highlightCardTemplate; |
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,31 @@ | ||
|
||
const heartIconData = `data:image/svg+xml,%3csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3e%3cpath fill-rule='evenodd' clip-rule='evenodd' d='M6.73649 2.5C3.82903 2.5 1 5.052 1 8.51351C1 12.3318 3.80141 15.5735 6.38882 17.7763C7.70549 18.8973 9.01844 19.7929 10.0004 20.4077C10.4922 20.7157 10.9029 20.9544 11.1922 21.1169C11.4093 21.2388 11.5582 21.318 11.6223 21.3516C11.7407 21.4132 11.8652 21.4527 12 21.4527C12.1193 21.4527 12.2378 21.4238 12.3438 21.3693C12.5003 21.2886 12.6543 21.2031 12.8078 21.1169C13.0971 20.9544 13.5078 20.7157 13.9996 20.4077C14.9816 19.7929 16.2945 18.8973 17.6112 17.7763C20.1986 15.5735 23 12.3318 23 8.51351C23 5.052 20.171 2.5 17.2635 2.5C14.9702 2.5 13.1192 3.72621 12 5.60482C10.8808 3.72621 9.02981 2.5 6.73649 2.5ZM6.73649 4C4.65746 4 2.5 5.88043 2.5 8.51351C2.5 11.6209 4.8236 14.4738 7.36118 16.6342C8.60701 17.6948 9.85656 18.5479 10.7965 19.1364C11.2656 19.4301 11.6557 19.6567 11.9269 19.8091L12 19.85L12.0731 19.8091C12.3443 19.6567 12.7344 19.4301 13.2035 19.1364C14.1434 18.5479 15.393 17.6948 16.6388 16.6342C19.1764 14.4738 21.5 11.6209 21.5 8.51351C21.5 5.88043 19.3425 4 17.2635 4C15.1581 4 13.4627 5.38899 12.7115 7.64258C12.6094 7.94883 12.3228 8.15541 12 8.15541C11.6772 8.15541 11.3906 7.94883 11.2885 7.64258C10.5373 5.38899 8.84185 4 6.73649 4Z' fill='%2324292F'/%3e%3c/svg%3e`; | ||
|
||
const cardFooter = (langs: string, repos: string, reactions?: number) => ` | ||
<div tw="flex-col" style="gap: 8px;"> | ||
<div tw="h-48px ${!reactions ? "items-center" : "justify-between"}" style="gap: 8px;"> | ||
<div tw="h-48px items-center" style="gap: 8px;"> | ||
${repos} | ||
</div> | ||
${reactions | ||
? ` | ||
<div tw="h-48px items-center" style="gap: 12px;"> | ||
<img tw="w-32px h-32px" width="1" height="1" src="${heartIconData}"/> | ||
<span tw="font-medium text-32px text-black"> | ||
${reactions} Reactions | ||
</span> | ||
</div> | ||
` | ||
: ""} | ||
</div> | ||
<div tw="flex-col h-18px justify-center overflow-hidden"> | ||
<div tw="h-12px" style="gap: 4px;"> | ||
${langs} | ||
</div> | ||
</div> | ||
</div> | ||
`; | ||
|
||
export default cardFooter; |
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,10 @@ | ||
|
||
const cardStyleSetup = ` | ||
<style> | ||
div { | ||
display: flex; | ||
} | ||
</style> | ||
`; | ||
|
||
export default cardStyleSetup; |
File renamed without changes.
File renamed without changes.
6 changes: 3 additions & 3 deletions
6
...cial-card/templates/user-profile-repos.ts → ...ocial-card/templates/shared/user-repos.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
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
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
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,14 @@ | ||
import { Module } from "@nestjs/common"; | ||
import { HttpModule } from "@nestjs/axios"; | ||
|
||
import { UserCardService } from "./user-card.service"; | ||
import { UserCardController } from "./user-card.controller"; | ||
import { GithubModule } from "../../github/github.module"; | ||
import { S3FileStorageModule } from "../../s3-file-storage/s3-file-storage.module"; | ||
|
||
@Module({ | ||
imports: [HttpModule, GithubModule, S3FileStorageModule], | ||
providers: [UserCardService], | ||
controllers: [UserCardController], | ||
}) | ||
export class UserCardModule {} |
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.