mirror of
https://github.com/JOYCEQL/magic-resume.git
synced 2026-06-02 07:43:34 +02:00
style: education preview
This commit is contained in:
@@ -3,7 +3,7 @@ import { Education, GlobalSettings } from "@/types/resume";
|
||||
import SectionTitle from "./SectionTitle";
|
||||
import SectionWrapper from "../../shared/SectionWrapper";
|
||||
import { useLocale } from "@/i18n/compat/client";
|
||||
import { normalizeRichTextContent } from "@/lib/richText";
|
||||
import { hasMeaningfulRichTextContent, normalizeRichTextContent } from "@/lib/richText";
|
||||
import { formatDateString } from "@/lib/utils";
|
||||
|
||||
interface EducationSectionProps {
|
||||
@@ -25,7 +25,7 @@ const EducationSection = ({ education, globalSettings, showTitle = true }: Educa
|
||||
{visibleEducation?.map((edu) => (
|
||||
<motion.div key={edu.id} layout="position" style={{ marginTop: `${globalSettings?.paragraphSpacing}px` }}>
|
||||
<motion.div layout="position" className="flex items-center gap-2">
|
||||
<div className={`font-bold ${flexLayout ? "" : "flex-1"}`} style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>
|
||||
<div className={`font-bold ${flexLayout ? "" : "flex-[1.5]"}`} style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>
|
||||
{edu.school}
|
||||
</div>
|
||||
{centerSubtitle && (
|
||||
@@ -45,7 +45,7 @@ const EducationSection = ({ education, globalSettings, showTitle = true }: Educa
|
||||
{edu.gpa && ` · GPA ${edu.gpa}`}
|
||||
</motion.div>
|
||||
)}
|
||||
{edu.description && (
|
||||
{hasMeaningfulRichTextContent(edu.description) && (
|
||||
<motion.div layout="position" className="mt-1 text-baseFont"
|
||||
style={{ fontSize: `${globalSettings?.baseFontSize || 14}px`, lineHeight: globalSettings?.lineHeight || 1.6 }}
|
||||
dangerouslySetInnerHTML={{ __html: normalizeRichTextContent(edu.description) }}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Education, GlobalSettings } from "@/types/resume";
|
||||
import SectionTitle from "./SectionTitle";
|
||||
import SectionWrapper from "../../shared/SectionWrapper";
|
||||
import { useLocale } from "@/i18n/compat/client";
|
||||
import { normalizeRichTextContent } from "@/lib/richText";
|
||||
import { hasMeaningfulRichTextContent, normalizeRichTextContent } from "@/lib/richText";
|
||||
import { formatDateString } from "@/lib/utils";
|
||||
|
||||
interface EducationSectionProps {
|
||||
@@ -25,7 +25,7 @@ const EducationSection = ({ education, globalSettings, showTitle = true }: Educa
|
||||
{visibleEducation?.map((edu) => (
|
||||
<motion.div key={edu.id} layout="position" style={{ marginTop: `${globalSettings?.paragraphSpacing}px` }}>
|
||||
<motion.div layout="position" className="flex items-center gap-2">
|
||||
<div className={`font-bold ${flexLayout ? "" : "flex-1"}`} style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>
|
||||
<div className={`font-bold ${flexLayout ? "" : "flex-[1.5]"}`} style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>
|
||||
{edu.school}
|
||||
</div>
|
||||
{centerSubtitle && (
|
||||
@@ -45,7 +45,7 @@ const EducationSection = ({ education, globalSettings, showTitle = true }: Educa
|
||||
{edu.gpa && ` · GPA ${edu.gpa}`}
|
||||
</motion.div>
|
||||
)}
|
||||
{edu.description && (
|
||||
{hasMeaningfulRichTextContent(edu.description) && (
|
||||
<motion.div layout="position" className="mt-1 text-baseFont"
|
||||
style={{ fontSize: `${globalSettings?.baseFontSize || 14}px`, lineHeight: globalSettings?.lineHeight || 1.6 }}
|
||||
dangerouslySetInnerHTML={{ __html: normalizeRichTextContent(edu.description) }}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Education, GlobalSettings } from "@/types/resume";
|
||||
import SectionTitle from "./SectionTitle";
|
||||
import SectionWrapper from "../../shared/SectionWrapper";
|
||||
import { useLocale } from "@/i18n/compat/client";
|
||||
import { normalizeRichTextContent } from "@/lib/richText";
|
||||
import { hasMeaningfulRichTextContent, normalizeRichTextContent } from "@/lib/richText";
|
||||
import { formatDateString } from "@/lib/utils";
|
||||
|
||||
interface EducationSectionProps {
|
||||
@@ -25,7 +25,7 @@ const EducationSection = ({ education, globalSettings, showTitle = true }: Educa
|
||||
{visibleEducation?.map((edu) => (
|
||||
<motion.div key={edu.id} layout="position" style={{ marginTop: `${globalSettings?.paragraphSpacing}px` }}>
|
||||
<motion.div layout="position" className="flex items-center gap-2">
|
||||
<div className={`font-bold ${flexLayout ? "" : "flex-1"}`} style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>
|
||||
<div className={`font-bold ${flexLayout ? "" : "flex-[1.5]"}`} style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>
|
||||
{edu.school}
|
||||
</div>
|
||||
{centerSubtitle && (
|
||||
@@ -45,7 +45,7 @@ const EducationSection = ({ education, globalSettings, showTitle = true }: Educa
|
||||
{edu.gpa && ` · GPA ${edu.gpa}`}
|
||||
</motion.div>
|
||||
)}
|
||||
{edu.description && (
|
||||
{hasMeaningfulRichTextContent(edu.description) && (
|
||||
<motion.div layout="position" className="mt-1 text-baseFont"
|
||||
style={{ fontSize: `${globalSettings?.baseFontSize || 14}px`, lineHeight: globalSettings?.lineHeight || 1.6 }}
|
||||
dangerouslySetInnerHTML={{ __html: normalizeRichTextContent(edu.description) }}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Education, GlobalSettings } from "@/types/resume";
|
||||
import SectionTitle from "./SectionTitle";
|
||||
import SectionWrapper from "../../shared/SectionWrapper";
|
||||
import { useLocale } from "@/i18n/compat/client";
|
||||
import { normalizeRichTextContent } from "@/lib/richText";
|
||||
import { hasMeaningfulRichTextContent, normalizeRichTextContent } from "@/lib/richText";
|
||||
import { formatDateString } from "@/lib/utils";
|
||||
|
||||
interface EducationSectionProps {
|
||||
@@ -25,7 +25,7 @@ const EducationSection = ({ education, globalSettings, showTitle = true }: Educa
|
||||
{visibleEducation?.map((edu) => (
|
||||
<motion.div key={edu.id} layout="position" style={{ marginTop: `${globalSettings?.paragraphSpacing}px` }}>
|
||||
<motion.div layout="position" className="flex items-center gap-2">
|
||||
<div className={`font-bold ${flexLayout ? "" : "flex-1"}`} style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>
|
||||
<div className={`font-bold ${flexLayout ? "" : "flex-[1.5]"}`} style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>
|
||||
{edu.school}
|
||||
</div>
|
||||
{centerSubtitle && (
|
||||
@@ -45,7 +45,7 @@ const EducationSection = ({ education, globalSettings, showTitle = true }: Educa
|
||||
{edu.gpa && ` · GPA ${edu.gpa}`}
|
||||
</motion.div>
|
||||
)}
|
||||
{edu.description && (
|
||||
{hasMeaningfulRichTextContent(edu.description) && (
|
||||
<motion.div layout="position" className="mt-1 text-baseFont"
|
||||
style={{ fontSize: `${globalSettings?.baseFontSize || 14}px`, lineHeight: globalSettings?.lineHeight || 1.6 }}
|
||||
dangerouslySetInnerHTML={{ __html: normalizeRichTextContent(edu.description) }}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Education, GlobalSettings } from "@/types/resume";
|
||||
import SectionTitle from "./SectionTitle";
|
||||
import SectionWrapper from "../../shared/SectionWrapper";
|
||||
import { useLocale } from "@/i18n/compat/client";
|
||||
import { normalizeRichTextContent } from "@/lib/richText";
|
||||
import { hasMeaningfulRichTextContent, normalizeRichTextContent } from "@/lib/richText";
|
||||
import { formatDateString } from "@/lib/utils";
|
||||
|
||||
interface EducationSectionProps {
|
||||
@@ -25,7 +25,7 @@ const EducationSection = ({ education, globalSettings, showTitle = true }: Educa
|
||||
{visibleEducation?.map((edu) => (
|
||||
<motion.div key={edu.id} layout="position" style={{ marginTop: `${globalSettings?.paragraphSpacing}px` }}>
|
||||
<motion.div layout="position" className="flex items-center gap-2">
|
||||
<div className={`font-bold ${flexLayout ? "" : "flex-1"}`} style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>
|
||||
<div className={`font-bold ${flexLayout ? "" : "flex-[1.5]"}`} style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>
|
||||
{edu.school}
|
||||
</div>
|
||||
{centerSubtitle && (
|
||||
@@ -45,7 +45,7 @@ const EducationSection = ({ education, globalSettings, showTitle = true }: Educa
|
||||
{edu.gpa && ` · GPA ${edu.gpa}`}
|
||||
</motion.div>
|
||||
)}
|
||||
{edu.description && (
|
||||
{hasMeaningfulRichTextContent(edu.description) && (
|
||||
<motion.div layout="position" className="mt-1 text-baseFont"
|
||||
style={{ fontSize: `${globalSettings?.baseFontSize || 14}px`, lineHeight: globalSettings?.lineHeight || 1.6 }}
|
||||
dangerouslySetInnerHTML={{ __html: normalizeRichTextContent(edu.description) }}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Education, GlobalSettings } from "@/types/resume";
|
||||
import SectionTitle from "./SectionTitle";
|
||||
import SectionWrapper from "../../shared/SectionWrapper";
|
||||
import { useLocale } from "@/i18n/compat/client";
|
||||
import { normalizeRichTextContent } from "@/lib/richText";
|
||||
import { hasMeaningfulRichTextContent, normalizeRichTextContent } from "@/lib/richText";
|
||||
import { formatDateString, cn } from "@/lib/utils";
|
||||
|
||||
interface EducationSectionProps {
|
||||
@@ -57,7 +57,7 @@ const EducationSection = ({ education, globalSettings, showTitle = true, variant
|
||||
{edu.gpa && ` · GPA ${edu.gpa}`}
|
||||
</div>
|
||||
)}
|
||||
{edu.description && (
|
||||
{hasMeaningfulRichTextContent(edu.description) && (
|
||||
<motion.div layout="position" className={cn("mt-1 text-baseFont", isSidebar && " opacity-80")}
|
||||
style={{
|
||||
fontSize: `${isSidebar ? (globalSettings?.baseFontSize || 14) - 2 : (globalSettings?.baseFontSize || 14)}px`,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Education, GlobalSettings } from "@/types/resume";
|
||||
import SectionTitle from "./SectionTitle";
|
||||
import SectionWrapper from "../../shared/SectionWrapper";
|
||||
import { useLocale } from "@/i18n/compat/client";
|
||||
import { normalizeRichTextContent } from "@/lib/richText";
|
||||
import { hasMeaningfulRichTextContent, normalizeRichTextContent } from "@/lib/richText";
|
||||
import { formatDateString } from "@/lib/utils";
|
||||
|
||||
interface EducationSectionProps {
|
||||
@@ -25,7 +25,7 @@ const EducationSection = ({ education, globalSettings, showTitle = true }: Educa
|
||||
{visibleEducation?.map((edu) => (
|
||||
<motion.div key={edu.id} layout="position" style={{ marginTop: `${globalSettings?.paragraphSpacing}px` }}>
|
||||
<motion.div layout="position" className="flex items-center gap-2">
|
||||
<div className={`font-bold ${flexLayout ? "" : "flex-1"}`} style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>
|
||||
<div className={`font-bold ${flexLayout ? "" : "flex-[1.5]"}`} style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>
|
||||
{edu.school}
|
||||
</div>
|
||||
{centerSubtitle && (
|
||||
@@ -45,7 +45,7 @@ const EducationSection = ({ education, globalSettings, showTitle = true }: Educa
|
||||
{edu.gpa && ` · GPA ${edu.gpa}`}
|
||||
</motion.div>
|
||||
)}
|
||||
{edu.description && (
|
||||
{hasMeaningfulRichTextContent(edu.description) && (
|
||||
<motion.div layout="position" className="mt-1 text-baseFont"
|
||||
style={{ fontSize: `${globalSettings?.baseFontSize || 14}px`, lineHeight: globalSettings?.lineHeight || 1.6 }}
|
||||
dangerouslySetInnerHTML={{ __html: normalizeRichTextContent(edu.description) }}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
const HTML_TAG_REGEX = /<\/?[a-z][\s\S]*>/i;
|
||||
const EMPTY_PARAGRAPH_REGEX = /<p>(?:\s| |<br\s*\/?>)*<\/p>/gi;
|
||||
const HTML_BREAK_REGEX = /<br\s*\/?>/gi;
|
||||
const HTML_ANY_TAG_REGEX = /<\/?[^>]+>/g;
|
||||
const INVISIBLE_WHITESPACE_REGEX = /[\s\u200B-\u200D\uFEFF]/g;
|
||||
|
||||
const escapeHtml = (text: string) =>
|
||||
text
|
||||
@@ -23,3 +26,20 @@ export const normalizeRichTextContent = (content?: string) => {
|
||||
|
||||
return normalized.replace(EMPTY_PARAGRAPH_REGEX, "<p><br /></p>");
|
||||
};
|
||||
|
||||
export const hasMeaningfulRichTextContent = (content?: string) => {
|
||||
if (!content) return false;
|
||||
|
||||
if (!HTML_TAG_REGEX.test(content)) {
|
||||
return content.replace(INVISIBLE_WHITESPACE_REGEX, "").length > 0;
|
||||
}
|
||||
|
||||
const plainText = content
|
||||
.replace(EMPTY_PARAGRAPH_REGEX, "")
|
||||
.replace(HTML_BREAK_REGEX, "")
|
||||
.replace(/ /gi, " ")
|
||||
.replace(HTML_ANY_TAG_REGEX, "")
|
||||
.replace(INVISIBLE_WHITESPACE_REGEX, "");
|
||||
|
||||
return plainText.length > 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user