chore: update tool count to 50 across all references

This commit is contained in:
SnapOtter
2026-05-08 16:33:12 +08:00
parent 466ef1efb1
commit 3d9324b82a
8 changed files with 22 additions and 22 deletions
+1 -1
View File
@@ -64,7 +64,7 @@ pnpm dev
## What You Can Do ## What You Can Do
### Image Processing (49 Tools) ### Image Processing (50 Tools)
| Category | Tools | | Category | Tools |
|----------|-------| |----------|-------|
+1 -1
View File
@@ -396,7 +396,7 @@ export function BentoGrid() {
<div className="mx-auto max-w-6xl"> <div className="mx-auto max-w-6xl">
<FadeIn> <FadeIn>
<h2 className="font-[family-name:var(--font-nunito)] text-center text-3xl font-bold tracking-tight md:text-4xl"> <h2 className="font-[family-name:var(--font-nunito)] text-center text-3xl font-bold tracking-tight md:text-4xl">
48 tools. Zero cloud dependency. 50 tools. Zero cloud dependency.
</h2> </h2>
<p className="mx-auto mt-4 max-w-xl text-center text-lg text-muted"> <p className="mx-auto mt-4 max-w-xl text-center text-lg text-muted">
Search to find exactly what you need. Every tool runs 100% locally. Search to find exactly what you need. Every tool runs 100% locally.
@@ -2456,7 +2456,7 @@ function AboutSection() {
</div> </div>
</div> </div>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
A self-hosted, privacy-first image processing suite with 48 tools. Resize, compress, A self-hosted, privacy-first image processing suite with 50 tools. Resize, compress,
convert, watermark, and automate your image workflows without sending data to the cloud. convert, watermark, and automate your image workflows without sending data to the cloud.
</p> </p>
<div className="flex items-center gap-4 text-sm"> <div className="flex items-center gap-4 text-sm">
+1 -1
View File
@@ -215,7 +215,7 @@ export const en = {
regenerateKey: "Regenerate", regenerateKey: "Regenerate",
copyKey: "Copy Key", copyKey: "Copy Key",
aboutDescription: aboutDescription:
"SnapOtter is a self-hosted, privacy-first image processing suite with 48 tools.", "SnapOtter is a self-hosted, privacy-first image processing suite with 50 tools.",
aboutLinks: "Links", aboutLinks: "Links",
github: "GitHub", github: "GitHub",
documentation: "Documentation", documentation: "Documentation",
+1 -1
View File
@@ -13,7 +13,7 @@ test.describe("Docs Homepage", () => {
await expect(page.getByText("SnapOtter").first()).toBeVisible(); await expect(page.getByText("SnapOtter").first()).toBeVisible();
await expect(page.getByText("A Self Hosted Image Manipulator")).toBeVisible(); await expect(page.getByText("A Self Hosted Image Manipulator")).toBeVisible();
await expect( await expect(
page.getByText("48 tools. Local AI. No cloud. Your images never leave your home."), page.getByText("50 tools. Local AI. No cloud. Your images never leave your home."),
).toBeVisible(); ).toBeVisible();
}); });
+2 -2
View File
@@ -59,9 +59,9 @@ test.describe("Landing Homepage", () => {
}); });
test("bento grid renders with search and tool count", async ({ page }) => { test("bento grid renders with search and tool count", async ({ page }) => {
await expect(page.getByText("48 tools. Zero cloud dependency.")).toBeVisible(); await expect(page.getByText("50 tools. Zero cloud dependency.")).toBeVisible();
await expect(page.getByPlaceholder("Search tools...")).toBeVisible(); await expect(page.getByPlaceholder("Search tools...")).toBeVisible();
await expect(page.getByText(/Showing 48 of 48 tools/)).toBeVisible(); await expect(page.getByText(/Showing 50 of 50 tools/)).toBeVisible();
}); });
test("enterprise section renders feature cards", async ({ page }) => { test("enterprise section renders feature cards", async ({ page }) => {
+6 -6
View File
@@ -9,28 +9,28 @@ test.describe("BentoGrid Interactions", () => {
const input = page.getByPlaceholder("Search tools..."); const input = page.getByPlaceholder("Search tools...");
await input.fill("resize"); await input.fill("resize");
await expect(page.getByText("Resize", { exact: true }).first()).toBeVisible(); await expect(page.getByText("Resize", { exact: true }).first()).toBeVisible();
await expect(page.getByText(/Showing \d+ of 48 tools/)).toBeVisible(); await expect(page.getByText(/Showing \d+ of 50 tools/)).toBeVisible();
}); });
test("category pill filters tools", async ({ page }) => { test("category pill filters tools", async ({ page }) => {
await page.getByText(/AI Tools/).click(); await page.getByText(/AI Tools/).click();
await expect(page.getByText(/Showing 15 of 48 tools/)).toBeVisible(); await expect(page.getByText(/Showing 15 of 50 tools/)).toBeVisible();
await expect(page.getByText("Remove Background")).toBeVisible(); await expect(page.getByText("Remove Background")).toBeVisible();
}); });
test("clicking All resets category filter", async ({ page }) => { test("clicking All resets category filter", async ({ page }) => {
await page.getByText(/AI Tools/).click(); await page.getByText(/AI Tools/).click();
await expect(page.getByText(/Showing 15 of 48 tools/)).toBeVisible(); await expect(page.getByText(/Showing 15 of 50 tools/)).toBeVisible();
await page.getByText(/All \(48\)/).click(); await page.getByText(/All \(50\)/).click();
await expect(page.getByText(/Showing 48 of 48 tools/)).toBeVisible(); await expect(page.getByText(/Showing 50 of 50 tools/)).toBeVisible();
}); });
test("search with no results shows empty state", async ({ page }) => { test("search with no results shows empty state", async ({ page }) => {
const input = page.getByPlaceholder("Search tools..."); const input = page.getByPlaceholder("Search tools...");
await input.fill("xyznonexistent"); await input.fill("xyznonexistent");
await expect(page.getByText("No tools found. Try a different search.")).toBeVisible(); await expect(page.getByText("No tools found. Try a different search.")).toBeVisible();
await expect(page.getByText(/Showing 0 of 48 tools/)).toBeVisible(); await expect(page.getByText(/Showing 0 of 50 tools/)).toBeVisible();
}); });
test("combined search and category filter works", async ({ page }) => { test("combined search and category filter works", async ({ page }) => {
+9 -9
View File
@@ -25,7 +25,7 @@ function getCountText(): string {
describe("BentoGrid", () => { describe("BentoGrid", () => {
it("renders the section heading", () => { it("renders the section heading", () => {
render(<BentoGrid />); render(<BentoGrid />);
expect(screen.getByText("48 tools. Zero cloud dependency.")).toBeDefined(); expect(screen.getByText("50 tools. Zero cloud dependency.")).toBeDefined();
}); });
it("renders the search input", () => { it("renders the search input", () => {
@@ -36,12 +36,12 @@ describe("BentoGrid", () => {
it("shows all tools by default", () => { it("shows all tools by default", () => {
render(<BentoGrid />); render(<BentoGrid />);
const text = getCountText(); const text = getCountText();
expect(text).toMatch(/Showing 48 of 48 tools/); expect(text).toMatch(/Showing 50 of 50 tools/);
}); });
it("renders category filter pills including All", () => { it("renders category filter pills including All", () => {
render(<BentoGrid />); render(<BentoGrid />);
expect(screen.getByText((_, el) => el?.textContent === "All (48)")).toBeDefined(); expect(screen.getByText((_, el) => el?.textContent === "All (50)")).toBeDefined();
expect(screen.getByText(/Essentials/)).toBeDefined(); expect(screen.getByText(/Essentials/)).toBeDefined();
expect(screen.getByText(/AI Tools/)).toBeDefined(); expect(screen.getByText(/AI Tools/)).toBeDefined();
expect(screen.getByText(/Optimization/)).toBeDefined(); expect(screen.getByText(/Optimization/)).toBeDefined();
@@ -53,7 +53,7 @@ describe("BentoGrid", () => {
fireEvent.change(input, { target: { value: "resize" } }); fireEvent.change(input, { target: { value: "resize" } });
expect(screen.getByText("Resize")).toBeDefined(); expect(screen.getByText("Resize")).toBeDefined();
const text = getCountText(); const text = getCountText();
expect(text).toMatch(/Showing \d+ of 48 tools/); expect(text).toMatch(/Showing \d+ of 50 tools/);
expect(screen.queryByText("OCR / Text Extraction")).toBeNull(); expect(screen.queryByText("OCR / Text Extraction")).toBeNull();
}); });
@@ -62,7 +62,7 @@ describe("BentoGrid", () => {
const aiButton = screen.getByText(/AI Tools/); const aiButton = screen.getByText(/AI Tools/);
fireEvent.click(aiButton); fireEvent.click(aiButton);
const text = getCountText(); const text = getCountText();
expect(text).toMatch(/Showing 15 of 48 tools/); expect(text).toMatch(/Showing 15 of 50 tools/);
expect(screen.getByText("Remove Background")).toBeDefined(); expect(screen.getByText("Remove Background")).toBeDefined();
expect(screen.queryByText("Resize")).toBeNull(); expect(screen.queryByText("Resize")).toBeNull();
}); });
@@ -73,7 +73,7 @@ describe("BentoGrid", () => {
fireEvent.change(input, { target: { value: "xyznonexistent" } }); fireEvent.change(input, { target: { value: "xyznonexistent" } });
expect(screen.getByText("No tools found. Try a different search.")).toBeDefined(); expect(screen.getByText("No tools found. Try a different search.")).toBeDefined();
const text = getCountText(); const text = getCountText();
expect(text).toMatch(/Showing 0 of 48 tools/); expect(text).toMatch(/Showing 0 of 50 tools/);
}); });
it("combines search and category filter", () => { it("combines search and category filter", () => {
@@ -89,9 +89,9 @@ describe("BentoGrid", () => {
it("clicking All resets category filter", () => { it("clicking All resets category filter", () => {
render(<BentoGrid />); render(<BentoGrid />);
fireEvent.click(screen.getByText(/AI Tools/)); fireEvent.click(screen.getByText(/AI Tools/));
expect(getCountText()).toMatch(/Showing 15 of 48 tools/); expect(getCountText()).toMatch(/Showing 15 of 50 tools/);
fireEvent.click(screen.getByText((_, el) => el?.textContent === "All (48)")); fireEvent.click(screen.getByText((_, el) => el?.textContent === "All (50)"));
expect(getCountText()).toMatch(/Showing 48 of 48 tools/); expect(getCountText()).toMatch(/Showing 50 of 50 tools/);
}); });
it("renders each tool with name and description", () => { it("renders each tool with name and description", () => {