mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-11 05:24:59 +10:00
fix(#2978): implement inlineLink functionality
This commit is contained in:
@@ -121,8 +121,7 @@ export function RichInput({ value, onChange, style, className, editorClassName,
|
||||
"data-editor": "true",
|
||||
"data-fullscreen": isFullscreen ? "true" : "false",
|
||||
class: cn(
|
||||
"group/editor overflow-y-auto p-3 pb-4",
|
||||
"prose prose-sm prose-zinc dark:prose-invert max-w-none",
|
||||
"wysiwyg group/editor overflow-y-auto p-3 pb-4",
|
||||
"rounded-md rounded-t-none border outline-none focus-visible:border-ring",
|
||||
"[td:has(.selectedCell)]:bg-primary",
|
||||
"data-[fullscreen=false]:max-h-[400px] data-[fullscreen=false]:min-h-[100px]",
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { getInlineItemWebsiteUrl, shouldRenderSeparateItemWebsite } from "./section-links";
|
||||
|
||||
describe("section item website links", () => {
|
||||
test("uses inline website URL and suppresses the separate website link when inlineLink is true", () => {
|
||||
const website = {
|
||||
url: "https://example.com/company",
|
||||
label: "example.com/company",
|
||||
inlineLink: true,
|
||||
};
|
||||
|
||||
expect(getInlineItemWebsiteUrl(website)).toBe("https://example.com/company");
|
||||
expect(shouldRenderSeparateItemWebsite(website)).toBe(false);
|
||||
});
|
||||
|
||||
test("renders the website separately when inlineLink is false", () => {
|
||||
const website = {
|
||||
url: "https://example.com/company",
|
||||
label: "example.com/company",
|
||||
inlineLink: false,
|
||||
};
|
||||
|
||||
expect(getInlineItemWebsiteUrl(website)).toBeUndefined();
|
||||
expect(shouldRenderSeparateItemWebsite(website)).toBe(true);
|
||||
});
|
||||
|
||||
test("does not create an inline or separate link without a URL", () => {
|
||||
const website = {
|
||||
url: "",
|
||||
label: "",
|
||||
inlineLink: true,
|
||||
};
|
||||
|
||||
expect(getInlineItemWebsiteUrl(website)).toBeUndefined();
|
||||
expect(shouldRenderSeparateItemWebsite(website)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
import type { Website } from "@reactive-resume/schema/resume/data";
|
||||
|
||||
type ItemWebsite = Website & {
|
||||
inlineLink?: boolean | undefined;
|
||||
};
|
||||
|
||||
export const getInlineItemWebsiteUrl = (website: ItemWebsite): string | undefined => {
|
||||
if (!website.url || !website.inlineLink) return undefined;
|
||||
|
||||
return website.url;
|
||||
};
|
||||
|
||||
export const shouldRenderSeparateItemWebsite = (website: ItemWebsite): boolean => {
|
||||
return Boolean(website.url && !website.inlineLink);
|
||||
};
|
||||
@@ -38,6 +38,7 @@ 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 { composeStyles } from "./styles";
|
||||
|
||||
type SectionItemsContextValue = {
|
||||
@@ -206,6 +207,27 @@ const SectionItemHeader = ({ children }: { children: ReactNode }) => {
|
||||
return <View style={composeStyles(sectionItemHeaderStyle)}>{children}</View>;
|
||||
};
|
||||
|
||||
type ItemWebsite = {
|
||||
url: string;
|
||||
label: string;
|
||||
inlineLink?: boolean | undefined;
|
||||
};
|
||||
|
||||
const ItemTitle = ({ children, website }: { children: ReactNode; website: ItemWebsite }) => {
|
||||
const inlineWebsiteUrl = getInlineItemWebsiteUrl(website);
|
||||
const title = <Bold>{children}</Bold>;
|
||||
|
||||
if (!inlineWebsiteUrl) return title;
|
||||
|
||||
return <Link src={inlineWebsiteUrl}>{title}</Link>;
|
||||
};
|
||||
|
||||
const ItemWebsiteLink = ({ website }: { website: ItemWebsite }) => {
|
||||
if (!shouldRenderSeparateItemWebsite(website)) return null;
|
||||
|
||||
return <Link src={website.url}>{website.label || website.url}</Link>;
|
||||
};
|
||||
|
||||
const SummarySection = ({ showHeading = true }: { showHeading?: boolean } = {}) => {
|
||||
const data = useRender();
|
||||
const { summary } = data;
|
||||
@@ -272,9 +294,7 @@ const ProfileSection = ({
|
||||
<Bold>{item.network}</Bold>
|
||||
</View>
|
||||
</SectionItemHeader>
|
||||
<Link src={item.website.url}>
|
||||
<Text>{item.username}</Text>
|
||||
</Link>
|
||||
<Link src={item.website.url}>{item.username}</Link>
|
||||
</SectionItem>
|
||||
))}
|
||||
</SectionItems>
|
||||
@@ -316,7 +336,7 @@ const ExperienceSection = ({
|
||||
</Text>
|
||||
) : null
|
||||
}
|
||||
middle={<Bold>{item.company}</Bold>}
|
||||
middle={<ItemTitle website={item.website}>{item.company}</ItemTitle>}
|
||||
trailing={<Text style={composeStyles(alignRightStyle)}>{item.period}</Text>}
|
||||
/>
|
||||
);
|
||||
@@ -324,7 +344,7 @@ const ExperienceSection = ({
|
||||
const renderSplitHeader = () => (
|
||||
<>
|
||||
<View style={composeStyles(splitRowStyle)}>
|
||||
<Bold>{item.company}</Bold>
|
||||
<ItemTitle website={item.website}>{item.company}</ItemTitle>
|
||||
<Text style={composeStyles(alignRightStyle)}>{item.location}</Text>
|
||||
</View>
|
||||
|
||||
@@ -355,11 +375,7 @@ const ExperienceSection = ({
|
||||
|
||||
{item.roles.length === 0 && <RichText>{item.description}</RichText>}
|
||||
|
||||
{item.website.url && (
|
||||
<Link src={item.website.url}>
|
||||
<Small>{item.website.label || item.website.url}</Small>
|
||||
</Link>
|
||||
)}
|
||||
<ItemWebsiteLink website={item.website} />
|
||||
</SectionItem>
|
||||
);
|
||||
})}
|
||||
@@ -406,7 +422,7 @@ const EducationSection = ({
|
||||
</Text>
|
||||
) : null
|
||||
}
|
||||
middle={<Bold>{item.school}</Bold>}
|
||||
middle={<ItemTitle website={item.website}>{item.school}</ItemTitle>}
|
||||
trailing={<Text style={composeStyles(alignRightStyle)}>{item.period}</Text>}
|
||||
/>
|
||||
{gradeAndLocation && <Text>{gradeAndLocation}</Text>}
|
||||
@@ -416,7 +432,7 @@ const EducationSection = ({
|
||||
const renderSplitHeader = () => (
|
||||
<>
|
||||
<View style={composeStyles(splitRowStyle)}>
|
||||
<Bold>{item.school}</Bold>
|
||||
<ItemTitle website={item.website}>{item.school}</ItemTitle>
|
||||
<Text style={composeStyles(alignRightStyle)}>{degreeAndGrade}</Text>
|
||||
</View>
|
||||
|
||||
@@ -433,11 +449,7 @@ const EducationSection = ({
|
||||
|
||||
<RichText>{item.description}</RichText>
|
||||
|
||||
{item.website.url && (
|
||||
<Link src={item.website.url}>
|
||||
<Small>{item.website.label || item.website.url}</Small>
|
||||
</Link>
|
||||
)}
|
||||
<ItemWebsiteLink website={item.website} />
|
||||
</SectionItem>
|
||||
);
|
||||
})}
|
||||
@@ -468,18 +480,14 @@ const ProjectsSection = ({
|
||||
<SectionItem key={item.id}>
|
||||
<SectionItemHeader>
|
||||
<View style={composeStyles(splitRowStyle)}>
|
||||
<Bold>{item.name}</Bold>
|
||||
<ItemTitle website={item.website}>{item.name}</ItemTitle>
|
||||
<Text style={composeStyles(alignRightStyle)}>{item.period}</Text>
|
||||
</View>
|
||||
</SectionItemHeader>
|
||||
|
||||
<RichText>{item.description}</RichText>
|
||||
|
||||
{item.website.url && (
|
||||
<Link src={item.website.url}>
|
||||
<Small>{item.website.label || item.website.url}</Small>
|
||||
</Link>
|
||||
)}
|
||||
<ItemWebsiteLink website={item.website} />
|
||||
</SectionItem>
|
||||
))}
|
||||
</SectionItems>
|
||||
@@ -610,17 +618,13 @@ const AwardsSection = ({
|
||||
{items.map((item) => (
|
||||
<SectionItem key={item.id}>
|
||||
<SectionItemHeader>
|
||||
<Bold>{item.title}</Bold>
|
||||
<ItemTitle website={item.website}>{item.title}</ItemTitle>
|
||||
<Text>{item.awarder}</Text>
|
||||
<Small>{item.date}</Small>
|
||||
</SectionItemHeader>
|
||||
<RichText>{item.description}</RichText>
|
||||
|
||||
{item.website.url && (
|
||||
<Link src={item.website.url}>
|
||||
<Small>{item.website.label || item.website.url}</Small>
|
||||
</Link>
|
||||
)}
|
||||
<ItemWebsiteLink website={item.website} />
|
||||
</SectionItem>
|
||||
))}
|
||||
</SectionItems>
|
||||
@@ -647,17 +651,13 @@ const CertificationsSection = ({
|
||||
{items.map((item) => (
|
||||
<SectionItem key={item.id}>
|
||||
<SectionItemHeader>
|
||||
<Bold>{item.title}</Bold>
|
||||
<ItemTitle website={item.website}>{item.title}</ItemTitle>
|
||||
<Text>{item.issuer}</Text>
|
||||
<Small>{item.date}</Small>
|
||||
</SectionItemHeader>
|
||||
<RichText>{item.description}</RichText>
|
||||
|
||||
{item.website.url && (
|
||||
<Link src={item.website.url}>
|
||||
<Small>{item.website.label || item.website.url}</Small>
|
||||
</Link>
|
||||
)}
|
||||
<ItemWebsiteLink website={item.website} />
|
||||
</SectionItem>
|
||||
))}
|
||||
</SectionItems>
|
||||
@@ -684,17 +684,13 @@ const PublicationsSection = ({
|
||||
{items.map((item) => (
|
||||
<SectionItem key={item.id}>
|
||||
<SectionItemHeader>
|
||||
<Bold>{item.title}</Bold>
|
||||
<ItemTitle website={item.website}>{item.title}</ItemTitle>
|
||||
<Text>{item.publisher}</Text>
|
||||
<Small>{item.date}</Small>
|
||||
</SectionItemHeader>
|
||||
<RichText>{item.description}</RichText>
|
||||
|
||||
{item.website.url && (
|
||||
<Link src={item.website.url}>
|
||||
<Small>{item.website.label || item.website.url}</Small>
|
||||
</Link>
|
||||
)}
|
||||
<ItemWebsiteLink website={item.website} />
|
||||
</SectionItem>
|
||||
))}
|
||||
</SectionItems>
|
||||
@@ -727,13 +723,13 @@ const VolunteerSection = ({
|
||||
{inlineItemHeader ? (
|
||||
<InlineItemHeader
|
||||
leading={<Text>{item.location}</Text>}
|
||||
middle={<Bold>{item.organization}</Bold>}
|
||||
middle={<ItemTitle website={item.website}>{item.organization}</ItemTitle>}
|
||||
trailing={<Text style={composeStyles(alignRightStyle)}>{item.period}</Text>}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<View style={composeStyles(splitRowStyle)}>
|
||||
<Bold>{item.organization}</Bold>
|
||||
<ItemTitle website={item.website}>{item.organization}</ItemTitle>
|
||||
<Text style={composeStyles(alignRightStyle)}>{item.location}</Text>
|
||||
</View>
|
||||
|
||||
@@ -743,11 +739,7 @@ const VolunteerSection = ({
|
||||
</SectionItemHeader>
|
||||
<RichText>{item.description}</RichText>
|
||||
|
||||
{item.website.url && (
|
||||
<Link src={item.website.url}>
|
||||
<Small>{item.website.label || item.website.url}</Small>
|
||||
</Link>
|
||||
)}
|
||||
<ItemWebsiteLink website={item.website} />
|
||||
</SectionItem>
|
||||
))}
|
||||
</SectionItems>
|
||||
@@ -774,17 +766,13 @@ const ReferencesSection = ({
|
||||
{items.map((item) => (
|
||||
<SectionItem key={item.id}>
|
||||
<SectionItemHeader>
|
||||
<Bold>{item.name}</Bold>
|
||||
<ItemTitle website={item.website}>{item.name}</ItemTitle>
|
||||
<Text>{item.position}</Text>
|
||||
<MetaLine>{[item.phone]}</MetaLine>
|
||||
</SectionItemHeader>
|
||||
<RichText>{item.description}</RichText>
|
||||
|
||||
{item.website.url && (
|
||||
<Link src={item.website.url}>
|
||||
<Small>{item.website.label || item.website.url}</Small>
|
||||
</Link>
|
||||
)}
|
||||
<ItemWebsiteLink website={item.website} />
|
||||
</SectionItem>
|
||||
))}
|
||||
</SectionItems>
|
||||
|
||||
@@ -152,6 +152,10 @@
|
||||
[role="button"]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.wysiwyg {
|
||||
@apply prose prose-sm prose-zinc dark:prose-invert max-w-none prose-p:my-0! prose-li:my-0! prose-ul:my-0! prose-ol:my-0!;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
|
||||
Reference in New Issue
Block a user