mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-13 22:37:14 +10:00
fixes #2727
This commit is contained in:
@@ -55,114 +55,129 @@ function renderItemByType(type: CustomSectionType, item: CustomSectionItem, item
|
||||
.exhaustive();
|
||||
}
|
||||
|
||||
type SectionProps = { id: string };
|
||||
|
||||
export function getSectionComponent(
|
||||
section: "summary" | SectionType | (string & {}),
|
||||
{ sectionClassName, itemClassName }: SectionComponentProps = {},
|
||||
) {
|
||||
return match(section)
|
||||
.with("summary", () => {
|
||||
const SummarySection = ({ id: _id }: { id: string }) => <PageSummary className={sectionClassName} />;
|
||||
const SummarySection = (_: SectionProps) => <PageSummary className={sectionClassName} />;
|
||||
|
||||
return SummarySection;
|
||||
})
|
||||
.with("profiles", () => {
|
||||
const ProfilesSection = ({ id: _id }: { id: string }) => (
|
||||
const ProfilesSection = (_: SectionProps) => (
|
||||
<PageSection type="profiles" className={sectionClassName}>
|
||||
{(item) => <ProfilesItem {...item} className={itemClassName} />}
|
||||
</PageSection>
|
||||
);
|
||||
|
||||
return ProfilesSection;
|
||||
})
|
||||
.with("experience", () => {
|
||||
const ExperienceSection = ({ id: _id }: { id: string }) => (
|
||||
const ExperienceSection = (_: SectionProps) => (
|
||||
<PageSection type="experience" className={sectionClassName}>
|
||||
{(item) => <ExperienceItem {...item} className={itemClassName} />}
|
||||
</PageSection>
|
||||
);
|
||||
|
||||
return ExperienceSection;
|
||||
})
|
||||
.with("education", () => {
|
||||
const EducationSection = ({ id: _id }: { id: string }) => (
|
||||
const EducationSection = (_: SectionProps) => (
|
||||
<PageSection type="education" className={sectionClassName}>
|
||||
{(item) => <EducationItem {...item} className={itemClassName} />}
|
||||
</PageSection>
|
||||
);
|
||||
|
||||
return EducationSection;
|
||||
})
|
||||
.with("projects", () => {
|
||||
const ProjectsSection = ({ id: _id }: { id: string }) => (
|
||||
const ProjectsSection = (_: SectionProps) => (
|
||||
<PageSection type="projects" className={sectionClassName}>
|
||||
{(item) => <ProjectsItem {...item} className={itemClassName} />}
|
||||
</PageSection>
|
||||
);
|
||||
|
||||
return ProjectsSection;
|
||||
})
|
||||
.with("skills", () => {
|
||||
const SkillsSection = ({ id: _id }: { id: string }) => (
|
||||
const SkillsSection = (_: SectionProps) => (
|
||||
<PageSection type="skills" className={sectionClassName}>
|
||||
{(item) => <SkillsItem {...item} className={itemClassName} />}
|
||||
</PageSection>
|
||||
);
|
||||
|
||||
return SkillsSection;
|
||||
})
|
||||
.with("languages", () => {
|
||||
const LanguagesSection = ({ id: _id }: { id: string }) => (
|
||||
const LanguagesSection = (_: SectionProps) => (
|
||||
<PageSection type="languages" className={sectionClassName}>
|
||||
{(item) => <LanguagesItem {...item} className={itemClassName} />}
|
||||
</PageSection>
|
||||
);
|
||||
|
||||
return LanguagesSection;
|
||||
})
|
||||
.with("interests", () => {
|
||||
const InterestsSection = ({ id: _id }: { id: string }) => (
|
||||
const InterestsSection = (_: SectionProps) => (
|
||||
<PageSection type="interests" className={sectionClassName}>
|
||||
{(item) => <InterestsItem {...item} className={itemClassName} />}
|
||||
</PageSection>
|
||||
);
|
||||
|
||||
return InterestsSection;
|
||||
})
|
||||
.with("awards", () => {
|
||||
const AwardsSection = ({ id: _id }: { id: string }) => (
|
||||
const AwardsSection = (_: SectionProps) => (
|
||||
<PageSection type="awards" className={sectionClassName}>
|
||||
{(item) => <AwardsItem {...item} className={itemClassName} />}
|
||||
</PageSection>
|
||||
);
|
||||
|
||||
return AwardsSection;
|
||||
})
|
||||
.with("certifications", () => {
|
||||
const CertificationsSection = ({ id: _id }: { id: string }) => (
|
||||
const CertificationsSection = (_: SectionProps) => (
|
||||
<PageSection type="certifications" className={sectionClassName}>
|
||||
{(item) => <CertificationsItem {...item} className={itemClassName} />}
|
||||
</PageSection>
|
||||
);
|
||||
|
||||
return CertificationsSection;
|
||||
})
|
||||
.with("publications", () => {
|
||||
const PublicationsSection = ({ id: _id }: { id: string }) => (
|
||||
const PublicationsSection = (_: SectionProps) => (
|
||||
<PageSection type="publications" className={sectionClassName}>
|
||||
{(item) => <PublicationsItem {...item} className={itemClassName} />}
|
||||
</PageSection>
|
||||
);
|
||||
|
||||
return PublicationsSection;
|
||||
})
|
||||
.with("volunteer", () => {
|
||||
const VolunteerSection = ({ id: _id }: { id: string }) => (
|
||||
const VolunteerSection = (_: SectionProps) => (
|
||||
<PageSection type="volunteer" className={sectionClassName}>
|
||||
{(item) => <VolunteerItem {...item} className={itemClassName} />}
|
||||
</PageSection>
|
||||
);
|
||||
|
||||
return VolunteerSection;
|
||||
})
|
||||
.with("references", () => {
|
||||
const ReferencesSection = ({ id: _id }: { id: string }) => (
|
||||
const ReferencesSection = (_: SectionProps) => (
|
||||
<PageSection type="references" className={sectionClassName}>
|
||||
{(item) => <ReferencesItem {...item} className={itemClassName} />}
|
||||
</PageSection>
|
||||
);
|
||||
|
||||
return ReferencesSection;
|
||||
})
|
||||
.otherwise(() => {
|
||||
// Custom section - render based on its type
|
||||
const CustomSectionComponent = ({ id }: { id: string }) => {
|
||||
const CustomSectionComponent = ({ id }: SectionProps) => {
|
||||
const customSection = useResumeStore((state) => state.resume.data.customSections.find((s) => s.id === id));
|
||||
|
||||
if (!customSection) return null;
|
||||
|
||||
@@ -11,15 +11,10 @@ type PageSummaryProps = {
|
||||
export function PageSummary({ className }: PageSummaryProps) {
|
||||
const section = useResumeStore((state) => state.resume.data.summary);
|
||||
|
||||
if (section.hidden || !stripHtml(section.content)) return null;
|
||||
|
||||
return (
|
||||
<section
|
||||
className={cn(
|
||||
"page-section page-section-summary",
|
||||
section.hidden && "hidden",
|
||||
!stripHtml(section.content) && "hidden",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<section className={cn("page-section page-section-summary", className)}>
|
||||
<h6 className="mb-1.5 text-(--page-primary-color)">{section.title || getSectionTitle("summary")}</h6>
|
||||
|
||||
<div className="section-content">
|
||||
|
||||
@@ -29,10 +29,6 @@ export function DitgarTemplate({ pageIndex, pageLayout }: TemplateProps) {
|
||||
const isFirstPage = pageIndex === 0;
|
||||
const { main, sidebar, fullWidth } = pageLayout;
|
||||
|
||||
const SummaryComponent = getSectionComponent("summary", {
|
||||
sectionClassName: cn(sectionClassName, "px-(--page-margin-x) pt-(--page-margin-y)"),
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="template-ditgar page-content">
|
||||
{/* Sidebar Background */}
|
||||
@@ -55,15 +51,11 @@ export function DitgarTemplate({ pageIndex, pageLayout }: TemplateProps) {
|
||||
)}
|
||||
|
||||
<main data-layout="main" className={cn("main group z-10", !fullWidth ? "col-span-2" : "col-span-3")}>
|
||||
{isFirstPage && <SummaryComponent id="summary" />}
|
||||
|
||||
<div className="space-y-4 px-(--page-margin-x) pt-(--page-margin-y)">
|
||||
{main
|
||||
.filter((section) => section !== "summary")
|
||||
.map((section) => {
|
||||
const Component = getSectionComponent(section, { sectionClassName });
|
||||
return <Component key={section} id={section} />;
|
||||
})}
|
||||
{main.map((section) => {
|
||||
const Component = getSectionComponent(section, { sectionClassName });
|
||||
return <Component key={section} id={section} />;
|
||||
})}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BetterAuthError } from "@better-auth/core/error";
|
||||
import { BetterAuthError } from "better-auth";
|
||||
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
||||
import { betterAuth } from "better-auth/minimal";
|
||||
import { apiKey, type GenericOAuthConfig, genericOAuth, openAPI, twoFactor } from "better-auth/plugins";
|
||||
|
||||
@@ -153,6 +153,7 @@ export const printerService = {
|
||||
|
||||
// Now measure the total height (margins are now part of the DOM)
|
||||
let totalHeight = 0;
|
||||
|
||||
for (const el of pageElements) {
|
||||
const pageEl = el as HTMLElement;
|
||||
// offsetHeight includes padding and border, but not margin
|
||||
@@ -164,23 +165,13 @@ export const printerService = {
|
||||
return Math.max(totalHeight, minPageHeight);
|
||||
}
|
||||
|
||||
// For A4/Letter: existing behavior
|
||||
// The --page-height CSS variable controls the height of each resume page.
|
||||
// We need to reduce it by the PDF margins so content fits within the printable area.
|
||||
// Without this, content would overflow and create empty pages.
|
||||
const rootHeight = getComputedStyle(root).getPropertyValue("--page-height").trim();
|
||||
const containerHeight = container
|
||||
? getComputedStyle(container).getPropertyValue("--page-height").trim()
|
||||
: null;
|
||||
const currentHeight = containerHeight || rootHeight;
|
||||
const heightValue = Math.min(Number.parseFloat(currentHeight), minPageHeight);
|
||||
// For A4/Letter
|
||||
const heightValue = minPageHeight;
|
||||
|
||||
if (!Number.isNaN(heightValue)) {
|
||||
// Subtract top + bottom margins from page height
|
||||
const newHeight = `${heightValue - marginY}px`;
|
||||
if (container) container.style.setProperty("--page-height", newHeight);
|
||||
root.style.setProperty("--page-height", newHeight);
|
||||
}
|
||||
// Subtract top + bottom margins from page height
|
||||
const newHeight = `${heightValue - marginY}px`;
|
||||
if (container) container.style.setProperty("--page-height", newHeight);
|
||||
root.style.setProperty("--page-height", newHeight);
|
||||
|
||||
// Add page break CSS to each resume page element (identified by data-page-index attribute)
|
||||
// This ensures each visual resume page starts a new PDF page
|
||||
|
||||
@@ -25,9 +25,9 @@ function RouteComponent() {
|
||||
queryKey: ["auth", "api-keys"],
|
||||
queryFn: () => authClient.apiKey.list(),
|
||||
select: ({ data }) => {
|
||||
if (!data?.apiKeys) return [];
|
||||
if (!data) return [];
|
||||
|
||||
return data.apiKeys
|
||||
return data
|
||||
.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())
|
||||
.filter((key) => !!key.expiresAt && key.expiresAt.getTime() > Date.now());
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user