Version: 1.0.0 | Updated: December 2025
A powerful, client-side Content Management System (CMS) for managing Markdown/MDX content and images directly on GitHub, Gitea, or Gogs repositories. Built with React 19 and TypeScript, featuring a modern Notion-inspired UI.
A modern Git-first CMS for Astro & Next.js
Quick Links: Changelog β’ Licenses β’ Contributing
| Feature | Description |
|---|---|
| π No Backend Required | Runs entirely in your browser, communicates directly with Git APIs |
| π Client-Side Encryption | PAT encrypted with Web Crypto API (AES-GCM), stored in sessionStorage |
| π Multi-Platform Support | GitHub, Gitea, and Gogs (self-hosted) |
| π Multi-Language | English and Vietnamese (i18n ready) |
| π¨ Notion-Style UI | Clean, minimalist, distraction-free interface |
| β‘ Optimistic Locking | SHA-check prevents overwriting concurrent changes |
| π Deep Linking | URL query parameters sync with app state |
The central hub for content management.
- View Modes: Switch between dense data table or visual card grid with cover image previews
- Smart Search: Instant filtering by title, author, tags, or any frontmatter field
- Quick Actions:
- Edit frontmatter properties inline
- Split-pane Markdown editor with live preview
- Upload new post file / Replace existing
- Update cover image
- Delete posts with confirmation
- Sorting: Sort by name, date (asc/desc)
- SHA Validation: Ensures file integrity before updates
Dedicated asset library for managing media files.
- Gallery View: Visual grid with lazy-loaded thumbnails
- Upload Features:
- Bulk upload with drag & drop
- Client-side compression (configurable max size/width)
- Rename files before upload
- Quick Actions:
- View in lightbox with zoom
- Copy public URL (relative or absolute based on project type)
- Delete with confirmation
- Filtering: Search by filename, sort by name/size
Define and validate content structure.
- Schema Generation:
- Upload existing post to auto-generate validation schema
- Scan repository to select from existing posts
- Field Types: String, Date, Array, Object, Boolean, Number
- Table Configuration:
- Choose which frontmatter fields appear in Posts table
- Configure column widths (percentage-based)
- Max 5 visible columns
- Sample Download: Export blank Markdown template with defined frontmatter
Guided 3-step wizard for creating quality content.
Step 1 - Assets:
- Bulk upload images with preview
- Auto-compression based on settings
- Rename images before commit
Step 2 - Content:
- Upload Markdown file
- Automatic frontmatter validation against template
- Smart image path detection and mapping
- Link uploaded images to frontmatter fields (e.g.,
image,cover) - Update body image references automatically
Step 3 - Publish:
- Review all changes
- Commit images first, then post
- Customizable commit message templates
- Success confirmation with quick actions
Data safety and export tools.
- Archive Downloads:
- Generate
.zipof entirepostsdirectory - Generate
.zipof entireimagesdirectory - File size display before download
- Generate
- Config Export:
- Download
.acmrc.jsonconfiguration file from repository
- Download
Global application configuration.
Project Configuration:
| Setting | Description |
|---|---|
| Project Type | "Web Project" (Astro/Next.js with domain) or "File Library" (raw GitHub links) |
| Posts Path | Directory containing Markdown/MDX files |
| Images Path | Directory containing media assets |
| Domain URL | Production URL for asset links (Web Project mode) |
Content Settings:
| Setting | Description |
|---|---|
| Post File Types | Extensions to include (e.g., md,mdx) |
| Image File Types | Extensions to include (e.g., jpg,png,webp,gif,svg) |
| Publish Date Source | Use file date or system date for new posts |
Image Optimization:
| Setting | Description |
|---|---|
| Compression Enabled | Toggle client-side image compression |
| Max File Size | Maximum KB before compression triggers |
| Max Width | Resize images exceeding this width |
Commit Templates:
| Template | Default Value |
|---|---|
| New Post | Add: {filename} |
| Update Post | Update: {filename} |
| New Image | Add image: {filename} |
| Update Image | Update image: {filename} |
Other Options:
- Import/Export local settings as JSON
- Sync settings to
.acmrc.jsonin repository - Delete remote config file
- Language switcher (EN/VI)
- Logout with optional settings reset
pageel-core/
βββ core/
β βββ src/
β β βββ App.tsx # Main application entry point
β β βββ index.tsx # React DOM render
β β βββ types.ts # TypeScript interfaces & types
β β β
β β βββ components/
β β β βββ Dashboard.tsx # Main layout with sidebar navigation
β β β βββ GitServiceConnect.tsx # Login form component
β β β βββ SetupWizard.tsx # Initial configuration wizard
β β β βββ PostList.tsx # Posts management module
β β β βββ PostDetailView.tsx # Single post editor
β β β βββ ImageList.tsx # Images management module
β β β βββ TemplateGenerator.tsx # Schema configuration
β β β βββ PostWorkflow.tsx # New post creation wizard
β β β βββ BackupManager.tsx # Backup/export tools
β β β βββ SettingsView.tsx # Application settings
β β β βββ Sidebar.tsx # Navigation sidebar
β β β βββ icons/ # 42 SVG icon components
β β β
β β βββ services/
β β β βββ baseGitService.ts # Shared Git service logic
β β β βββ baseGiteaService.ts # Gitea/Gogs shared adapter
β β β βββ githubService.ts # GitHub API adapter
β β β βββ giteaService.ts # Gitea API adapter
β β β βββ gogsService.ts # Gogs API adapter
β β β
β β βββ utils/
β β β βββ crypto.ts # Web Crypto API utilities (AES-GCM)
β β β βββ image.ts # Image compression & validation
β β β βββ parsing.ts # Markdown/frontmatter parsing
β β β
β β βββ i18n/
β β βββ I18nContext.tsx # React i18n context provider
β β βββ translations.ts # EN/VI translation strings
β β
β βββ index.html # HTML shell with CDN dependencies
β βββ vite.config.ts # Vite development configuration
β βββ tsconfig.json # TypeScript configuration
β βββ package.json # Dependencies
β
βββ docs/
β βββ guides/
β βββ CONTRIBUTING.md # Contribution guidelines
β βββ DEVELOPMENT.md # Development guide
β
βββ README.md
βββ CHANGELOG.md
βββ LICENSES.md
1. Adapter Pattern (IGitService Interface)
interface IGitService {
getRepoContents(path: string): Promise<ContentInfo[]>;
listFiles(path: string): Promise<RepoTreeInfo[]>;
getFileContent(path: string): Promise<string>;
uploadFile(path, file, commitMessage, sha?): Promise<any>;
createFileFromString(path, content, commitMessage): Promise<any>;
updateFileContent(path, content, commitMessage, sha): Promise<any>;
deleteFile(path, sha, commitMessage): Promise<any>;
getFileAsBlob(path: string): Promise<Blob>;
// ... discovery methods
}GithubAdapter- GitHub REST API v3GiteaAdapter- Gitea API (self-hosted)GogsAdapter- Gogs API (self-hosted)
2. Security Model
- PAT encrypted with AES-GCM (256-bit key)
- Key generated per session via
crypto.getRandomValues() - Encrypted token stored in
sessionStorage(cleared on tab close) - Key stored separately as exported JWK
3. State Management
| Location | Data |
|---|---|
sessionStorage |
Encrypted PAT, crypto key, selected repo, service type |
localStorage |
Settings (keyed by repo: postsPath_{repo}, projectType_{repo}, etc.) |
| URL Query String | Active view/tab (?view=posts, ?view=images) |
Remote .acmrc.json |
Repository-synced configuration file |
4. Performance Optimizations
- Git Tree API (Recursive): Fetches entire directory tree in single request
- Lazy Loading: Images loaded on scroll (IntersectionObserver)
- Blob Fetching: Private repo images fetched via authenticated API
- Optimistic Locking: SHA validation before all write operations
- Modern browser with ES2020+ support
- Node.js 20.19+ or 22.12+ (for development)
- Git repository on GitHub, Gitea, or Gogs
git clone https://github.com/pageel/pageel-core.git
cd pageel-core/core
npm installnpm run devOpen http://localhost:3000 in your browser.
For GitHub:
- Go to GitHub Token Settings
- Create a Fine-Grained Personal Access Token
- Select your repository
- Grant Contents permission (Read and write)
For Gitea/Gogs:
- Navigate to Settings β Applications β Generate Token
- Copy the access token
- Select your Git service (GitHub/Gitea/Gogs)
- Enter repository URL (e.g.,
username/repoor full URL) - Paste your access token
- For self-hosted: Enter instance URL (e.g.,
https://git.example.com)
- Follow the file tree explorer to select your content directory
- Select your images directory
- Choose project type (Web Project or File Library)
- Configuration is saved locally and optionally synced to repository
| Command | Description |
|---|---|
npm run dev |
Start Vite development server (port 3000) |
npm run build |
Build production bundle |
npm run preview |
Preview production build locally |
| Category | Technology |
|---|---|
| Framework | React 19 |
| Language | TypeScript 5.9+ |
| Build Tool | Vite 5+ |
| Styling | Tailwind CSS (CDN with Typography plugin) |
| Icons | Custom SVG components (42 icons) |
| Fonts | Inter (Google Fonts) |
| Library | Purpose |
|---|---|
marked |
Markdown to HTML parsing |
DOMPurify |
HTML sanitization |
JSZip |
ZIP archive generation |
js-yaml |
YAML frontmatter parsing |
- WYSIWYG Markdown Editor: Rich-text editing for non-technical users
- Image Gallery in Editor: Insert images directly from asset library
- GitLab Support
- Draft Mode with local auto-save
- Scheduled Publishing
- Social Sharing integration
Contributions are welcome! Please see our Contributing Guide for details.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Use GitHub Issues
- Include browser version and console errors
- Describe steps to reproduce
This project is licensed under the MIT License. See the LICENSES.md file for more details on third-party software.
Made with βοΈ by Pageel
