add user profile templating
This commit is contained in:
parent
f0fc3df881
commit
1dafd75723
4 changed files with 115 additions and 6 deletions
|
@ -1,4 +1,4 @@
|
|||
import html2png, { renderHtml as htmlParser } from '@besties/html2png'
|
||||
import html2png from '@besties/html2png'
|
||||
import fs from 'node:fs'
|
||||
|
||||
const style = fs.readFileSync('./assets/style.css', 'utf8')
|
||||
|
@ -9,5 +9,5 @@ export default async function (html, options = {}) {
|
|||
|
||||
export async function renderHtml(html) {
|
||||
const styleNow = await fs.promises.readFile('./assets/style.css', 'utf8')
|
||||
return await htmlParser(`<style>${styleNow}</style>${html}`)
|
||||
return `<style>${styleNow}</style>${html}`
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ settings:
|
|||
|
||||
dependencies:
|
||||
'@besties/html2png':
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
specifier: ^1.0.1
|
||||
version: 1.0.1
|
||||
dotenv:
|
||||
specifier: ^16.3.1
|
||||
version: 16.3.1
|
||||
|
@ -63,8 +63,8 @@ packages:
|
|||
js-tokens: 4.0.0
|
||||
dev: true
|
||||
|
||||
/@besties/html2png@1.0.0:
|
||||
resolution: {integrity: sha512-34dB4CxXL5xA/rJtpqI4UVp62DeQf2DQY3t37xSwar1nUde+i8VCCrRb6NfvZK7pz3v7gHk1M4uA7JDZpeWqKw==}
|
||||
/@besties/html2png@1.0.1:
|
||||
resolution: {integrity: sha512-qBkWy66WjvF8hrY2yEzPAIgbyCpTQZI1nt5+KcKg6kZtzvJb1w9GqoGp2MaRKmFTSENyjwK2WYY3CzkI7d49lw==}
|
||||
dependencies:
|
||||
'@resvg/resvg-wasm': 2.4.1
|
||||
html-entities: 2.4.0
|
||||
|
|
38
server.js
38
server.js
|
@ -52,6 +52,44 @@ async function getLanguages(owner, repo) {
|
|||
|
||||
const comicSansNames = new Set(['trixie'])
|
||||
|
||||
app.get('/:user', async function (req, res) {
|
||||
const [userResp, reposResp] = await Promise.all([
|
||||
await fetch(
|
||||
`${forgejoBaseUrl}/api/v1/users/${encodeURIComponent(req.params.user)}`
|
||||
),
|
||||
await fetch(
|
||||
`${forgejoBaseUrl}/api/v1/users/${encodeURIComponent(
|
||||
req.params.user
|
||||
)}/repos`
|
||||
)
|
||||
])
|
||||
if (!userResp.ok) {
|
||||
res.status(userResp.status)
|
||||
res.end()
|
||||
return
|
||||
}
|
||||
const [user, repos] = await Promise.all([
|
||||
await userResp.json(),
|
||||
await reposResp.json()
|
||||
])
|
||||
user.repo_count = repos.length
|
||||
const html = await eta.renderAsync('user', {
|
||||
user,
|
||||
debug
|
||||
})
|
||||
if (debug) {
|
||||
res.send(await renderHtml(html))
|
||||
return
|
||||
}
|
||||
const options = {
|
||||
fonts: DMSans,
|
||||
format: req.query.format == 'svg' ? 'svg' : 'png'
|
||||
}
|
||||
res.type(options.format)
|
||||
res.set('Content-Disposition', 'inline')
|
||||
res.send(await render(html, options))
|
||||
})
|
||||
|
||||
app.get('/:owner/:repo', async function (req, res) {
|
||||
const [repoResp, commitsResp, languages] = await Promise.all([
|
||||
fetch(
|
||||
|
|
71
views/user.eta
Normal file
71
views/user.eta
Normal file
|
@ -0,0 +1,71 @@
|
|||
<% layout('layout') %>
|
||||
<%
|
||||
let description = it.user.description?.replace(/https?:\/\/([\S]+)/g, '$1')
|
||||
function prettyNumber(number) {
|
||||
if (number < 30) return number
|
||||
if (number < 1000) return Math.floor(number/10) * 10 + '+'
|
||||
return Math.floor(number / 1000)+'k'
|
||||
}
|
||||
%>
|
||||
<div class="main user">
|
||||
<div class="contents">
|
||||
<div class="info">
|
||||
<p class="title"><span><%= it.user.full_name || it.user.username %></span> <span class="username">@<%= it.user.username %></span></p>
|
||||
<p class="description"><%= description %></p>
|
||||
</div>
|
||||
<div class="graphics">
|
||||
<% if (it.user.avatar_url) { %>
|
||||
<img width="120" height="120" src="<%= it.user.avatar_url %>"></img>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-line">
|
||||
<div class="fact">
|
||||
<p class="fact-heading"><%= it.user.followers_count %></p>
|
||||
<p class="fact-subtitle">Followers</p>
|
||||
</div>
|
||||
<div class="fact">
|
||||
<p class="fact-heading"><%= it.user.following_count %></p>
|
||||
<p class="fact-subtitle">Following</p>
|
||||
</div>
|
||||
<div class="fact">
|
||||
<p class="fact-heading"><%= prettyNumber(it.user.repo_count) %></p>
|
||||
<p class="fact-subtitle">Repos</p>
|
||||
</div>
|
||||
<div class="fact">
|
||||
<p class="fact-heading"><%= it.user.starred_repos_count %></p>
|
||||
<p class="fact-subtitle">Stars Given</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.user .title {
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
}
|
||||
.user .title span:not(.username) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
font-size: 3rem;
|
||||
font-weight: 600;
|
||||
color: #aeb3d0;
|
||||
}
|
||||
.user .title .username {
|
||||
font-size: 1.75rem;
|
||||
gap: 0.5rem;
|
||||
font-weight: 400;
|
||||
color: #6d728f;
|
||||
}
|
||||
.fact {
|
||||
display: flex;
|
||||
margin-right: 0.5em;
|
||||
font-size: 1.5rem;
|
||||
flex-direction: column;
|
||||
}
|
||||
.fact-heading {
|
||||
color: #8c91af;
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
Loading…
Reference in a new issue