npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@partyvelope/react-block-cms

v0.4.0

Published

블록 기반 콘텐츠 CMS — SSR/SEO 안전한 렌더러 + 실시간 미리보기 admin 에디터 (데이터 계층 무관, React).

Readme

@partyvelope/react-block-cms

블록 기반 콘텐츠 CMS 툴킷. SSR/SEO 안전한 렌더러실시간 미리보기 admin 에디터를 제공하며, 데이터 계층(백엔드)에 종속되지 않습니다.

  • 🧱 블록 타입: hero, rich-text, card-grid, two-column, process-steps, faq, cta, text-panel, callout, table, card-list, info-columns, raw-html, floating-toolbar
  • 🖥️ 렌더러는 서버 컴포넌트 안전(hooks 없음) → Next.js App Router / RSC에서 그대로 SSR, 봇 크롤링/SEO OK
  • ✏️ 에디터: 블록 추가·순서변경·표시토글·삭제 + 타입별 폼 + 편집 옆 실시간 미리보기 + 토스트 + 삭제 확인
  • 🔌 데이터 계층 무관: onSave(payload) 콜백만 연결하면 REST/GraphQL/무엇이든
  • 🎨 비개발자용 입력: 제목 강조·줄바꿈·이미지 좌우 위치 등 태그 없이 칸으로 입력

설치

npm i @partyvelope/react-block-cms

peer deps: react >=18, react-dom >=18.

스타일 (둘 중 하나)

A. 컴파일된 CSS (Tailwind 불필요)

import "@partyvelope/react-block-cms/styles.css";

B. Tailwind v4 프로젝트globals.css:

@import "tailwindcss";
@import "@partyvelope/react-block-cms/theme.css";
@source "../node_modules/@partyvelope/react-block-cms/dist";

테마 색상 변경 (어느 방식이든)

:root {
  --cms-primary: #16a34a;
  --cms-primary-dark: #15803d;
  --cms-primary-surface: #f0fdf4;
  --cms-primary-light: #dcfce7;
  --cms-primary-300: #86efac;
}

공개 페이지 렌더링 (서버 컴포넌트)

import { BlockRenderer, type CmsBlock } from "@partyvelope/react-block-cms";

export default async function Page() {
  const blocks: CmsBlock[] = await loadBlocksFromAnywhere(); // 당신의 백엔드
  return <BlockRenderer blocks={blocks} />;
}

Admin 에디터 (클라이언트 컴포넌트)

"use client";
import { PageEditor } from "@partyvelope/react-block-cms/editor";
import type { AdminPage, SavePagePayload } from "@partyvelope/react-block-cms";

export default function Editor({ page }: { page: AdminPage }) {
  const handleSave = async (payload: SavePagePayload) => {
    await fetch(`/api/pages/${page.slug}`, {
      method: "PUT",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(payload),
    });
  };
  return <PageEditor page={page} onSave={handleSave} />;
}

데이터 형태 (최상위)

interface CmsBlock { id: string; type: BlockType; data: BlockDataMap[BlockType]; order?: number; visible?: boolean; }
interface AdminPage { slug: string; displayName: string; theme: { seo?: { title?: string; description?: string } }; blocks: AdminBlock[]; }
interface SavePagePayload { displayName?: string; theme?: {...}; blocks: { type; data; visible }[]; }
type CmsButton = { label: string; href: string; style: "primary" | "outline"; icon?: string };

블록의 data는 JSON이므로 DB에 그대로 저장(JSONB 권장). 타입 단일 소스는 src/blocks.ts — 아래는 그 요약이다.

⚠️ [bespoke] 필드 주의: 타입·에디터(BlockForm)로는 지원하지만 번들 BlockRenderer는 렌더하지 않는다. 시안 맞춤 등 소비자 커스텀 렌더러에서 읽어 렌더하는 필드다(번들 렌더러만 쓰면 무시 = 빈 출력). 표시 없는 필드는 번들 렌더러가 렌더한다.

블록별 data 필드

대부분 블록 공통: eyebrow?(윗 라벨), heading(제목), intro?(소개), bg?(섹션 배경).

hero — 상단 배너

title, titleAccent?(강조 줄), subtitle?, subtitle2?, eyebrow?, breadcrumb?, badge?, bg:{type:"color"|"image",value}, bgImage?, theme?:"dark"|"light", tags?:string[], buttons:CmsButton[] [bespoke] image?:{src,alt} · imageStyle?:"portrait"|"visual"|"wide" · panel?:{title?,items?:string[],note?}(이미지 대신 우측 리스트 카드)

rich-text — 제목+본문(HTML)

eyebrow?, heading?, html(신뢰 입력 → dangerouslySetInnerHTML)

card-grid — 카드 그리드

columns:2|3|4, variant?:"icon"|"number"|"number-lg"|"icon-num", bg?:"white"|"neutral", cards:{icon,num?,title,desc,href?,items?:string[]}[] [bespoke] gallery?:{src,alt}[](있으면 카드 대신 사진 갤러리)

two-column — 이미지+텍스트

heading, paragraphs:string[], image:{src,alt}, imageSide:"left"|"right", list?:string[], badges?:string[], imageCaption?:{label?,title?}, blob?, listCard?:{title,items,link?}, buttons? [bespoke] bg? · listCard.note?(작은 주석) · calloutCard?:{title?,text?,buttons?}(우측 강조박스) · note?:{text,style?:"notice"|"legal"}(본문 아래 안내/면책 박스)

text-panel — 텍스트 + 우측 패널

heading, headingAccent?, paragraphs, quote?(인용박스), bg?:"white"|"surface", panelTitle, panelItems?(체크리스트) 또는 panelIcon?+panelText?+panelTone?:"primary"|"warning"(하이라이트 카드) [bespoke] quoteStyle?:"notice"|"legal"(인용박스 스타일) · buttons?(본문 아래 버튼)

callout — 가운데 강조 밴드

heading, headingAccent?, text?, badges?:string[], theme?:"surface"|"dark"

cta — 강조 배너(버튼)

heading, text?, buttons, theme:"dark"|"light" · [bespoke] bg?

table — 표

heading?, intro?, bg?:"white"|"neutral", dense?, headers:string[], rows:string[][]

card-list — 리스트 카드

columns:2|3, bg?, cards:{num?,title,subtitle?,items:string[]}[]

process-steps — 단계 안내

heading, intro?, steps:{num,title,desc}[]

faq — 자주 묻는 질문

heading?, items:{q,a}[] · [bespoke] note?:{text,style?:"notice"|"legal"}(하단 안내/면책 박스)

info-columns — 2단 정보(시간·지도·연락처)

bg?, left/right: InfoPanel. InfoPanel kind별:

  • card: title?,icon?,rows?:{label,value,highlight?}[],lines?:{icon?,text,href?}[],note?:{icon?,title?,text},buttons?:{label,href,primary?}[] · [bespoke] table?:{headers?:string[],rows:string[][]}
  • text: eyebrow?,heading?,paragraphs?,buttons?
  • map: title?,addressLines?:string[],sub?,links?:{label,href,primary?}[]

raw-html — 임의 HTML 섹션

bg?:"white"|"neutral"|"surface", html(신뢰 입력)

floating-toolbar — 우하단 플로팅 버튼

items:{icon,href,label,primary?}[]

빌드 / 배포

npm run build         # tsup(JS+타입) + tailwind(CSS)
npm publish --access public   # 스코프 공개 패키지

라이선스

MIT