This commit is contained in:
Amruth Pillai
2026-01-26 06:38:59 +01:00
parent 49585940f7
commit 946bf9ec38
12 changed files with 59 additions and 17 deletions
@@ -1,5 +1,6 @@
import { TiptapContent } from "@/components/input/rich-input";
import type { SectionItem } from "@/schema/resume/data";
import { stripHtml } from "@/utils/string";
import { cn } from "@/utils/style";
import { PageLink } from "../page-link";
@@ -25,7 +26,7 @@ export function AwardsItem({ className, ...item }: AwardsItemProps) {
</div>
{/* Description */}
<div className="section-item-description awards-item-description">
<div className={cn("section-item-description awards-item-description", !stripHtml(item.description) && "hidden")}>
<TiptapContent content={item.description} />
</div>
@@ -1,5 +1,6 @@
import { TiptapContent } from "@/components/input/rich-input";
import type { SectionItem } from "@/schema/resume/data";
import { stripHtml } from "@/utils/string";
import { cn } from "@/utils/style";
import { PageLink } from "../page-link";
@@ -25,7 +26,12 @@ export function CertificationsItem({ className, ...item }: CertificationsItemPro
</div>
{/* Description */}
<div className="section-item-description certifications-item-description">
<div
className={cn(
"section-item-description certifications-item-description",
!stripHtml(item.description) && "hidden",
)}
>
<TiptapContent content={item.description} />
</div>
@@ -1,5 +1,6 @@
import { TiptapContent } from "@/components/input/rich-input";
import type { SectionItem } from "@/schema/resume/data";
import { stripHtml } from "@/utils/string";
import { cn } from "@/utils/style";
import { PageLink } from "../page-link";
@@ -30,7 +31,9 @@ export function EducationItem({ className, ...item }: EducationItemProps) {
</div>
{/* Description */}
<div className="section-item-description education-item-description">
<div
className={cn("section-item-description education-item-description", !stripHtml(item.description) && "hidden")}
>
<TiptapContent content={item.description} />
</div>
@@ -1,5 +1,6 @@
import { TiptapContent } from "@/components/input/rich-input";
import type { SectionItem } from "@/schema/resume/data";
import { stripHtml } from "@/utils/string";
import { cn } from "@/utils/style";
import { PageLink } from "../page-link";
@@ -26,7 +27,9 @@ export function ExperienceItem({ className, ...item }: ExperienceItemProps) {
</div>
{/* Description */}
<div className="section-item-description experience-item-description">
<div
className={cn("section-item-description experience-item-description", !stripHtml(item.description) && "hidden")}
>
<TiptapContent content={item.description} />
</div>
@@ -1,5 +1,6 @@
import { TiptapContent } from "@/components/input/rich-input";
import type { SectionItem } from "@/schema/resume/data";
import { stripHtml } from "@/utils/string";
import { cn } from "@/utils/style";
import { PageLink } from "../page-link";
@@ -20,7 +21,9 @@ export function ProjectsItem({ className, ...item }: ProjectsItemProps) {
</div>
{/* Description */}
<div className="section-item-description projects-item-description">
<div
className={cn("section-item-description projects-item-description", !stripHtml(item.description) && "hidden")}
>
<TiptapContent content={item.description} />
</div>
@@ -1,5 +1,6 @@
import { TiptapContent } from "@/components/input/rich-input";
import type { SectionItem } from "@/schema/resume/data";
import { stripHtml } from "@/utils/string";
import { cn } from "@/utils/style";
import { PageLink } from "../page-link";
@@ -25,7 +26,12 @@ export function PublicationsItem({ className, ...item }: PublicationsItemProps)
</div>
{/* Description */}
<div className="section-item-description publications-item-description">
<div
className={cn(
"section-item-description publications-item-description",
!stripHtml(item.description) && "hidden",
)}
>
<TiptapContent content={item.description} />
</div>
@@ -1,5 +1,6 @@
import { TiptapContent } from "@/components/input/rich-input";
import type { SectionItem } from "@/schema/resume/data";
import { stripHtml } from "@/utils/string";
import { cn } from "@/utils/style";
import { PageLink } from "../page-link";
@@ -24,7 +25,9 @@ export function ReferencesItem({ className, ...item }: ReferencesItemProps) {
</div>
{/* Description */}
<div className="section-item-description references-item-description">
<div
className={cn("section-item-description references-item-description", !stripHtml(item.description) && "hidden")}
>
<TiptapContent content={item.description} />
</div>
@@ -1,5 +1,6 @@
import { TiptapContent } from "@/components/input/rich-input";
import type { SectionItem } from "@/schema/resume/data";
import { stripHtml } from "@/utils/string";
import { cn } from "@/utils/style";
import { PageLink } from "../page-link";
@@ -25,7 +26,9 @@ export function VolunteerItem({ className, ...item }: VolunteerItemProps) {
</div>
{/* Description */}
<div className="section-item-description volunteer-item-description">
<div
className={cn("section-item-description volunteer-item-description", !stripHtml(item.description) && "hidden")}
>
<TiptapContent content={item.description} />
</div>
@@ -1,5 +1,6 @@
import { TiptapContent } from "@/components/input/rich-input";
import { getSectionTitle } from "@/utils/resume/section";
import { stripHtml } from "@/utils/string";
import { cn } from "@/utils/style";
import { useResumeStore } from "../store/resume";
@@ -15,7 +16,7 @@ export function PageSummary({ className }: PageSummaryProps) {
className={cn(
"page-section page-section-summary",
section.hidden && "hidden",
section.content === "" && "hidden",
!stripHtml(section.content) && "hidden",
className,
)}
>
+10 -4
View File
@@ -34,11 +34,17 @@ export const printerRouter = {
description: "Get a screenshot of a resume. Returns a URL to the screenshot image.",
})
.input(z.object({ id: z.string() }))
.output(z.object({ url: z.string() }))
.output(z.object({ url: z.string().nullable() }))
.handler(async ({ input }) => {
const { id, data, userId, updatedAt } = await resumeService.getByIdForPrinter({ id: input.id });
const url = await printerService.getResumeScreenshot({ id, data, userId, updatedAt });
try {
const { id, data, userId, updatedAt } = await resumeService.getByIdForPrinter({ id: input.id });
const url = await printerService.getResumeScreenshot({ id, data, userId, updatedAt });
return { url };
return { url };
} catch {
// ignore errors, as the screenshot is not critical
}
return { url: null };
}),
};
@@ -22,8 +22,6 @@ export function ResumeCard({ resume }: ResumeCardProps) {
orpc.printer.getResumeScreenshot.queryOptions({ input: { id: resume.id } }),
);
const imageSrc = screenshotData?.url;
const updatedAt = useMemo(() => {
return Intl.DateTimeFormat(i18n.locale, { dateStyle: "long", timeStyle: "short" }).format(resume.updatedAt);
}, [i18n.locale, resume.updatedAt]);
@@ -32,13 +30,13 @@ export function ResumeCard({ resume }: ResumeCardProps) {
<ResumeContextMenu resume={resume}>
<Link to="/builder/$resumeId" params={{ resumeId: resume.id }} className="cursor-default">
<BaseCard title={resume.name} description={t`Last updated on ${updatedAt}`} tags={resume.tags}>
{match({ isLoading, imageSrc })
{match({ isLoading, imageSrc: screenshotData?.url })
.with({ isLoading: true }, () => (
<div className="flex size-full items-center justify-center">
<CircleNotchIcon weight="thin" className="size-12 animate-spin" />
</div>
))
.with({ imageSrc: P.string }, () => (
.with({ imageSrc: P.string }, ({ imageSrc }) => (
<img
src={imageSrc}
alt={resume.name}
+9
View File
@@ -58,3 +58,12 @@ export function generateRandomName() {
length: 3,
});
}
/**
* Strips HTML tags from a string and returns the text content.
* @param html - The HTML string to strip.
* @returns The text content without HTML tags.
*/
export function stripHtml(html: string) {
return html.replace(/<[^>]*>/g, "").trim();
}