Switch display font from Atma to Bangers and update related imports and

This commit is contained in:
Riccardo Giorato
2025-12-28 13:13:52 +01:00
parent 0b65e78ea3
commit 6b19743950
6 changed files with 91 additions and 72 deletions
+2 -2
View File
@@ -48,7 +48,7 @@
@theme inline { @theme inline {
/* Adding tight tracking to Inter font for consistency */ /* Adding tight tracking to Inter font for consistency */
--font-sans: "Inter", sans-serif; --font-sans: "Inter", sans-serif;
--font-display: "Atma", cursive; --font-display: "Bangers", cursive;
--font-heading: "Instrument Serif", serif; --font-heading: "Instrument Serif", serif;
--color-background: var(--background); --color-background: var(--background);
--color-foreground: var(--foreground); --color-foreground: var(--foreground);
@@ -149,7 +149,7 @@
} }
.font-display { .font-display {
font-family: "Atma", cursive; font-family: "Bangers", cursive;
} }
/* Smooth fade-in animation */ /* Smooth fade-in animation */
+5 -5
View File
@@ -1,16 +1,16 @@
import type React from "react"; import type React from "react";
import type { Metadata } from "next"; import type { Metadata } from "next";
import { Inter, Atma, Space_Grotesk, Instrument_Serif } from "next/font/google"; import { Inter, Bangers, Space_Grotesk, Instrument_Serif } from "next/font/google";
import { Analytics } from "@vercel/analytics/next"; import { Analytics } from "@vercel/analytics/next";
import { Toaster } from "@/components/ui/toaster"; import { Toaster } from "@/components/ui/toaster";
import { ClerkProvider } from "@clerk/nextjs"; import { ClerkProvider } from "@clerk/nextjs";
import "./globals.css"; import "./globals.css";
const inter = Inter({ subsets: ["latin"], variable: "--font-inter" }); const inter = Inter({ subsets: ["latin"], variable: "--font-inter" });
const atma = Atma({ const bangers = Bangers({
weight: ["400", "500", "600", "700"], weight: "400",
subsets: ["latin"], subsets: ["latin"],
variable: "--font-atma", variable: "--font-bangers",
}); });
const spaceGrotesk = Space_Grotesk({ const spaceGrotesk = Space_Grotesk({
subsets: ["latin"], subsets: ["latin"],
@@ -37,7 +37,7 @@ export default function RootLayout({
<ClerkProvider> <ClerkProvider>
<html <html
lang="en" lang="en"
className={`${inter.variable} ${atma.variable} ${spaceGrotesk.variable} ${instrumentSerif.variable}`} className={`${inter.variable} ${bangers.variable} ${spaceGrotesk.variable} ${instrumentSerif.variable}`}
> >
<body className="font-sans antialiased"> <body className="font-sans antialiased">
{children} {children}
+3 -1
View File
@@ -83,7 +83,9 @@ export function ApiKeyModal({ isOpen, onClose, onSubmit }: ApiKeyModalProps) {
type="password" type="password"
value={apiKeyInput} value={apiKeyInput}
onChange={(e) => setApiKeyInput(e.target.value)} onChange={(e) => setApiKeyInput(e.target.value)}
placeholder={existingKey ? "Your current API key" : "Enter your API key..."} placeholder={
existingKey ? "Your current API key" : "Enter your API key..."
}
className="bg-secondary border-border/50 text-white placeholder-muted-foreground py-5 pr-10" className="bg-secondary border-border/50 text-white placeholder-muted-foreground py-5 pr-10"
/> />
{apiKeyInput && ( {apiKeyInput && (
+77 -60
View File
@@ -1,6 +1,13 @@
"use client"; "use client";
import { ArrowLeft, RefreshCw, Share, Plus, Info, Download } from "lucide-react"; import {
ArrowLeft,
RefreshCw,
Share,
Plus,
Info,
Download,
} from "lucide-react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useToast } from "@/hooks/use-toast"; import { useToast } from "@/hooks/use-toast";
@@ -50,16 +57,19 @@ export function EditorToolbar({
const newTitle = editingTitle.trim(); const newTitle = editingTitle.trim();
if (newTitle && newTitle !== title) { if (newTitle && newTitle !== title) {
try { try {
const response = await fetch(`/api/stories/${window.location.pathname.split('/').pop()}`, { const response = await fetch(
method: 'PUT', `/api/stories/${window.location.pathname.split("/").pop()}`,
headers: { {
'Content-Type': 'application/json', method: "PUT",
}, headers: {
body: JSON.stringify({ title: newTitle }), "Content-Type": "application/json",
}); },
body: JSON.stringify({ title: newTitle }),
}
);
if (!response.ok) { if (!response.ok) {
throw new Error('Failed to update title'); throw new Error("Failed to update title");
} }
onTitleUpdate?.(newTitle); onTitleUpdate?.(newTitle);
@@ -69,7 +79,7 @@ export function EditorToolbar({
duration: 2000, duration: 2000,
}); });
} catch (error) { } catch (error) {
console.error('Error updating title:', error); console.error("Error updating title:", error);
toast({ toast({
title: "Failed to update title", title: "Failed to update title",
description: "Could not update the story title.", description: "Could not update the story title.",
@@ -88,9 +98,9 @@ export function EditorToolbar({
}; };
const handleKeyDown = (e: React.KeyboardEvent) => { const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Enter') { if (e.key === "Enter") {
handleTitleSave(); handleTitleSave();
} else if (e.key === 'Escape') { } else if (e.key === "Escape") {
handleTitleCancel(); handleTitleCancel();
} }
}; };
@@ -120,7 +130,11 @@ export function EditorToolbar({
/> />
) : ( ) : (
<h1 <h1
className={`text-sm sm:text-base text-white font-normal tracking-[-0.02em] truncate ${isOwner && onTitleUpdate ? 'cursor-pointer hover:text-gray-300' : ''}`} className={`text-sm sm:text-base text-white font-display font-normal tracking-[-0.02em] truncate ${
isOwner && onTitleUpdate
? "cursor-pointer hover:text-gray-300"
: ""
}`}
onClick={handleTitleClick} onClick={handleTitleClick}
> >
{title} {title}
@@ -129,55 +143,58 @@ export function EditorToolbar({
</div> </div>
<div className="flex items-center gap-1 sm:gap-2 shrink-0"> <div className="flex items-center gap-1 sm:gap-2 shrink-0">
<Button <Button
variant="ghost" variant="ghost"
className="hover:bg-secondary text-muted-foreground hover:text-white gap-1.5 sm:gap-2 text-xs h-8 sm:h-9 px-2 sm:px-3 hidden md:flex" className="hover:bg-secondary text-muted-foreground hover:text-white gap-1.5 sm:gap-2 text-xs h-8 sm:h-9 px-2 sm:px-3 hidden md:flex"
onClick={async () => { onClick={async () => {
const url = window.location.href; const url = window.location.href;
try { try {
await navigator.clipboard.writeText(url); await navigator.clipboard.writeText(url);
toast({ toast({
title: "Link copied!", title: "Link copied!",
description: "Story URL has been copied to your clipboard.", description: "Story URL has been copied to your clipboard.",
duration: 2000, duration: 2000,
}); });
} catch (err) { } catch (err) {
console.error("Failed to copy URL:", err); console.error("Failed to copy URL:", err);
toast({ toast({
title: "Failed to copy", title: "Failed to copy",
description: "Could not copy the URL to clipboard.", description: "Could not copy the URL to clipboard.",
variant: "destructive", variant: "destructive",
duration: 3000, duration: 3000,
}); });
} }
}} }}
> >
<Share className="w-3.5 h-3.5 sm:w-4 sm:h-4" /> <Share className="w-3.5 h-3.5 sm:w-4 sm:h-4" />
<span>Share</span> <span>Share</span>
</Button> </Button>
{onDownloadPDF && ( {onDownloadPDF && (
<Button <Button
variant="ghost" variant="ghost"
className="hover:bg-secondary text-muted-foreground hover:text-white gap-1.5 sm:gap-2 text-xs h-8 sm:h-9 px-2 sm:px-3" className="hover:bg-secondary text-muted-foreground hover:text-white gap-1.5 sm:gap-2 text-xs h-8 sm:h-9 px-2 sm:px-3"
onClick={onDownloadPDF} onClick={onDownloadPDF}
disabled={isGeneratingPDF} disabled={isGeneratingPDF}
> >
<Download className="w-3.5 h-3.5 sm:w-4 sm:h-4" /> <Download className="w-3.5 h-3.5 sm:w-4 sm:h-4" />
<span>{isGeneratingPDF ? 'Generating...' : 'Download PDF'}</span> <span>{isGeneratingPDF ? "Generating..." : "Download PDF"}</span>
</Button> </Button>
)} )}
{isOwner && onContinueStory && ( {isOwner && onContinueStory && (
<Button <Button
onClick={onContinueStory} onClick={onContinueStory}
className="relative gap-1.5 sm:gap-2 text-xs bg-white hover:bg-neutral-200 text-black h-8 sm:h-9 px-3 sm:px-4" className="relative gap-1.5 sm:gap-2 text-xs bg-white hover:bg-neutral-200 text-black h-8 sm:h-9 px-3 sm:px-4"
> >
<Plus className="w-3.5 h-3.5 sm:w-4 sm:h-4" /> <Plus className="w-3.5 h-3.5 sm:w-4 sm:h-4" />
<span className="hidden sm:inline">Continue story <span className="text-gray-500 text-[10px]">(C)</span></span> <span className="hidden sm:inline">
<span className="sm:hidden">Add</span> Continue story{" "}
</Button> <span className="text-gray-500 text-[10px]">(C)</span>
)} </span>
<span className="sm:hidden">Add</span>
</Button>
)}
</div> </div>
</header> </header>
); );
+1 -1
View File
@@ -156,7 +156,7 @@ export function ComicPreview({
</div> </div>
</div> </div>
<div className="hidden lg:flex absolute -right-20 top-1/2 -translate-y-1/2 flex flex-col gap-3"> <div className="hidden lg:flex absolute -right-20 top-1/2 -translate-y-1/2 lg:flex-col gap-3">
<button <button
onClick={() => goToPage(1)} onClick={() => goToPage(1)}
className={`w-8 h-8 rounded-full glass-panel flex items-center justify-center shadow-lg cursor-pointer transition-all duration-200 ${ className={`w-8 h-8 rounded-full glass-panel flex items-center justify-center shadow-lg cursor-pointer transition-all duration-200 ${
+3 -3
View File
@@ -27,10 +27,10 @@ export function StoryLoader({ text = "Loading story..." }: StoryLoaderProps) {
src={`/loader/${loaderSvgs[currentSvgIndex]}`} src={`/loader/${loaderSvgs[currentSvgIndex]}`}
alt="Loading..." alt="Loading..."
className="w-full h-full object-contain animate-pulse transition-all duration-700 ease-in-out transform" className="w-full h-full object-contain animate-pulse transition-all duration-700 ease-in-out transform"
style={{ filter: 'invert(1)' }} style={{ filter: "invert(1)" }}
/> />
</div> </div>
<div className="text-white text-lg">{text}</div> <div className="text-white text-2xl font-display">{text}</div>
</div> </div>
); );
} }