Skip to content

Commit d235f57

Browse files
docs: update project website
1 parent 9ac3923 commit d235f57

5 files changed

Lines changed: 81 additions & 38 deletions

File tree

afterpython/_website/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@afterpython/project-website-template",
3-
"version": "0.3.4",
3+
"version": "0.3.5",
44
"license": "Apache-2.0",
55
"type": "module",
66
"packageManager": "pnpm@11.1.1",

afterpython/_website/src/app.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
<html lang="en">
33
<head>
44
<meta charset="utf-8" />
5-
<link rel="icon" href="%sveltekit.assets%/favicon.svg" />
5+
<link rel="icon" type="image/svg+xml" href="%sveltekit.assets%/favicon.svg" />
6+
<link rel="icon" type="image/x-icon" href="%sveltekit.assets%/favicon.ico" />
67
<meta name="viewport" content="width=device-width, initial-scale=1" />
78
<script>
89
// Prevent theme flash by applying theme before page renders

afterpython/_website/src/lib/components/Logo.svelte

Lines changed: 63 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,50 @@
11
<script lang="ts">
2-
import { asset, resolve } from "$app/paths";
2+
import { asset, resolve } from '$app/paths';
33
44
type LogoProps = {
55
class?: string;
6-
size?: 'sm' | 'md' | 'lg' | 'xl';
6+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
77
text?: string;
88
showText?: boolean;
9+
logo?: string | null;
10+
logoDark?: string | null;
11+
};
12+
13+
let {
14+
class: className = '',
15+
size = 'md',
16+
text = '',
17+
showText = true,
18+
logo,
19+
logoDark
20+
}: LogoProps = $props();
21+
22+
// Probed in order when no explicit `logo` is configured via metadata.
23+
const DEFAULT_FORMATS = ['/logo.svg', '/logo.png', '/logo.jpg', '/logo.jpeg'];
24+
25+
function normalizePath(value: string | null | undefined): string | null {
26+
const trimmed = value?.trim();
27+
if (!trimmed) return null;
28+
return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
929
}
1030
11-
let { class: className = '', size = 'md', text = '', showText = true }: LogoProps = $props();
31+
const explicitLight = $derived(normalizePath(logo));
32+
const darkPath = $derived(normalizePath(logoDark));
33+
34+
let lightFallbackIndex = $state(0);
35+
let hasLight = $state(true);
36+
let hasDark = $state(true);
1237
13-
let hasLogo = $state(true);
38+
const lightSrc = $derived.by(() => {
39+
if (!hasLight) return null;
40+
if (explicitLight) return asset(explicitLight);
41+
if (lightFallbackIndex >= DEFAULT_FORMATS.length) return null;
42+
return asset(DEFAULT_FORMATS[lightFallbackIndex]);
43+
});
44+
const darkSrc = $derived(darkPath && hasDark ? asset(darkPath) : null);
1445
15-
// Size classes for logo image
1646
const sizeClasses = {
47+
xs: 'h-6',
1748
sm: 'h-10',
1849
md: 'h-14',
1950
lg: 'h-18',
@@ -22,41 +53,46 @@
2253
2354
// Font size classes for logo text - matching MyST's responsive sizing
2455
const textSizeClasses = {
56+
xs: 'text-sm sm:text-md tracking-tight',
2557
sm: 'text-md sm:text-lg tracking-tight',
2658
md: 'text-md sm:text-xl tracking-tight',
2759
lg: 'text-lg sm:text-2xl tracking-tight',
2860
xl: 'text-xl sm:text-3xl tracking-tight'
2961
};
3062
31-
// Handle fallback to different image formats
32-
function handleImageError(event: Event) {
33-
const img = event.target as HTMLImageElement;
34-
const currentSrc = img.src;
35-
36-
// Try formats in priority order: svg -> png -> jpg -> jpeg
37-
if (currentSrc.endsWith('/logo.svg')) {
38-
img.src = asset('/logo.png');
39-
} else if (currentSrc.endsWith('/logo.png')) {
40-
img.src = asset('/logo.jpg');
41-
} else if (currentSrc.endsWith('/logo.jpg')) {
42-
img.src = asset('/logo.jpeg');
63+
function handleLightError() {
64+
if (!explicitLight && lightFallbackIndex < DEFAULT_FORMATS.length - 1) {
65+
lightFallbackIndex += 1;
4366
} else {
44-
// All formats failed, hide the logo
45-
hasLogo = false;
67+
hasLight = false;
4668
}
4769
}
70+
71+
function handleDarkError() {
72+
hasDark = false;
73+
}
4874
</script>
4975

50-
{#if hasLogo}
76+
{#if lightSrc || darkSrc || (showText && text)}
5177
<a href={resolve('/')} class="flex items-center gap-3 {className}">
52-
<img
53-
src={asset('/logo.svg')}
54-
alt="Logo"
55-
class="{sizeClasses[size]} w-auto"
56-
onerror={handleImageError}
57-
/>
78+
{#if lightSrc}
79+
<img
80+
src={lightSrc}
81+
alt="Logo"
82+
class="{sizeClasses[size]} w-auto {darkSrc ? 'dark:hidden' : ''}"
83+
onerror={handleLightError}
84+
/>
85+
{/if}
86+
{#if darkSrc}
87+
<img
88+
src={darkSrc}
89+
alt="Logo"
90+
class="{sizeClasses[size]} w-auto {lightSrc ? 'hidden dark:block' : ''}"
91+
onerror={handleDarkError}
92+
/>
93+
{/if}
5894
{#if showText && text}
59-
<span class="{textSizeClasses[size]}">
95+
<span class={textSizeClasses[size]}>
6096
{text}
6197
</span>
6298
{/if}

afterpython/_website/src/routes/+layout.server.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,16 @@ function checkApiReferenceExists(): boolean {
2626
return existsSync(resolve('static', 'api_reference'));
2727
}
2828

29+
type LogoMetadata = {
30+
logo?: string;
31+
logo_dark?: string;
32+
};
33+
2934
export const load: LayoutServerLoad = async () => {
3035
try {
3136
// Dynamic import to handle missing file gracefully
3237
const metadata = await import('$static/metadata.json');
38+
const metadataData = metadata.default as typeof metadata.default & LogoMetadata;
3339

3440
// Check which content types exist - dynamically from CONTENT_TYPES
3541
const contentTypesArray = await Promise.all(
@@ -45,7 +51,7 @@ export const load: LayoutServerLoad = async () => {
4551
contentTypes.faq = await checkContentType('faq');
4652

4753
return {
48-
...metadata.default,
54+
...metadataData,
4955
metadataError: null,
5056
contentTypes
5157
};
@@ -54,7 +60,7 @@ export const load: LayoutServerLoad = async () => {
5460
const emptyContentTypes = Object.fromEntries(
5561
[...CONTENT_TYPES, 'doc', 'faq', 'api_reference'].map((type) => [type, false])
5662
);
57-
63+
5864
return {
5965
name: '',
6066
summary: '',
@@ -65,4 +71,4 @@ export const load: LayoutServerLoad = async () => {
6571
contentTypes: emptyContentTypes
6672
};
6773
}
68-
};
74+
};

afterpython/_website/src/routes/+layout.svelte

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@
2828
<div class="flex min-h-screen flex-col bg-bg50">
2929
<nav class="container mx-auto py-3 text-base font-medium text-tx50">
3030
<div class="flex items-center">
31-
<Logo size="md" text={data.name} />
31+
<Logo size="md" text={data.name} logo={data.logo} logoDark={data.logo_dark} />
3232
<ul class="flex flex-1 justify-center gap-18">
33-
{#if (dev ? env.PUBLIC_DOC_URL : data.contentTypes?.doc)}
33+
{#if dev ? env.PUBLIC_DOC_URL : data.contentTypes?.doc}
3434
<li>
3535
<a
3636
href={dev ? env.PUBLIC_DOC_URL : resolve('/doc')}
@@ -52,22 +52,22 @@
5252
</a>
5353
</li>
5454
{/if}
55-
{#if (dev ? env.PUBLIC_TUTORIAL_URL : data.contentTypes?.tutorial)}
55+
{#if dev ? env.PUBLIC_TUTORIAL_URL : data.contentTypes?.tutorial}
5656
<li>
5757
<a href={resolve('/tutorial')} data-sveltekit-preload-data>Tutorials</a>
5858
</li>
5959
{/if}
60-
{#if (dev ? env.PUBLIC_EXAMPLE_URL : data.contentTypes?.example)}
60+
{#if dev ? env.PUBLIC_EXAMPLE_URL : data.contentTypes?.example}
6161
<li>
6262
<a href={resolve('/example')} data-sveltekit-preload-data>Examples</a>
6363
</li>
6464
{/if}
65-
{#if (dev ? env.PUBLIC_GUIDE_URL : data.contentTypes?.guide)}
65+
{#if dev ? env.PUBLIC_GUIDE_URL : data.contentTypes?.guide}
6666
<li>
6767
<a href={resolve('/guide')} data-sveltekit-preload-data>Guides</a>
6868
</li>
6969
{/if}
70-
{#if (dev ? env.PUBLIC_BLOG_URL : data.contentTypes?.blog)}
70+
{#if dev ? env.PUBLIC_BLOG_URL : data.contentTypes?.blog}
7171
<li>
7272
<a href={resolve('/blog')} data-sveltekit-preload-data>Blog</a>
7373
</li>

0 commit comments

Comments
 (0)