Pages CMS · GitHub · Cloudflare Pages
Admin Publishing Studio
Manage your novel library, bulk-convert .zip / .md / .txt chapter batches, generate frontmatter-ready Markdown files, or open Pages CMS to commit directly to GitHub.
Tip: For direct one-command import into your local repository, run npm run import -- --novel <slug> --src ./chapters.zip.
| Ch. # | Chapter Title | Status | Source | Action |
|---|
Create Chapter Markdown File
Generates a validated src/content/chapters/<novelSlug>-chapter-<N>.md file ready for Pages CMS or GitHub.
0 words
Create Novel Metadata File
Generates a validated src/content/novels/<slug>.md file matching the Zod content schema and Pages CMS fields.
Pages CMS Configuration (.pages.yml)
Committed at the repository root. Sign in at app.pagescms.org to edit novels, chapters, and announcements visually.
# Pages CMS configuration - https://pagescms.org
# 1. Open https://app.pagescms.org 2. Sign in with GitHub 3. Pick this repository.
# Every save becomes a Git commit -> Cloudflare Pages rebuilds automatically.
media:
- name: covers
label: Novel covers
input: public/images/covers
output: /images/covers
extensions: [webp, avif, jpg, jpeg, png, svg]
- name: uploads
label: Chapter images
input: public/images/uploads
output: /images/uploads
extensions: [webp, avif, jpg, jpeg, png, gif]
# ADVANCED bulk path: upload several ready-made chapter .md files (each must already contain the
# front matter shown in README "Bulk import"). For ZIP / TXT / numbering help use `npm run import`.
- name: chapter-files
label: Chapter files (advanced bulk upload)
input: src/content/chapters
output: /src/content/chapters
extensions: [md]
content:
# ------------------------------------------------------------------ NOVELS
- name: novels
label: Novels
type: collection
path: src/content/novels
filename: "{primary}.md" # slug is generated from the title (slugified file name)
format: yaml-frontmatter
view:
primary: title
fields: [title, status, countryOfOrigin, isFeatured, isPopular]
sort: [title]
default:
sort: title
fields:
- { name: title, label: Title, type: string, required: true }
- { name: slug, label: "Slug (optional manual override - lowercase-with-dashes)", type: string, description: "Leave empty to use the file name generated from the title. If you set it, use the SAME value in each chapter's novelSlug." }
- { name: alternativeTitle, label: Alternative title, type: string }
- { name: originalTitle, label: Original title (CJK), type: string }
- { name: author, label: Author, type: string, required: true }
- { name: translator, label: Translator, type: string }
- { name: coverImage, label: Cover image (2:3, WebP recommended), type: image, options: { media: covers, path: public/images/covers } }
- { name: synopsis, label: Synopsis (short, used for SEO), type: text, required: true }
- { name: description, label: Short extra description, type: text }
- name: status
label: Status
type: select
required: true
default: Ongoing
options: { values: [Ongoing, Completed, Hiatus, Dropped] }
- name: countryOfOrigin
label: Country of origin
type: select
default: China
options: { values: [China, Korea, Japan, Other] }
- { name: originalLanguage, label: Original language, type: string, default: Chinese }
- { name: genres, label: Genres, type: string, list: true, description: "e.g. Xianxia, Cultivation, Romance, Regression, Slice of Life..." }
- { name: tags, label: Tags, type: string, list: true }
- { name: releaseFrequency, label: "Release frequency (e.g. Daily, Weekly)", type: string }
- { name: publicationDate, label: Publication date, type: date, required: true }
- { name: lastUpdated, label: Last updated (optional - auto from newest chapter), type: date }
- { name: totalChapters, label: Total chapters of the original work, type: number }
- { name: isFeatured, label: Featured on homepage, type: boolean, default: false }
- { name: isPopular, label: Show in Popular, type: boolean, default: false }
- { name: popularRank, label: Popular rank (1 = first), type: number }
- { name: rating, label: "Rating 0-5 (optional - leave empty if none)", type: number }
- { name: patreonUrl, label: Novel Patreon URL, type: string }
- { name: supportUrl, label: Other support URL, type: string }
- { name: contentWarning, label: Content warning, type: text }
- { name: seoTitle, label: SEO title, type: string }
- { name: seoDescription, label: SEO description, type: text }
- { name: body, label: Long description (Markdown), type: rich-text }
# ---------------------------------------------------------------- CHAPTERS
- name: chapters
label: Chapters
type: collection
path: src/content/chapters
filename: "{novelSlug}-chapter-{chapterNumber}.md"
format: yaml-frontmatter
view:
primary: title
fields: [novelSlug, chapterNumber, isPublished, isAdvanceChapter, publishDate]
sort: [novelSlug, chapterNumber]
search: [title, novelSlug]
default:
sort: chapterNumber
order: desc
fields:
- { name: novelSlug, label: "Novel slug (the novel's file name, e.g. heavenly-sword-ascension)", type: string, required: true }
- { name: chapterNumber, label: Chapter number, type: number, required: true }
- { name: title, label: Chapter title, type: string, required: true }
- { name: publishDate, label: Publish date, type: date, required: true }
- { name: lastModified, label: Last modified, type: date }
- { name: isPublished, label: "Published (untick to save as draft)", type: boolean, default: true }
- { name: isAdvanceChapter, label: "Advance chapter (Patreon only - never published on the site)", type: boolean, default: false }
- { name: patreonPostUrl, label: Patreon post URL for this chapter (advance only), type: string }
- { name: translatorNote, label: Translator's note (shown under free chapters), type: text }
- { name: wordCount, label: Word count (leave empty - calculated automatically), type: number }
- { name: body, label: "Chapter content (Markdown; may stay empty for advance chapters)", type: rich-text }
# ----------------------------------------------------------- ANNOUNCEMENTS
- name: announcements
label: Homepage announcements
type: collection
path: src/content/announcements
filename: "{primary}.md"
format: yaml-frontmatter
view: { primary: title, fields: [title, active, date], sort: [date], default: { sort: date, order: desc } }
fields:
- { name: title, label: Title, type: string, required: true }
- { name: active, label: Show on homepage, type: boolean, default: true }
- { name: date, label: Date, type: date, required: true }
- { name: linkUrl, label: Link URL, type: string }
- { name: linkLabel, label: Link label, type: string }
- { name: body, label: Message, type: text }