mirror of
https://github.com/backnotprop/plannotator.git
synced 2026-09-14 14:17:26 +08:00
feat: add favicon (Purple P + gold highlight) (#312)
* feat: add favicon (option 2 — purple P with gold highlight) Adds the "Purple P + Highlight" favicon across all three Plannotator servers (plan, review, annotate). The icon is a rounded purple square with a bold white "P" and a semi-transparent gold stripe through the middle — typographic, on-brand, and legible at 16px. Implementation: - shared-handlers.ts: handleFavicon() serves the inline SVG with a 1-day cache header, shared by all servers - index.ts, review.ts, annotate.ts: /favicon.svg route added before the SPA catch-all - apps/hook/index.html, apps/review/index.html: <link rel="icon"> added pointing to /favicon.svg SVG favicons are the modern standard and render crisply at all sizes without a separate .ico file. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: add favicon to marketing site Use the same purple P + gold highlight SVG favicon on plannotator.ai. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Michael Ramos <mdramos8@gmail.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Plannotator</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<rect width="64" height="64" rx="14" fill="#6B3FA0"/>
|
||||
<rect x="12" y="28" width="40" height="14" rx="3" fill="#E0BA55" opacity="0.35"/>
|
||||
<text x="32" y="46" text-anchor="middle" font-family="Inter,system-ui,sans-serif" font-weight="800" font-size="42" fill="white">P</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 347 B |
@@ -23,6 +23,7 @@ import '../styles/global.css';
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{title}</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||
<meta name="description" content={description} />
|
||||
|
||||
<meta property="og:type" content="website" />
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Code Review</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
import { isRemoteSession, getServerPort } from "./remote";
|
||||
import { getRepoInfo } from "./repo";
|
||||
import { handleImage, handleUpload, handleServerReady, handleDraftSave, handleDraftLoad, handleDraftDelete } from "./shared-handlers";
|
||||
import { handleImage, handleUpload, handleServerReady, handleDraftSave, handleDraftLoad, handleDraftDelete, handleFavicon } from "./shared-handlers";
|
||||
import { handleDoc } from "./reference-handlers";
|
||||
import { contentHash, deleteDraft } from "./draft";
|
||||
import { dirname } from "path";
|
||||
@@ -179,6 +179,9 @@ export async function startAnnotateServer(
|
||||
}
|
||||
}
|
||||
|
||||
// Favicon
|
||||
if (url.pathname === "/favicon.svg") return handleFavicon();
|
||||
|
||||
// Serve embedded HTML for all other routes (SPA)
|
||||
return new Response(htmlContent, {
|
||||
headers: { "Content-Type": "text/html" },
|
||||
|
||||
@@ -35,7 +35,7 @@ import {
|
||||
} from "./storage";
|
||||
import { getRepoInfo } from "./repo";
|
||||
import { detectProjectName } from "./project";
|
||||
import { handleImage, handleUpload, handleAgents, handleServerReady, handleDraftSave, handleDraftLoad, handleDraftDelete, type OpencodeClient } from "./shared-handlers";
|
||||
import { handleImage, handleUpload, handleAgents, handleServerReady, handleDraftSave, handleDraftLoad, handleDraftDelete, handleFavicon, type OpencodeClient } from "./shared-handlers";
|
||||
import { contentHash, deleteDraft } from "./draft";
|
||||
import { handleDoc, handleObsidianVaults, handleObsidianFiles, handleObsidianDoc } from "./reference-handlers";
|
||||
import { createEditorAnnotationHandler } from "./editor-annotations";
|
||||
@@ -431,6 +431,9 @@ export async function startPlannotatorServer(
|
||||
return Response.json({ ok: true, savedPath });
|
||||
}
|
||||
|
||||
// Favicon
|
||||
if (url.pathname === "/favicon.svg") return handleFavicon();
|
||||
|
||||
// Serve embedded HTML for all other routes (SPA)
|
||||
return new Response(htmlContent, {
|
||||
headers: { "Content-Type": "text/html" },
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import { isRemoteSession, getServerPort } from "./remote";
|
||||
import { type DiffType, type GitContext, runGitDiff, getFileContentsForDiff, gitAddFile, gitResetFile, parseWorktreeDiffType, validateFilePath } from "./git";
|
||||
import { getRepoInfo } from "./repo";
|
||||
import { handleImage, handleUpload, handleAgents, handleServerReady, handleDraftSave, handleDraftLoad, handleDraftDelete, type OpencodeClient } from "./shared-handlers";
|
||||
import { handleImage, handleUpload, handleAgents, handleServerReady, handleDraftSave, handleDraftLoad, handleDraftDelete, handleFavicon, type OpencodeClient } from "./shared-handlers";
|
||||
import { contentHash, deleteDraft } from "./draft";
|
||||
import { createEditorAnnotationHandler } from "./editor-annotations";
|
||||
|
||||
@@ -284,6 +284,9 @@ export async function startReviewServer(
|
||||
}
|
||||
}
|
||||
|
||||
// Favicon
|
||||
if (url.pathname === "/favicon.svg") return handleFavicon();
|
||||
|
||||
// Serve embedded HTML for all other routes (SPA)
|
||||
return new Response(htmlContent, {
|
||||
headers: { "Content-Type": "text/html" },
|
||||
|
||||
@@ -125,6 +125,19 @@ export function handleDraftDelete(contentKey: string): Response {
|
||||
return Response.json({ ok: true });
|
||||
}
|
||||
|
||||
const FAVICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<rect width="64" height="64" rx="14" fill="#6B3FA0"/>
|
||||
<rect x="12" y="28" width="40" height="14" rx="3" fill="#E0BA55" opacity="0.35"/>
|
||||
<text x="32" y="46" text-anchor="middle" font-family="Inter,system-ui,sans-serif" font-weight="800" font-size="42" fill="white">P</text>
|
||||
</svg>`;
|
||||
|
||||
/** Serve the app favicon. Used by all 3 servers. */
|
||||
export function handleFavicon(): Response {
|
||||
return new Response(FAVICON_SVG, {
|
||||
headers: { "Content-Type": "image/svg+xml", "Cache-Control": "public, max-age=86400" },
|
||||
});
|
||||
}
|
||||
|
||||
/** Open browser for local sessions or when a custom handler (e.g. VS Code extension) is configured. */
|
||||
export async function handleServerReady(
|
||||
url: string,
|
||||
|
||||
Reference in New Issue
Block a user