Skip to content

Commit 987ca0c

Browse files
committed
feat: dynamic image generation
1 parent a8f5a3a commit 987ca0c

36 files changed

+486
-347
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ deno task start
7979
### Deployment Notes
8080

8181
- **main.ts**: Re-exports from `main.tsx` for Fresh build compatibility
82-
- **Build Output**: The `_fresh/` directory contains the compiled server and assets
82+
- **Build Output**: The `_fresh/` directory contains the compiled server and
83+
assets
8384
- **Environment**: Ensure Deno 2.0+ is installed on your deployment platform
8485
- **Port**: Default port is 8000 (configurable via environment variables)
8586

components/CodeBlock.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import Prism from "npm:[email protected]";
33

44
export function CodeBlock(
5-
{ code, lang }: { code: string; lang: "js" | "ts" | "jsx" | "md" | "bash" },
5+
{ code, lang }: { code: string; lang: "js" | "ts" | "jsx" | "md" | "bash"; },
66
) {
77
const langMap: Record<string, string> = {
88
"ts": "typescript",

components/Meta.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,18 @@ interface MetaProps {
1414
export default function Meta({ meta }: MetaProps) {
1515
const title = generateTitle(meta.title);
1616
const url = meta.url || defaultSiteConfig.url;
17-
const image = generateImageUrl(meta.image || defaultSiteConfig.image);
1817
const description = meta.description || defaultSiteConfig.description;
1918
const type = meta.type || "website";
2019

20+
let image: string;
21+
if (meta.image && !meta.image.includes("cover.svg")) {
22+
image = generateImageUrl(meta.image);
23+
} else {
24+
const pageTitle = meta.title === defaultSiteConfig.name ? "" : meta.title;
25+
const encodedTitle = encodeURIComponent(pageTitle);
26+
image = generateImageUrl(`/og/${encodedTitle}`);
27+
}
28+
2129
return (
2230
<Head>
2331
{/* Primary Meta Tags */}

components/NavBar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { GithubIcon } from "lucide-preact";
2+
import MobileMenu from "../islands/MobileMenu.tsx";
23
import PWAStatus from "../islands/PWAStatus.tsx";
34
import SearchTrigger from "../islands/SearchTrigger.tsx";
4-
import MobileMenu from "../islands/MobileMenu.tsx";
55

66
export default function NavBar() {
77
return (

islands/CodeCopyButton.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,20 @@ export function CodeCopyButton({ code, className = "" }: CodeCopyButtonProps) {
2424
type="button"
2525
onClick={copyToClipboard}
2626
className={`inline-flex items-center gap-2 px-3 py-1.5 text-xs font-medium rounded-lg transition-all duration-200 ${
27-
copied
28-
? "bg-green/20 text-green border border-green/30"
29-
: "bg-surface1/80 text-subtext1 border border-surface2/50 hover:bg-surface2/80 hover:text-text"
27+
copied ?
28+
"bg-green/20 text-green border border-green/30" :
29+
"bg-surface1/80 text-subtext1 border border-surface2/50 hover:bg-surface2/80 hover:text-text"
3030
} ${className}`}
3131
title={copied ? "Copied!" : "Copy code"}
3232
>
33-
{copied
34-
? (
33+
{copied ?
34+
(
3535
<>
3636
<Check size={14} />
3737
<span>Copied!</span>
3838
</>
39-
)
40-
: (
39+
) :
40+
(
4141
<>
4242
<Copy size={14} />
4343
<span>Copy</span>

islands/DocNav.tsx

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ export function DocNav({
8080
},
8181
);
8282

83-
const searchResults = searchTerm
84-
? fuse.search(searchTerm).map((result: any) => result.item)
85-
: null;
83+
const searchResults = searchTerm ?
84+
fuse.search(searchTerm).map((result: any) => result.item) :
85+
null;
8686

8787
const filteredData = searchTerm ? [] : data;
8888

@@ -159,11 +159,11 @@ export function DocNav({
159159

160160
{/* Navigation content */}
161161
<div class="flex-1 overflow-y-auto px-6 py-4">
162-
{searchResults
163-
? (
162+
{searchResults ?
163+
(
164164
/* Search results */
165-
searchResults.length > 0
166-
? (
165+
searchResults.length > 0 ?
166+
(
167167
<div class="space-y-1">
168168
<div class="text-xs font-semibold uppercase text-subtext0 tracking-wider mb-3">
169169
Search Results ({searchResults.length})
@@ -174,9 +174,9 @@ export function DocNav({
174174
href={result.path}
175175
onClick={closeNav}
176176
class={`flex items-center space-x-3 py-3 px-4 rounded-lg text-sm transition-all duration-200 ${
177-
path === result.path
178-
? "bg-surface1 text-text font-medium border border-surface2"
179-
: "text-subtext1 hover:bg-surface0/50 hover:text-text"
177+
path === result.path ?
178+
"bg-surface1 text-text font-medium border border-surface2" :
179+
"text-subtext1 hover:bg-surface0/50 hover:text-text"
180180
}`}
181181
>
182182
<span class="text-lg">{result.sectionIcon}</span>
@@ -189,8 +189,8 @@ export function DocNav({
189189
</a>
190190
))}
191191
</div>
192-
)
193-
: (
192+
) :
193+
(
194194
<div class="text-center py-12">
195195
<div class="text-4xl mb-3">🔍</div>
196196
<div class="text-subtext0 text-sm">No results found</div>
@@ -199,8 +199,8 @@ export function DocNav({
199199
</div>
200200
</div>
201201
)
202-
)
203-
: (
202+
) :
203+
(
204204
/* Regular navigation */
205205
<div class="space-y-2">
206206
{filteredData.map(
@@ -216,9 +216,9 @@ export function DocNav({
216216
type="button"
217217
onClick={() => toggleSection(topicName)}
218218
class={`w-full flex items-center justify-between py-3 px-4 rounded-lg text-sm font-semibold transition-all duration-200 ${
219-
hasCurrentPage
220-
? "bg-surface0/50 text-text"
221-
: "text-subtext0 hover:bg-surface0/30 hover:text-text"
219+
hasCurrentPage ?
220+
"bg-surface0/50 text-text" :
221+
"text-subtext0 hover:bg-surface0/30 hover:text-text"
222222
}`}
223223
>
224224
<div class="flex items-center space-x-3">
@@ -249,9 +249,9 @@ export function DocNav({
249249
href={routePath}
250250
onClick={closeNav}
251251
class={`block py-2.5 px-3 rounded-lg text-sm transition-all duration-200 ${
252-
path === routePath
253-
? "bg-surface1 text-text font-medium border border-surface2 shadow-sm"
254-
: "text-subtext1 hover:bg-surface0/50 hover:text-text hover:translate-x-1"
252+
path === routePath ?
253+
"bg-surface1 text-text font-medium border border-surface2 shadow-sm" :
254+
"text-subtext1 hover:bg-surface0/50 hover:text-text hover:translate-x-1"
255255
}`}
256256
>
257257
{routeName}

islands/GitHubStats.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export default function GitHubStats() {
5858
const release = await releaseResponse.json();
5959

6060
const downloadCount = release.assets?.reduce(
61-
(total: number, asset: { download_count?: number }) =>
61+
(total: number, asset: { download_count?: number; }) =>
6262
total + (asset.download_count || 0),
6363
0,
6464
) || 0;
@@ -173,9 +173,9 @@ export default function GitHubStats() {
173173

174174
<div class="text-center">
175175
<div class="text-2xl font-bold text-mauve mb-1">
176-
{latestRelease?.download_count
177-
? formatNumber(latestRelease.download_count)
178-
: "—"}
176+
{latestRelease?.download_count ?
177+
formatNumber(latestRelease.download_count) :
178+
"—"}
179179
</div>
180180
<div class="text-xs text-subtext1">Downloads</div>
181181
</div>

islands/InstallToggle.tsx

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -128,37 +128,37 @@ export default function InstallToggle() {
128128
type="button"
129129
onClick={() => setSelectedPlatform(platform.id)}
130130
class={`group relative overflow-hidden p-4 rounded-lg border transition-all duration-500 transform hover:scale-105 ${
131-
isSelected
132-
? `bg-${platform.color} text-base border-${platform.color} shadow-lg scale-105 animate-pulse-glow`
133-
: "bg-surface0 hover:bg-surface1 border-surface1 hover:border-surface2 hover:shadow-xl hover:shadow-blue/10"
131+
isSelected ?
132+
`bg-${platform.color} text-base border-${platform.color} shadow-lg scale-105 animate-pulse-glow` :
133+
"bg-surface0 hover:bg-surface1 border-surface1 hover:border-surface2 hover:shadow-xl hover:shadow-blue/10"
134134
}`}
135-
style={isSelected
136-
? {
135+
style={isSelected ?
136+
{
137137
backgroundColor: `var(--color-${platform.color})`,
138138
borderColor: `var(--color-${platform.color})`,
139139
color: "var(--color-base)",
140140
boxShadow:
141141
`0 0 20px color-mix(in srgb, var(--color-${platform.color}) 40%, transparent), 0 8px 25px rgba(0, 0, 0, 0.15)`,
142-
}
143-
: {
142+
} :
143+
{
144144
color: "var(--color-text)",
145145
}}
146146
>
147147
{/* Icon */}
148148
<div class="flex justify-center mb-2">
149149
<div
150150
class={`p-2 rounded-lg transition-colors ${
151-
isSelected
152-
? "bg-base/20"
153-
: "bg-surface1 group-hover:bg-surface2"
151+
isSelected ?
152+
"bg-base/20" :
153+
"bg-surface1 group-hover:bg-surface2"
154154
}`}
155155
>
156156
<IconComponent
157157
size={20}
158158
class={isSelected ? "text-base" : ""}
159-
style={isSelected
160-
? { color: "var(--color-base)" }
161-
: { color: "var(--color-text)" }}
159+
style={isSelected ?
160+
{ color: "var(--color-base)" } :
161+
{ color: "var(--color-text)" }}
162162
/>
163163
</div>
164164
</div>{" "}
@@ -168,9 +168,9 @@ export default function InstallToggle() {
168168
class={`text-xs sm:text-sm font-semibold ${
169169
isSelected ? "text-base" : ""
170170
}`}
171-
style={isSelected
172-
? { color: "var(--color-base)" }
173-
: { color: "var(--color-text)" }}
171+
style={isSelected ?
172+
{ color: "var(--color-base)" } :
173+
{ color: "var(--color-text)" }}
174174
>
175175
{platform.name}
176176
</div>

islands/MobileMenu.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// deno-lint-ignore-file no-window
2-
import { useEffect, useRef, useState } from "preact/hooks";
32
import { BookOpen, Code, Menu, Newspaper, Satellite, X } from "lucide-preact";
3+
import { useEffect, useRef, useState } from "preact/hooks";
44

55
interface NavLink {
66
href: string;

islands/PWAStatus.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,15 @@ export default function PWAStatus() {
4141
<div class="fixed top-20 right-4 z-40 max-w-sm">
4242
<div class="bg-surface0 border border-surface1 rounded-lg p-3 shadow-lg backdrop-blur-sm">
4343
<div class="flex items-center gap-2">
44-
{!isOnline
45-
? (
44+
{!isOnline ?
45+
(
4646
<>
4747
<WifiOff class="w-4 h-4 text-red" />
4848
<span class="text-sm text-text">Offline Mode</span>
4949
</>
50-
)
51-
: updateAvailable
52-
? (
50+
) :
51+
updateAvailable ?
52+
(
5353
<>
5454
<Download class="w-4 h-4 text-blue" />
5555
<span class="text-sm text-text">Update Available</span>
@@ -61,8 +61,8 @@ export default function PWAStatus() {
6161
Reload
6262
</button>
6363
</>
64-
)
65-
: null}
64+
) :
65+
null}
6666
</div>
6767
</div>
6868
</div>

0 commit comments

Comments
 (0)