Add whale logo, favicon, apple-touch-icon, and social embeds
Logo: hand-crafted SVG whale silhouette in blue gradient (#3b82f6 to #1d4ed8), DeepSeek-inspired minimalist style with water spout, eye, and wave arc. Renders at 28px in the nav header. Embeds: Open Graph and Twitter Card meta tags on every page. og:image is a 1200x630 embed card with the whale logo, WhalePrep title, tagline, and stats. Favicon.png (32x32) and apple-touch-icon.png (180x180) generated from the same SVG. theme-color #0a0f1c for mobile browsers.
This commit is contained in:
parent
51a01cc2cf
commit
b1b6887a26
7 changed files with 156 additions and 5 deletions
33
src/views.rs
33
src/views.rs
|
|
@ -88,12 +88,27 @@ pub struct SubjectBlock {
|
||||||
|
|
||||||
fn head(ctx: &Ctx, title: &str) -> String {
|
fn head(ctx: &Ctx, title: &str) -> String {
|
||||||
format!(
|
format!(
|
||||||
r#"<!doctype html><html lang="en"><head><meta charset="utf-8">
|
r##"<!doctype html><html lang="en"><head><meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title>{t} · WhalePrep</title><link rel="stylesheet" href="{b}/static/style.css">
|
<title>{t} · WhalePrep</title>
|
||||||
|
<link rel="icon" type="image/png" href="{b}/static/favicon.png">
|
||||||
|
<link rel="apple-touch-icon" href="{b}/static/apple-touch-icon.png">
|
||||||
|
<link rel="stylesheet" href="{b}/static/style.css">
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:site_name" content="WhalePrep">
|
||||||
|
<meta property="og:title" content="{t} · WhalePrep">
|
||||||
|
<meta property="og:description" content="Practice JEE Main previous year questions on a timed exam screen. 9,813 PYQs from 2002-2025 across 53 official NTA syllabus units.">
|
||||||
|
<meta property="og:image" content="{origin}/static/embed.png">
|
||||||
|
<meta property="og:image:width" content="1200">
|
||||||
|
<meta property="og:image:height" content="630">
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta name="twitter:title" content="{t} · WhalePrep">
|
||||||
|
<meta name="twitter:description" content="Practice JEE Main previous year questions on a timed exam screen. 9,813 PYQs from 2002-2025.">
|
||||||
|
<meta name="twitter:image" content="{origin}/static/embed.png">
|
||||||
|
<meta name="theme-color" content="#0a0f1c">
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js"></script>
|
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js"></script>
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/contrib/auto-render.min.js"></script>
|
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/contrib/auto-render.min.js"></script>
|
||||||
<script>document.addEventListener("DOMContentLoaded", function() {{
|
<script>document.addEventListener("DOMContentLoaded", function() {{
|
||||||
|
|
@ -102,15 +117,23 @@ fn head(ctx: &Ctx, title: &str) -> String {
|
||||||
trust: false, strict: false, throwOnError: false
|
trust: false, strict: false, throwOnError: false
|
||||||
}});
|
}});
|
||||||
}});</script>
|
}});</script>
|
||||||
</head><body>"#,
|
</head><body>"##,
|
||||||
t = esc(title),
|
t = esc(title),
|
||||||
b = ctx.base
|
b = ctx.base,
|
||||||
|
origin = public_origin()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The absolute origin for og:image URLs — meta tags need a full URL, not a
|
||||||
|
/// relative path. Derived from the request when behind the tunnel; falls
|
||||||
|
/// back to the production domain.
|
||||||
|
fn public_origin() -> String {
|
||||||
|
std::env::var("PUBLIC_ORIGIN").unwrap_or_else(|_| "https://whaleprep.oiupoyt.space".into())
|
||||||
|
}
|
||||||
|
|
||||||
fn nav(ctx: &Ctx, user: Option<&str>) -> String {
|
fn nav(ctx: &Ctx, user: Option<&str>) -> String {
|
||||||
let brand = format!(
|
let brand = format!(
|
||||||
r##"<header class="topbar"><div class="brand-group"><a class="brand" href="{b}/"><svg class="brand-logo" viewBox="0 0 24 24" width="22" height="22"><path fill="#60a5fa" d="M12 2L1 21h22L12 2zm0 4.5l7.5 13H4.5L12 6.5z"/></svg> WhalePrep</a></div><nav class="nav">"##,
|
r##"<header class="topbar"><div class="brand-group"><a class="brand" href="{b}/"><img class="brand-logo" src="{b}/static/logo.svg" alt="WhalePrep logo" width="28" height="28"> WhalePrep</a></div><nav class="nav">"##,
|
||||||
b = ctx.base
|
b = ctx.base
|
||||||
);
|
);
|
||||||
let links = match user {
|
let links = match user {
|
||||||
|
|
|
||||||
BIN
static/apple-touch-icon.png
Normal file
BIN
static/apple-touch-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.2 KiB |
BIN
static/embed.png
Normal file
BIN
static/embed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
70
static/embed.svg
Normal file
70
static/embed.svg
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 630">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
||||||
|
<stop offset="0" stop-color="#3b82f6"/>
|
||||||
|
<stop offset="1" stop-color="#1d4ed8"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<!-- Dark background -->
|
||||||
|
<rect width="1200" height="630" rx="0" fill="#0a0f1c"/>
|
||||||
|
|
||||||
|
<!-- Subtle glow behind whale -->
|
||||||
|
<ellipse cx="600" cy="300" rx="250" ry="200" fill="#1d4ed8" opacity="0.08"/>
|
||||||
|
|
||||||
|
<!-- Whale body -->
|
||||||
|
<g transform="translate(120, 130) scale(0.72)">
|
||||||
|
<path fill="url(#g)" d="
|
||||||
|
M 100 320
|
||||||
|
C 100 220 190 120 320 120
|
||||||
|
C 370 120 410 140 435 175
|
||||||
|
C 448 192 452 210 450 225
|
||||||
|
C 448 238 438 244 426 240
|
||||||
|
C 400 230 360 228 320 240
|
||||||
|
C 270 256 230 290 215 330
|
||||||
|
L 210 345
|
||||||
|
C 207 352 200 355 194 351
|
||||||
|
L 120 310
|
||||||
|
C 108 303 98 305 94 314
|
||||||
|
C 91 320 93 327 100 320
|
||||||
|
Z"/>
|
||||||
|
|
||||||
|
<!-- Tail -->
|
||||||
|
<path fill="url(#g)" d="
|
||||||
|
M 435 175
|
||||||
|
L 475 95
|
||||||
|
C 480 84 494 84 497 96
|
||||||
|
L 512 135
|
||||||
|
C 515 145 508 155 497 153
|
||||||
|
L 448 138
|
||||||
|
L 485 170
|
||||||
|
C 492 176 490 188 481 191
|
||||||
|
L 450 200
|
||||||
|
Z"/>
|
||||||
|
|
||||||
|
<!-- Eye -->
|
||||||
|
<circle cx="300" cy="190" r="16" fill="#fff"/>
|
||||||
|
|
||||||
|
<!-- Spout -->
|
||||||
|
<circle cx="290" cy="95" r="10" fill="url(#g)" opacity="0.9"/>
|
||||||
|
<circle cx="315" cy="70" r="7" fill="url(#g)" opacity="0.7"/>
|
||||||
|
<circle cx="335" cy="50" r="5" fill="url(#g)" opacity="0.5"/>
|
||||||
|
|
||||||
|
<!-- Smile -->
|
||||||
|
<path d="M 270 240 Q 290 255 315 242" stroke="#fff" stroke-width="8" fill="none" stroke-linecap="round" opacity="0.3"/>
|
||||||
|
|
||||||
|
<!-- Wave -->
|
||||||
|
<path d="M 40 430 Q 128 400 216 430 T 392 430" stroke="#3b82f6" stroke-width="16" fill="none" stroke-linecap="round" opacity="0.3"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- WhalePrep text -->
|
||||||
|
<text x="640" y="280" font-family="system-ui, -apple-system, sans-serif" font-size="72" font-weight="700" fill="#f8fafc" letter-spacing="-2">
|
||||||
|
WhalePrep
|
||||||
|
</text>
|
||||||
|
<text x="642" y="330" font-family="system-ui, -apple-system, sans-serif" font-size="28" font-weight="500" fill="#94a3b8">
|
||||||
|
JEE Main practice, built like the real exam
|
||||||
|
</text>
|
||||||
|
<text x="642" y="375" font-family="system-ui, -apple-system, sans-serif" font-size="22" font-weight="500" fill="#38bdf8">
|
||||||
|
9,813 PYQs · 2002-2025 · +4/−1 marking
|
||||||
|
</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.3 KiB |
BIN
static/favicon.png
Normal file
BIN
static/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1,005 B |
51
static/logo.svg
Normal file
51
static/logo.svg
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
||||||
|
<stop offset="0" stop-color="#3b82f6"/>
|
||||||
|
<stop offset="1" stop-color="#1d4ed8"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<!-- Whale body: rounded paisley shape with the tail curving up-right -->
|
||||||
|
<path fill="url(#g)" d="
|
||||||
|
M 100 320
|
||||||
|
C 100 220 190 120 320 120
|
||||||
|
C 370 120 410 140 435 175
|
||||||
|
C 448 192 452 210 450 225
|
||||||
|
C 448 238 438 244 426 240
|
||||||
|
C 400 230 360 228 320 240
|
||||||
|
C 270 256 230 290 215 330
|
||||||
|
L 210 345
|
||||||
|
C 207 352 200 355 194 351
|
||||||
|
L 120 310
|
||||||
|
C 108 303 98 305 94 314
|
||||||
|
C 91 320 93 327 100 320
|
||||||
|
Z"/>
|
||||||
|
|
||||||
|
<!-- Tail fluke: two pointed triangles -->
|
||||||
|
<path fill="url(#g)" d="
|
||||||
|
M 435 175
|
||||||
|
L 475 95
|
||||||
|
C 480 84 494 84 497 96
|
||||||
|
L 512 135
|
||||||
|
C 515 145 508 155 497 153
|
||||||
|
L 448 138
|
||||||
|
L 485 170
|
||||||
|
C 492 176 490 188 481 191
|
||||||
|
L 450 200
|
||||||
|
Z"/>
|
||||||
|
|
||||||
|
<!-- Eye -->
|
||||||
|
<circle cx="300" cy="190" r="16" fill="#fff"/>
|
||||||
|
|
||||||
|
<!-- Water spout -->
|
||||||
|
<circle cx="290" cy="95" r="10" fill="url(#g)" opacity="0.9"/>
|
||||||
|
<circle cx="315" cy="70" r="7" fill="url(#g)" opacity="0.7"/>
|
||||||
|
<circle cx="335" cy="50" r="5" fill="url(#g)" opacity="0.5"/>
|
||||||
|
|
||||||
|
<!-- Smile curve -->
|
||||||
|
<path d="M 270 240 Q 290 255 315 242" stroke="#fff" stroke-width="8" fill="none" stroke-linecap="round" opacity="0.3"/>
|
||||||
|
|
||||||
|
<!-- Wave -->
|
||||||
|
<path d="M 40 430 Q 128 400 216 430 T 392 430" stroke="#3b82f6" stroke-width="16" fill="none" stroke-linecap="round" opacity="0.3"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -2216,3 +2216,10 @@ button.pal-fab {
|
||||||
.zp-subtopic-row:has(input:checked) .zp-subtopic-title {
|
.zp-subtopic-row:has(input:checked) .zp-subtopic-title {
|
||||||
color: #60a5fa;
|
color: #60a5fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===== brand logo ===== */
|
||||||
|
img.brand-logo {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
filter: drop-shadow(0 0 6px rgba(59, 130, 246, 0.3));
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue