feat: initial fonts support
This commit is contained in:
@ -1,4 +1,3 @@
|
||||
import { Inter } from "next/font/google";
|
||||
import { ThemeProvider } from "next-themes";
|
||||
import { Analytics } from "@vercel/analytics/react";
|
||||
import Script from "next/script";
|
||||
@ -8,11 +7,7 @@ import { TooltipProvider } from "../components/ui/tooltip";
|
||||
import { DevelopmentDebug } from "../components/development-debug";
|
||||
import { StorageProvider } from "../components/storage-provider";
|
||||
import { baseMetaData } from "./metadata";
|
||||
|
||||
const inter = Inter({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-inter",
|
||||
});
|
||||
import { defaultFont } from "../lib/font-config";
|
||||
|
||||
export const metadata = baseMetaData;
|
||||
|
||||
@ -23,7 +18,7 @@ export default function RootLayout({
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<body className={`${inter.variable} font-sans antialiased`}>
|
||||
<body className={`${defaultFont.className} font-sans antialiased`}>
|
||||
<ThemeProvider attribute="class" forcedTheme="dark" enableSystem>
|
||||
<TooltipProvider>
|
||||
<StorageProvider>{children}</StorageProvider>
|
||||
|
@ -20,6 +20,7 @@ import { Play, Pause } from "lucide-react";
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { formatTimeCode } from "@/lib/time";
|
||||
import { FONT_CLASS_MAP } from "@/lib/font-config";
|
||||
|
||||
interface ActiveElement {
|
||||
element: TimelineElement;
|
||||
@ -141,6 +142,9 @@ export function PreviewPanel() {
|
||||
|
||||
// Text elements
|
||||
if (element.type === "text") {
|
||||
const fontClassName =
|
||||
FONT_CLASS_MAP[element.fontFamily as keyof typeof FONT_CLASS_MAP] || "";
|
||||
|
||||
return (
|
||||
<div
|
||||
key={element.id}
|
||||
@ -154,9 +158,9 @@ export function PreviewPanel() {
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={fontClassName}
|
||||
style={{
|
||||
fontSize: `${element.fontSize}px`,
|
||||
fontFamily: element.fontFamily,
|
||||
color: element.color,
|
||||
backgroundColor: element.backgroundColor,
|
||||
textAlign: element.textAlign,
|
||||
@ -166,6 +170,8 @@ export function PreviewPanel() {
|
||||
padding: "4px 8px",
|
||||
borderRadius: "2px",
|
||||
whiteSpace: "pre-wrap",
|
||||
// Fallback for system fonts that don't have classes
|
||||
...(fontClassName === "" && { fontFamily: element.fontFamily }),
|
||||
}}
|
||||
>
|
||||
{element.content}
|
||||
|
@ -15,6 +15,7 @@ import {
|
||||
SelectValue,
|
||||
SelectItem,
|
||||
} from "../ui/select";
|
||||
import { FONT_OPTIONS, type FontFamily } from "@/constants/font-constants";
|
||||
|
||||
export function PropertiesPanel() {
|
||||
const { activeProject } = useProjectStore();
|
||||
@ -49,14 +50,21 @@ export function PropertiesPanel() {
|
||||
/>
|
||||
<div className="flex items-center justify-between gap-6">
|
||||
<Label className="text-xs">Font</Label>
|
||||
<Select>
|
||||
<Select
|
||||
defaultValue={element.fontFamily}
|
||||
onValueChange={(value: FontFamily) =>
|
||||
updateTextElement(trackId, element.id, { fontFamily: value })
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="w-full text-xs">
|
||||
<SelectValue placeholder="Select a font" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="Arial">Arial</SelectItem>
|
||||
<SelectItem value="Helvetica">Helvetica</SelectItem>
|
||||
<SelectItem value="Times New Roman">Times New Roman</SelectItem>
|
||||
{FONT_OPTIONS.map((font) => (
|
||||
<SelectItem key={font.value} value={font.value}>
|
||||
{font.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
@ -24,7 +24,7 @@ import { useTimelineElementResize } from "@/hooks/use-timeline-element-resize";
|
||||
import {
|
||||
getTrackElementClasses,
|
||||
TIMELINE_CONSTANTS,
|
||||
} from "@/lib/timeline-constants";
|
||||
} from "@/constants/timeline-constants";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
|
@ -17,7 +17,7 @@ import type {
|
||||
TimelineElement as TimelineElementType,
|
||||
DragData,
|
||||
} from "@/types/timeline";
|
||||
import { TIMELINE_CONSTANTS } from "@/lib/timeline-constants";
|
||||
import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants";
|
||||
|
||||
export function TimelineTrackContent({
|
||||
track,
|
||||
|
@ -50,7 +50,7 @@ import {
|
||||
getCumulativeHeightBefore,
|
||||
getTotalTracksHeight,
|
||||
TIMELINE_CONSTANTS,
|
||||
} from "@/lib/timeline-constants";
|
||||
} from "@/constants/timeline-constants";
|
||||
|
||||
export function Timeline() {
|
||||
// Timeline shows all tracks (video, audio, effects) and their elements.
|
||||
|
79
apps/web/src/constants/font-constants.ts
Normal file
79
apps/web/src/constants/font-constants.ts
Normal file
@ -0,0 +1,79 @@
|
||||
export interface FontOption {
|
||||
value: string;
|
||||
label: string;
|
||||
category: "system" | "google" | "custom";
|
||||
weights?: number[];
|
||||
hasClassName?: boolean;
|
||||
}
|
||||
|
||||
export const FONT_OPTIONS: FontOption[] = [
|
||||
// System fonts (always available)
|
||||
{ value: "Arial", label: "Arial", category: "system", hasClassName: false },
|
||||
{
|
||||
value: "Helvetica",
|
||||
label: "Helvetica",
|
||||
category: "system",
|
||||
hasClassName: false,
|
||||
},
|
||||
{
|
||||
value: "Times New Roman",
|
||||
label: "Times New Roman",
|
||||
category: "system",
|
||||
hasClassName: false,
|
||||
},
|
||||
{
|
||||
value: "Georgia",
|
||||
label: "Georgia",
|
||||
category: "system",
|
||||
hasClassName: false,
|
||||
},
|
||||
|
||||
// Google Fonts (loaded in layout.tsx)
|
||||
{
|
||||
value: "Inter",
|
||||
label: "Inter",
|
||||
category: "google",
|
||||
weights: [400, 700],
|
||||
hasClassName: true,
|
||||
},
|
||||
{
|
||||
value: "Roboto",
|
||||
label: "Roboto",
|
||||
category: "google",
|
||||
weights: [400, 700],
|
||||
hasClassName: true,
|
||||
},
|
||||
{
|
||||
value: "Open Sans",
|
||||
label: "Open Sans",
|
||||
category: "google",
|
||||
hasClassName: true,
|
||||
},
|
||||
{
|
||||
value: "Playfair Display",
|
||||
label: "Playfair Display",
|
||||
category: "google",
|
||||
hasClassName: true,
|
||||
},
|
||||
{
|
||||
value: "Comic Neue",
|
||||
label: "Comic Neue",
|
||||
category: "google",
|
||||
hasClassName: false,
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const DEFAULT_FONT = "Arial";
|
||||
|
||||
// Type-safe font family union
|
||||
export type FontFamily = (typeof FONT_OPTIONS)[number]["value"];
|
||||
|
||||
// Helper functions
|
||||
export const getFontByValue = (value: string): FontOption | undefined =>
|
||||
FONT_OPTIONS.find((font) => font.value === value);
|
||||
|
||||
export const getGoogleFonts = (): FontOption[] =>
|
||||
FONT_OPTIONS.filter((font) => font.category === "google");
|
||||
|
||||
export const getSystemFonts = (): FontOption[] =>
|
||||
FONT_OPTIONS.filter((font) => font.category === "system");
|
39
apps/web/src/lib/font-config.ts
Normal file
39
apps/web/src/lib/font-config.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import {
|
||||
Inter,
|
||||
Roboto,
|
||||
Open_Sans,
|
||||
Playfair_Display,
|
||||
Comic_Neue,
|
||||
} from "next/font/google";
|
||||
|
||||
// Configure all fonts
|
||||
const inter = Inter({ subsets: ["latin"] });
|
||||
const roboto = Roboto({ subsets: ["latin"], weight: ["400", "700"] });
|
||||
const openSans = Open_Sans({ subsets: ["latin"] });
|
||||
const playfairDisplay = Playfair_Display({ subsets: ["latin"] });
|
||||
const comicNeue = Comic_Neue({ subsets: ["latin"], weight: ["400", "700"] });
|
||||
|
||||
// Export font class mapping for use in components
|
||||
export const FONT_CLASS_MAP = {
|
||||
Inter: inter.className,
|
||||
Roboto: roboto.className,
|
||||
"Open Sans": openSans.className,
|
||||
"Playfair Display": playfairDisplay.className,
|
||||
"Comic Neue": comicNeue.className,
|
||||
Arial: "",
|
||||
Helvetica: "",
|
||||
"Times New Roman": "",
|
||||
Georgia: "",
|
||||
} as const;
|
||||
|
||||
// Export individual fonts for use in layout
|
||||
export const fonts = {
|
||||
inter,
|
||||
roboto,
|
||||
openSans,
|
||||
playfairDisplay,
|
||||
comicNeue,
|
||||
};
|
||||
|
||||
// Default font for the body
|
||||
export const defaultFont = inter;
|
Reference in New Issue
Block a user