Skip to content

Commit 1f1e0e1

Browse files
Added logo PNG fallback
X-Lovable-Edit-ID: edt-ed88ae64-c0eb-40e1-9cd6-1f833b6007c2 Co-authored-by: ghostcodedynamics <295822717+ghostcodedynamics@users.noreply.github.com>
2 parents 0930bdd + 8e5a4ad commit 1f1e0e1

6 files changed

Lines changed: 45 additions & 72 deletions

File tree

public/favicon.png

716 KB
Loading

src/assets/brand/logo.png

716 KB
Loading

src/components/brand/logo.tsx

Lines changed: 40 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,54 @@
11
/**
22
* GhostCode Dynamics — Brand Logo System
33
* ---------------------------------------------------------------
4-
* This file is the single source of truth for the brand mark across
5-
* the navbar, footer, mobile menu, favicon, OG images, etc.
4+
* Single source of truth for the brand mark.
65
*
7-
* REPLACING THE PLACEHOLDER WITH THE FINAL PNG (≤ 2 min):
8-
* 1. Drop the final files into `src/assets/brand/`:
9-
* - logo-mark.png (square icon, ≥ 512×512)
10-
* - logo-mark-light.png (optional, for light backgrounds)
11-
* - logo-full.png (optional full lockup; if absent we
12-
* keep the SVG monogram + typeset wordmark)
13-
* 2. Flip `USE_PNG_MARK = true` below.
14-
* 3. (Optional) Replace `public/favicon.svg` with the new icon.
15-
*
16-
* Nothing else in the codebase needs to change — every surface
17-
* imports <Logo />, <LogoCompact />, or <LogoMark /> from this file.
6+
* REPLACING THE PLACEHOLDER:
7+
* Drop the final file at `src/assets/brand/logo.png` (same path).
8+
* No code change needed — every surface reads from this file.
9+
* If the PNG is ever missing, the inline SVG fallback renders
10+
* automatically so layout never breaks.
1811
* ---------------------------------------------------------------
1912
*/
2013

14+
import { useState } from "react";
2115
import { cn } from "@/lib/utils";
22-
23-
// Toggle this to `true` once the founder ships the final PNG assets.
24-
const USE_PNG_MARK = false;
25-
26-
// When USE_PNG_MARK is true these are imported lazily by <LogoMark />.
27-
// Keeping them as string paths means the build never fails if the
28-
// PNGs are not yet present in the repo.
29-
const PNG_MARK_DARK = "/brand/logo-mark.png";
30-
const PNG_MARK_LIGHT = "/brand/logo-mark-light.png";
16+
import logoPng from "@/assets/brand/logo.png";
3117

3218
// ---------------------------------------------------------------
33-
// Variant: <LogoMark /> — icon only (favicon, app icon, avatar)
19+
// <LogoMark /> — icon only, height-driven, aspect-preserving
3420
// ---------------------------------------------------------------
3521

3622
interface LogoMarkProps {
37-
size?: number;
23+
/** Rendered height in px. Width auto-scales to preserve aspect ratio. */
24+
height?: number;
3825
className?: string;
39-
/** Force a specific contrast mode. Defaults to currentColor (auto). */
4026
tone?: "auto" | "dark" | "light";
4127
}
4228

