Skip to content

Commit 29cb64d

Browse files
committed
feat: add premium Crowned S favicon and personal logo mark
1 parent a6cc880 commit 29cb64d

7 files changed

Lines changed: 322 additions & 3 deletions

File tree

src/app/apple-icon.tsx

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { ImageResponse } from "next/og";
2+
3+
export const size = { width: 180, height: 180 };
4+
export const contentType = "image/png";
5+
6+
/**
7+
* Apple Touch Icon — The Crowned S at 180x180.
8+
* Full detail with refined crown strokes and subtle glow.
9+
*/
10+
export default async function AppleIcon() {
11+
const playfairFont = await fetch(
12+
new URL(
13+
"https://fonts.gstatic.com/s/playfairdisplay/v37/nuFvD-vYSZviVYUb_rj3ij__anPXJzDwcbmjWBN2PKdFvXDXbtY.ttf",
14+
),
15+
).then((res) => res.arrayBuffer());
16+
17+
return new ImageResponse(
18+
<div
19+
style={{
20+
width: "180px",
21+
height: "180px",
22+
background: "#06080d",
23+
display: "flex",
24+
flexDirection: "column",
25+
alignItems: "center",
26+
justifyContent: "center",
27+
borderRadius: "24px",
28+
}}
29+
>
30+
{/* Subtle outer glow ring */}
31+
<div
32+
style={{
33+
position: "absolute",
34+
width: "160px",
35+
height: "160px",
36+
borderRadius: "20px",
37+
border: "1px solid rgba(201, 169, 110, 0.15)",
38+
display: "flex",
39+
}}
40+
/>
41+
42+
{/* Crown chevron — three elegant lines */}
43+
<div
44+
style={{
45+
display: "flex",
46+
alignItems: "flex-end",
47+
gap: "8px",
48+
marginBottom: "-4px",
49+
}}
50+
>
51+
<div
52+
style={{
53+
width: "2px",
54+
height: "24px",
55+
background: "#E8C88A",
56+
transform: "rotate(-25deg)",
57+
borderRadius: "1px",
58+
}}
59+
/>
60+
<div
61+
style={{
62+
width: "2px",
63+
height: "24px",
64+
background: "#E8C88A",
65+
borderRadius: "1px",
66+
}}
67+
/>
68+
<div
69+
style={{
70+
width: "2px",
71+
height: "24px",
72+
background: "#E8C88A",
73+
transform: "rotate(25deg)",
74+
borderRadius: "1px",
75+
}}
76+
/>
77+
</div>
78+
79+
{/* S letterform with gold gradient */}
80+
<div
81+
style={{
82+
fontFamily: "Playfair Display",
83+
fontWeight: 700,
84+
fontSize: "110px",
85+
lineHeight: 1,
86+
background: "linear-gradient(180deg, #E8C88A 0%, #C9A96E 100%)",
87+
backgroundClip: "text",
88+
color: "transparent",
89+
}}
90+
>
91+
S
92+
</div>
93+
</div>,
94+
{
95+
...size,
96+
fonts: [
97+
{
98+
name: "Playfair Display",
99+
data: playfairFont,
100+
weight: 700,
101+
style: "normal",
102+
},
103+
],
104+
},
105+
);
106+
}

src/app/favicon.ico

-25.3 KB
Binary file not shown.

src/app/icon.tsx

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { ImageResponse } from "next/og";
2+
3+
export const size = { width: 32, height: 32 };
4+
export const contentType = "image/png";
5+
6+
/**
7+
* Dynamic favicon — The Crowned S at 32x32.
8+
* Uses Next.js ImageResponse (Satori) for server-side rendering.
9+
*/
10+
export default async function Icon() {
11+
const playfairFont = await fetch(
12+
new URL(
13+
"https://fonts.gstatic.com/s/playfairdisplay/v37/nuFvD-vYSZviVYUb_rj3ij__anPXJzDwcbmjWBN2PKdFvXDXbtY.ttf",
14+
),
15+
).then((res) => res.arrayBuffer());
16+
17+
return new ImageResponse(
18+
<div
19+
style={{
20+
width: "32px",
21+
height: "32px",
22+
background: "#06080d",
23+
display: "flex",
24+
flexDirection: "column",
25+
alignItems: "center",
26+
justifyContent: "center",
27+
borderRadius: "4px",
28+
}}
29+
>
30+
{/* Crown chevron */}
31+
<div
32+
style={{
33+
display: "flex",
34+
alignItems: "flex-end",
35+
gap: "2px",
36+
marginBottom: "-2px",
37+
}}
38+
>
39+
<div
40+
style={{
41+
width: "1px",
42+
height: "5px",
43+
background: "#E8C88A",
44+
transform: "rotate(-25deg)",
45+
}}
46+
/>
47+
<div
48+
style={{
49+
width: "1px",
50+
height: "5px",
51+
background: "#E8C88A",
52+
}}
53+
/>
54+
<div
55+
style={{
56+
width: "1px",
57+
height: "5px",
58+
background: "#E8C88A",
59+
transform: "rotate(25deg)",
60+
}}
61+
/>
62+
</div>
63+
64+
{/* S letterform */}
65+
<div
66+
style={{
67+
fontFamily: "Playfair Display",
68+
fontWeight: 700,
69+
fontSize: "20px",
70+
lineHeight: 1,
71+
background: "linear-gradient(180deg, #E8C88A 0%, #C9A96E 100%)",
72+
backgroundClip: "text",
73+
color: "transparent",
74+
}}
75+
>
76+
S
77+
</div>
78+
</div>,
79+
{
80+
...size,
81+
fonts: [
82+
{
83+
name: "Playfair Display",
84+
data: playfairFont,
85+
weight: 700,
86+
style: "normal",
87+
},
88+
],
89+
},
90+
);
91+
}

