mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-23 13:11:27 +10:00
feat(i18n): implement localization using LinguiJS
This commit is contained in:
@ -1,3 +1,4 @@
|
||||
import { t } from "@lingui/macro";
|
||||
import { ScrollArea, Separator } from "@reactive-resume/ui";
|
||||
import { useRef } from "react";
|
||||
|
||||
@ -56,26 +57,30 @@ export const RightSidebar = () => {
|
||||
<div />
|
||||
|
||||
<div className="flex flex-col items-center justify-center gap-y-2">
|
||||
<SectionIcon id="template" name="Template" onClick={() => scrollIntoView("#template")} />
|
||||
<SectionIcon id="layout" name="Layout" onClick={() => scrollIntoView("#layout")} />
|
||||
<SectionIcon
|
||||
id="template"
|
||||
name={t`Template`}
|
||||
onClick={() => scrollIntoView("#template")}
|
||||
/>
|
||||
<SectionIcon id="layout" name={t`Layout`} onClick={() => scrollIntoView("#layout")} />
|
||||
<SectionIcon
|
||||
id="typography"
|
||||
name="Typography"
|
||||
name={t`Typography`}
|
||||
onClick={() => scrollIntoView("#typography")}
|
||||
/>
|
||||
<SectionIcon id="theme" name="Theme" onClick={() => scrollIntoView("#theme")} />
|
||||
<SectionIcon id="page" name="Page" onClick={() => scrollIntoView("#page")} />
|
||||
<SectionIcon id="sharing" name="Sharing" onClick={() => scrollIntoView("#sharing")} />
|
||||
<SectionIcon id="theme" name={t`Theme`} onClick={() => scrollIntoView("#theme")} />
|
||||
<SectionIcon id="page" name={t`Page`} onClick={() => scrollIntoView("#page")} />
|
||||
<SectionIcon id="sharing" name={t`Sharing`} onClick={() => scrollIntoView("#sharing")} />
|
||||
<SectionIcon
|
||||
id="statistics"
|
||||
name="Statistics"
|
||||
name={t`Statistics`}
|
||||
onClick={() => scrollIntoView("#statistics")}
|
||||
/>
|
||||
<SectionIcon id="export" name="Export" onClick={() => scrollIntoView("#export")} />
|
||||
<SectionIcon id="notes" name="Notes" onClick={() => scrollIntoView("#notes")} />
|
||||
<SectionIcon id="export" name={t`Export`} onClick={() => scrollIntoView("#export")} />
|
||||
<SectionIcon id="notes" name={t`Notes`} onClick={() => scrollIntoView("#notes")} />
|
||||
<SectionIcon
|
||||
id="information"
|
||||
name="Information"
|
||||
name={t`Information`}
|
||||
onClick={() => scrollIntoView("#information")}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -1,16 +1,15 @@
|
||||
import { t } from "@lingui/macro";
|
||||
import { CircleNotch, FileJs, FilePdf } from "@phosphor-icons/react";
|
||||
import { buttonVariants, Card, CardContent, CardDescription, CardTitle } from "@reactive-resume/ui";
|
||||
import { cn } from "@reactive-resume/utils";
|
||||
import { saveAs } from "file-saver";
|
||||
|
||||
import { useToast } from "@/client/hooks/use-toast";
|
||||
import { usePrintResume } from "@/client/services/resume/print";
|
||||
import { useResumeStore } from "@/client/stores/resume";
|
||||
|
||||
import { getSectionIcon } from "../shared/section-icon";
|
||||
|
||||
export const ExportSection = () => {
|
||||
const { toast } = useToast();
|
||||
const { printResume, loading } = usePrintResume();
|
||||
|
||||
const onJsonExport = () => {
|
||||
@ -19,11 +18,6 @@ export const ExportSection = () => {
|
||||
const resumeJSON = JSON.stringify(resume.data, null, 2);
|
||||
|
||||
saveAs(new Blob([resumeJSON], { type: "application/json" }), filename);
|
||||
|
||||
toast({
|
||||
variant: "success",
|
||||
title: "A JSON snapshot of your resume has been successfully exported.",
|
||||
});
|
||||
};
|
||||
|
||||
const onPdfExport = async () => {
|
||||
@ -43,7 +37,7 @@ export const ExportSection = () => {
|
||||
<header className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-x-4">
|
||||
{getSectionIcon("export")}
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">Export</h2>
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">{t`Export`}</h2>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@ -57,10 +51,9 @@ export const ExportSection = () => {
|
||||
>
|
||||
<FileJs size={22} />
|
||||
<CardContent className="flex-1">
|
||||
<CardTitle className="text-sm">JSON</CardTitle>
|
||||
<CardTitle className="text-sm">{t`JSON`}</CardTitle>
|
||||
<CardDescription className="font-normal">
|
||||
Download a JSON snapshot of your resume. This file can be used to import your resume
|
||||
in the future, or can even be shared with others to collaborate.
|
||||
{t`Download a JSON snapshot of your resume. This file can be used to import your resume in the future, or can even be shared with others to collaborate.`}
|
||||
</CardDescription>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@ -76,10 +69,9 @@ export const ExportSection = () => {
|
||||
{loading ? <CircleNotch size={22} className="animate-spin" /> : <FilePdf size={22} />}
|
||||
|
||||
<CardContent className="flex-1">
|
||||
<CardTitle className="text-sm">PDF</CardTitle>
|
||||
<CardTitle className="text-sm">{t`PDF`}</CardTitle>
|
||||
<CardDescription className="font-normal">
|
||||
Download a PDF of your resume. This file can be used to print your resume, send it to
|
||||
recruiters, or upload on job portals.
|
||||
{t`Download a PDF of your resume. This file can be used to print your resume, send it to recruiters, or upload on job portals.`}
|
||||
</CardDescription>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { t, Trans } from "@lingui/macro";
|
||||
import { Book, EnvelopeSimpleOpen, GithubLogo, HandHeart } from "@phosphor-icons/react";
|
||||
import {
|
||||
buttonVariants,
|
||||
@ -14,28 +15,30 @@ import { getSectionIcon } from "../shared/section-icon";
|
||||
const DonateCard = () => (
|
||||
<Card className="space-y-4 bg-info text-info-foreground">
|
||||
<CardContent className="space-y-2">
|
||||
<CardTitle>Support the app by donating what you can!</CardTitle>
|
||||
<CardTitle>{t`Support the app by donating what you can!`}</CardTitle>
|
||||
<CardDescription className="space-y-2">
|
||||
<p>
|
||||
I built Reactive Resume mostly by myself during my spare time, with a lot of help from
|
||||
other great open-source contributors.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you like the app and want to support keeping it free forever, please donate whatever
|
||||
you can afford to give.
|
||||
</p>
|
||||
<Trans>
|
||||
<p>
|
||||
I built Reactive Resume mostly by myself during my spare time, with a lot of help from
|
||||
other great open-source contributors.
|
||||
</p>
|
||||
<p>
|
||||
If you like the app and want to support keeping it free forever, please donate whatever
|
||||
you can afford to give.
|
||||
</p>
|
||||
<p>Your donations could be tax-deductible, depending on your location.</p>
|
||||
</Trans>
|
||||
</CardDescription>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<a
|
||||
href="https://opencollective.com/reactive-resume"
|
||||
className={cn(buttonVariants({ size: "sm" }))}
|
||||
href="https://github.com/sponsors/AmruthPillai"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer nofollow"
|
||||
target="_blank"
|
||||
>
|
||||
<HandHeart size={14} weight="bold" className="mr-2" />
|
||||
<span>Donate to Reactive Resume</span>
|
||||
<span>{t`Donate to Reactive Resume`}</span>
|
||||
</a>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
@ -44,36 +47,37 @@ const DonateCard = () => (
|
||||
const IssuesCard = () => (
|
||||
<Card className="space-y-4">
|
||||
<CardContent className="space-y-2">
|
||||
<CardTitle>Found a bug, or have an idea for a new feature?</CardTitle>
|
||||
<CardTitle>{t`Found a bug, or have an idea for a new feature?`}</CardTitle>
|
||||
<CardDescription className="space-y-2">
|
||||
<p>I'm sure the app is not perfect, but I'd like for it to be.</p>
|
||||
|
||||
<p>
|
||||
If you faced any issues while creating your resume, or have an idea that would help you
|
||||
and other users in creating your resume more easily, drop an issue on the repository or
|
||||
send me an email about it.
|
||||
</p>
|
||||
<Trans>
|
||||
<p>I'm sure the app is not perfect, but I'd like for it to be.</p>
|
||||
<p>
|
||||
If you faced any issues while creating your resume, or have an idea that would help you
|
||||
and other users in creating your resume more easily, drop an issue on the repository or
|
||||
send me an email about it.
|
||||
</p>
|
||||
</Trans>
|
||||
</CardDescription>
|
||||
</CardContent>
|
||||
<CardFooter className="space-x-4">
|
||||
<a
|
||||
className={cn(buttonVariants({ size: "sm" }))}
|
||||
href="https://github.com/AmruthPillai/Reactive-Resume/issues/new/choose"
|
||||
target="_blank"
|
||||
className={cn(buttonVariants({ size: "sm" }))}
|
||||
rel="noopener noreferrer nofollow"
|
||||
target="_blank"
|
||||
>
|
||||
<GithubLogo size={14} weight="bold" className="mr-2" />
|
||||
<span>Raise an issue</span>
|
||||
<span>{t`Raise an issue`}</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
className={cn(buttonVariants({ size: "sm" }))}
|
||||
href="mailto:hello@amruthpillai.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer nofollow"
|
||||
target="_blank"
|
||||
>
|
||||
<EnvelopeSimpleOpen size={14} weight="bold" className="mr-2" />
|
||||
<span>Send me a message</span>
|
||||
<span>{t`Send me a message`}</span>
|
||||
</a>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
@ -82,17 +86,18 @@ const IssuesCard = () => (
|
||||
const DocumentationCard = () => (
|
||||
<Card className="space-y-4">
|
||||
<CardContent className="space-y-2">
|
||||
<CardTitle>Don't know where to begin? Hit the docs!</CardTitle>
|
||||
<CardTitle>{t`Don't know where to begin? Hit the docs!`}</CardTitle>
|
||||
<CardDescription className="space-y-2">
|
||||
<p>
|
||||
The community has spent a lot of time writing the documentation for Reactive Resume, and
|
||||
I'm sure it will help you get started with the app.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There are also a lot of examples to help you get started, and features that you might not
|
||||
know about which could help you build your perfect resume.
|
||||
</p>
|
||||
<Trans>
|
||||
<p>
|
||||
The community has spent a lot of time writing the documentation for Reactive Resume, and
|
||||
I'm sure it will help you get started with the app.
|
||||
</p>
|
||||
<p>
|
||||
There are also a lot of examples to help you get started, and features that you might
|
||||
not know about which could help you build your perfect resume.
|
||||
</p>
|
||||
</Trans>
|
||||
</CardDescription>
|
||||
</CardContent>
|
||||
<CardFooter className="space-x-4">
|
||||
@ -103,7 +108,7 @@ const DocumentationCard = () => (
|
||||
rel="noopener noreferrer nofollow"
|
||||
>
|
||||
<Book size={14} weight="bold" className="mr-2" />
|
||||
<span>Documentation</span>
|
||||
<span>{t`Documentation`}</span>
|
||||
</a>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
@ -115,7 +120,7 @@ export const InformationSection = () => {
|
||||
<header className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-x-4">
|
||||
{getSectionIcon("information")}
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">Information</h2>
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">{t`Information`}</h2>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@ import {
|
||||
verticalListSortingStrategy,
|
||||
} from "@dnd-kit/sortable";
|
||||
import { CSS } from "@dnd-kit/utilities";
|
||||
import { t, Trans } from "@lingui/macro";
|
||||
import { ArrowCounterClockwise, DotsSixVertical, Plus, TrashSimple } from "@phosphor-icons/react";
|
||||
import { defaultMetadata } from "@reactive-resume/schema";
|
||||
import { Button, Portal, Tooltip } from "@reactive-resume/ui";
|
||||
@ -203,10 +204,10 @@ export const LayoutSection = () => {
|
||||
<header className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-x-4">
|
||||
{getSectionIcon("layout")}
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">Layout</h2>
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">{t`Layout`}</h2>
|
||||
</div>
|
||||
|
||||
<Tooltip content="Reset Layout">
|
||||
<Tooltip content={t`Reset Layout`}>
|
||||
<Button size="icon" variant="ghost" onClick={onResetLayout}>
|
||||
<ArrowCounterClockwise />
|
||||
</Button>
|
||||
@ -232,7 +233,9 @@ export const LayoutSection = () => {
|
||||
return (
|
||||
<div key={pageIndex} className="rounded border p-3 pb-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="mb-3 text-xs font-bold">Page {pageIndex + 1}</p>
|
||||
<p className="mb-3 text-xs font-bold">
|
||||
<Trans>Page {pageIndex + 1}</Trans>
|
||||
</p>
|
||||
|
||||
{pageIndex !== 0 && (
|
||||
<Button
|
||||
@ -247,8 +250,8 @@ export const LayoutSection = () => {
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 items-start gap-x-4">
|
||||
<Column id={mainIndex} name="Main" items={main} />
|
||||
<Column id={sidebarIndex} name="Sidebar" items={sidebar} />
|
||||
<Column id={mainIndex} name={t`Main`} items={main} />
|
||||
<Column id={sidebarIndex} name={t`Sidebar`} items={sidebar} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@ -261,7 +264,7 @@ export const LayoutSection = () => {
|
||||
|
||||
<Button variant="outline" className="ml-auto" onClick={onAddPage}>
|
||||
<Plus />
|
||||
<span className="ml-2">Add New Page</span>
|
||||
<span className="ml-2">{t`Add New Page`}</span>
|
||||
</Button>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { t } from "@lingui/macro";
|
||||
import { RichInput } from "@reactive-resume/ui";
|
||||
|
||||
import { useResumeStore } from "@/client/stores/resume";
|
||||
@ -13,22 +14,20 @@ export const NotesSection = () => {
|
||||
<header className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-x-4">
|
||||
{getSectionIcon("notes")}
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">Notes</h2>
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">{t`Notes`}</h2>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main className="grid gap-y-4">
|
||||
<p className="leading-relaxed">
|
||||
This section is reserved for your personal notes specific to this resume. The content here
|
||||
remains private and is not shared with anyone else.
|
||||
{t`This section is reserved for your personal notes specific to this resume. The content here remains private and is not shared with anyone else.`}
|
||||
</p>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<RichInput content={notes} onChange={(content) => setValue("metadata.notes", content)} />
|
||||
|
||||
<p className="text-xs leading-relaxed opacity-75">
|
||||
For example, information regarding which companies you sent this resume to or the links
|
||||
to the job descriptions can be noted down here.
|
||||
{t`For example, information regarding which companies you sent this resume to or the links to the job descriptions can be noted down here.`}
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { t } from "@lingui/macro";
|
||||
import {
|
||||
Label,
|
||||
Select,
|
||||
@ -22,13 +23,13 @@ export const PageSection = () => {
|
||||
<header className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-x-4">
|
||||
{getSectionIcon("page")}
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">Page</h2>
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">{t`Page`}</h2>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main className="grid gap-y-4">
|
||||
<div className="space-y-1.5">
|
||||
<Label>Format</Label>
|
||||
<Label>{t`Format`}</Label>
|
||||
<Select
|
||||
value={page.format}
|
||||
onValueChange={(value) => {
|
||||
@ -36,17 +37,17 @@ export const PageSection = () => {
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Format" />
|
||||
<SelectValue placeholder={t`Format`} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="a4">A4</SelectItem>
|
||||
<SelectItem value="letter">Letter</SelectItem>
|
||||
<SelectItem value="a4">{t`A4`}</SelectItem>
|
||||
<SelectItem value="letter">{t`Letter`}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label>Margin</Label>
|
||||
<Label>{t`Margin`}</Label>
|
||||
<div className="flex items-center gap-x-4 py-1">
|
||||
<Slider
|
||||
min={0}
|
||||
@ -63,7 +64,7 @@ export const PageSection = () => {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label>Options</Label>
|
||||
<Label>{t`Options`}</Label>
|
||||
|
||||
<div className="py-2">
|
||||
<div className="flex items-center gap-x-4">
|
||||
@ -74,7 +75,7 @@ export const PageSection = () => {
|
||||
setValue("metadata.page.options.breakLine", checked);
|
||||
}}
|
||||
/>
|
||||
<Label htmlFor="metadata.page.options.breakLine">Show Break Line</Label>
|
||||
<Label htmlFor="metadata.page.options.breakLine">{t`Show Break Line`}</Label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -87,7 +88,7 @@ export const PageSection = () => {
|
||||
setValue("metadata.page.options.pageNumbers", checked);
|
||||
}}
|
||||
/>
|
||||
<Label htmlFor="metadata.page.options.pageNumbers">Show Page Numbers</Label>
|
||||
<Label htmlFor="metadata.page.options.pageNumbers">{t`Show Page Numbers`}</Label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { t } from "@lingui/macro";
|
||||
import { CopySimple } from "@phosphor-icons/react";
|
||||
import { Button, Input, Label, Switch, Tooltip } from "@reactive-resume/ui";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
@ -25,9 +26,8 @@ export const SharingSection = () => {
|
||||
|
||||
toast({
|
||||
variant: "success",
|
||||
title: "A link has been copied to your clipboard.",
|
||||
description:
|
||||
"Anyone with this link can view and download the resume. Share it on your profile or with recruiters.",
|
||||
title: t`A link has been copied to your clipboard.`,
|
||||
description: t`Anyone with this link can view and download the resume. Share it on your profile or with recruiters.`,
|
||||
});
|
||||
};
|
||||
|
||||
@ -36,7 +36,7 @@ export const SharingSection = () => {
|
||||
<header className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-x-4">
|
||||
{getSectionIcon("sharing")}
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">Sharing</h2>
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">{t`Sharing`}</h2>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@ -52,9 +52,9 @@ export const SharingSection = () => {
|
||||
/>
|
||||
<div>
|
||||
<Label htmlFor="visibility" className="space-y-1">
|
||||
<p>Public</p>
|
||||
<p>{t`Public`}</p>
|
||||
<p className="text-xs opacity-60">
|
||||
Anyone with the link can view and download the resume.
|
||||
{t`Anyone with the link can view and download the resume.`}
|
||||
</p>
|
||||
</Label>
|
||||
</div>
|
||||
@ -70,12 +70,12 @@ export const SharingSection = () => {
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
>
|
||||
<Label htmlFor="resume-url">URL</Label>
|
||||
<Label htmlFor="resume-url">{t`URL`}</Label>
|
||||
|
||||
<div className="flex gap-x-1.5">
|
||||
<Input id="resume-url" readOnly value={url} className="flex-1" />
|
||||
|
||||
<Tooltip content="Copy to Clipboard">
|
||||
<Tooltip content={t`Copy to Clipboard`}>
|
||||
<Button size="icon" variant="ghost" onClick={onCopy}>
|
||||
<CopySimple />
|
||||
</Button>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { t } from "@lingui/macro";
|
||||
import { Info } from "@phosphor-icons/react";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@reactive-resume/ui";
|
||||
import { cn } from "@reactive-resume/utils";
|
||||
@ -19,7 +20,7 @@ export const StatisticsSection = () => {
|
||||
<header className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-x-4">
|
||||
{getSectionIcon("statistics")}
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">Statistics</h2>
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">{t`Statistics`}</h2>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@ -34,12 +35,9 @@ export const StatisticsSection = () => {
|
||||
>
|
||||
<Alert variant="info">
|
||||
<Info size={18} />
|
||||
|
||||
<AlertTitle>Statistics are available only for public resumes.</AlertTitle>
|
||||
|
||||
<AlertTitle>{t`Statistics are available only for public resumes.`}</AlertTitle>
|
||||
<AlertDescription className="text-xs leading-relaxed">
|
||||
You can track the number of views your resume has received, or how many people
|
||||
have downloaded the resume by enabling public sharing.
|
||||
{t`You can track the number of views your resume has received, or how many people have downloaded the resume by enabling public sharing.`}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</motion.div>
|
||||
@ -50,14 +48,14 @@ export const StatisticsSection = () => {
|
||||
<h3 className={cn("text-4xl font-bold blur-none transition-all", !isPublic && "blur-sm")}>
|
||||
{statistics?.views ?? 0}
|
||||
</h3>
|
||||
<p className="opacity-75">Views</p>
|
||||
<p className="opacity-75">{t`Views`}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className={cn("text-4xl font-bold blur-none transition-all", !isPublic && "blur-sm")}>
|
||||
{statistics?.downloads ?? 0}
|
||||
</h3>
|
||||
<p className="opacity-75">Downloads</p>
|
||||
<p className="opacity-75">{t`Downloads`}</p>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { t } from "@lingui/macro";
|
||||
import { Button, HoverCard, HoverCardContent, HoverCardTrigger } from "@reactive-resume/ui";
|
||||
import { cn, templatesList } from "@reactive-resume/utils";
|
||||
|
||||
@ -14,7 +15,7 @@ export const TemplateSection = () => {
|
||||
<header className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-x-4">
|
||||
{getSectionIcon("template")}
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">Template</h2>
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">{t`Template`}</h2>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { t } from "@lingui/macro";
|
||||
import { Input, Label, Popover, PopoverContent, PopoverTrigger } from "@reactive-resume/ui";
|
||||
import { cn } from "@reactive-resume/utils";
|
||||
import { HexColorPicker } from "react-colorful";
|
||||
@ -16,7 +17,7 @@ export const ThemeSection = () => {
|
||||
<header className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-x-4">
|
||||
{getSectionIcon("theme")}
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">Theme</h2>
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">{t`Theme`}</h2>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@ -39,7 +40,7 @@ export const ThemeSection = () => {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="theme.primary">Primary Color</Label>
|
||||
<Label htmlFor="theme.primary">{t`Primary Color`}</Label>
|
||||
<div className="relative">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
@ -69,7 +70,7 @@ export const ThemeSection = () => {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="theme.primary">Background Color</Label>
|
||||
<Label htmlFor="theme.primary">{t`Background Color`}</Label>
|
||||
<div className="relative">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
@ -99,7 +100,7 @@ export const ThemeSection = () => {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="theme.primary">Text Color</Label>
|
||||
<Label htmlFor="theme.primary">{t`Text Color`}</Label>
|
||||
<div className="relative">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
/* eslint-disable lingui/no-unlocalized-strings */
|
||||
|
||||
import { t } from "@lingui/macro";
|
||||
import { Button, Combobox, ComboboxOption, Label, Slider, Switch } from "@reactive-resume/ui";
|
||||
import { cn } from "@reactive-resume/utils";
|
||||
import { fonts } from "@reactive-resume/utils";
|
||||
@ -61,7 +64,7 @@ export const TypographySection = () => {
|
||||
<header className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-x-4">
|
||||
{getSectionIcon("typography")}
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">Typography</h2>
|
||||
<h2 className="line-clamp-1 text-3xl font-bold">{t`Typography`}</h2>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@ -89,11 +92,11 @@ export const TypographySection = () => {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label>Font Family</Label>
|
||||
<Label>{t`Font Family`}</Label>
|
||||
<Combobox
|
||||
options={families}
|
||||
value={typography.font.family}
|
||||
searchPlaceholder="Search for a font family"
|
||||
searchPlaceholder={t`Search for a font family`}
|
||||
onValueChange={(value) => {
|
||||
setValue("metadata.typography.font.family", value);
|
||||
setValue("metadata.typography.font.subset", "latin");
|
||||
@ -104,11 +107,11 @@ export const TypographySection = () => {
|
||||
|
||||
<div className="grid grid-cols-2 gap-x-4">
|
||||
<div className="space-y-1.5">
|
||||
<Label>Font Subset</Label>
|
||||
<Label>{t`Font Subset`}</Label>
|
||||
<Combobox
|
||||
options={subsets}
|
||||
value={typography.font.subset}
|
||||
searchPlaceholder="Search for a font subset"
|
||||
searchPlaceholder={t`Search for a font subset`}
|
||||
onValueChange={(value) => {
|
||||
setValue("metadata.typography.font.subset", value);
|
||||
}}
|
||||
@ -116,12 +119,12 @@ export const TypographySection = () => {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label>Font Variants</Label>
|
||||
<Label>{t`Font Variants`}</Label>
|
||||
<Combobox
|
||||
multiple
|
||||
options={variants}
|
||||
value={typography.font.variants}
|
||||
searchPlaceholder="Search for a font variant"
|
||||
searchPlaceholder={t`Search for a font variant`}
|
||||
onValueChange={(value) => {
|
||||
setValue("metadata.typography.font.variants", value);
|
||||
}}
|
||||
@ -130,7 +133,7 @@ export const TypographySection = () => {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label>Font Size</Label>
|
||||
<Label>{t`Font Size`}</Label>
|
||||
<div className="flex items-center gap-x-4 py-1">
|
||||
<Slider
|
||||
min={12}
|
||||
@ -147,7 +150,7 @@ export const TypographySection = () => {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label>Line Height</Label>
|
||||
<Label>{t`Line Height`}</Label>
|
||||
<div className="flex items-center gap-x-4 py-1">
|
||||
<Slider
|
||||
min={0}
|
||||
@ -164,7 +167,7 @@ export const TypographySection = () => {
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label>Options</Label>
|
||||
<Label>{t`Options`}</Label>
|
||||
|
||||
<div className="py-2">
|
||||
<div className="flex items-center gap-x-4">
|
||||
@ -175,7 +178,7 @@ export const TypographySection = () => {
|
||||
setValue("metadata.typography.underlineLinks", checked);
|
||||
}}
|
||||
/>
|
||||
<Label htmlFor="metadata.typography.underlineLinks">Underline Links</Label>
|
||||
<Label htmlFor="metadata.typography.underlineLinks">{t`Underline Links`}</Label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user