feat(identity): real author photo across the site + About page rewrite
Deploy / build (push) Successful in 48s

The photo is the identity evidence the external review flagged as the biggest
gap. One source image (Pictures/Professional Portrait with Blue Gradient
Background.png, 1254x1254), two sizes, WebP first with a JPEG fallback —
continuous tone is the case where WebP/JPEG beat PNG:

  640x640  42 KB JPG / 26 KB WebP   About page (190 CSS px)
  128x128   3 KB JPG /  2 KB WebP   author card + home hero avatar

It now appears in the About hero, the author card at the end of every post, the
home hero (both languages), and JSON-LD Person.image — the node search engines
read to associate the name with a face.

About went from 1,024 characters to five sections: identity with photo, "By the
numbers" (162 containers / 3 hosts / 71 essays / 0 hosting companies between me
and the servers), the real tech stack in four columns, the Hoelee Enterprise
block (website design and development is the main business, email hosting
secondary), and a contact split between hiring and business.

Also: the headshot's dark-blue background sits close to the page background, so
the photo, hero avatar and card avatar get a faint brand ring plus shadow.

Pictures/ keeps the converted JPG master next to the untouched PNG.
This commit is contained in:
hoelee committed 2026-10-16 22:07:25 +08:00
1 parent 215051ef08
commit 6b7c5a983f
12 files changed
+410 -65

No files matched your search

+46 -5
View File
@@ -3,21 +3,62 @@ import { SITE } from '../config';
interface Props {
bio?: string;
lang?: 'en' | 'zh';
}
const { bio = 'Full-stack developer & DevOps engineer. I build web apps, self-host infrastructure, and automate things — this blog is my living portfolio.' } = Astro.props;
const {
bio = 'Full-stack developer & DevOps engineer based in Malaysia. I run my own production infrastructure and build web systems for small businesses — this blog is the living record.',
lang = 'en',
} = Astro.props;
const isZh = lang === 'zh';
const t = isZh
? {
hiring: '招聘方:技术栈与履历',
hiringHref: '/zh/about/',
sme: '马来西亚中小企业:网站设计与开发',
smeHref: SITE.website,
stack: '全部技术文章',
stackHref: '/zh/posts/',
}
: {
hiring: 'Hiring? Profile & stack',
hiringHref: '/about/',
sme: 'Malaysian SME? Website design & development',
smeHref: SITE.website,
stack: 'All posts',
stackHref: '/posts/',
};
---
<div class="author-card">
<div class="avatar" aria-hidden="true">{SITE.handle.charAt(0)}</div>
<div>
<p class="who">{SITE.author}</p>
<picture>
<source srcset={SITE.photo.smallWebp} type="image/webp" />
<img
class="avatar"
src={SITE.photo.small}
alt={SITE.author}
width="64"
height="64"
loading="lazy"
decoding="async"
/>
</picture>
<div class="author-body">
<p class="who">{SITE.author} · {SITE.handle}</p>
<p class="bio">{bio}</p>
<div class="links">
<a href={SITE.linkedin} target="_blank" rel="noopener">LinkedIn</a>
<a href={SITE.github} target="_blank" rel="noopener">GitHub</a>
<a href={SITE.gitea} target="_blank" rel="noopener">Gitea</a>
<a href={SITE.website} target="_blank" rel="noopener">hoelee.com</a>
<a href={`mailto:${SITE.email}`}>{SITE.email}</a>
</div>
<p class="author-split">
<a href={t.hiringHref}>{t.hiring}</a>
<span class="sep">·</span>
<a href={t.smeHref} target="_blank" rel="noopener">{t.sme} ↗</a>
<span class="sep">·</span>
<a href={t.stackHref}>{t.stack}</a>
</p>
</div>
</div>