fix: update tool count to 51, refresh hero copy and login page

- Update stale tool counts (48/49/50) to 51 across all apps, docs, and tests
- Add Meme Generator to landing page bento grid (was missing)
- Add 12 SEO-friendly rotating phrases to hero typing cursor
- Change landing hero subtitle to "Every image tool you need."
- Replace outdated login page copy with branded hero + rotating phrases
This commit is contained in:
SnapOtter
2026-05-10 22:18:11 +08:00
parent 32e7b03ab4
commit 172c0fa772
22 changed files with 125 additions and 52 deletions
@@ -2460,7 +2460,7 @@ function AboutSection() {
</div>
</div>
<p className="text-sm text-muted-foreground">
A self-hosted, privacy-first image processing suite with 50 tools. Resize, compress,
A self-hosted, privacy-first image processing suite with 51 tools. Resize, compress,
convert, watermark, and automate your image workflows without sending data to the cloud.
</p>
<div className="flex items-center gap-4 text-sm">
+64 -6
View File
@@ -1,6 +1,64 @@
import { type FormEvent, useState } from "react";
import { type FormEvent, useCallback, useEffect, useState } from "react";
import { setToken } from "@/lib/api";
const phrases = [
"No signups. No accounts.",
"No uploads to the cloud. Ever.",
"100% local processing.",
"Free. Forever.",
"No limits. No hidden caps.",
"Works fully offline.",
"Unlimited batch processing.",
"51 image tools.",
"15 AI models. Your hardware.",
"Lightning fast. Built on Sharp.",
"Air-gapped ready.",
"One Docker container.",
"Open source. Always.",
"Every pixel stays on your hardware.",
"Your server. Your rules.",
"Deploys in a single docker pull.",
"The self-hosted alternative.",
"Resize, compress, convert. Locally.",
"Free image editor. No watermarks.",
"Bulk image processing. Unlimited.",
"Remove backgrounds offline.",
"Self-hosted Canva alternative.",
"No API keys needed.",
"GDPR compliant by design.",
"Works without internet.",
];
function RotatingPhrase() {
const [index, setIndex] = useState(0);
const [visible, setVisible] = useState(true);
const advance = useCallback(() => {
setVisible(false);
setTimeout(() => {
setIndex((i) => (i + 1) % phrases.length);
setVisible(true);
}, 300);
}, []);
useEffect(() => {
const timer = setInterval(advance, 3000);
return () => clearInterval(timer);
}, [advance]);
return (
<span
className="inline-block transition-all duration-300 text-white/90"
style={{
opacity: visible ? 1 : 0,
transform: visible ? "translateY(0)" : "translateY(-8px)",
}}
>
{phrases[index]}
</span>
);
}
export function LoginPage() {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
@@ -94,11 +152,11 @@ export function LoginPage() {
</div>
</div>
<div className="hidden lg:flex flex-1 bg-primary/90 items-center justify-center p-12 text-white rounded-l-3xl">
<div className="max-w-lg space-y-6 text-center">
<h2 className="text-3xl font-bold">Your one-stop-shop for all your image needs.</h2>
<p className="text-lg text-white/80">
A privacy-first image suite that lets you resize, compress, convert, and process images
with 33+ powerful tools.
<div className="max-w-lg space-y-4 text-center">
<h2 className="text-4xl font-extrabold tracking-tight">Your images. Stay yours.</h2>
<p className="text-lg text-white/70">Every image tool you need.</p>
<p className="text-xl font-medium h-8">
<RotatingPhrase />
</p>
</div>
</div>