src/app/manifest.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { MetadataRoute } from "next";
2+
3+
/**
4+
* Web App Manifest for the portfolio PWA.
5+
*/
6+
export default function manifest(): MetadataRoute.Manifest {
7+
return {
8+
name: "Pyae Sone Kyaw | AI Engineer",
9+
short_name: "PSK",
10+
description: "Portfolio of Pyae Sone Kyaw — Founding AI Engineer",
11+
start_url: "/",
12+
display: "standalone",
13+
background_color: "#06080d",
14+
theme_color: "#06080d",
15+
icons: [
16+
{
17+
src: "/icon",
18+
sizes: "32x32",
19+
type: "image/png",
20+
},
21+
{
22+
src: "/apple-icon",
23+
sizes: "180x180",
24+
type: "image/png",
25+
},
26+
],
27+
};
28+
}

src/components/footer.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1+
import { Logo } from "./logo";
2+
13
export function Footer() {
24
return (
35
<footer className="flex flex-wrap items-center justify-between gap-3.5 border-t border-border px-10 py-7">
4-
<div className="font-playfair text-[18px] font-bold text-accent">PSK</div>
6+
<div className="flex items-center gap-2">
7+
<Logo size={22} />
8+
<span className="font-playfair text-[18px] font-bold text-accent">
9+
PSK
10+
</span>
11+
</div>
512
<div className="font-dm-mono text-[8px] tracking-[.2em] text-muted">
613
PYAE SONE KYAW &middot; FOUNDING AI ENGINEER &middot; PARIS 2026
714
</div>

src/components/logo.tsx

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
"use client";
2+
3+
interface LogoProps {
4+
/** Size in pixels (default 24) */
5+
size?: number;
6+
/** Additional CSS classes */
7+
className?: string;
8+
}
9+
10+
/**
11+
* The Crowned S — premium personal logo mark.
12+
* Bold serif S with a minimal three-line crown chevron above.
13+
*/
14+
export function Logo({ size = 24, className = "" }: LogoProps) {
15+
const id = `logo-grad-${size}`;
16+
const crownY = size * 0.18;
17+
const crownSpread = size * 0.18;
18+
const crownCenter = size / 2;
19+
const strokeWidth = size < 28 ? 1.2 : 1.5;
20+
21+
return (
22+
<svg
23+
width={size}
24+
height={size}
25+
viewBox={`0 0 ${size} ${size}`}
26+
fill="none"
27+
xmlns="http://www.w3.org/2000/svg"
28+
className={className}
29+
aria-label="Pyae Sone Kyaw logo"
30+
>
31+
<defs>
32+
<linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
33+
<stop offset="0%" stopColor="#E8C88A" />
34+
<stop offset="100%" stopColor="#C9A96E" />
35+
</linearGradient>
36+
</defs>
37+
38+
{/* Crown chevron — three angled lines */}
39+
<line
40+
x1={crownCenter}
41+
y1={crownY - size * 0.06}
42+
x2={crownCenter}
43+
y2={crownY + size * 0.06}
44+
stroke="#E8C88A"
45+
strokeWidth={strokeWidth}
46+
strokeLinecap="round"
47+
/>
48+
<line
49+
x1={crownCenter - crownSpread}
50+
y1={crownY + size * 0.06}
51+
x2={crownCenter - crownSpread * 0.45}
52+
y2={crownY - size * 0.06}
53+
stroke="#E8C88A"
54+
strokeWidth={strokeWidth}
55+
strokeLinecap="round"
56+
/>
57+
<line
58+
x1={crownCenter + crownSpread}
59+
y1={crownY + size * 0.06}
60+
x2={crownCenter + crownSpread * 0.45}
61+
y2={crownY - size * 0.06}
62+
stroke="#E8C88A"
63+
strokeWidth={strokeWidth}
64+
strokeLinecap="round"
65+
/>
66+
67+
{/* Bold serif S */}
68+
<text
69+
x="50%"
70+
y="66%"
71+
dominantBaseline="central"
72+
textAnchor="middle"
73+
fill={`url(#${id})`}
74+
fontFamily="var(--font-playfair-display), 'Playfair Display', serif"
75+
fontWeight="700"
76+
fontSize={size * 0.55}
77+
letterSpacing=".02em"
78+
>
79+
S
80+
</text>
81+
</svg>
82+
);
83+
}

src/components/navbar.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { useState, useEffect, useCallback } from "react";
44
import { NAV_LINKS } from "@/lib/data";
55
import { scrollToSection } from "@/lib/hooks";
6+
import { Logo } from "./logo";
67

78
export function Navbar() {
89
const [scrolled, setScrolled] = useState(false);
@@ -28,9 +29,12 @@ export function Navbar() {
2829
>
2930
<div
3031
onClick={() => handleNav("hero")}
31-
className="cursor-pointer font-playfair text-[20px] font-bold tracking-[.06em] text-accent"
32+
className="flex cursor-pointer items-center gap-2"
3233
>
33-
PSK
34+
<Logo size={28} />
35+
<span className="font-playfair text-[16px] font-bold tracking-[.06em] text-accent">
36+
PSK
37+
</span>
3438
</div>
3539

3640
<div className="flex flex-wrap gap-7">

0 commit comments

Comments
 (0)