File size: 6,234 Bytes
88b6846
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
'use client';

import React, { useState, useEffect, useRef } from 'react';
import { Type, Upload, Check, Star } from 'lucide-react';
import { toast } from 'sonner';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { getSuggestedFont } from '@/lib/language';

interface Font {
    name: string;
    family: string;
    css: string;
    url?: string;
}

interface FontSelectorProps {
    currentFont: string;
    onFontChange: (font: string) => void;
    detectedLang?: string;
}

export default function FontSelector({ currentFont, onFontChange, detectedLang }: FontSelectorProps) {
    const [fonts, setFonts] = useState<Font[]>([]);
    const [loading, setLoading] = useState(true);
    const [suggestedFont, setSuggestedFont] = useState<string | null>(null);
    const fileInputRef = useRef<HTMLInputElement>(null);

    const fetchFonts = async () => {
        try {
            const res = await fetch('/api/fonts');
            const data = await res.json();
            if (data.fonts) {
                setFonts(data.fonts);

                // Inject custom fonts styles
                data.fonts.forEach((font: Font) => {
                    if (font.url) {
                        const style = document.createElement('style');
                        style.textContent = `
              @font-face {
                font-family: '${font.family}';
                src: url('${font.url}') format('truetype');
              }
            `;
                        document.head.appendChild(style);
                    }
                });
            }
        } catch (error) {
            console.error('Failed to fetch fonts', error);
            toast.error('Failed to load fonts');
        } finally {
            setLoading(false);
        }
    };

    useEffect(() => {
        fetchFonts();
    }, []);

    useEffect(() => {
        if (detectedLang) {
            const suggested = getSuggestedFont(detectedLang);
            setSuggestedFont(suggested);
        }
    }, [detectedLang]);

    const handleFileUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
        const file = e.target.files?.[0];
        if (!file) return;

        const formData = new FormData();
        formData.append('font', file);

        const promise = fetch('/api/upload-font', {
            method: 'POST',
            body: formData,
        }).then(async (res) => {
            if (!res.ok) throw new Error('Upload failed');
            await fetchFonts();
            return 'Font uploaded successfully';
        });

        toast.promise(promise, {
            loading: 'Uploading font...',
            success: (data) => data,
            error: 'Failed to upload font',
        });
    };

    return (
        <Card>
            <CardHeader>
                <CardTitle className="text-lg flex items-center gap-2">
                    <Type className="w-4 h-4" />
                    Typography
                </CardTitle>
            </CardHeader>
            <CardContent className="space-y-4">
                <div className="space-y-2">
                    <label className="label">Display Font</label>
                    <div className="space-y-2 max-h-[200px] overflow-y-auto pr-2 custom-scrollbar">
                        {fonts.map((font) => (
                            <div
                                key={font.family}
                                className={`
                                    p-3 rounded-lg border cursor-pointer transition-all flex items-center justify-between group
                                    ${currentFont === font.family
                                        ? 'bg-primary/10 border-primary shadow-sm'
                                        : 'bg-background hover:bg-secondary/50 border-border/50 hover:border-border'
                                    }
                                `}
                                onClick={() => onFontChange(font.family)}
                            >
                                <div className="flex flex-col gap-1">
                                    <span className="text-sm font-medium" style={{ fontFamily: font.family }}>
                                        {font.name}
                                    </span>
                                    {suggestedFont === font.name && (
                                        <Badge variant="secondary" className="text-[10px] w-fit px-1.5 h-4 gap-1">
                                            <Star className="w-2 h-2 fill-current" /> Recommended
                                        </Badge>
                                    )}
                                </div>
                                {currentFont === font.family && (
                                    <Check className="w-4 h-4 text-primary" />
                                )}
                            </div>
                        ))}
                    </div>
                    <p className="text-xs text-muted-foreground mt-2">
                        Select a font optimized for the target language.
                    </p>
                </div>

                <div className="relative">
                    <div className="absolute inset-0 flex items-center">
                        <span className="w-full border-t border-border" />
                    </div>
                    <div className="relative flex justify-center text-xs uppercase">
                        <span className="bg-card px-2 text-muted-foreground">Custom Font</span>
                    </div>
                </div>

                <button
                    className="btn btn-secondary w-full"
                    onClick={() => fileInputRef.current?.click()}
                >
                    <Upload className="w-4 h-4 mr-2" />
                    Upload .ttf File
                </button>
                <input
                    type="file"
                    accept=".ttf"
                    ref={fileInputRef}
                    className="hidden"
                    onChange={handleFileUpload}
                />
            </CardContent>
        </Card>
    );
}