43-
/**
44-
* Ghost-in-monogram mark. Pure SVG so it is sharp on every density,
45-
* inherits theme color via `currentColor`, and ships zero bytes of
46-
* raster data until the real PNG is wired in.
47-
*/
48-
export function LogoMark({ size = 32, className, tone = "auto" }: LogoMarkProps) {
49-
if (USE_PNG_MARK) {
50-
const src = tone === "light" ? PNG_MARK_LIGHT : PNG_MARK_DARK;
29+
export function LogoMark({ height = 36, className, tone = "auto" }: LogoMarkProps) {
30+
const [failed, setFailed] = useState(false);
31+
32+
if (!failed && logoPng) {
5133
return (
5234
<img
53-
src={src}
54-
width={size}
55-
height={size}
35+
src={logoPng}
5636
alt="GhostCode Dynamics"
57-
className={cn("shrink-0 select-none", className)}
37+
onError={() => setFailed(true)}
38+
style={{ height, width: "auto" }}
39+
className={cn("shrink-0 select-none object-contain", className)}
5840
draggable={false}
5941
/>
6042
);
6143
}
6244

45+
// ---- SVG fallback (only renders if PNG fails to load) ----
6346
const fg =
64-
tone === "dark"
65-
? "#0a0a0f"
66-
: tone === "light"
67-
? "#ffffff"
68-
: "currentColor";
69-
47+
tone === "dark" ? "#0a0a0f" : tone === "light" ? "#ffffff" : "currentColor";
7048
return (
7149
<svg
72-
width={size}
73-
height={size}
50+
height={height}
51+
width={height}
7452
viewBox="0 0 64 64"
7553
fill="none"
7654
xmlns="http://www.w3.org/2000/svg"
@@ -79,42 +57,30 @@ export function LogoMark({ size = 32, className, tone = "auto" }: LogoMarkProps)
7957
aria-label="GhostCode Dynamics"
8058
shapeRendering="geometricPrecision"
8159
>
82-
{/* Rounded squircle backdrop — the monogram "G" */}
8360
<rect x="1" y="1" width="62" height="62" rx="16" fill={fg} />
84-
85-
{/* Ghost silhouette cut out of the squircle */}
8661
<path
8762
d="M32 16c-7 0-12 5-12 12v18.2c0 1.4 1.6 2.2 2.7 1.3l2.2-1.7c.6-.5 1.5-.5 2.1 0l2.2 1.7c.6.5 1.5.5 2.1 0l2.2-1.7c.6-.5 1.5-.5 2.1 0l2.2 1.7c1.1.9 2.7.1 2.7-1.3V28c0-7-5-12-12-12Z"
8863
fill="var(--background)"
8964
/>
90-
91-
{/* Eyes — restate foreground for a crisp 3-tone read */}
9265
<circle cx="28.4" cy="29.5" r="1.9" fill={fg} />
9366
<circle cx="35.6" cy="29.5" r="1.9" fill={fg} />
94-
95-
{/* Subtle "C / D" tick: opening on the right side of the G */}
96-
<path
97-
d="M46 30v6"
98-
stroke="var(--background)"
99-
strokeWidth="3"
100-
strokeLinecap="round"
101-
/>
10267
</svg>
10368
);
10469
}
10570

10671
// ---------------------------------------------------------------
107-
// Variant: <Logo /> — full lockup (icon + "GhostCode Dynamics")
72+
// <Logo /> — full lockup (mark + wordmark)
10873
// ---------------------------------------------------------------
10974

11075
interface LogoProps {
11176
className?: string;
112-
size?: number;
113-
/** Hide the wordmark, keep only the mark. */
77+
/** Mark height in px. Defaults sized for navbar use. */
78+
height?: number;
11479
iconOnly?: boolean;
11580
}
11681

117-
export function Logo({ className, size = 32, iconOnly = false }: LogoProps) {
82+
export function Logo({ className, height, iconOnly = false }: LogoProps) {
83+
// Responsive default: 36px mobile → 42px desktop. Caller can override.
11884
return (
11985
<span
12086
className={cn(
@@ -123,17 +89,24 @@ export function Logo({ className, size = 32, iconOnly = false }: LogoProps) {
12389
)}
12490
aria-label="GhostCode Dynamics"
12591
>
126-
<LogoMark size={size} />
92+
{height ? (
93+
<LogoMark height={height} />
94+
) : (
95+
<>
96+
<LogoMark height={36} className="sm:hidden" />
97+
<LogoMark height={42} className="hidden sm:block" />
98+
</>
99+
)}
127100
{!iconOnly && <Wordmark />}
128101
</span>
129102
);
130103
}
131104

132105
// ---------------------------------------------------------------
133-
// Variant: <LogoCompact /> — icon + "GCD" (tight navs, mobile)
106+
// <LogoCompact /> — icon + "GCD"
134107
// ---------------------------------------------------------------
135108

136-
export function LogoCompact({ className, size = 28 }: LogoProps) {
109+
export function LogoCompact({ className, height = 32 }: LogoProps) {
137110
return (
138111
<span
139112
className={cn(
@@ -142,7 +115,7 @@ export function LogoCompact({ className, size = 28 }: LogoProps) {
142115
)}
143116
aria-label="GhostCode Dynamics"
144117
>
145-
<LogoMark size={size} />
118+
<LogoMark height={height} />
146119
<span className="font-display text-base font-semibold tracking-[0.18em] text-foreground">
147120
GCD
148121
</span>
@@ -151,7 +124,7 @@ export function LogoCompact({ className, size = 28 }: LogoProps) {
151124
}
152125

153126
// ---------------------------------------------------------------
154-
// Wordmark — geometric, Linear / Vercel / Stripe inspired
127+
// Wordmark
155128
// ---------------------------------------------------------------
156129

157130
function Wordmark() {
@@ -167,5 +140,4 @@ function Wordmark() {
167140
);
168141
}
169142

170-
// Re-export the icon under its previous name to keep older imports working.
171143
export { LogoMark as GhostIcon };

src/components/site-footer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export function SiteFooter() {
88
<div className="container-prose py-16">
99
<div className="grid gap-12 md:grid-cols-12">
1010
<div className="md:col-span-5">
11-
<Logo />
11+
<Logo height={38} />
1212
<p className="mt-4 max-w-sm text-sm leading-relaxed text-muted-foreground">
1313
Building digital solutions for businesses while empowering the next generation of tech professionals.
1414
</p>

src/routes/__root.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ export const Route = createRootRouteWithContext<{ queryClient: QueryClient }>()(
113113
],
114114
links: [
115115
{ rel: "stylesheet", href: appCss },
116+
{ rel: "icon", href: "/favicon.png", type: "image/png" },
116117
{ rel: "icon", href: "/favicon.svg", type: "image/svg+xml" },
117118
],
118119
}),

src/routes/founder.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@ function FounderPage() {
5353
<section className="container-prose pb-16 md:pb-24">
5454
<div className="grid gap-12 lg:grid-cols-12 items-start">
5555
<Reveal className="lg:col-span-5 lg:sticky lg:top-28">
56-
<div className="relative aspect-[4/5] w-full max-w-md mx-auto overflow-hidden rounded-3xl glass-strong ring-glow">
56+
<div className="relative mx-auto aspect-[4/5] w-full max-w-[220px] overflow-hidden rounded-3xl shadow-[0_20px_60px_-15px_rgba(0,0,0,0.35)] ring-1 ring-border/60 sm:max-w-[260px] lg:max-w-[300px]">
5757
<img
5858
src={founderImg}
5959
alt="Jeet Ahirwar — Founder of GhostCode Dynamics"
6060
className="h-full w-full object-cover"
61-
width={896}
62-
height={1120}
61+
width={600}
62+
height={750}
6363
loading="eager"
6464
/>
6565
</div>

0 commit comments

Comments
 (0)