“에디터는 직관적인 숏코드로 빠르게 작성하고, 빌드 파이프라인은 검색엔진과 AI 에이전트를 위한 시맨틱 HTML5와 Schema.org JSON-LD를 100% 무결하게 컴파일한다.”
본 문서는 mktg.kr에 구축된 시맨틱 숏코드(MDX Custom Components) 시스템의 기획부터 아키텍처 설계 과정, 그리고 파트너사 및 자체 콘텐츠 에디터에서 즉시 연동할 수 있도록 차트(<Chart />)를 제외한 7대 핵심 시맨틱 숏코드의 전체 입력 규격과 라이브 렌더링 결과를 집대성한 엔지니어링 플레이북입니다.
(※ 데이터 시각화 차트 컴포넌트에 대한 상세 가이드는 시맨틱 데이터 시각화 차트(<Chart />) 시스템 기획 및 구축기 문서를 참조하세요.)
1. 시맨틱 숏코드 시스템 기획 배경 및 설계 철학
일반 마크다운(Markdown)은 문단(p), 제목(h2~h4), 리스트(ul/ol)를 빠르게 작성하는 데는 탁월하지만, 테크니컬 SEO와 생성형 엔진 최적화(GEO) 관점에서는 세 가지 구조적 한계를 지닙니다:
- 표준 마크다운 테이블의 접근성(A11y) 및 모바일 레이아웃 한계:
- 기본 마크다운 표(
| 컬럼 |)는<caption>,scope="col", 행 헤더(<th scope="row">) 속성을 지원하지 않으며, 모바일 화면에서 표가 깨지거나 카드 테두리가 본문 가독성을 해치는 문제가 발생합니다.
- 기본 마크다운 표(
- UI와 Schema.org 구조화 데이터(JSON-LD)의 이원화로 인한 휴먼 에러:
- 전문 기술 용어 설명을 위한 문맥 단절:
- 독자가 아티클을 읽다 생소한 기술 용어를 만났을 때 외부 검색으로 이탈하지 않도록, 본문 흐름을 깨지 않는 인라인 호버 툴팁과 용어사전 내부 링크 구조가 필요했습니다.
1.1 MKTG Edge 시맨틱 숏코드의 3대 핵심 원칙
- 원칙 1. Single Source of Truth (UI + JSON-LD 동시 컴파일): 에디터가 숏코드 속성(Props)에 값을 한 번만 입력하면, 시각적 모노그래프 UI 카드와 검색엔진용 Schema.org JSON-LD 스크립트가 동일한 데이터에서 동시에 생성됩니다.
- 원칙 2. Zero-JS 네이티브 웹 표준 우선: 테이블, FAQ 아코디언(
<details>/<summary>), 카드, 배지 등 모든 시맨틱 숏코드는 클라이언트 자바스크립트(0KB) 없이 순수 HTML5/CSS로 작동하여 Core Web Vitals(INP, CLS, LCP) 만점을 보장합니다. - 원칙 3. Zero-Import 전역 주입: 작성자가 파일 상단에 복잡한
import경로를 신경 쓰지 않고 본문 어디서나<SemanticTable />,<SemanticFAQ />태그를 바로 호출할 수 있도록 설계했습니다.
2. 전역 MDX 자동 주입 및 하이브리드 렌더링 아키텍처
mktg.kr에서 시맨틱 숏코드가 생성되고 페이지에 렌더링되기까지의 전체 파이프라인 구조입니다.
[1. 컴포넌트 모듈 계층 (src/components/semantic/)]
├── SemanticTable.astro (반응형 모노그래프 표 + sr-only caption + scope)
├── SemanticFAQ.astro (네이티브 <details> 아코디언 + FAQPage JSON-LD)
├── SoftwareCard.astro (제품 스펙 그리드 + SoftwareApplication JSON-LD)
├── PersonBadge.astro (저자/전문가 프로필 + Person JSON-LD)
├── YouTubeEmbed.astro (YouTube Lite Facade + oEmbed + VideoObject JSON-LD)
├── LinkCard.astro (외부 URL Open Graph 메타 자동 추출 + 북마크 카드)
├── Term.astro (인라인 용어사전 호버 툴팁 + /glossary/[slug] 링킹)
└── AutoLinkParagraph.astro / FigureImage.astro (문단 자동 링킹 & 이미지 <figure> 변환)
│
▼ (src/components/semantic/index.ts 배럴 모듈 통합 export)
[2. 라우트 템플릿 전역 주입 계층]
├── 블로그 상세: src/pages/blog/[slug].astro
└── Docs 상세: src/pages/docs/[...slug].astro
│ const mdxComponents = { SemanticTable, SemanticFAQ, FAQ, SoftwareCard, PersonBadge, YouTubeEmbed, YouTube, LinkCard, BookmarkCard, Term, ... }
│ <Content components={mdxComponents} />
▼
[3. 최종 빌드 산출물 (HTML5 + JSON-LD)]
2.1 구축 과정에서 해결한 핵심 엔지니어링 이슈
- Vite 개발 서버
@/별칭 Import 오류 해결 (Global Injection 전환):- 초기에는 각
.mdx문서 상단에import SemanticTable from '@/components/SemanticTable.astro'를 선언했으나, Astro Content Layer와 Vite 모듈 러너 환경에서 경로 해석 충돌이 발생했습니다. - 이를 해결하기 위해 동적 라우트(
[slug].astro,[...slug].astro)에서<Content components={mdxComponents} />형태로 모든 숏코드 컴포넌트를 사전 전역 주입하여, MDX 본문에서는import없이 순수 숏코드 태그만 사용하도록 표준화했습니다.
- 초기에는 각
- 로컬 MDX와 원격 CMS(Notion/Emdash) 하이브리드 렌더링 분기:
- 원격 마크다운은
marked파서와autoLinkGlossaryTerms()를 거치고, 로컬.mdx문서는 Astro의 네이티브render()파이프라인을 타도록 엄격히 분리하여 JSX 숏코드 컴포넌트가 문자열로 이스케이프되지 않고 온전한 HTML과 JSON-LD로 실행되도록 구현했습니다.
- 원격 마크다운은
- MDX 문단 내 자동 용어사전 링킹 (
AutoLinkParagraph,AutoLinkListItem):- 일반
<p>와<li>태그를 커스텀 시맨틱 래퍼로 오버라이드하여, 에디터가 별도 태그를 쓰지 않아도 본문 중 235개 등록 기술 용어가 최초 1회 자동으로 툴팁 링크로 변환되도록 구축했습니다.
- 일반
3. 7대 시맨틱 숏코드 컴포넌트 규격 및 라이브 데모
파트너사 또는 자체 콘텐츠 에디터에서 바로 생성·활용할 수 있는 7가지 시맨틱 숏코드(차트 제외) 의 전체 속성(Props) 명세와 실제 렌더링 결과입니다.
3.1 한눈에 보는 7대 숏코드 요약표
| 컴포넌트 태그 | 주요 용도 | 자동 주입되는 Schema.org / 메타 | 클라이언트 JS |
|---|---|---|---|
| <SemanticTable /> | 비교표, 벤치마크, 사양 매트릭스 | 시맨틱 <table>, <caption>, scope="col/row" | 0 KB (Zero-JS) |
| <SemanticFAQ /> (또는 <FAQ />) | 자주 묻는 질문 아코디언 (PAA/GEO 대응) | FAQPage, Question, Answer JSON-LD | 0 KB (Native <details>) |
| <SoftwareCard /> | 프레임워크, SaaS, 마케팅 툴 소개 및 평점 | SoftwareApplication, Offer, AggregateRating JSON-LD | 0 KB (Zero-JS) |
| <PersonBadge /> | 저자 바이라인, 전문가 인용구, 인터뷰이 프로필 | Person, Organization(worksFor), sameAs JSON-LD | 0 KB (Zero-JS) |
| <YouTubeEmbed /> (또는 <YouTube />) | YouTube 영상 임베딩 및 비디오 검색 최적화 | VideoObject JSON-LD + oEmbed 제목 자동 조회 | Lite Facade (클릭 시 로드) |
| <LinkCard /> (또는 <BookmarkCard />) | 외부/내부 URL 프리뷰 북마크 박스 | Open Graph (og:title, og:description, og:image) 자동 추출 | 0 KB (Zero-JS) |
| <Term /> | 본문 내 전문 기술 용어 호버 툴팁 및 사전 연결 | 용어사전 엔티티 링크 (/glossary/[slug]) | 전역 싱글톤 공유 |
3.2 ① 시맨틱 테이블 (<SemanticTable />)
외곽 박스 테두리와 불필요한 배경색을 제거하고, 상단 2px 블랙 헤어라인과 행 구분선만으로 정갈한 에디토리얼 가독성을 구현한 표 컴포넌트입니다.
📌 Props 입력 규격
caption(또는title)string: 표 상단에 노출되는 제목 라벨이자 검색엔진용<caption>텍스트headersstring[](필수): 열 제목 배열 (예:["구분", "기존 방식", "개선 방식"])rows(string | number)[][](필수): 2차원 행 데이터 배열. 각 행의 첫 번째 셀(cellIdx === 0)은 자동으로<th scope="row">로 승격되어 접근성을 높입니다.
📌 숏코드 작성 예시
<SemanticTable
caption="표 2: 모놀리식 CMS 대 Astro 하이브리드 헤드리스 아키텍처 비교"
headers={["비교 항목", "전통적 모놀리식 CMS", "Astro + Headless 하이브리드"]}
rows={[
["초기 응답 속도 (TTFB)", "600ms ~ 1,500ms (DB 쿼리 병목)", "50ms 미만 (글로벌 Edge 정적 서빙)"],
["자바스크립트 페이로드", "수백 KB (테마 및 플러그인 스크립트)", "기본 0 KB (필요한 아일랜드만 선택 로드)"],
["보안 공격 표면", "플러그인 및 런타임 RCE 상시 노출", "정적 HTML 서빙으로 오리진 공격 원천 차단"],
["구조화 데이터 관리", "서드파티 SEO 플러그인 의존", "시맨틱 컴포넌트 기반 JSON-LD 자동 컴파일"]
]}
/>
📌 실제 렌더링 결과
| 비교 항목 | 전통적 모놀리식 CMS | Astro + Headless 하이브리드 |
|---|---|---|
| 초기 응답 속도 (TTFB) | 600ms ~ 1,500ms (DB 쿼리 병목) | 50ms 미만 (글로벌 Edge 정적 서빙) |
| 자바스크립트 페이로드 | 수백 KB (테마 및 플러그인 스크립트) | 기본 0 KB (필요한 아일랜드만 선택 로드) |
| 보안 공격 표면 | 플러그인 및 런타임 RCE 상시 노출 | 정적 HTML 서빙으로 오리진 공격 원천 차단 |
| 구조화 데이터 관리 | 서드파티 SEO 플러그인 의존 | 시맨틱 컴포넌트 기반 JSON-LD 자동 컴파일 |
3.3 ② 시맨틱 FAQ 아코디언 (<SemanticFAQ /> 또는 <FAQ />)
구글 검색의 FAQ 리치 결과, PAA(People Also Ask) 박스, 그리고 ChatGPT·Perplexity 등 생성형 AI 답변 엔진(GEO) 이 질문-답변 쌍을 즉각 추출할 수 있도록 FAQPage Schema.org JSON-LD를 자동으로 생성·주입하는 아코디언 컴포넌트입니다.
- 네이티브 HTML5
<details>및<summary>요소를 사용하여 자바스크립트0KB로 동작하며, 접혀 있는 답변도 브라우저 페이지 내 검색(Ctrl+F) 시 자동으로 펼쳐집니다.
📌 Props 입력 규격
titlestring(선택, 기본값:"자주 묻는 질문 (FAQ)"): FAQ 섹션 상단 라벨subtitlestring(선택): 상단 보조 설명 텍스트itemsArray<{ question: string; answer: string; open?: boolean }>(필수): 질문(question)과 답변(answer) 객체 배열 (답변 내 간단한 HTML 태그 지원)exclusiveboolean(선택, 기본값:false):true로 설정하면 HTML5 표준<details name="...">속성이 활성화되어 한 번에 하나의 질문만 열리는 배타적 아코디언으로 작동합니다.defaultOpenFirstboolean(선택, 기본값:true): 첫 번째 질문을 기본으로 펼쳐둘지 여부
📌 숏코드 작성 예시
<SemanticFAQ
title="자주 묻는 질문 (FAQ) — 시맨틱 숏코드 연동"
subtitle="파트너 에디터 및 외부 CMS 연동 시 자주 문의하는 핵심 기술 사양"
exclusive={true}
items={[
{
question: "<SemanticFAQ />와 <FAQ /> 중 어떤 태그 이름을 써야 하나요?",
answer: "두 태그 모두 동일하게 작동합니다. 명시적인 이름을 선호하면 <code><SemanticFAQ /></code>를, 빠르고 간결한 숏코드 작성을 원하면 <code><FAQ /></code>를 사용하시면 됩니다."
},
{
question: "FAQPage JSON-LD 스키마를 별도로 페이지 상단에 또 작성해야 하나요?",
answer: "아닙니다. 컴포넌트에 전달된 <code>items</code> 배열을 기반으로 HTML 태그를 정제한 뒤, 표준 <code>FAQPage</code> JSON-LD 스크립트를 컴포넌트가 스스로 생성하여 주입합니다."
},
{
question: "아코디언이 닫혀 있으면 검색엔진 크롤러가 답변 내용을 무시하지 않나요?",
answer: "표준 HTML5 <code><details></code> 태그 내부의 콘텐츠는 초기 DOM에 완전히 존재하므로 Googlebot, Naver Yeti 및 AI 크롤러가 100% 정상 수집하며, 사용자의 페이지 내 텍스트 검색(Find in page) 시에도 브라우저가 자동으로 해당 항목을 열어줍니다."
}
]}
/>
📌 실제 렌더링 결과
파트너 에디터 및 외부 CMS 연동 시 자주 문의하는 핵심 기술 사양
Q1.<SemanticFAQ />와 <FAQ /> 중 어떤 태그 이름을 써야 하나요?
<SemanticFAQ />를, 빠르고 간결한 숏코드 작성을 원하면 <FAQ />를 사용하시면 됩니다.Q2.FAQPage JSON-LD 스키마를 별도로 페이지 상단에 또 작성해야 하나요?
items 배열을 기반으로 HTML 태그를 정제한 뒤, 표준 FAQPage JSON-LD 스크립트를 컴포넌트가 스스로 생성하여 주입합니다.Q3.아코디언이 닫혀 있으면 검색엔진 크롤러가 답변 내용을 무시하지 않나요?
<details> 태그 내부의 콘텐츠는 초기 DOM에 완전히 존재하므로 Googlebot, Naver Yeti 및 AI 크롤러가 100% 정상 수집하며, 사용자의 페이지 내 텍스트 검색(Find in page) 시에도 브라우저가 자동으로 해당 항목을 열어줍니다.3.4 ③ 소프트웨어 애플리케이션 카드 (<SoftwareCard />)
아티클에서 다루는 프레임워크, SaaS, SEO 분석 도구, 오픈소스 라이브러리의 핵심 제원과 평점을 요약해 보여주는 제품 카드입니다. 호출 시 SoftwareApplication, Offer, AggregateRating JSON-LD가 자동 삽입됩니다.
📌 Props 입력 규격
namestring(필수): 소프트웨어/솔루션 명칭 (예:"Astro")applicationCategory(또는category)string(선택, 기본값:"Web Development Application"): 제품 분류 카테고리operatingSystemstring(선택, 기본값:"Web / Cross-platform"): 구동 환경 및 OSpricestring(선택, 기본값:"Free"): 가격 정책 표기 (내부 숫자를 추출해Offer.price스키마에 자동 반영)ratingnumber | string(선택): 5점 만점 기준 평점 (예:"4.9"입력 시 우측 상단 별점 배지 및AggregateRating스키마 활성화)descriptionstring(선택): 제품 핵심 요약 설명urlstring(선택): 공식 웹사이트 링크logostring(선택): 로고 이미지 경로 (미입력 시 기본 아이콘 폴백)
📌 숏코드 작성 예시
<SoftwareCard
name="Astro"
applicationCategory="Web Framework"
operatingSystem="Node.js / Edge Runtime"
price="Free (MIT Open Source)"
rating="4.9"
logo="/images/logos/astro-icon.svg"
description="콘텐츠 중심 웹사이트를 위한 아일랜드 아키텍처(Islands Architecture) 기반 초고속 웹 프레임워크"
url="https://astro.build"
/>
📌 실제 렌더링 결과
Astro
Web Framework
콘텐츠 중심 웹사이트를 위한 아일랜드 아키텍처(Islands Architecture) 기반 초고속 웹 프레임워크
3.5 ④ 저자 및 전문가 배지 (<PersonBadge />)
아티클 본문 중간이나 하단에서 집필진, 감수자, 또는 인용된 업계 전문가의 신원(E-E-A-T)을 명확히 밝힐 때 사용하는 컴포넌트입니다. Person 스키마와 소속 기관(worksFor), 소셜 프로필(sameAs) JSON-LD를 자동으로 생성합니다.
📌 Props 입력 규격
namestring(필수): 인물 성명 (대표 저자인"정상원"입력 시src/lib/author.ts의 마스터 엔티티@id및 기본 프로필과 자동 연동)jobTitlestring(선택): 직책/직함 (예:"Head of Marketing Engineering")affiliationstring(선택): 소속 조직/기업명 (예:"MKTG Edge")avatarstring(선택): 프로필 이미지 경로 (미입력 시 이름 첫 글자 이니셜 아바타 자동 생성)urlstring(선택): 저자 소개 또는 공식 프로필 URLsameAsstring | string[](선택): LinkedIn, GitHub 등 동일인 검증용 외부 소셜 URL 배열
📌 숏코드 작성 예시
<PersonBadge
name="정상원"
jobTitle="Head of Marketing Engineering"
affiliation="MKTG Edge"
avatar="/images/authors/sangwon.jpeg"
url="https://mktg.kr/author/sangwon"
sameAs={["https://www.linkedin.com/in/jeongsangwon/"]}
/>
📌 실제 렌더링 결과
3.6 ⑤ 인라인 기술 용어 툴팁 (<Term /> / <GlossaryTooltip />)
mktg.kr의 용어사전(src/data/glossary.json, 235개 전문 용어) 데이터베이스와 실시간으로 바인딩되는 인라인 숏코드입니다. 마우스를 올리거나 모바일에서 탭하면 용어의 정의와 비즈니스 영향이 담긴 팝오버 카드가 나타납니다.
📌 Props 입력 규격
name(또는term)string: 용어사전에 등록된 한글 표준 용어명 또는 영문 약어 (예:"SSG","Core Web Vitals")slugstring(선택): 특정 용어 슬러그를 직접 지정할 때 사용 (예:"headless-content-management-system")children(내부 텍스트) (선택): 태그 사이에 원하는 문구를 넣으면 해당 문구에 툴팁이 걸리고, 비워두면(<Term name="SSG" />)name값이 그대로 출력됩니다.
📌 숏코드 작성 예시
모던 웹 퍼블리싱에서는 <Term name="SSG">정적 사이트 생성(SSG)</Term>과 <Term slug="headless-content-management-system">헤드리스 CMS</Term>를 결합하여 보안과 성능을 동시에 달성합니다.
📌 실제 렌더링 결과
모던 웹 퍼블리싱에서는 정적 사이트 생성(SSG)과 헤드리스 CMS를 결합하여 보안과 성능을 동시에 달성합니다.
3.7 ⑥ YouTube 비디오 임베드 (<YouTubeEmbed /> 또는 <YouTube />)
YouTube 영상 URL만 넣으면 영상 ID를 자동으로 추출하여 16:9 반응형 플레이어로 임베딩하고, 구글 동영상 검색 리치 결과를 위한 VideoObject Schema.org JSON-LD를 자동으로 생성·주입하는 컴포넌트입니다.
- oEmbed 메타데이터 자동 조회:
title이나author(채널명)를 생략해도 빌드/SSR 시점에 YouTube 공식 oEmbed API를 통해 영상 제목과 채널명을 자동으로 가져옵니다. - Lite Facade (Core Web Vitals 보호): 초기 로드 시 무거운 YouTube
<iframe>스크립트 대신 고화질 썸네일(maxresdefault.jpg)과 재생 버튼을 먼저 렌더링하고, 사용자가 클릭하는 순간 실제 플레이어를 로드하여 페이지 속도(LCP/INP/TBT) 저하를 원천 차단합니다.
📌 Props 입력 규격
urlstring(필수, 또는id지정): YouTube 영상 주소 (watch?v=...,youtu.be/...,shorts/...,embed/...모두 지원)titlestring(선택): 영상 제목 (미입력 시 YouTube oEmbed로 자동 조회)descriptionstring(선택): 영상 설명 (VideoObject스키마의description에 반영)uploadDatestring(선택): 업로드 일자 (YYYY-MM-DD,VideoObject.uploadDate에 반영)durationstring(선택): ISO 8601 재생 시간 (예:"PT3M45S")captionstring(선택): 영상 하단<figcaption>캡션 문구startnumber(선택): 재생 시작 지점(초 단위, 예:30)
📌 숏코드 작성 예시
{/* 1) 가장 간단한 사용법: URL만 입력 (제목/채널명/썸네일/스키마 자동 생성) */}
<YouTube url="https://www.youtube.com/watch?v=dsTXcSeAZq8" />
{/* 2) 상세 스키마 메타데이터 직접 지정 */}
<YouTubeEmbed
url="https://www.youtube.com/watch?v=dsTXcSeAZq8"
title="Astro in 100 Seconds — 초고속 웹 프레임워크 개요"
description="Fireship 채널의 Astro 웹 프레임워크 및 아일랜드 아키텍처 핵심 개념 100초 요약 영상"
uploadDate="2022-08-09"
duration="PT2M32S"
caption="영상 1: Astro의 아일랜드 아키텍처와 Zero-JS 작동 원리 (출처: Fireship)"
/>
📌 실제 렌더링 결과
3.8 ⑦ 외부 URL 프리뷰 북마크 카드 (<LinkCard /> 또는 <BookmarkCard />)
외부 참고 문헌, 공식 문서, 뉴스 기사, 혹은 사이트 내부 아티클의 URL을 전달하면 페이지 썸네일(og:image), 타이틀(og:title), 요약 설명(og:description), 도메인 파비콘을 추출하여 노션(Notion) 스타일의 북마크 박스로 노출하는 컴포넌트입니다.
- Open Graph 자동 스크래핑:
url속성 하나만 입력해도 빌드/SSR 시점에 대상 웹페이지의<head>메타태그를 파싱하여 제목·설명·대표 이미지를 자동으로 채워줍니다. - 수동 오버라이드 지원: 보안 방화벽으로 봇 접근을 막는 외부 사이트이거나, 에디터가 원하는 문구로 다듬고 싶을 때는
title,description,image속성을 직접 지정할 수 있습니다.
📌 Props 입력 규격
urlstring(필수): 연결할 대상 웹페이지 주소titlestring(선택): 카드 제목 (미입력 시 대상 URL의og:title또는<title>자동 추출)descriptionstring(선택): 요약 설명 2줄 노출 (미입력 시 대상 URL의og:description자동 추출)imagestring(선택): 우측 썸네일 이미지 URL (미입력 시 대상 URL의og:image자동 추출)siteNamestring(선택): 출처 사이트명 (미입력 시og:site_name또는 도메인 호스트명 자동 표기)
📌 숏코드 작성 예시
{/* 1) URL만 입력하여 Open Graph 메타데이터 자동 추출 */}
<LinkCard url="https://astro.build/blog/2023-web-framework-performance-report/" />
{/* 2) 타이틀·설명·썸네일을 명시적으로 지정하는 방식 */}
<LinkCard
url="https://docs.astro.build/en/concepts/islands/"
title="Astro Islands Architecture — 공식 아키텍처 문서"
description="정적 HTML 페이지 안에서 인터랙티브한 UI 컴포넌트만 독립된 섬(Island)처럼 병렬 하이드레이션하는 Astro의 핵심 설계 철학을 설명합니다."
siteName="Astro Docs"
image="https://astro.build/_astro/social.FlPxeRsG.jpg"
/>
📌 실제 렌더링 결과
3.9 [보너스] 마크다운 이미지 <figure> 캡션 자동 변환 규격
별도의 JSX 태그를 쓰지 않고 표준 마크다운 이미지 문법 뒤에 큰따옴표("캡션 내용")만 붙이면, 빌드 파이프라인(rehype-figure 및 커스텀 렌더러)이 자동으로 시맨틱 <figure class="article-image">와 <figcaption>으로 변환합니다.

4. 파트너 에디터(CMS) 노코드 숏코드 빌더 연동 명세
파트너사 또는 자체 제작 콘텐츠 에디터에서 개발 지식이 없는 작성자도 버튼 클릭과 폼 입력만으로 위 7가지 숏코드를 생성할 수 있도록, 에디터에 그대로 내장할 수 있는 TypeScript 직렬화(Serializer) 함수 모음입니다.
/**
* MKTG Edge 7대 시맨틱 숏코드 자동 생성기 (파트너 에디터 내장용)
*/
// 1. <SemanticTable /> 생성기
export function buildSemanticTableShortcode(params: {
caption: string;
headers: string[];
rows: string[][];
}): string {
return [
`<SemanticTable`,
` caption=${JSON.stringify(params.caption.trim())}`,
` headers={${JSON.stringify(params.headers.map((h) => h.trim()))}}`,
` rows={${JSON.stringify(params.rows, null, 2).replace(/\n/g, '\n ')}}`,
`/>`,
].join('\n');
}
// 2. <SemanticFAQ /> 생성기
export function buildSemanticFAQShortcode(params: {
title?: string;
subtitle?: string;
exclusive?: boolean;
items: Array<{ question: string; answer: string }>;
}): string {
const lines = [`<SemanticFAQ`];
if (params.title?.trim()) lines.push(` title=${JSON.stringify(params.title.trim())}`);
if (params.subtitle?.trim()) lines.push(` subtitle=${JSON.stringify(params.subtitle.trim())}`);
if (params.exclusive) lines.push(` exclusive={true}`);
const itemsJson = JSON.stringify(
params.items.map((it) => ({
question: it.question.trim(),
answer: it.answer.trim(),
})),
null,
2
).replace(/\n/g, '\n ');
lines.push(` items={${itemsJson}}`);
lines.push(`/>`);
return lines.join('\n');
}
// 3. <SoftwareCard /> 생성기
export function buildSoftwareCardShortcode(params: {
name: string;
applicationCategory?: string;
operatingSystem?: string;
price?: string;
rating?: string;
logo?: string;
description?: string;
url?: string;
}): string {
const lines = [`<SoftwareCard`, ` name=${JSON.stringify(params.name.trim())}`];
if (params.applicationCategory?.trim()) {
lines.push(` applicationCategory=${JSON.stringify(params.applicationCategory.trim())}`);
}
if (params.operatingSystem?.trim()) {
lines.push(` operatingSystem=${JSON.stringify(params.operatingSystem.trim())}`);
}
if (params.price?.trim()) lines.push(` price=${JSON.stringify(params.price.trim())}`);
if (params.rating?.trim()) lines.push(` rating=${JSON.stringify(params.rating.trim())}`);
if (params.logo?.trim()) lines.push(` logo=${JSON.stringify(params.logo.trim())}`);
if (params.description?.trim()) {
lines.push(` description=${JSON.stringify(params.description.trim())}`);
}
if (params.url?.trim()) lines.push(` url=${JSON.stringify(params.url.trim())}`);
lines.push(`/>`);
return lines.join('\n');
}
// 4. <PersonBadge /> 생성기
export function buildPersonBadgeShortcode(params: {
name: string;
jobTitle?: string;
affiliation?: string;
avatar?: string;
url?: string;
sameAs?: string[];
}): string {
const lines = [`<PersonBadge`, ` name=${JSON.stringify(params.name.trim())}`];
if (params.jobTitle?.trim()) lines.push(` jobTitle=${JSON.stringify(params.jobTitle.trim())}`);
if (params.affiliation?.trim()) {
lines.push(` affiliation=${JSON.stringify(params.affiliation.trim())}`);
}
if (params.avatar?.trim()) lines.push(` avatar=${JSON.stringify(params.avatar.trim())}`);
if (params.url?.trim()) lines.push(` url=${JSON.stringify(params.url.trim())}`);
if (params.sameAs && params.sameAs.length > 0) {
lines.push(` sameAs={${JSON.stringify(params.sameAs)}}`);
}
lines.push(`/>`);
return lines.join('\n');
}
// 5. <Term /> 인라인 툴팁 생성기
export function buildTermShortcode(params: {
name?: string;
slug?: string;
displayText?: string;
}): string {
const attr = params.slug
? `slug=${JSON.stringify(params.slug.trim())}`
: `name=${JSON.stringify((params.name || '').trim())}`;
return params.displayText?.trim()
? `<Term ${attr}>${params.displayText.trim()}</Term>`
: `<Term ${attr} />`;
}
// 6. <YouTubeEmbed /> (또는 <YouTube />) 생성기
export function buildYouTubeShortcode(params: {
url: string;
title?: string;
description?: string;
uploadDate?: string;
duration?: string;
caption?: string;
start?: number;
}): string {
const lines = [`<YouTubeEmbed`, ` url=${JSON.stringify(params.url.trim())}`];
if (params.title?.trim()) lines.push(` title=${JSON.stringify(params.title.trim())}`);
if (params.description?.trim()) {
lines.push(` description=${JSON.stringify(params.description.trim())}`);
}
if (params.uploadDate?.trim()) {
lines.push(` uploadDate=${JSON.stringify(params.uploadDate.trim())}`);
}
if (params.duration?.trim()) lines.push(` duration=${JSON.stringify(params.duration.trim())}`);
if (params.caption?.trim()) lines.push(` caption=${JSON.stringify(params.caption.trim())}`);
if (params.start && Number(params.start) > 0) lines.push(` start={${Number(params.start)}}`);
lines.push(`/>`);
return lines.join('\n');
}
// 7. <LinkCard /> 외부/내부 URL 북마크 카드 생성기
export function buildLinkCardShortcode(params: {
url: string;
title?: string;
description?: string;
image?: string;
siteName?: string;
}): string {
const lines = [`<LinkCard`, ` url=${JSON.stringify(params.url.trim())}`];
if (params.title?.trim()) lines.push(` title=${JSON.stringify(params.title.trim())}`);
if (params.description?.trim()) {
lines.push(` description=${JSON.stringify(params.description.trim())}`);
}
if (params.image?.trim()) lines.push(` image=${JSON.stringify(params.image.trim())}`);
if (params.siteName?.trim()) lines.push(` siteName=${JSON.stringify(params.siteName.trim())}`);
lines.push(`/>`);
return lines.join('\n');
}
5. 시맨틱 컴포넌트 신규 추가 및 확장 절차 (개발자용 체크리스트)
향후 새로운 종류의 시맨틱 숏코드 컴포넌트(예: <HowToSteps />, <CalloutBox /> 등)를 mktg.kr에 추가할 때는 아래 4단계 표준 절차를 따릅니다:
- 컴포넌트 생성 (
src/components/semantic/[ComponentName].astro):- 최상위 컨테이너에
not-prose클래스를 부여하여 Tailwind Typography(.prose) 기본 스타일과의 충돌을 방지합니다. - 해당하는 Schema.org 타입이 있다면 컴포넌트 상단에서
<script type="application/ld+json" set:html={JSON.stringify(schema)} />를 출력하도록 설계합니다.
- 최상위 컨테이너에
- 배럴 파일 등록 (
src/components/semantic/index.ts):export { default as NewComponent } from './NewComponent.astro';를 추가합니다.
- 전역 MDX 주입 등록 (
src/pages/blog/[slug].astro,src/pages/docs/[...slug].astro):- 두 라우트 파일의
mdxComponents객체에 새 컴포넌트를 추가하여, 작성자가import없이 본문에서 즉시 사용할 수 있게 만듭니다.
- 두 라우트 파일의
- 가이드 문서 업데이트:
- 본 문서(
/docs/semantic-shortcode-components-guide)와/docs/content-authoring-guide에 Props 명세와 라이브 예시를 추가합니다.
- 본 문서(
