https://github.com/imigueldiaz/zephyr-md
A lightning-fast, zero-config TypeScript blog engine that turns Markdown into static HTML. No database, no complexity.
https://github.com/imigueldiaz/zephyr-md
Last synced: 4 months ago
JSON representation
A lightning-fast, zero-config TypeScript blog engine that turns Markdown into static HTML. No database, no complexity.
- Host: GitHub
- URL: https://github.com/imigueldiaz/zephyr-md
- Owner: imigueldiaz
- License: mit
- Created: 2025-01-08T08:59:35.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2025-01-18T07:09:54.000Z (9 months ago)
- Last Synced: 2025-01-18T07:17:20.304Z (9 months ago)
- Language: TypeScript
- Size: 235 KB
- Stars: 0
- Watchers: 1
- Forks: 1
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Zephyr MD
![]()
[](https://www.typescriptlang.org/)
[](https://nodejs.org/)
[](https://github.com/imigueldiaz/zephyr-md/tags)
[](LICENSE)A modern, lightweight static site generator focused on markdown-based blogging with exceptional syntax highlighting and accessibility.
[Demo](https://example.com) ยท [Documentation](https://example.com/docs) ยท [Report Bug](https://github.com/yourusername/zephyr-md/issues)
## โจ Features
- ๐ **Blazing Fast**: Built with TypeScript and optimized for performance
- ๐ **Markdown-First**: Full support for GitHub Flavored Markdown
- ๐จ **Syntax Highlighting**: Beautiful code highlighting with highlight.js
- ๐ฑ **Responsive Design**: Looks great on all devices
- ๐ **Dark Mode**: Automatic and manual theme switching
- โฟ **Accessibility**: WCAG 2.1 compliant
- ๐ **Code Copying**: One-click code block copying
- ๐ง **Customizable**: Easy to extend and modify
- ๐ **Security**: JWT authentication and secure file uploads
- ๐ก๏ธ **Helmet Integration**: Comprehensive security headers
- ๐ฆ **Rate Limiting**: Protection against abuse (100 requests per 15 minutes)
- ๐ค **Non-root Docker User**: Enhanced container security
- ๐ **CSP Headers**: Strict Content Security Policy## ๐ Quick Start
### Prerequisites
- Node.js 18.20.5 or higher (tested versions: 18.20.5, 22.13.0)
- Yarn 1.22.22 or higher### Installation
1. Clone the repository:
```bash
git clone https://github.com/yourusername/zephyr-md.git
cd zephyr-md
```2. Install dependencies:
```bash
yarn
```3. Start the development server:
```bash
yarn dev
```Your site will be available at `http://localhost:8585`
## ๐ Usage
### Creating Posts
1. Add your markdown files to the `content/posts` directory
2. Include front matter at the top of your markdown files:```markdown
---
title: My First Post
date: 2025-01-08
excerpt: A brief description of your post
---Your content here...
```### Configuration
Edit `config.json` to customize your site:
```json
{
"site": {
"title": "Your Site Name",
"description": "Your site description",
"author": {
"name": "Your Name",
"email": "your@email.com",
"url": "https://yoursite.com"
}
}
}
```### Building for Production
```bash
yarn build
```The static site will be generated in the `dist` directory.
## ๐ Authentication and Admin Features
Zephyr MD includes a secure admin interface for managing content:
1. Access the login page at `/login`
2. After authentication, you can:
- Upload new markdown posts through the web interface at `/upload`
- Access protected admin features
- Manage your content securely### ๐ณ Docker Deployment
#### Using Docker Run
```bash
docker run -d \
--name zephyr-md \
-p 8585:8585 \
-e JWT_SECRET=your_jwt_secret \
-e ADMIN_PASSWORD_HASH=your_bcrypt_hash \
-e ADMIN_USERNAME=admin \
-v $(pwd)/content:/app/content \
-v $(pwd)/public:/app/public \
-v $(pwd)/templates:/app/templates \
ghcr.io/imigueldiaz/zephyr-md:latest
```#### Using Docker Compose
1. Create a `.env` file:
```bash
# Authentication
JWT_SECRET=your_jwt_secret
ADMIN_PASSWORD_HASH=your_bcrypt_hash
ADMIN_USERNAME=admin# Node Environment
NODE_ENV=production
PORT=8585
```2. Run with docker-compose:
```bash
docker-compose up -d
```#### Environment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| `JWT_SECRET` | Secret key for JWT token generation (required) | - |
| `ADMIN_PASSWORD_HASH` | Bcrypt hash of admin password (required) | - |
| `ADMIN_USERNAME` | Admin username | admin |
| `PORT` | Server port | 8585 |
| `NODE_ENV` | Node environment | production |#### Generating Secure Credentials
1. Generate a secure JWT secret:
```bash
openssl rand -hex 64
```2. Generate a bcrypt hash for your password:
```bash
# Using Node.js
node -e "const bcrypt = require('bcryptjs'); bcrypt.hash('your_password', 10).then(console.log)"
```#### Security Notes
- Never store plain text passwords
- Keep your `.env` file secure and never commit it to version control
- Use strong passwords and a secure JWT secret
- The admin interface is rate-limited to prevent brute force attacks
- All uploads are validated and sanitized
- The application runs as a non-root user in Docker for enhanced security### ๐ Creating Posts via Upload
1. Log in to the admin interface at `/login`
2. Navigate to `/upload`
3. Select your markdown file
4. The file will be automatically:
- Validated for proper markdown format
- Checked for required front matter
- Sanitized for security
- Added to your content directory
- Available immediately on your site#### Markdown Front Matter Requirements
```markdown
---
title: Your Post Title
date: YYYY-MM-DD
excerpt: A brief description
---Your content here...
```## ๐จ Customization
### Themes
Zephyr MD comes with a light and dark theme out of the box. You can customize colors in:
- `templates/css/base.css`: Global styles
- `templates/css/code.css`: Code highlighting
- `templates/css/post.css`: Post-specific styles### Templates
Modify HTML templates in the `templates` directory:
- `base.html`: Main layout template
- `post.html`: Individual post template
- `index.html`: Home page template## Themes
Zephyr MD comes with a powerful theming system that allows you to completely customize the look and feel of your site. The default theme provides a modern, clean design with both light and dark modes.
### Creating a New Theme
Creating a new theme from scratch can be challenging due to the complexity of the CSS and the need to handle both light and dark modes, responsive design, and various components like code blocks, tables, and navigation. The recommended approach is:
1. **Duplicate the Default Theme**
```bash
cp -r templates/default templates/your-theme-name
```2. **Update Configuration**
Edit `config.json` to use your new theme:
```json
{
"site": {
"siteTheme": "your-theme-name",
...
}
}
```3. **Customize the Theme**
The theme structure includes:
- `base.html`: Main template with header, footer, and scripts
- `post.html`: Template for blog posts
- `index.html`: Template for the home page
- `css/`
- `base.css`: Core styles and variables
- `code.css`: Code block styling (syntax highlighting)
- `post.css`: Blog post specific styles
- `scripts/`: JavaScript files for interactivity### Theme Development Tips
- **CSS Variables**: The default theme uses CSS variables for colors, spacing, and other properties. These are defined at the root level with light/dark mode variants:
```css
:root {
--bg-color: #ffffff;
--text-color: #1a202c;
/* ... other variables ... */
}[data-theme="dark"] {
--bg-color: #1a202c;
--text-color: #f7fafc;
/* ... dark mode overrides ... */
}
```- **Code Block Styling**: Code blocks use highlight.js for syntax highlighting. The CSS is complex and carefully tuned for readability. Consider keeping the default code styling as a base.
- **Responsive Design**: The default theme includes comprehensive media queries for various screen sizes. Test your modifications across different devices.
- **Accessibility**: The default theme follows WCAG guidelines. Maintain good color contrast ratios and semantic HTML structure.
### Testing Your Theme
1. Make sure all features work in both light and dark modes
2. Test responsive layouts at different screen sizes
3. Verify code block formatting with different languages
4. Check table layouts and responsive behavior
5. Test navigation and interactive elements### Common Pitfalls
- **Starting from Scratch**: The default theme's CSS is complex and handles many edge cases. Starting from scratch means reimplementing all this functionality.
- **Dark Mode**: Implementing a good dark mode requires careful consideration of colors, contrasts, and transitions.
- **Code Blocks**: Syntax highlighting and line numbers require specific CSS structure. Modifying these can break functionality.
- **Performance**: Complex CSS selectors and transitions can impact performance. The default theme is optimized for this.### Recommended Workflow
1. Start by duplicating the default theme
2. Make small, incremental changes
3. Test frequently across different devices and modes
4. Use browser dev tools to understand the existing styles
5. Document your changes for future maintenance## Docker
You can run Zephyr MD using Docker:
```bash
# Build the image
docker build -t zephyr-md .# Run the container
docker run -d \
-p 8585:8585 \
-v $(pwd)/content:/app/content \
-v $(pwd)/public:/app/public \
--name zephyr-md \
zephyr-md
```The container exposes port 8585 and uses two volumes:
- `/app/content`: For your markdown files
- `/app/public`: For static files (images, css, etc)You can customize the theme by mounting the templates directory:
```bash
docker run -d \
-p 8585:8585 \
-v $(pwd)/content:/app/content \
-v $(pwd)/public:/app/public \
-v $(pwd)/templates:/app/templates \
--name zephyr-md \
zephyr-md
```## ๐ณ Docker Support
### Quick Start
The easiest way to get started is using Docker. Just run:
```bash
docker run -d \
-p 8585:8585 \
-v ./content:/app/content \
--name zephyr-md \
ghcr.io/imigueldiaz/zephyr-md:latest
```### Using Docker Compose
For a more complete setup, use Docker Compose:
1. Create a `docker-compose.yml`:
```yaml
services:
app:
image: ghcr.io/imigueldiaz/zephyr-md:latest
ports:
- "8585:8585"
volumes:
- ./content:/app/content
- ./public:/app/public
- ./templates:/app/templates
environment:
- NODE_ENV=production
- PORT=8585
restart: unless-stopped
```2. Start the service:
```bash
docker-compose up -d
```### Environment Variables
- `PORT`: Server port (default: 8585)
- `HOST`: Server host (default: localhost)
- `NODE_ENV`: Environment mode (development/production)### Volumes
- `/app/content`: Blog posts and content
- `/app/public`: Static files (images, etc.)
- `/app/templates`: Theme templates## ๐ง Advanced Configuration
### Security Settings
The application uses Helmet for security headers. Default CSP configuration:
```javascript
{
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'", 'cdnjs.cloudflare.com'],
styleSrc: ["'self'", "'unsafe-inline'", 'fonts.googleapis.com', 'cdnjs.cloudflare.com'],
imgSrc: ["'self'", "data:", "https:"],
fontSrc: ["'self'", "fonts.gstatic.com", "fonts.googleapis.com"]
}
```### Rate Limiting
Default rate limit configuration:
- Window: 15 minutes
- Max Requests: 100 per IP
- Standard Headers: Enabled
- Legacy Headers: Disabled### Logging
- Automatic log directory creation at `logs/`
- Structured logging with timestamp and log levels
- Production-ready logging configuration## ๐๏ธ Project Structure
```
zephyr-md/
โโโ content/ # Blog posts and content
โ โโโ posts/ # Markdown files
โโโ public/ # Static assets
โโโ src/ # TypeScript source
โโโ templates/ # Theme templates
โ โโโ default/ # Default theme
โ โโโ css/ # Stylesheets
โ โโโ scripts/ # JavaScript
โ โโโ *.html # Template files
โโโ config.json # Site configuration
```## ๐ License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## ๐ Acknowledgments
- [marked](https://github.com/markedjs/marked) for Markdown parsing
- [highlight.js](https://highlightjs.org/) for syntax highlighting
- [Express](https://expressjs.com/) for the development server## ๐ Support
- Create a [GitHub Issue](https://github.com/yourusername/zephyr-md/issues) for bug reports and feature requests
- For detailed questions, use [GitHub Discussions](https://github.com/yourusername/zephyr-md/discussions)---
Made with โค๏ธ by [Ignacio de Miguel Diaz](https://imigueldiaz.dev)