Compare commits

..

9 Commits

24 changed files with 120 additions and 97 deletions

View File

@ -5,7 +5,6 @@
"overrides": [ "overrides": [
{ {
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"], "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"extends": ["plugin:prettier/recommended"],
"plugins": ["simple-import-sort", "unused-imports"], "plugins": ["simple-import-sort", "unused-imports"],
"rules": { "rules": {
// eslint // eslint
@ -42,14 +41,6 @@
} }
] ]
} }
],
// prettier
"prettier/prettier": [
"warn",
{
"endOfLine": "auto"
}
] ]
} }
}, },

View File

@ -4,13 +4,6 @@
"overrides": [ "overrides": [
{ {
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"], "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"extends": ["plugin:tailwindcss/recommended"],
"settings": {
"tailwindcss": {
"callees": ["cn", "clsx", "cva"],
"config": "tailwind.config.js"
}
},
"rules": { "rules": {
// eslint // eslint
"@typescript-eslint/no-require-imports": "off", "@typescript-eslint/no-require-imports": "off",
@ -28,10 +21,7 @@
], ],
// react-hooks // react-hooks
"react-hooks/exhaustive-deps": "off", "react-hooks/exhaustive-deps": "off"
// tailwindcss
"tailwindcss/no-custom-classname": "off"
} }
}, },
{ {

View File

@ -1,3 +1,4 @@
import { isLocalFont } from "@reactive-resume/utils";
import { useEffect, useMemo } from "react"; import { useEffect, useMemo } from "react";
import { Helmet } from "react-helmet-async"; import { Helmet } from "react-helmet-async";
import { Outlet } from "react-router"; import { Outlet } from "react-router";
@ -18,6 +19,18 @@ export const ArtboardPage = () => {
}, [metadata.typography.font]); }, [metadata.typography.font]);
useEffect(() => { useEffect(() => {
const family = metadata.typography.font.family;
if (isLocalFont(family)) {
let frame = 0;
frame = requestAnimationFrame(() => {
const width = window.document.body.offsetWidth;
const height = window.document.body.offsetHeight;
const message = { type: "PAGE_LOADED", payload: { width, height } };
window.postMessage(message, "*");
});
return () => { cancelAnimationFrame(frame); };
}
webfontloader.load({ webfontloader.load({
google: { families: [fontString] }, google: { families: [fontString] },
active: () => { active: () => {

View File

@ -131,13 +131,13 @@ const Link = ({ url, icon, iconOnRight, label, className }: LinkProps) => {
if (!isUrl(url.href)) return null; if (!isUrl(url.href)) return null;
return ( return (
<div className="flex items-center gap-x-1.5"> <div className="flex items-center gap-x-1.5 break-all">
{!iconOnRight && (icon ?? <i className="ph ph-bold ph-link text-primary" />)} {!iconOnRight && (icon ?? <i className="ph ph-bold ph-link text-primary" />)}
<a <a
href={url.href} href={url.href}
target="_blank" target="_blank"
rel="noreferrer noopener nofollow" rel="noreferrer noopener nofollow"
className={cn("inline-block", className)} className={cn("line-clamp-1 max-w-fit", className)}
> >
{label ?? (url.label || url.href)} {label ?? (url.label || url.href)}
</a> </a>
@ -553,7 +553,7 @@ export const Azurill = ({ columns, isFirstPage = false }: TemplateProps) => {
const [main, sidebar] = columns; const [main, sidebar] = columns;
return ( return (
<div className="p-custom space-y-3"> <div className="space-y-3 p-custom">
{isFirstPage && <Header />} {isFirstPage && <Header />}
<div className="grid grid-cols-3 gap-x-4"> <div className="grid grid-cols-3 gap-x-4">

View File

@ -122,13 +122,13 @@ const Link = ({ url, icon, iconOnRight, label, className }: LinkProps) => {
if (!isUrl(url.href)) return null; if (!isUrl(url.href)) return null;
return ( return (
<div className="flex items-center gap-x-1.5"> <div className="flex items-center gap-x-1.5 break-all">
{!iconOnRight && (icon ?? <i className="ph ph-bold ph-link text-primary" />)} {!iconOnRight && (icon ?? <i className="ph ph-bold ph-link text-primary" />)}
<a <a
href={url.href} href={url.href}
target="_blank" target="_blank"
rel="noreferrer noopener nofollow" rel="noreferrer noopener nofollow"
className={cn("inline-block", className)} className={cn("line-clamp-1 max-w-fit", className)}
> >
{label ?? (url.label || url.href)} {label ?? (url.label || url.href)}
</a> </a>
@ -568,7 +568,7 @@ export const Bronzor = ({ columns, isFirstPage = false }: TemplateProps) => {
const [main, sidebar] = columns; const [main, sidebar] = columns;
return ( return (
<div className="p-custom space-y-4"> <div className="space-y-4 p-custom">
{isFirstPage && <Header />} {isFirstPage && <Header />}
<div className="space-y-4"> <div className="space-y-4">

View File

@ -125,14 +125,14 @@ const Link = ({ url, icon, iconOnRight, label, className }: LinkProps) => {
if (!isUrl(url.href)) return null; if (!isUrl(url.href)) return null;
return ( return (
<div className="flex items-center gap-x-1.5"> <div className="flex items-center gap-x-1.5 break-all">
{!iconOnRight && {!iconOnRight &&
(icon ?? <i className="ph ph-bold ph-link text-primary group-[.sidebar]:text-white" />)} (icon ?? <i className="ph ph-bold ph-link text-primary group-[.sidebar]:text-white" />)}
<a <a
href={url.href} href={url.href}
target="_blank" target="_blank"
rel="noreferrer noopener nofollow" rel="noreferrer noopener nofollow"
className={cn("inline-block", className)} className={cn("line-clamp-1 max-w-fit", className)}
> >
{label ?? (url.label || url.href)} {label ?? (url.label || url.href)}
</a> </a>
@ -571,7 +571,7 @@ export const Chikorita = ({ columns, isFirstPage = false }: TemplateProps) => {
<div className="grid min-h-[inherit] grid-cols-3"> <div className="grid min-h-[inherit] grid-cols-3">
<div <div
className={cn( className={cn(
"main p-custom group space-y-4", "main group space-y-4 p-custom",
sidebar.length > 0 ? "col-span-2" : "col-span-3", sidebar.length > 0 ? "col-span-2" : "col-span-3",
)} )}
> >
@ -584,7 +584,7 @@ export const Chikorita = ({ columns, isFirstPage = false }: TemplateProps) => {
<div <div
className={cn( className={cn(
"sidebar p-custom group h-full space-y-4 bg-primary text-background", "sidebar group h-full space-y-4 bg-primary p-custom text-background",
sidebar.length === 0 && "hidden", sidebar.length === 0 && "hidden",
)} )}
> >

View File

@ -28,7 +28,7 @@ const Header = () => {
const basics = useArtboardStore((state) => state.resume.basics); const basics = useArtboardStore((state) => state.resume.basics);
return ( return (
<div className="p-custom relative grid grid-cols-3 space-x-4 pb-0"> <div className="relative grid grid-cols-3 space-x-4 p-custom pb-0">
<Picture className="mx-auto" /> <Picture className="mx-auto" />
<div className="relative z-10 col-span-2 text-background"> <div className="relative z-10 col-span-2 text-background">
@ -142,13 +142,13 @@ const Link = ({ url, icon, iconOnRight, label, className }: LinkProps) => {
if (!isUrl(url.href)) return null; if (!isUrl(url.href)) return null;
return ( return (
<div className="flex items-center gap-x-1.5"> <div className="flex items-center gap-x-1.5 break-all">
{!iconOnRight && (icon ?? <i className="ph ph-bold ph-link text-primary" />)} {!iconOnRight && (icon ?? <i className="ph ph-bold ph-link text-primary" />)}
<a <a
href={url.href} href={url.href}
target="_blank" target="_blank"
rel="noreferrer noopener nofollow" rel="noreferrer noopener nofollow"
className={cn("inline-block", className)} className={cn("line-clamp-1 max-w-fit", className)}
> >
{label ?? (url.label || url.href)} {label ?? (url.label || url.href)}
</a> </a>
@ -604,7 +604,7 @@ export const Ditto = ({ columns, isFirstPage = false }: TemplateProps) => {
)} )}
<div className="grid grid-cols-3"> <div className="grid grid-cols-3">
<div className="sidebar p-custom group space-y-4"> <div className="sidebar group space-y-4 p-custom">
{sidebar.map((section) => ( {sidebar.map((section) => (
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment> <Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
))} ))}
@ -612,7 +612,7 @@ export const Ditto = ({ columns, isFirstPage = false }: TemplateProps) => {
<div <div
className={cn( className={cn(
"main p-custom group space-y-4", "main group space-y-4 p-custom",
sidebar.length > 0 ? "col-span-2" : "col-span-3", sidebar.length > 0 ? "col-span-2" : "col-span-3",
)} )}
> >

View File

@ -28,7 +28,7 @@ const Header = () => {
const basics = useArtboardStore((state) => state.resume.basics); const basics = useArtboardStore((state) => state.resume.basics);
return ( return (
<div className="p-custom space-y-4 bg-primary text-background"> <div className="space-y-4 bg-primary p-custom text-background">
<Picture className="border-background" /> <Picture className="border-background" />
<div> <div>
@ -86,7 +86,7 @@ const Summary = () => {
if (!section.visible || isEmptyString(section.content)) return null; if (!section.visible || isEmptyString(section.content)) return null;
return ( return (
<div className="p-custom space-y-4" style={{ backgroundColor: hexToRgb(primaryColor, 0.2) }}> <div className="space-y-4 p-custom" style={{ backgroundColor: hexToRgb(primaryColor, 0.2) }}>
<section id={section.id}> <section id={section.id}>
<div <div
dangerouslySetInnerHTML={{ __html: sanitize(section.content) }} dangerouslySetInnerHTML={{ __html: sanitize(section.content) }}
@ -123,7 +123,7 @@ const Link = ({ url, icon, iconOnRight, label, className }: LinkProps) => {
if (!isUrl(url.href)) return null; if (!isUrl(url.href)) return null;
return ( return (
<div className="flex items-center gap-x-1.5"> <div className="flex items-center gap-x-1.5 break-all">
{!iconOnRight && {!iconOnRight &&
(icon ?? ( (icon ?? (
<i className="ph ph-bold ph-link text-primary group-[.sidebar]:text-background" /> <i className="ph ph-bold ph-link text-primary group-[.sidebar]:text-background" />
@ -132,7 +132,7 @@ const Link = ({ url, icon, iconOnRight, label, className }: LinkProps) => {
href={url.href} href={url.href}
target="_blank" target="_blank"
rel="noreferrer noopener nofollow" rel="noreferrer noopener nofollow"
className={cn("inline-block", className)} className={cn("line-clamp-1 max-w-fit", className)}
> >
{label ?? (url.label || url.href)} {label ?? (url.label || url.href)}
</a> </a>
@ -587,7 +587,7 @@ export const Gengar = ({ columns, isFirstPage = false }: TemplateProps) => {
{isFirstPage && <Header />} {isFirstPage && <Header />}
<div <div
className="p-custom flex-1 space-y-4" className="flex-1 space-y-4 p-custom"
style={{ backgroundColor: hexToRgb(primaryColor, 0.2) }} style={{ backgroundColor: hexToRgb(primaryColor, 0.2) }}
> >
{sidebar.map((section) => ( {sidebar.map((section) => (
@ -597,7 +597,7 @@ export const Gengar = ({ columns, isFirstPage = false }: TemplateProps) => {
</div> </div>
<div className={cn("main group", sidebar.length > 0 ? "col-span-2" : "col-span-3")}> <div className={cn("main group", sidebar.length > 0 ? "col-span-2" : "col-span-3")}>
<div className="p-custom space-y-4"> <div className="space-y-4 p-custom">
{main.map((section) => ( {main.map((section) => (
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment> <Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
))} ))}

View File

@ -135,14 +135,14 @@ const Link = ({ url, icon, iconOnRight, label, className }: LinkProps) => {
if (!isUrl(url.href)) return null; if (!isUrl(url.href)) return null;
return ( return (
<div className="flex items-center gap-x-1.5"> <div className="flex items-center gap-x-1.5 break-all">
{!iconOnRight && {!iconOnRight &&
(icon ?? <i className="ph ph-bold ph-link text-primary group-[.sidebar]:text-primary" />)} (icon ?? <i className="ph ph-bold ph-link text-primary group-[.sidebar]:text-primary" />)}
<a <a
href={url.href} href={url.href}
target="_blank" target="_blank"
rel="noreferrer noopener nofollow" rel="noreferrer noopener nofollow"
className={cn("inline-block", className)} className={cn("line-clamp-1 max-w-fit", className)}
> >
{label ?? (url.label || url.href)} {label ?? (url.label || url.href)}
</a> </a>
@ -587,7 +587,7 @@ export const Glalie = ({ columns, isFirstPage = false }: TemplateProps) => {
return ( return (
<div className="grid min-h-[inherit] grid-cols-3"> <div className="grid min-h-[inherit] grid-cols-3">
<div <div
className={cn("sidebar p-custom group space-y-4", sidebar.length === 0 && "hidden")} className={cn("sidebar group space-y-4 p-custom", sidebar.length === 0 && "hidden")}
style={{ backgroundColor: hexToRgb(primaryColor, 0.2) }} style={{ backgroundColor: hexToRgb(primaryColor, 0.2) }}
> >
{isFirstPage && <Header />} {isFirstPage && <Header />}
@ -599,7 +599,7 @@ export const Glalie = ({ columns, isFirstPage = false }: TemplateProps) => {
<div <div
className={cn( className={cn(
"main p-custom group space-y-4", "main group space-y-4 p-custom",
sidebar.length > 0 ? "col-span-2" : "col-span-3", sidebar.length > 0 ? "col-span-2" : "col-span-3",
)} )}
> >

View File

@ -141,13 +141,13 @@ const Link = ({ url, icon, iconOnRight, label, className }: LinkProps) => {
if (!isUrl(url.href)) return null; if (!isUrl(url.href)) return null;
return ( return (
<div className="flex items-center gap-x-1.5"> <div className="flex items-center gap-x-1.5 break-all">
{!iconOnRight && (icon ?? <i className="ph ph-bold ph-link text-primary" />)} {!iconOnRight && (icon ?? <i className="ph ph-bold ph-link text-primary" />)}
<a <a
href={url.href} href={url.href}
target="_blank" target="_blank"
rel="noreferrer noopener nofollow" rel="noreferrer noopener nofollow"
className={cn("inline-block", className)} className={cn("line-clamp-1 max-w-fit", className)}
> >
{label ?? (url.label || url.href)} {label ?? (url.label || url.href)}
</a> </a>
@ -524,7 +524,7 @@ export const Kakuna = ({ columns, isFirstPage = false }: TemplateProps) => {
const [main, sidebar] = columns; const [main, sidebar] = columns;
return ( return (
<div className="p-custom space-y-4"> <div className="space-y-4 p-custom">
{isFirstPage && <Header />} {isFirstPage && <Header />}
<div className="space-y-4"> <div className="space-y-4">

View File

@ -32,7 +32,7 @@ const Header = () => {
return ( return (
<div> <div>
<div <div
className="p-custom flex items-center space-x-8" className="flex items-center space-x-8 p-custom"
style={{ backgroundColor: hexToRgb(primaryColor, 0.2) }} style={{ backgroundColor: hexToRgb(primaryColor, 0.2) }}
> >
<div className="space-y-3"> <div className="space-y-3">
@ -51,7 +51,7 @@ const Header = () => {
<Picture /> <Picture />
</div> </div>
<div className="p-custom space-y-3" style={{ backgroundColor: hexToRgb(primaryColor, 0.4) }}> <div className="space-y-3 p-custom" style={{ backgroundColor: hexToRgb(primaryColor, 0.4) }}>
<div className="flex flex-wrap items-center gap-x-3 gap-y-0.5 text-sm"> <div className="flex flex-wrap items-center gap-x-3 gap-y-0.5 text-sm">
{basics.location && ( {basics.location && (
<div className="flex items-center gap-x-1.5"> <div className="flex items-center gap-x-1.5">
@ -136,13 +136,13 @@ const Link = ({ url, icon, iconOnRight, label, className }: LinkProps) => {
if (!isUrl(url.href)) return null; if (!isUrl(url.href)) return null;
return ( return (
<div className="flex items-center gap-x-1.5"> <div className="flex items-center gap-x-1.5 break-all">
{!iconOnRight && (icon ?? <i className="ph ph-bold ph-link text-primary" />)} {!iconOnRight && (icon ?? <i className="ph ph-bold ph-link text-primary" />)}
<a <a
href={url.href} href={url.href}
target="_blank" target="_blank"
rel="noreferrer noopener nofollow" rel="noreferrer noopener nofollow"
className={cn("inline-block", className)} className={cn("line-clamp-1 max-w-fit", className)}
> >
{label ?? (url.label || url.href)} {label ?? (url.label || url.href)}
</a> </a>
@ -519,7 +519,7 @@ export const Leafish = ({ columns, isFirstPage = false }: TemplateProps) => {
<div> <div>
{isFirstPage && <Header />} {isFirstPage && <Header />}
<div className="p-custom grid grid-cols-2 items-start space-x-6"> <div className="grid grid-cols-2 items-start space-x-6 p-custom">
<div className={cn("grid gap-y-4", sidebar.length === 0 && "col-span-2")}> <div className={cn("grid gap-y-4", sidebar.length === 0 && "col-span-2")}>
{main.map((section) => ( {main.map((section) => (
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment> <Fragment key={section}>{mapSectionToComponent(section)}</Fragment>

View File

@ -126,13 +126,13 @@ const Link = ({ url, icon, iconOnRight, label, className }: LinkProps) => {
if (!isUrl(url.href)) return null; if (!isUrl(url.href)) return null;
return ( return (
<div className="flex items-center gap-x-1.5"> <div className="flex items-center gap-x-1.5 break-all">
{!iconOnRight && (icon ?? <i className="ph ph-bold ph-link text-primary" />)} {!iconOnRight && (icon ?? <i className="ph ph-bold ph-link text-primary" />)}
<a <a
href={url.href} href={url.href}
target="_blank" target="_blank"
rel="noreferrer noopener nofollow" rel="noreferrer noopener nofollow"
className={cn("inline-block", className)} className={cn("line-clamp-1 max-w-fit", className)}
> >
{label ?? (url.label || url.href)} {label ?? (url.label || url.href)}
</a> </a>
@ -575,7 +575,7 @@ export const Nosepass = ({ columns, isFirstPage = false }: TemplateProps) => {
const [main, sidebar] = columns; const [main, sidebar] = columns;
return ( return (
<div className="p-custom space-y-6"> <div className="space-y-6 p-custom">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<img alt="Europass Logo" className="h-[42px]" src="/assets/europass.png" /> <img alt="Europass Logo" className="h-[42px]" src="/assets/europass.png" />

View File

@ -142,13 +142,13 @@ const Link = ({ url, icon, iconOnRight, label, className }: LinkProps) => {
if (!isUrl(url.href)) return null; if (!isUrl(url.href)) return null;
return ( return (
<div className="flex items-center gap-x-1.5"> <div className="flex items-center gap-x-1.5 break-all">
{!iconOnRight && (icon ?? <i className="ph ph-bold ph-link text-primary" />)} {!iconOnRight && (icon ?? <i className="ph ph-bold ph-link text-primary" />)}
<a <a
href={url.href} href={url.href}
target="_blank" target="_blank"
rel="noreferrer noopener nofollow" rel="noreferrer noopener nofollow"
className={cn("inline-block", className)} className={cn("line-clamp-1 max-w-fit", className)}
> >
{label ?? (url.label || url.href)} {label ?? (url.label || url.href)}
</a> </a>
@ -564,7 +564,7 @@ export const Onyx = ({ columns, isFirstPage = false }: TemplateProps) => {
const [main, sidebar] = columns; const [main, sidebar] = columns;
return ( return (
<div className="p-custom space-y-4"> <div className="space-y-4 p-custom">
{isFirstPage && <Header />} {isFirstPage && <Header />}
{main.map((section) => ( {main.map((section) => (

View File

@ -126,15 +126,11 @@ const Rating = ({ level }: RatingProps) => (
<i <i
key={index} key={index}
className={cn( className={cn(
"ph ph-diamond text-primary", "ph ph-bold ph-diamond text-primary",
level > index && "ph-fill", level > index && "ph-fill",
level <= index && "ph-bold", level <= index && "ph-bold",
)} )}
/> />
// <div
// key={index}
// className={cn("h-2 w-4 border border-primary", level > index && "bg-primary")}
// />
))} ))}
</div> </div>
); );
@ -151,7 +147,7 @@ const Link = ({ url, icon, iconOnRight, label, className }: LinkProps) => {
if (!isUrl(url.href)) return null; if (!isUrl(url.href)) return null;
return ( return (
<div className="flex items-center gap-x-1.5"> <div className="flex items-center gap-x-1.5 break-all">
{!iconOnRight && {!iconOnRight &&
(icon ?? ( (icon ?? (
<i className="ph ph-bold ph-link text-primary group-[.summary]:text-background" /> <i className="ph ph-bold ph-link text-primary group-[.summary]:text-background" />
@ -160,7 +156,7 @@ const Link = ({ url, icon, iconOnRight, label, className }: LinkProps) => {
href={url.href} href={url.href}
target="_blank" target="_blank"
rel="noreferrer noopener nofollow" rel="noreferrer noopener nofollow"
className={cn("inline-block", className)} className={cn("line-clamp-1 max-w-fit", className)}
> >
{label ?? (url.label || url.href)} {label ?? (url.label || url.href)}
</a> </a>
@ -601,7 +597,7 @@ export const Pikachu = ({ columns, isFirstPage = false }: TemplateProps) => {
const [main, sidebar] = columns; const [main, sidebar] = columns;
return ( return (
<div className="p-custom grid grid-cols-3 space-x-6"> <div className="grid grid-cols-3 space-x-6 p-custom">
<div className="sidebar group space-y-4"> <div className="sidebar group space-y-4">
{isFirstPage && <Picture className="w-full !max-w-none" />} {isFirstPage && <Picture className="w-full !max-w-none" />}

View File

@ -123,13 +123,13 @@ const Link = ({ url, icon, iconOnRight, label, className }: LinkProps) => {
if (!isUrl(url.href)) return null; if (!isUrl(url.href)) return null;
return ( return (
<div className="flex items-center gap-x-1.5 border-r pr-2 last:border-r-0 last:pr-0"> <div className="flex items-center gap-x-1.5 break-all border-r pr-2 last:border-r-0 last:pr-0">
{!iconOnRight && (icon ?? <i className="ph ph-bold ph-link text-primary" />)} {!iconOnRight && (icon ?? <i className="ph ph-bold ph-link text-primary" />)}
<a <a
href={url.href} href={url.href}
target="_blank" target="_blank"
rel="noreferrer noopener nofollow" rel="noreferrer noopener nofollow"
className={cn("inline-block", className)} className={cn("line-clamp-1 max-w-fit", className)}
> >
{label ?? (url.label || url.href)} {label ?? (url.label || url.href)}
</a> </a>
@ -567,7 +567,7 @@ export const Rhyhorn = ({ columns, isFirstPage = false }: TemplateProps) => {
const [main, sidebar] = columns; const [main, sidebar] = columns;
return ( return (
<div className="p-custom space-y-4"> <div className="space-y-4 p-custom">
{isFirstPage && <Header />} {isFirstPage && <Header />}
{main.map((section) => ( {main.map((section) => (

View File

@ -4,20 +4,10 @@
"overrides": [ "overrides": [
{ {
"files": ["*.ts", "*.tsx"], "files": ["*.ts", "*.tsx"],
"extends": [ "extends": ["plugin:@tanstack/eslint-plugin-query/recommended"],
"plugin:tailwindcss/recommended",
"plugin:@tanstack/eslint-plugin-query/recommended"
],
"parserOptions": { "parserOptions": {
"projectService": "./apps/client/tsconfig.json" "projectService": "./apps/client/tsconfig.json"
}, },
"settings": {
"tailwindcss": {
"callees": ["cn", "clsx", "cva"],
"config": "tailwind.config.js",
"whitelist": ["ph", "ph\\-.*", "si", "si\\-.*"]
}
},
"plugins": ["lingui"], "plugins": ["lingui"],
"rules": { "rules": {
// eslint // eslint

View File

@ -8,7 +8,7 @@ msgstr ""
"Language: te\n" "Language: te\n"
"Project-Id-Version: reactive-resume\n" "Project-Id-Version: reactive-resume\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-11-04 14:22\n" "PO-Revision-Date: 2025-11-06 00:11\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Telugu\n" "Language-Team: Telugu\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
@ -314,13 +314,13 @@ msgstr "కోడ్ ఖచ్చితంగా 6 అంకెలు ఉండ
#: apps/client/src/pages/builder/sidebars/left/index.tsx:272 #: apps/client/src/pages/builder/sidebars/left/index.tsx:272
msgid "Collapse All" msgid "Collapse All"
msgstr "" msgstr "అన్నిటినీ మూసివేయి"
#: apps/client/src/pages/builder/sidebars/left/sections/basics.tsx:30 #: apps/client/src/pages/builder/sidebars/left/sections/basics.tsx:30
#: apps/client/src/pages/builder/sidebars/left/sections/shared/section-base.tsx:115 #: apps/client/src/pages/builder/sidebars/left/sections/shared/section-base.tsx:115
#: apps/client/src/pages/builder/sidebars/left/sections/summary.tsx:33 #: apps/client/src/pages/builder/sidebars/left/sections/summary.tsx:33
msgid "Collapse section" msgid "Collapse section"
msgstr "" msgstr "విభాగాన్ని మూసివేయి"
#: apps/client/src/pages/builder/sidebars/left/sections/shared/section-options.tsx:136 #: apps/client/src/pages/builder/sidebars/left/sections/shared/section-options.tsx:136
msgid "Columns" msgid "Columns"
@ -583,13 +583,13 @@ msgstr "మీరు ఆర్థికంగా సహాయం చేయలే
#: apps/client/src/pages/builder/sidebars/left/index.tsx:271 #: apps/client/src/pages/builder/sidebars/left/index.tsx:271
msgid "Expand All" msgid "Expand All"
msgstr "" msgstr "అన్నింటినీ తెరవు"
#: apps/client/src/pages/builder/sidebars/left/sections/basics.tsx:30 #: apps/client/src/pages/builder/sidebars/left/sections/basics.tsx:30
#: apps/client/src/pages/builder/sidebars/left/sections/shared/section-base.tsx:115 #: apps/client/src/pages/builder/sidebars/left/sections/shared/section-base.tsx:115
#: apps/client/src/pages/builder/sidebars/left/sections/summary.tsx:33 #: apps/client/src/pages/builder/sidebars/left/sections/summary.tsx:33
msgid "Expand section" msgid "Expand section"
msgstr "" msgstr "విభాగాన్ని తెరవు"
#: apps/client/src/pages/home/sections/templates/index.tsx:12 #: apps/client/src/pages/home/sections/templates/index.tsx:12
msgid "Explore the templates available in Reactive Resume and view the resumes crafted with them. They could also serve as examples to help guide the creation of your next resume." msgid "Explore the templates available in Reactive Resume and view the resumes crafted with them. They could also serve as examples to help guide the creation of your next resume."

View File

@ -23,7 +23,6 @@ export const AuthLayout = () => {
const hideDivider = !providers.includes("email") || providers.length === 1; const hideDivider = !providers.includes("email") || providers.length === 1;
return ( return (
// eslint-disable-next-line tailwindcss/enforces-shorthand -- size-screen not implemented yet
<div className="flex h-screen w-screen"> <div className="flex h-screen w-screen">
<div className="relative flex w-full flex-col justify-center gap-y-8 px-12 sm:mx-auto sm:basis-[420px] sm:px-0 lg:basis-[480px] lg:px-12"> <div className="relative flex w-full flex-col justify-center gap-y-8 px-12 sm:mx-auto sm:basis-[420px] sm:px-0 lg:basis-[480px] lg:px-12">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">

View File

@ -53,7 +53,11 @@ export const CustomField = ({ field, onChange, onRemove }: CustomFieldProps) =>
<Tooltip content={t`Icon`}> <Tooltip content={t`Icon`}>
<PopoverTrigger asChild> <PopoverTrigger asChild>
<Button size="icon" variant="ghost" className="shrink-0"> <Button size="icon" variant="ghost" className="shrink-0">
{field.icon ? <i className={cn(`ph ph-${field.icon}`)} /> : <EnvelopeIcon />} {field.icon ? (
<i className={cn(`ph ph-bold ph-${field.icon}`)} />
) : (
<EnvelopeIcon />
)}
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
</Tooltip> </Tooltip>

View File

@ -21,6 +21,13 @@ export default defineConfig({
host: true, host: true,
port: 5173, port: 5173,
fs: { allow: [searchForWorkspaceRoot(process.cwd())] }, fs: { allow: [searchForWorkspaceRoot(process.cwd())] },
proxy: {
"/artboard": {
target: "http://localhost:6173",
changeOrigin: true,
},
},
}, },
optimizeDeps: { optimizeDeps: {

View File

@ -4,13 +4,6 @@
"overrides": [ "overrides": [
{ {
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"], "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"extends": ["plugin:tailwindcss/recommended"],
"settings": {
"tailwindcss": {
"callees": ["cn", "clsx", "cva"],
"config": "tailwind.config.js"
}
},
"rules": { "rules": {
// eslint // eslint
"@typescript-eslint/no-require-imports": "off", "@typescript-eslint/no-require-imports": "off",

View File

@ -6,6 +6,21 @@ export type Font = {
files: Record<string, string>; files: Record<string, string>;
}; };
/**
* Known system fonts we consider available locally without fetching from Google Fonts.
* Extend this list when adding more system-safe families to the app.
*/
export const localFonts = ["Arial", "Cambria", "Garamond", "Times New Roman"];
/**
* Checks whether a font family is a local/system font.
*
* Input: font family name (case-insensitive)
* Output: true if present in localFonts, otherwise false
*/
export const isLocalFont = (family: string): boolean =>
localFonts.some((f) => f.toLowerCase() === family.toLowerCase());
export const fonts: Font[] = [ export const fonts: Font[] = [
{ {
family: "Roboto", family: "Roboto",

View File

@ -0,0 +1,25 @@
import { describe, expect, it } from "vitest";
import { isLocalFont, localFonts } from "../fonts";
describe("isLocalFont", () => {
it("returns true for known local fonts (case-insensitive)", () => {
expect(isLocalFont("Arial")).toBe(true);
expect(isLocalFont("arial")).toBe(true);
expect(isLocalFont("Times New Roman")).toBe(true);
expect(isLocalFont("times new roman")).toBe(true);
});
it("returns false for non-local fonts", () => {
expect(isLocalFont("Roboto")).toBe(false);
expect(isLocalFont("Open Sans")).toBe(false);
});
});
describe("localFonts", () => {
it("includes the expected base set", () => {
for (const f of ["Arial", "Cambria", "Garamond", "Times New Roman"]) {
expect(localFonts).toContain(f);
}
});
});

View File

@ -1,7 +1,7 @@
{ {
"name": "@reactive-resume/source", "name": "@reactive-resume/source",
"description": "A free and open-source resume builder that simplifies the process of creating, updating, and sharing your resume.", "description": "A free and open-source resume builder that simplifies the process of creating, updating, and sharing your resume.",
"version": "4.5.4", "version": "4.5.5",
"license": "MIT", "license": "MIT",
"private": true, "private": true,
"packageManager": "pnpm@10.20.0", "packageManager": "pnpm@10.20.0",