mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-14 06:47:00 +10:00
- fixes #2598
This commit is contained in:
@@ -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,
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user