@roottale/cms-core 0.57.0 → 0.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/dist/index.cjs +76 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -13
- package/dist/index.d.ts +45 -13
- package/dist/index.js +70 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -475,15 +475,16 @@ declare function injectStableIdsTree(blocks: readonly (Omit<Block, "_id"> & {
|
|
|
475
475
|
* 공통 블록(Site Patterns) — 여러 글에 같은 자리로 붙는 재사용 블록의 순수 규칙.
|
|
476
476
|
*
|
|
477
477
|
* 블록 본문은 ROOT-ADMIN 이 `site_patterns` 에 저장하고, "어느 자리(slot)에 어느
|
|
478
|
-
*
|
|
479
|
-
* 으로 정한다.
|
|
478
|
+
* 콘텐츠 모델(`model_key`)의 글이면 어떤 블록"인지는 배치 규칙
|
|
479
|
+
* (`settings.site_pattern_placements`)으로 정한다. 유형의 단위는 콘텐츠 모델이다 —
|
|
480
|
+
* 컬렉션 설정(ADR-0060)은 ADR-0105 로 폐기 중이라 규칙 키로 쓰지 않는다. 공개 API 는 글마다 `pattern_slots`(자리 → 블록 key | null) 를 계산해
|
|
480
481
|
* 내려주므로 FRONT 는 규칙을 몰라도 된다. 이 파일은 api-core(계산)·tenant-admin(편집)·
|
|
481
482
|
* cms-renderer-next(렌더)가 같은 판정을 공유하기 위한 프레임워크 비의존 모듈이다.
|
|
482
483
|
*
|
|
483
484
|
* 규칙 판정:
|
|
484
485
|
* - 자리는 `SITE_PATTERN_SLOTS` 에 선언된 것만 계산한다(미선언 자리는 무시).
|
|
485
|
-
* - 글의 `
|
|
486
|
-
* - 없으면 `
|
|
486
|
+
* - 글의 `modelKey` 와 같은 규칙이 있으면 그 규칙(블록 없음 = null 도 명시적 결정).
|
|
487
|
+
* - 없으면 `modelKey: null`(모든 글 기본) 규칙.
|
|
487
488
|
* - 가리키는 블록이 발행 상태가 아니면 null(FRONT 가 미발행 블록을 그리지 않게).
|
|
488
489
|
*/
|
|
489
490
|
/** 블록을 놓을 수 있는 자리. key 는 공개 API `pattern_slots` 의 키와 같다. */
|
|
@@ -501,12 +502,12 @@ declare const SITE_PATTERN_KEY_PATTERN: RegExp;
|
|
|
501
502
|
declare function isValidSitePatternKey(key: string): boolean;
|
|
502
503
|
declare function isSitePatternSlotKey(value: string): value is SitePatternSlotKey;
|
|
503
504
|
/**
|
|
504
|
-
* 배치 규칙 1건. `
|
|
505
|
+
* 배치 규칙 1건. `modelKey: null` = 모든 글의 기본값, 문자열 = 그 콘텐츠 모델의 글만.
|
|
505
506
|
* `patternKey: null` = 이 자리에 블록을 놓지 않는다(유형 규칙이면 기본값 덮어쓰기).
|
|
506
507
|
*/
|
|
507
508
|
interface SitePatternPlacementRule {
|
|
508
509
|
readonly slot: SitePatternSlotKey;
|
|
509
|
-
readonly
|
|
510
|
+
readonly modelKey: string | null;
|
|
510
511
|
readonly patternKey: string | null;
|
|
511
512
|
}
|
|
512
513
|
interface SitePatternPlacements {
|
|
@@ -517,31 +518,62 @@ declare const EMPTY_SITE_PATTERN_PLACEMENTS: SitePatternPlacements;
|
|
|
517
518
|
type PatternSlots = Record<string, string | null>;
|
|
518
519
|
/**
|
|
519
520
|
* 저장된 값(unknown) → 정규화된 배치 규칙. 형식이 틀린 항목·미선언 자리는 버리고,
|
|
520
|
-
* 같은 (slot,
|
|
521
|
+
* 같은 (slot, modelKey) 는 마지막 항목이 이긴다. 이중 인코딩된 JSON 문자열도 받는다.
|
|
522
|
+
* 2026-08-19 이전에 저장된 규칙은 `collectionKey` 필드를 썼다 — `modelKey` 가 없으면 그
|
|
523
|
+
* 값을 읽는다(실측상 남은 규칙은 기본값 `null` 뿐이라 의미가 같다). 다시 저장하면
|
|
524
|
+
* `modelKey` 로 쓰인다.
|
|
521
525
|
*/
|
|
522
526
|
declare function readSitePatternPlacements(raw: unknown): SitePatternPlacements;
|
|
523
|
-
/** (slot,
|
|
524
|
-
declare function findSitePatternPlacementRule(placements: SitePatternPlacements, slot: SitePatternSlotKey,
|
|
527
|
+
/** (slot, modelKey) 에 해당하는 규칙. 없으면 undefined(= 기본값으로 위임). */
|
|
528
|
+
declare function findSitePatternPlacementRule(placements: SitePatternPlacements, slot: SitePatternSlotKey, modelKey: string | null): SitePatternPlacementRule | undefined;
|
|
525
529
|
/**
|
|
526
530
|
* 규칙 1건을 갈아 끼운 새 배치 규칙을 돌려준다(불변). `patternKey: undefined` 는
|
|
527
531
|
* "규칙 삭제 = 기본값으로 위임"이다 — 유형 규칙에서 "표시 안 함"(null)과 구분된다.
|
|
528
532
|
*/
|
|
529
533
|
declare function setSitePatternPlacementRule(placements: SitePatternPlacements, target: {
|
|
530
534
|
slot: SitePatternSlotKey;
|
|
531
|
-
|
|
535
|
+
modelKey: string | null;
|
|
532
536
|
}, patternKey: string | null | undefined): SitePatternPlacements;
|
|
533
537
|
/** 선언된 자리마다 null 인 빈 결과 — 규칙이나 발행 블록이 없을 때의 기본 응답. */
|
|
534
538
|
declare function emptyPatternSlots(): PatternSlots;
|
|
535
539
|
/**
|
|
536
|
-
* 글 1건의 자리별 블록 key 를 계산한다. `
|
|
540
|
+
* 글 1건의 자리별 블록 key 를 계산한다. 글의 콘텐츠 모델(`modelKey`) 규칙 > 모든 글 기본
|
|
541
|
+
* 규칙. `publishedKeys` 에 없는 블록(미발행·삭제)은 null.
|
|
537
542
|
*/
|
|
538
543
|
declare function resolvePatternSlots(post: {
|
|
539
|
-
readonly
|
|
544
|
+
readonly modelKey: string | null;
|
|
540
545
|
}, placements: SitePatternPlacements, publishedKeys: ReadonlySet<string>): PatternSlots;
|
|
541
546
|
/**
|
|
542
547
|
* 규칙에서 참조하는 블록 key 집합 — 어드민이 "이 블록은 어디에 쓰이는가"를 표시하거나
|
|
543
548
|
* 삭제 전 경고할 때 쓴다.
|
|
544
549
|
*/
|
|
545
550
|
declare function referencedSitePatternKeys(placements: SitePatternPlacements): ReadonlySet<string>;
|
|
551
|
+
type SitePatternLayout = "plain" | "card";
|
|
552
|
+
type SitePatternLinkStyle = "text" | "buttons";
|
|
553
|
+
interface SitePatternPresentation {
|
|
554
|
+
/** `plain` = 본문처럼 흐름에 놓임, `card` = 배경색이 있는 카드. */
|
|
555
|
+
readonly layout: SitePatternLayout;
|
|
556
|
+
/** 카드 배경색(hex). layout 이 card 일 때만 의미. */
|
|
557
|
+
readonly background: string;
|
|
558
|
+
/** 마지막 문단의 링크를 버튼으로 그릴지. */
|
|
559
|
+
readonly linkStyle: SitePatternLinkStyle;
|
|
560
|
+
/** 버튼 배경색(hex, 순서대로 1·2·3…; 링크가 더 많으면 마지막 색을 반복). 글자는 흰색. */
|
|
561
|
+
readonly buttonColors: readonly string[];
|
|
562
|
+
}
|
|
563
|
+
declare const DEFAULT_SITE_PATTERN_PRESENTATION: SitePatternPresentation;
|
|
564
|
+
declare const SITE_PATTERN_BUTTON_COLORS_MAX = 4;
|
|
565
|
+
declare function normalizeHexColor(value: unknown): string | null;
|
|
566
|
+
/** 저장된 값(unknown) → 표시 형태. 틀린 값은 기본값으로 채운다(절대 throw 하지 않음). */
|
|
567
|
+
declare function readSitePatternPresentation(raw: unknown): SitePatternPresentation;
|
|
568
|
+
/** 버튼 n번째(0부터)의 색 — 링크가 색 개수보다 많으면 마지막 색을 반복. */
|
|
569
|
+
declare function sitePatternButtonColor(presentation: SitePatternPresentation, index: number): string;
|
|
570
|
+
/**
|
|
571
|
+
* FRONT 가 래퍼 요소에 얹을 data 속성과 CSS 변수. 사이트 CSS 는 이 변수만 읽는다 —
|
|
572
|
+
* `data-pattern-layout`·`data-pattern-link-style`, `--rt-pattern-bg`, `--rt-pattern-btn-1..n`.
|
|
573
|
+
*/
|
|
574
|
+
declare function sitePatternPresentationAttributes(presentation: SitePatternPresentation): {
|
|
575
|
+
readonly dataset: Readonly<Record<string, string>>;
|
|
576
|
+
readonly cssVariables: Readonly<Record<string, string>>;
|
|
577
|
+
};
|
|
546
578
|
|
|
547
|
-
export { BLOCK_NAME_PATTERN, type BindingResolver, type Block, type BlockBinding, type BlockDefinition, type BlockRegistry, type CategoryTreeEntry, type CategoryTreePresentation, type CategoryTreeTerm, type ClientHydrationSpec, EMPTY_SITE_PATTERN_PLACEMENTS, type EmbedProvider, FIELD_BINDING_SOURCE, FIELD_BINDING_SOURCE_ALIAS, type FaqEntry, IMAGE_ALT_MAX_LENGTH, INTERNAL_CONTENT_LINK_CLASS, INTERNAL_CONTENT_LINK_PENDING_ATTR, INTERNAL_CONTENT_LINK_PENDING_CLASS, INTERNAL_CONTENT_LINK_TOKEN_SOURCE, type InternalContentLinkResolver, type InternalContentLinkToken, LEGACY_BLOG_DETAIL_PATH, type NormalizedEmbed, PHASE_1_CORE_BLOCKS, PHASE_1_CSP, POST_FOOTER_SLOT, type PatternSlots, type Phase1CoreBlockName, type PreviewTokenPayload, type PublicPathContext, type PublicPathPost, type PublicPathPresentation, type RoutablePost, type RouteCollection, SITE_PATTERN_KEY_PATTERN, SITE_PATTERN_PLACEMENTS_KEY, SITE_PATTERN_SLOTS, type SitePatternPlacementRule, type SitePatternPlacements, type SitePatternSlotKey, applyBlockBindings, bindingSrcValue, bindingTextValue, blockSchema, boundFieldValue, chainResolvers, createFieldBindingResolver, emptyPatternSlots, ensureImportedHtmlDocumentRoots, ensureStableIds, extractFaqEntries, faqPageJsonLd, findInternalContentLinkTokens, findSitePatternPlacementRule, htmlToPlainText, injectStableIdsTree, internalContentKeyFromPath, internalContentLinkResolverFrom, internalContentPathIndex, isAllowedEmbedSrc, isAllowedMapEmbedSrc, isInCollectionMode, isSitePatternSlotKey, isValidBlock, isValidSitePatternKey, issuePreviewToken, normalizeEmbed, normalizeImageAlt, parseBlock, postsForCollection, postsInAnyCollection, postsNotInAnyCollection, readSitePatternPlacements, referencedSitePatternKeys, renderInternalContentLinksInHtml, renderInternalContentLinksInText, resolveCategoryPath, resolveCategoryTreeChain, resolveCategoryTreeEntryPath, resolveCategoryTreeHubPaths, resolvePatternSlots, resolvePostCategorySlug, resolvePostCollection, resolvePostPath, resolvePostPublicPath, resolvePostUrl, sanitizeHtml, sanitizeImportedCss, sanitizeImportedHtml, scopeImportedCss, serializeBlock, setSitePatternPlacementRule, validateCollections, verifyPreviewToken };
|
|
579
|
+
export { BLOCK_NAME_PATTERN, type BindingResolver, type Block, type BlockBinding, type BlockDefinition, type BlockRegistry, type CategoryTreeEntry, type CategoryTreePresentation, type CategoryTreeTerm, type ClientHydrationSpec, DEFAULT_SITE_PATTERN_PRESENTATION, EMPTY_SITE_PATTERN_PLACEMENTS, type EmbedProvider, FIELD_BINDING_SOURCE, FIELD_BINDING_SOURCE_ALIAS, type FaqEntry, IMAGE_ALT_MAX_LENGTH, INTERNAL_CONTENT_LINK_CLASS, INTERNAL_CONTENT_LINK_PENDING_ATTR, INTERNAL_CONTENT_LINK_PENDING_CLASS, INTERNAL_CONTENT_LINK_TOKEN_SOURCE, type InternalContentLinkResolver, type InternalContentLinkToken, LEGACY_BLOG_DETAIL_PATH, type NormalizedEmbed, PHASE_1_CORE_BLOCKS, PHASE_1_CSP, POST_FOOTER_SLOT, type PatternSlots, type Phase1CoreBlockName, type PreviewTokenPayload, type PublicPathContext, type PublicPathPost, type PublicPathPresentation, type RoutablePost, type RouteCollection, SITE_PATTERN_BUTTON_COLORS_MAX, SITE_PATTERN_KEY_PATTERN, SITE_PATTERN_PLACEMENTS_KEY, SITE_PATTERN_SLOTS, type SitePatternLayout, type SitePatternLinkStyle, type SitePatternPlacementRule, type SitePatternPlacements, type SitePatternPresentation, type SitePatternSlotKey, applyBlockBindings, bindingSrcValue, bindingTextValue, blockSchema, boundFieldValue, chainResolvers, createFieldBindingResolver, emptyPatternSlots, ensureImportedHtmlDocumentRoots, ensureStableIds, extractFaqEntries, faqPageJsonLd, findInternalContentLinkTokens, findSitePatternPlacementRule, htmlToPlainText, injectStableIdsTree, internalContentKeyFromPath, internalContentLinkResolverFrom, internalContentPathIndex, isAllowedEmbedSrc, isAllowedMapEmbedSrc, isInCollectionMode, isSitePatternSlotKey, isValidBlock, isValidSitePatternKey, issuePreviewToken, normalizeEmbed, normalizeHexColor, normalizeImageAlt, parseBlock, postsForCollection, postsInAnyCollection, postsNotInAnyCollection, readSitePatternPlacements, readSitePatternPresentation, referencedSitePatternKeys, renderInternalContentLinksInHtml, renderInternalContentLinksInText, resolveCategoryPath, resolveCategoryTreeChain, resolveCategoryTreeEntryPath, resolveCategoryTreeHubPaths, resolvePatternSlots, resolvePostCategorySlug, resolvePostCollection, resolvePostPath, resolvePostPublicPath, resolvePostUrl, sanitizeHtml, sanitizeImportedCss, sanitizeImportedHtml, scopeImportedCss, serializeBlock, setSitePatternPlacementRule, sitePatternButtonColor, sitePatternPresentationAttributes, validateCollections, verifyPreviewToken };
|
package/dist/index.d.ts
CHANGED
|
@@ -475,15 +475,16 @@ declare function injectStableIdsTree(blocks: readonly (Omit<Block, "_id"> & {
|
|
|
475
475
|
* 공통 블록(Site Patterns) — 여러 글에 같은 자리로 붙는 재사용 블록의 순수 규칙.
|
|
476
476
|
*
|
|
477
477
|
* 블록 본문은 ROOT-ADMIN 이 `site_patterns` 에 저장하고, "어느 자리(slot)에 어느
|
|
478
|
-
*
|
|
479
|
-
* 으로 정한다.
|
|
478
|
+
* 콘텐츠 모델(`model_key`)의 글이면 어떤 블록"인지는 배치 규칙
|
|
479
|
+
* (`settings.site_pattern_placements`)으로 정한다. 유형의 단위는 콘텐츠 모델이다 —
|
|
480
|
+
* 컬렉션 설정(ADR-0060)은 ADR-0105 로 폐기 중이라 규칙 키로 쓰지 않는다. 공개 API 는 글마다 `pattern_slots`(자리 → 블록 key | null) 를 계산해
|
|
480
481
|
* 내려주므로 FRONT 는 규칙을 몰라도 된다. 이 파일은 api-core(계산)·tenant-admin(편집)·
|
|
481
482
|
* cms-renderer-next(렌더)가 같은 판정을 공유하기 위한 프레임워크 비의존 모듈이다.
|
|
482
483
|
*
|
|
483
484
|
* 규칙 판정:
|
|
484
485
|
* - 자리는 `SITE_PATTERN_SLOTS` 에 선언된 것만 계산한다(미선언 자리는 무시).
|
|
485
|
-
* - 글의 `
|
|
486
|
-
* - 없으면 `
|
|
486
|
+
* - 글의 `modelKey` 와 같은 규칙이 있으면 그 규칙(블록 없음 = null 도 명시적 결정).
|
|
487
|
+
* - 없으면 `modelKey: null`(모든 글 기본) 규칙.
|
|
487
488
|
* - 가리키는 블록이 발행 상태가 아니면 null(FRONT 가 미발행 블록을 그리지 않게).
|
|
488
489
|
*/
|
|
489
490
|
/** 블록을 놓을 수 있는 자리. key 는 공개 API `pattern_slots` 의 키와 같다. */
|
|
@@ -501,12 +502,12 @@ declare const SITE_PATTERN_KEY_PATTERN: RegExp;
|
|
|
501
502
|
declare function isValidSitePatternKey(key: string): boolean;
|
|
502
503
|
declare function isSitePatternSlotKey(value: string): value is SitePatternSlotKey;
|
|
503
504
|
/**
|
|
504
|
-
* 배치 규칙 1건. `
|
|
505
|
+
* 배치 규칙 1건. `modelKey: null` = 모든 글의 기본값, 문자열 = 그 콘텐츠 모델의 글만.
|
|
505
506
|
* `patternKey: null` = 이 자리에 블록을 놓지 않는다(유형 규칙이면 기본값 덮어쓰기).
|
|
506
507
|
*/
|
|
507
508
|
interface SitePatternPlacementRule {
|
|
508
509
|
readonly slot: SitePatternSlotKey;
|
|
509
|
-
readonly
|
|
510
|
+
readonly modelKey: string | null;
|
|
510
511
|
readonly patternKey: string | null;
|
|
511
512
|
}
|
|
512
513
|
interface SitePatternPlacements {
|
|
@@ -517,31 +518,62 @@ declare const EMPTY_SITE_PATTERN_PLACEMENTS: SitePatternPlacements;
|
|
|
517
518
|
type PatternSlots = Record<string, string | null>;
|
|
518
519
|
/**
|
|
519
520
|
* 저장된 값(unknown) → 정규화된 배치 규칙. 형식이 틀린 항목·미선언 자리는 버리고,
|
|
520
|
-
* 같은 (slot,
|
|
521
|
+
* 같은 (slot, modelKey) 는 마지막 항목이 이긴다. 이중 인코딩된 JSON 문자열도 받는다.
|
|
522
|
+
* 2026-08-19 이전에 저장된 규칙은 `collectionKey` 필드를 썼다 — `modelKey` 가 없으면 그
|
|
523
|
+
* 값을 읽는다(실측상 남은 규칙은 기본값 `null` 뿐이라 의미가 같다). 다시 저장하면
|
|
524
|
+
* `modelKey` 로 쓰인다.
|
|
521
525
|
*/
|
|
522
526
|
declare function readSitePatternPlacements(raw: unknown): SitePatternPlacements;
|
|
523
|
-
/** (slot,
|
|
524
|
-
declare function findSitePatternPlacementRule(placements: SitePatternPlacements, slot: SitePatternSlotKey,
|
|
527
|
+
/** (slot, modelKey) 에 해당하는 규칙. 없으면 undefined(= 기본값으로 위임). */
|
|
528
|
+
declare function findSitePatternPlacementRule(placements: SitePatternPlacements, slot: SitePatternSlotKey, modelKey: string | null): SitePatternPlacementRule | undefined;
|
|
525
529
|
/**
|
|
526
530
|
* 규칙 1건을 갈아 끼운 새 배치 규칙을 돌려준다(불변). `patternKey: undefined` 는
|
|
527
531
|
* "규칙 삭제 = 기본값으로 위임"이다 — 유형 규칙에서 "표시 안 함"(null)과 구분된다.
|
|
528
532
|
*/
|
|
529
533
|
declare function setSitePatternPlacementRule(placements: SitePatternPlacements, target: {
|
|
530
534
|
slot: SitePatternSlotKey;
|
|
531
|
-
|
|
535
|
+
modelKey: string | null;
|
|
532
536
|
}, patternKey: string | null | undefined): SitePatternPlacements;
|
|
533
537
|
/** 선언된 자리마다 null 인 빈 결과 — 규칙이나 발행 블록이 없을 때의 기본 응답. */
|
|
534
538
|
declare function emptyPatternSlots(): PatternSlots;
|
|
535
539
|
/**
|
|
536
|
-
* 글 1건의 자리별 블록 key 를 계산한다. `
|
|
540
|
+
* 글 1건의 자리별 블록 key 를 계산한다. 글의 콘텐츠 모델(`modelKey`) 규칙 > 모든 글 기본
|
|
541
|
+
* 규칙. `publishedKeys` 에 없는 블록(미발행·삭제)은 null.
|
|
537
542
|
*/
|
|
538
543
|
declare function resolvePatternSlots(post: {
|
|
539
|
-
readonly
|
|
544
|
+
readonly modelKey: string | null;
|
|
540
545
|
}, placements: SitePatternPlacements, publishedKeys: ReadonlySet<string>): PatternSlots;
|
|
541
546
|
/**
|
|
542
547
|
* 규칙에서 참조하는 블록 key 집합 — 어드민이 "이 블록은 어디에 쓰이는가"를 표시하거나
|
|
543
548
|
* 삭제 전 경고할 때 쓴다.
|
|
544
549
|
*/
|
|
545
550
|
declare function referencedSitePatternKeys(placements: SitePatternPlacements): ReadonlySet<string>;
|
|
551
|
+
type SitePatternLayout = "plain" | "card";
|
|
552
|
+
type SitePatternLinkStyle = "text" | "buttons";
|
|
553
|
+
interface SitePatternPresentation {
|
|
554
|
+
/** `plain` = 본문처럼 흐름에 놓임, `card` = 배경색이 있는 카드. */
|
|
555
|
+
readonly layout: SitePatternLayout;
|
|
556
|
+
/** 카드 배경색(hex). layout 이 card 일 때만 의미. */
|
|
557
|
+
readonly background: string;
|
|
558
|
+
/** 마지막 문단의 링크를 버튼으로 그릴지. */
|
|
559
|
+
readonly linkStyle: SitePatternLinkStyle;
|
|
560
|
+
/** 버튼 배경색(hex, 순서대로 1·2·3…; 링크가 더 많으면 마지막 색을 반복). 글자는 흰색. */
|
|
561
|
+
readonly buttonColors: readonly string[];
|
|
562
|
+
}
|
|
563
|
+
declare const DEFAULT_SITE_PATTERN_PRESENTATION: SitePatternPresentation;
|
|
564
|
+
declare const SITE_PATTERN_BUTTON_COLORS_MAX = 4;
|
|
565
|
+
declare function normalizeHexColor(value: unknown): string | null;
|
|
566
|
+
/** 저장된 값(unknown) → 표시 형태. 틀린 값은 기본값으로 채운다(절대 throw 하지 않음). */
|
|
567
|
+
declare function readSitePatternPresentation(raw: unknown): SitePatternPresentation;
|
|
568
|
+
/** 버튼 n번째(0부터)의 색 — 링크가 색 개수보다 많으면 마지막 색을 반복. */
|
|
569
|
+
declare function sitePatternButtonColor(presentation: SitePatternPresentation, index: number): string;
|
|
570
|
+
/**
|
|
571
|
+
* FRONT 가 래퍼 요소에 얹을 data 속성과 CSS 변수. 사이트 CSS 는 이 변수만 읽는다 —
|
|
572
|
+
* `data-pattern-layout`·`data-pattern-link-style`, `--rt-pattern-bg`, `--rt-pattern-btn-1..n`.
|
|
573
|
+
*/
|
|
574
|
+
declare function sitePatternPresentationAttributes(presentation: SitePatternPresentation): {
|
|
575
|
+
readonly dataset: Readonly<Record<string, string>>;
|
|
576
|
+
readonly cssVariables: Readonly<Record<string, string>>;
|
|
577
|
+
};
|
|
546
578
|
|
|
547
|
-
export { BLOCK_NAME_PATTERN, type BindingResolver, type Block, type BlockBinding, type BlockDefinition, type BlockRegistry, type CategoryTreeEntry, type CategoryTreePresentation, type CategoryTreeTerm, type ClientHydrationSpec, EMPTY_SITE_PATTERN_PLACEMENTS, type EmbedProvider, FIELD_BINDING_SOURCE, FIELD_BINDING_SOURCE_ALIAS, type FaqEntry, IMAGE_ALT_MAX_LENGTH, INTERNAL_CONTENT_LINK_CLASS, INTERNAL_CONTENT_LINK_PENDING_ATTR, INTERNAL_CONTENT_LINK_PENDING_CLASS, INTERNAL_CONTENT_LINK_TOKEN_SOURCE, type InternalContentLinkResolver, type InternalContentLinkToken, LEGACY_BLOG_DETAIL_PATH, type NormalizedEmbed, PHASE_1_CORE_BLOCKS, PHASE_1_CSP, POST_FOOTER_SLOT, type PatternSlots, type Phase1CoreBlockName, type PreviewTokenPayload, type PublicPathContext, type PublicPathPost, type PublicPathPresentation, type RoutablePost, type RouteCollection, SITE_PATTERN_KEY_PATTERN, SITE_PATTERN_PLACEMENTS_KEY, SITE_PATTERN_SLOTS, type SitePatternPlacementRule, type SitePatternPlacements, type SitePatternSlotKey, applyBlockBindings, bindingSrcValue, bindingTextValue, blockSchema, boundFieldValue, chainResolvers, createFieldBindingResolver, emptyPatternSlots, ensureImportedHtmlDocumentRoots, ensureStableIds, extractFaqEntries, faqPageJsonLd, findInternalContentLinkTokens, findSitePatternPlacementRule, htmlToPlainText, injectStableIdsTree, internalContentKeyFromPath, internalContentLinkResolverFrom, internalContentPathIndex, isAllowedEmbedSrc, isAllowedMapEmbedSrc, isInCollectionMode, isSitePatternSlotKey, isValidBlock, isValidSitePatternKey, issuePreviewToken, normalizeEmbed, normalizeImageAlt, parseBlock, postsForCollection, postsInAnyCollection, postsNotInAnyCollection, readSitePatternPlacements, referencedSitePatternKeys, renderInternalContentLinksInHtml, renderInternalContentLinksInText, resolveCategoryPath, resolveCategoryTreeChain, resolveCategoryTreeEntryPath, resolveCategoryTreeHubPaths, resolvePatternSlots, resolvePostCategorySlug, resolvePostCollection, resolvePostPath, resolvePostPublicPath, resolvePostUrl, sanitizeHtml, sanitizeImportedCss, sanitizeImportedHtml, scopeImportedCss, serializeBlock, setSitePatternPlacementRule, validateCollections, verifyPreviewToken };
|
|
579
|
+
export { BLOCK_NAME_PATTERN, type BindingResolver, type Block, type BlockBinding, type BlockDefinition, type BlockRegistry, type CategoryTreeEntry, type CategoryTreePresentation, type CategoryTreeTerm, type ClientHydrationSpec, DEFAULT_SITE_PATTERN_PRESENTATION, EMPTY_SITE_PATTERN_PLACEMENTS, type EmbedProvider, FIELD_BINDING_SOURCE, FIELD_BINDING_SOURCE_ALIAS, type FaqEntry, IMAGE_ALT_MAX_LENGTH, INTERNAL_CONTENT_LINK_CLASS, INTERNAL_CONTENT_LINK_PENDING_ATTR, INTERNAL_CONTENT_LINK_PENDING_CLASS, INTERNAL_CONTENT_LINK_TOKEN_SOURCE, type InternalContentLinkResolver, type InternalContentLinkToken, LEGACY_BLOG_DETAIL_PATH, type NormalizedEmbed, PHASE_1_CORE_BLOCKS, PHASE_1_CSP, POST_FOOTER_SLOT, type PatternSlots, type Phase1CoreBlockName, type PreviewTokenPayload, type PublicPathContext, type PublicPathPost, type PublicPathPresentation, type RoutablePost, type RouteCollection, SITE_PATTERN_BUTTON_COLORS_MAX, SITE_PATTERN_KEY_PATTERN, SITE_PATTERN_PLACEMENTS_KEY, SITE_PATTERN_SLOTS, type SitePatternLayout, type SitePatternLinkStyle, type SitePatternPlacementRule, type SitePatternPlacements, type SitePatternPresentation, type SitePatternSlotKey, applyBlockBindings, bindingSrcValue, bindingTextValue, blockSchema, boundFieldValue, chainResolvers, createFieldBindingResolver, emptyPatternSlots, ensureImportedHtmlDocumentRoots, ensureStableIds, extractFaqEntries, faqPageJsonLd, findInternalContentLinkTokens, findSitePatternPlacementRule, htmlToPlainText, injectStableIdsTree, internalContentKeyFromPath, internalContentLinkResolverFrom, internalContentPathIndex, isAllowedEmbedSrc, isAllowedMapEmbedSrc, isInCollectionMode, isSitePatternSlotKey, isValidBlock, isValidSitePatternKey, issuePreviewToken, normalizeEmbed, normalizeHexColor, normalizeImageAlt, parseBlock, postsForCollection, postsInAnyCollection, postsNotInAnyCollection, readSitePatternPlacements, readSitePatternPresentation, referencedSitePatternKeys, renderInternalContentLinksInHtml, renderInternalContentLinksInText, resolveCategoryPath, resolveCategoryTreeChain, resolveCategoryTreeEntryPath, resolveCategoryTreeHubPaths, resolvePatternSlots, resolvePostCategorySlug, resolvePostCollection, resolvePostPath, resolvePostPublicPath, resolvePostUrl, sanitizeHtml, sanitizeImportedCss, sanitizeImportedHtml, scopeImportedCss, serializeBlock, setSitePatternPlacementRule, sitePatternButtonColor, sitePatternPresentationAttributes, validateCollections, verifyPreviewToken };
|
package/dist/index.js
CHANGED
|
@@ -1455,34 +1455,31 @@ function readSitePatternPlacements(raw) {
|
|
|
1455
1455
|
if (!isRecord(item)) continue;
|
|
1456
1456
|
const slot = typeof item.slot === "string" ? item.slot : "";
|
|
1457
1457
|
if (!isSitePatternSlotKey(slot)) continue;
|
|
1458
|
-
const
|
|
1459
|
-
|
|
1458
|
+
const modelKey = readNullableKey(
|
|
1459
|
+
item.modelKey === void 0 ? item.collectionKey : item.modelKey
|
|
1460
|
+
);
|
|
1461
|
+
if (modelKey === void 0) continue;
|
|
1460
1462
|
const patternKey = readNullableKey(item.patternKey);
|
|
1461
1463
|
if (patternKey === void 0) continue;
|
|
1462
1464
|
if (patternKey !== null && !isValidSitePatternKey(patternKey)) continue;
|
|
1463
|
-
byTarget.set(`${slot}\0${
|
|
1465
|
+
byTarget.set(`${slot}\0${modelKey ?? ""}`, {
|
|
1464
1466
|
slot,
|
|
1465
|
-
|
|
1467
|
+
modelKey,
|
|
1466
1468
|
patternKey
|
|
1467
1469
|
});
|
|
1468
1470
|
}
|
|
1469
1471
|
return { rules: [...byTarget.values()] };
|
|
1470
1472
|
}
|
|
1471
|
-
function findSitePatternPlacementRule(placements, slot,
|
|
1472
|
-
return placements.rules.find(
|
|
1473
|
-
(rule) => rule.slot === slot && rule.collectionKey === collectionKey
|
|
1474
|
-
);
|
|
1473
|
+
function findSitePatternPlacementRule(placements, slot, modelKey) {
|
|
1474
|
+
return placements.rules.find((rule) => rule.slot === slot && rule.modelKey === modelKey);
|
|
1475
1475
|
}
|
|
1476
1476
|
function setSitePatternPlacementRule(placements, target, patternKey) {
|
|
1477
1477
|
const rest = placements.rules.filter(
|
|
1478
|
-
(rule) => !(rule.slot === target.slot && rule.
|
|
1478
|
+
(rule) => !(rule.slot === target.slot && rule.modelKey === target.modelKey)
|
|
1479
1479
|
);
|
|
1480
1480
|
if (patternKey === void 0) return { rules: rest };
|
|
1481
1481
|
return {
|
|
1482
|
-
rules: [
|
|
1483
|
-
...rest,
|
|
1484
|
-
{ slot: target.slot, collectionKey: target.collectionKey, patternKey }
|
|
1485
|
-
]
|
|
1482
|
+
rules: [...rest, { slot: target.slot, modelKey: target.modelKey, patternKey }]
|
|
1486
1483
|
};
|
|
1487
1484
|
}
|
|
1488
1485
|
function emptyPatternSlots() {
|
|
@@ -1491,7 +1488,7 @@ function emptyPatternSlots() {
|
|
|
1491
1488
|
function resolvePatternSlots(post, placements, publishedKeys) {
|
|
1492
1489
|
const slots = emptyPatternSlots();
|
|
1493
1490
|
for (const slot of SITE_PATTERN_SLOTS) {
|
|
1494
|
-
const specific = post.
|
|
1491
|
+
const specific = post.modelKey !== null ? findSitePatternPlacementRule(placements, slot.key, post.modelKey) : void 0;
|
|
1495
1492
|
const rule = specific ?? findSitePatternPlacementRule(placements, slot.key, null);
|
|
1496
1493
|
const key = rule?.patternKey ?? null;
|
|
1497
1494
|
slots[slot.key] = key !== null && publishedKeys.has(key) ? key : null;
|
|
@@ -1503,8 +1500,62 @@ function referencedSitePatternKeys(placements) {
|
|
|
1503
1500
|
placements.rules.map((rule) => rule.patternKey).filter((key) => key !== null)
|
|
1504
1501
|
);
|
|
1505
1502
|
}
|
|
1503
|
+
var DEFAULT_SITE_PATTERN_PRESENTATION = {
|
|
1504
|
+
layout: "plain",
|
|
1505
|
+
background: "#f8f9fa",
|
|
1506
|
+
linkStyle: "text",
|
|
1507
|
+
buttonColors: ["#03c75a", "#1a1a1a", "#666666"]
|
|
1508
|
+
};
|
|
1509
|
+
var SITE_PATTERN_BUTTON_COLORS_MAX = 4;
|
|
1510
|
+
var HEX_COLOR_RE2 = /^#[0-9a-f]{6}$/;
|
|
1511
|
+
function normalizeHexColor(value) {
|
|
1512
|
+
if (typeof value !== "string") return null;
|
|
1513
|
+
let hex = value.trim().toLowerCase();
|
|
1514
|
+
if (/^#[0-9a-f]{3}$/.test(hex)) hex = `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}`;
|
|
1515
|
+
return HEX_COLOR_RE2.test(hex) ? hex : null;
|
|
1516
|
+
}
|
|
1517
|
+
function readSitePatternPresentation(raw) {
|
|
1518
|
+
let value = raw;
|
|
1519
|
+
if (typeof value === "string") {
|
|
1520
|
+
try {
|
|
1521
|
+
value = JSON.parse(value);
|
|
1522
|
+
} catch {
|
|
1523
|
+
value = null;
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
const base = DEFAULT_SITE_PATTERN_PRESENTATION;
|
|
1527
|
+
if (!isRecord(value)) return base;
|
|
1528
|
+
const layout = value.layout === "card" ? "card" : "plain";
|
|
1529
|
+
const linkStyle = value.linkStyle === "buttons" ? "buttons" : "text";
|
|
1530
|
+
const background = normalizeHexColor(value.background) ?? base.background;
|
|
1531
|
+
const colors = Array.isArray(value.buttonColors) ? value.buttonColors.map(normalizeHexColor).filter((c) => c !== null).slice(0, SITE_PATTERN_BUTTON_COLORS_MAX) : [];
|
|
1532
|
+
return {
|
|
1533
|
+
layout,
|
|
1534
|
+
background,
|
|
1535
|
+
linkStyle,
|
|
1536
|
+
buttonColors: colors.length > 0 ? colors : base.buttonColors
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
function sitePatternButtonColor(presentation, index) {
|
|
1540
|
+
const colors = presentation.buttonColors;
|
|
1541
|
+
return colors[Math.min(index, colors.length - 1)] ?? DEFAULT_SITE_PATTERN_PRESENTATION.buttonColors[0];
|
|
1542
|
+
}
|
|
1543
|
+
function sitePatternPresentationAttributes(presentation) {
|
|
1544
|
+
const cssVariables = { "--rt-pattern-bg": presentation.background };
|
|
1545
|
+
presentation.buttonColors.forEach((color, index) => {
|
|
1546
|
+
cssVariables[`--rt-pattern-btn-${index + 1}`] = color;
|
|
1547
|
+
});
|
|
1548
|
+
return {
|
|
1549
|
+
dataset: {
|
|
1550
|
+
"data-pattern-layout": presentation.layout,
|
|
1551
|
+
"data-pattern-link-style": presentation.linkStyle
|
|
1552
|
+
},
|
|
1553
|
+
cssVariables
|
|
1554
|
+
};
|
|
1555
|
+
}
|
|
1506
1556
|
export {
|
|
1507
1557
|
BLOCK_NAME_PATTERN,
|
|
1558
|
+
DEFAULT_SITE_PATTERN_PRESENTATION,
|
|
1508
1559
|
EMPTY_SITE_PATTERN_PLACEMENTS,
|
|
1509
1560
|
FIELD_BINDING_SOURCE,
|
|
1510
1561
|
FIELD_BINDING_SOURCE_ALIAS,
|
|
@@ -1517,6 +1568,7 @@ export {
|
|
|
1517
1568
|
PHASE_1_CORE_BLOCKS,
|
|
1518
1569
|
PHASE_1_CSP,
|
|
1519
1570
|
POST_FOOTER_SLOT,
|
|
1571
|
+
SITE_PATTERN_BUTTON_COLORS_MAX,
|
|
1520
1572
|
SITE_PATTERN_KEY_PATTERN,
|
|
1521
1573
|
SITE_PATTERN_PLACEMENTS_KEY,
|
|
1522
1574
|
SITE_PATTERN_SLOTS,
|
|
@@ -1547,12 +1599,14 @@ export {
|
|
|
1547
1599
|
isValidSitePatternKey,
|
|
1548
1600
|
issuePreviewToken,
|
|
1549
1601
|
normalizeEmbed,
|
|
1602
|
+
normalizeHexColor,
|
|
1550
1603
|
normalizeImageAlt,
|
|
1551
1604
|
parseBlock,
|
|
1552
1605
|
postsForCollection,
|
|
1553
1606
|
postsInAnyCollection,
|
|
1554
1607
|
postsNotInAnyCollection,
|
|
1555
1608
|
readSitePatternPlacements,
|
|
1609
|
+
readSitePatternPresentation,
|
|
1556
1610
|
referencedSitePatternKeys,
|
|
1557
1611
|
renderInternalContentLinksInHtml,
|
|
1558
1612
|
renderInternalContentLinksInText,
|
|
@@ -1572,6 +1626,8 @@ export {
|
|
|
1572
1626
|
scopeImportedCss,
|
|
1573
1627
|
serializeBlock,
|
|
1574
1628
|
setSitePatternPlacementRule,
|
|
1629
|
+
sitePatternButtonColor,
|
|
1630
|
+
sitePatternPresentationAttributes,
|
|
1575
1631
|
validateCollections,
|
|
1576
1632
|
verifyPreviewToken
|
|
1577
1633
|
};
|