mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-06-22 04:11:55 +10:00
Fix split row right content promotion (#3039)
* Fix split row right content promotion Co-authored-by: Amruth Pillai <im.amruth@gmail.com> * refactor: remove MetaLine component and update sections to use Text instead --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
import { Small } from "./primitives";
|
||||
|
||||
export const MetaLine = ({ children }: { children: Array<string | undefined> }) => {
|
||||
const content = children.filter(Boolean).join(" • ");
|
||||
|
||||
if (!content) return null;
|
||||
|
||||
return <Small>{content}</Small>;
|
||||
};
|
||||
@@ -35,11 +35,11 @@ import {
|
||||
} from "./context";
|
||||
import { filterItems, hasVisibleItems, isSectionVisible, isVisibleSummary } from "./filtering";
|
||||
import { LevelDisplay } from "./level-display";
|
||||
import { MetaLine } from "./meta-line";
|
||||
import { getTemplateMetrics } from "./metrics";
|
||||
import { Bold, Div, Heading, Icon, Link, Small, Text } from "./primitives";
|
||||
import { RichText } from "./rich-text";
|
||||
import { getInlineItemWebsiteUrl, shouldRenderSeparateItemWebsite } from "./section-links";
|
||||
import { hasSplitRowText, promoteSplitRowRight } from "./split-row";
|
||||
import { composeStyles } from "./styles";
|
||||
|
||||
type SectionItemsContextValue = {
|
||||
@@ -195,8 +195,8 @@ const awardTitleDateRowStyle = {
|
||||
} satisfies Style;
|
||||
|
||||
const useSectionSplitRowStyle = () => {
|
||||
const splitRowStyle = useTemplateStyle("splitRow");
|
||||
const placement = useTemplatePlacement();
|
||||
const splitRowStyle = useTemplateStyle("splitRow");
|
||||
const stackSidebarItemHeader = useTemplateFeature("stackSidebarItemHeader");
|
||||
|
||||
return composeStyles(
|
||||
@@ -331,6 +331,10 @@ const ExperienceSection = ({
|
||||
{items.map((item) => {
|
||||
const hasPosition = Boolean(item.position.trim());
|
||||
const hasLocation = Boolean(item.location.trim());
|
||||
const { top: headerLocation, bottom: headerPeriod } = promoteSplitRowRight({
|
||||
top: item.location,
|
||||
bottom: item.period,
|
||||
});
|
||||
|
||||
const renderInlineHeader = () => (
|
||||
<InlineItemHeader
|
||||
@@ -352,13 +356,15 @@ const ExperienceSection = ({
|
||||
<>
|
||||
<View style={composeStyles(splitRowStyle)}>
|
||||
<ItemTitle website={item.website}>{item.company}</ItemTitle>
|
||||
<Text style={composeStyles(alignRightStyle)}>{item.location}</Text>
|
||||
{hasSplitRowText(headerLocation) && (
|
||||
<Text style={composeStyles(alignRightStyle)}>{headerLocation}</Text>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{item.roles.length === 0 && (
|
||||
{item.roles.length === 0 && (hasPosition || hasSplitRowText(headerPeriod)) && (
|
||||
<View style={composeStyles(splitRowStyle)}>
|
||||
<Text>{item.position}</Text>
|
||||
<Text style={composeStyles(alignRightStyle)}>{item.period}</Text>
|
||||
{hasPosition && <Text>{item.position}</Text>}
|
||||
{hasSplitRowText(headerPeriod) && <Text style={composeStyles(alignRightStyle)}>{headerPeriod}</Text>}
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
@@ -368,7 +374,7 @@ const ExperienceSection = ({
|
||||
<SectionItem key={item.id}>
|
||||
<SectionItemHeader>{inlineItemHeader ? renderInlineHeader() : renderSplitHeader()}</SectionItemHeader>
|
||||
|
||||
{item.roles.length > 0 && <MetaLine>{[item.period]}</MetaLine>}
|
||||
{item.roles.length > 0 && <Text>{item.period}</Text>}
|
||||
|
||||
{item.roles.map((role) => (
|
||||
<View key={role.id}>
|
||||
@@ -416,6 +422,10 @@ const EducationSection = ({
|
||||
const gradeAndLocation = [item.grade, item.location].filter(Boolean).join(" • ");
|
||||
const hasArea = Boolean(item.area.trim());
|
||||
const hasDegree = Boolean(item.degree.trim());
|
||||
const { top: headerDegreeAndGrade, bottom: headerLocationAndPeriod } = promoteSplitRowRight({
|
||||
top: degreeAndGrade,
|
||||
bottom: locationAndPeriod,
|
||||
});
|
||||
|
||||
const renderInlineHeader = () => (
|
||||
<>
|
||||
@@ -440,13 +450,19 @@ const EducationSection = ({
|
||||
<>
|
||||
<View style={composeStyles(splitRowStyle)}>
|
||||
<ItemTitle website={item.website}>{item.school}</ItemTitle>
|
||||
<Text style={composeStyles(alignRightStyle)}>{degreeAndGrade}</Text>
|
||||
{hasSplitRowText(headerDegreeAndGrade) && (
|
||||
<Text style={composeStyles(alignRightStyle)}>{headerDegreeAndGrade}</Text>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<View style={composeStyles(splitRowStyle)}>
|
||||
<Text>{item.area}</Text>
|
||||
<Text style={composeStyles(alignRightStyle)}>{locationAndPeriod}</Text>
|
||||
</View>
|
||||
{(hasArea || hasSplitRowText(headerLocationAndPeriod)) && (
|
||||
<View style={composeStyles(splitRowStyle)}>
|
||||
{hasArea && <Text>{item.area}</Text>}
|
||||
{hasSplitRowText(headerLocationAndPeriod) && (
|
||||
<Text style={composeStyles(alignRightStyle)}>{headerLocationAndPeriod}</Text>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -629,7 +645,7 @@ const AwardsSection = ({
|
||||
<SectionItemHeader>
|
||||
<View style={composeStyles(splitRowStyle, awardTitleDateRowStyle)}>
|
||||
<ItemTitle website={item.website}>{item.title}</ItemTitle>
|
||||
<Small style={composeStyles(alignRightStyle)}>{item.date}</Small>
|
||||
<Text style={composeStyles(alignRightStyle)}>{item.date}</Text>
|
||||
</View>
|
||||
<Text>{item.awarder}</Text>
|
||||
</SectionItemHeader>
|
||||
@@ -653,6 +669,8 @@ const CertificationsSection = ({
|
||||
const data = useRender();
|
||||
const certifications = sectionData ?? data.sections.certifications;
|
||||
const items = getVisibleItems(certifications, "certifications");
|
||||
const splitRowStyle = useSectionSplitRowStyle();
|
||||
const alignRightStyle = useTemplateStyle("alignRight");
|
||||
|
||||
if (items.length === 0) return null;
|
||||
|
||||
@@ -662,10 +680,13 @@ const CertificationsSection = ({
|
||||
{items.map((item) => (
|
||||
<SectionItem key={item.id}>
|
||||
<SectionItemHeader>
|
||||
<ItemTitle website={item.website}>{item.title}</ItemTitle>
|
||||
<View style={composeStyles(splitRowStyle)}>
|
||||
<ItemTitle website={item.website}>{item.title}</ItemTitle>
|
||||
<Text style={composeStyles(alignRightStyle)}>{item.date}</Text>
|
||||
</View>
|
||||
<Text>{item.issuer}</Text>
|
||||
<Small>{item.date}</Small>
|
||||
</SectionItemHeader>
|
||||
|
||||
<RichText>{item.description}</RichText>
|
||||
|
||||
<ItemWebsiteLink website={item.website} />
|
||||
@@ -686,6 +707,8 @@ const PublicationsSection = ({
|
||||
const data = useRender();
|
||||
const publications = sectionData ?? data.sections.publications;
|
||||
const items = getVisibleItems(publications, "publications");
|
||||
const splitRowStyle = useSectionSplitRowStyle();
|
||||
const alignRightStyle = useTemplateStyle("alignRight");
|
||||
|
||||
if (items.length === 0) return null;
|
||||
|
||||
@@ -695,10 +718,14 @@ const PublicationsSection = ({
|
||||
{items.map((item) => (
|
||||
<SectionItem key={item.id}>
|
||||
<SectionItemHeader>
|
||||
<ItemTitle website={item.website}>{item.title}</ItemTitle>
|
||||
<View style={composeStyles(splitRowStyle)}>
|
||||
<ItemTitle website={item.website}>{item.title}</ItemTitle>
|
||||
<Text style={composeStyles(alignRightStyle)}>{item.date}</Text>
|
||||
</View>
|
||||
|
||||
<Text>{item.publisher}</Text>
|
||||
<Small>{item.date}</Small>
|
||||
</SectionItemHeader>
|
||||
|
||||
<RichText>{item.description}</RichText>
|
||||
|
||||
<ItemWebsiteLink website={item.website} />
|
||||
@@ -728,31 +755,35 @@ const VolunteerSection = ({
|
||||
return (
|
||||
<SectionShell sectionId={sectionId} title={volunteer.title}>
|
||||
<SectionItems columns={volunteer.columns}>
|
||||
{items.map((item) => (
|
||||
<SectionItem key={item.id}>
|
||||
<SectionItemHeader>
|
||||
{inlineItemHeader ? (
|
||||
<InlineItemHeader
|
||||
leading={<Text>{item.location}</Text>}
|
||||
middle={<ItemTitle website={item.website}>{item.organization}</ItemTitle>}
|
||||
trailing={<Text style={composeStyles(alignRightStyle)}>{item.period}</Text>}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<View style={composeStyles(splitRowStyle)}>
|
||||
<ItemTitle website={item.website}>{item.organization}</ItemTitle>
|
||||
<Text style={composeStyles(alignRightStyle)}>{item.location}</Text>
|
||||
</View>
|
||||
{items.map((item) => {
|
||||
return (
|
||||
<SectionItem key={item.id}>
|
||||
<SectionItemHeader>
|
||||
{inlineItemHeader ? (
|
||||
<InlineItemHeader
|
||||
leading={hasSplitRowText(item.location) ? <Text>{item.location}</Text> : null}
|
||||
middle={<ItemTitle website={item.website}>{item.organization}</ItemTitle>}
|
||||
trailing={<Text style={composeStyles(alignRightStyle)}>{item.period}</Text>}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<View style={composeStyles(splitRowStyle)}>
|
||||
<ItemTitle website={item.website}>{item.organization}</ItemTitle>
|
||||
{hasSplitRowText(item.period) && (
|
||||
<Text style={composeStyles(alignRightStyle)}>{item.period}</Text>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<MetaLine>{[item.period]}</MetaLine>
|
||||
</>
|
||||
)}
|
||||
</SectionItemHeader>
|
||||
<RichText>{item.description}</RichText>
|
||||
<Text>{item.location}</Text>
|
||||
</>
|
||||
)}
|
||||
</SectionItemHeader>
|
||||
<RichText>{item.description}</RichText>
|
||||
|
||||
<ItemWebsiteLink website={item.website} />
|
||||
</SectionItem>
|
||||
))}
|
||||
<ItemWebsiteLink website={item.website} />
|
||||
</SectionItem>
|
||||
);
|
||||
})}
|
||||
</SectionItems>
|
||||
</SectionShell>
|
||||
);
|
||||
@@ -779,7 +810,7 @@ const ReferencesSection = ({
|
||||
<SectionItemHeader>
|
||||
<ItemTitle website={item.website}>{item.name}</ItemTitle>
|
||||
<Text>{item.position}</Text>
|
||||
<MetaLine>{[item.phone]}</MetaLine>
|
||||
<Text>{item.phone}</Text>
|
||||
</SectionItemHeader>
|
||||
<RichText>{item.description}</RichText>
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { hasSplitRowText, promoteSplitRowRight } from "./split-row";
|
||||
|
||||
describe("hasSplitRowText", () => {
|
||||
it("returns true only for non-empty text", () => {
|
||||
expect(hasSplitRowText("2019 - 2024")).toBe(true);
|
||||
expect(hasSplitRowText(" ")).toBe(false);
|
||||
expect(hasSplitRowText(undefined)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("promoteSplitRowRight", () => {
|
||||
it("keeps both right cells when the top-right cell has content", () => {
|
||||
expect(promoteSplitRowRight({ top: "Remote", bottom: "2019 - 2024" })).toEqual({
|
||||
top: "Remote",
|
||||
bottom: "2019 - 2024",
|
||||
});
|
||||
});
|
||||
|
||||
it("moves bottom-right content to the top right when top-right content is missing", () => {
|
||||
expect(promoteSplitRowRight({ top: "", bottom: "2019 - 2024" })).toEqual({ top: "2019 - 2024", bottom: "" });
|
||||
});
|
||||
|
||||
it("treats whitespace-only cells as missing", () => {
|
||||
expect(promoteSplitRowRight({ top: " ", bottom: "\t" })).toEqual({ top: "", bottom: "" });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
export const hasSplitRowText = (value: string | undefined): value is string => {
|
||||
return typeof value === "string" && value.trim().length > 0;
|
||||
};
|
||||
|
||||
type SplitRowContent = { top: string; bottom: string };
|
||||
|
||||
export const promoteSplitRowRight = ({ top, bottom }: SplitRowContent): SplitRowContent => {
|
||||
if (hasSplitRowText(top)) return { top, bottom: hasSplitRowText(bottom) ? bottom : "" };
|
||||
|
||||
return { top: hasSplitRowText(bottom) ? bottom : "", bottom: "" };
|
||||
};
|
||||
Reference in New Issue
Block a user