Skip to content

playwjj/studio-inkless-blog

Repository files navigation

Studio Inkless Blog

A modern, feature-rich blog platform built with Nuxt 3, Tailwind CSS, and Cloudflare

Live Demo β€’ Features β€’ Getting Started β€’ Documentation

Nuxt 3 TypeScript Tailwind CSS Cloudflare Pages


🌐 Live Preview

Visit the live site: https://blog.404401.xyz

Experience all features in action including the admin dashboard, content management system, and responsive design.


πŸ“‘ Table of Contents


✨ Features

Core Features

  • Server-side Rendering: Built with Nuxt 3 for optimal SEO and performance
  • RESTful API: Clean API architecture with pagination support
  • Responsive Design: Beautiful UI with Tailwind CSS
  • Progressive Loading: Page transition indicators for smooth navigation

Content Discovery

  • Advanced Search: Real-time search across titles, excerpts, and tags
  • Pagination: Smooth pagination with page number navigation
  • Category & Tag Filtering: Easy content discovery with filters
  • Back to Top: Floating button for better navigation on long pages

SEO & Performance

  • Complete SEO Meta Tags: Open Graph and Twitter Card support
  • Image Optimization: Automatic optimization with Nuxt Image
  • Lazy Loading: Images load progressively for better performance
  • Fast & Global: Deployed on Cloudflare Pages CDN

Admin & Content Management

  • Authentication System: Secure login and session management
  • File Management: Upload and manage files with Cloudflare R2 (S3 API)
  • Database Integration: Full CRUD operations with D1 SQL Studio
  • User Management: Support for multiple users and roles
  • Content Blocks: 10+ reusable content blocks for page building

πŸ›  Tech Stack

Core Framework

  • Nuxt 3 - Vue.js framework with server-side rendering (SSR)
  • Vue 3 - Progressive JavaScript framework
  • TypeScript - Type-safe development

UI & Styling

Backend & Infrastructure

πŸš€ Getting Started

πŸ’‘ Tip: Check out the live demo to see all features in action before setting up your own instance!

Prerequisites

  • Node.js 20 or later
  • npm or yarn
  • Cloudflare account (for R2 storage and deployment)

Installation

# Install dependencies
npm install

# Start development server
npm run dev

# Build for production
npm run build

# Preview production build
npm run preview

Visit http://localhost:3000 to see your blog in action!

Environment Configuration

Create a .env.local file in the project root with the following variables:

# Database Configuration (D1 SQL Studio)
DB_API_KEY=your_db_api_key
DB_API_URL=https://your-d1-sql-studio.example.com

# File Storage Configuration (Cloudflare R2)
R2_ACCOUNT_ID=your_cloudflare_account_id
R2_ACCESS_KEY_ID=your_r2_access_key_id
R2_SECRET_ACCESS_KEY=your_r2_secret_access_key
R2_BUCKET_NAME=your_r2_bucket_name
R2_PUBLIC_URL=https://your-public-r2-url.com

# Session Configuration
SESSION_SECRET=your-secret-key-min-32-chars-required

For detailed setup instructions, see the sections below.

πŸ—„οΈ Database Setup with D1 SQL Studio

This project requires D1 SQL Studio. The application relies on the REST API exposed by D1 SQL Studio for all data reads and writes (posts, pages, categories, tags, site config). You must run or deploy D1 SQL Studio and provide its API URL and API key to the site via environment variables.

Quick steps:

  1. Install or deploy D1 SQL Studio. See the project on GitHub: https://github.com/playwjj/d1-sql-studio
  2. Follow the D1 SQL Studio README to start it locally or deploy to your hosting environment. After startup you will have a REST API endpoint and an API key/secret.
  3. Set environment variables for this project:
DB_API_KEY=your_db_api_key
DB_API_URL=https://your-d1-sql-studio.example.com
  1. Restart your application so Nuxt picks up the runtime config.

Deployment note β€” Cloudflare Pages / other platforms:

πŸ“ File Management with Cloudflare R2

This project includes a complete file management system using Cloudflare R2, an S3-compatible object storage service. All file uploads, downloads, and deletions are handled through the R2 API.

R2 Configuration

To use the file upload feature, you need to configure Cloudflare R2 credentials via environment variables:

# Cloudflare R2 Configuration
R2_ACCOUNT_ID=your_cloudflare_account_id
R2_ACCESS_KEY_ID=your_r2_access_key_id
R2_SECRET_ACCESS_KEY=your_r2_secret_access_key
R2_BUCKET_NAME=your_r2_bucket_name
R2_PUBLIC_URL=https://your-public-r2-url.com

Getting R2 Credentials

  1. Account ID: Get this from your Cloudflare dashboard

    • Go to Cloudflare Dashboard β†’ R2 β†’ Account details
    • Copy your Account ID
  2. Access Key & Secret:

    • In Cloudflare Dashboard β†’ R2 β†’ API tokens
    • Click "Create API token"
    • Generate a token with permissions for reading and writing to R2
    • Save the Access Key ID and Secret Access Key
  3. Bucket Name:

    • Create a bucket in R2 (e.g., studio-inkless-files)
    • Use this name in the configuration
  4. Public URL:

    • If you want public file access, create a custom domain or use R2's default URL
    • Example: https://files.example.com or https://your-bucket.your-domain.com
    • Configure in Cloudflare R2 settings

File Upload API

Endpoint: POST /api/admin/files/upload

Upload one or multiple files to R2 storage:

curl -X POST http://localhost:3000/api/admin/files/upload \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -F "file=@/path/to/image.jpg" \
  -F "file=@/path/to/document.pdf"

Response:

{
  "success": true,
  "files": [
    {
      "id": "file-uuid",
      "file_name": "image.jpg",
      "file_key": "uploads/2024/12/uuid.jpg",
      "file_size": 102400,
      "mime_type": "image/jpeg",
      "public_url": "https://files.example.com/uploads/2024/12/uuid.jpg",
      "created_at": "2024-12-14T10:30:00Z",
      "user_id": "user-uuid"
    }
  ]
}

File Retrieval API

Endpoint: GET /api/admin/files

List all uploaded files with pagination and filtering:

Query Parameters:

  • page - Page number (default: 1)
  • limit - Results per page (default: 20)
  • search - Search by file name
  • mime_type - Filter by MIME type (e.g., image/jpeg, application/pdf)

Example:

GET /api/admin/files?page=1&limit=20&search=avatar&mime_type=image%2Fjpeg

Response:

{
  "success": true,
  "files": [
    {
      "id": "file-uuid",
      "file_name": "avatar.jpg",
      "file_key": "uploads/2024/12/uuid.jpg",
      "file_size": 51200,
      "mime_type": "image/jpeg",
      "public_url": "https://files.example.com/uploads/2024/12/uuid.jpg",
      "created_at": "2024-12-14T10:00:00Z",
      "user_id": "user-uuid"
    }
  ],
  "total": 1,
  "totalSize": 51200,
  "page": 1,
  "limit": 20
}

File Deletion API

Endpoint: DELETE /api/admin/files/[id]

Delete a file from R2 storage:

curl -X DELETE http://localhost:3000/api/admin/files/file-uuid \
  -H "Authorization: Bearer YOUR_TOKEN"

Response:

{
  "success": true,
  "message": "File deleted successfully"
}

File Storage Structure

Files are automatically organized in R2 by upload date:

uploads/
β”œβ”€β”€ 2024/
β”‚   β”œβ”€β”€ 12/
β”‚   β”‚   β”œβ”€β”€ uuid-1.jpg
β”‚   β”‚   β”œβ”€β”€ uuid-2.pdf
β”‚   β”‚   └── uuid-3.png
β”‚   └── 11/
β”‚       β”œβ”€β”€ uuid-4.jpg
β”‚       └── uuid-5.doc

Supported File Types

The system validates files based on:

  • MIME types: Images (JPEG, PNG, WebP), Documents (PDF, DOC, DOCX), Videos (MP4, WebM)
  • File size limits: Configurable per file type
  • Extensions: Validated against allowed extensions

Deployment with R2

When deploying to Cloudflare Pages:

  1. Add R2 credentials to your Pages project environment variables:

    • Go to Pages β†’ Your project β†’ Settings β†’ Environment variables
    • Add each R2 environment variable for both Preview and Production environments
  2. S3 API Compatibility:

    • R2 uses S3 API, so the configuration is fully compatible
    • No special Cloudflare Workers code needed
    • File uploads work seamlessly on Pages runtime
  3. Public Access:

    • Configure a custom domain or R2's default public URL
    • Files are served directly from R2 or your custom domain
    • CDN caching can be enabled for optimal performance

Project Structure

studio-inkless-blog/
β”œβ”€β”€ components/                    # Vue components
β”‚   β”œβ”€β”€ Header.vue                # Header component
β”‚   β”œβ”€β”€ Footer.vue                # Footer component
β”‚   β”œβ”€β”€ BlogCard.vue              # Blog post card
β”‚   β”œβ”€β”€ Pagination.vue            # Pagination component
β”‚   β”œβ”€β”€ BackToTop.vue             # Back to top button
β”‚   β”œβ”€β”€ admin/                    # Admin UI components
β”‚   β”‚   β”œβ”€β”€ ConfirmDialog.vue
β”‚   β”‚   β”œβ”€β”€ EditorFileDialog.vue
β”‚   β”‚   β”œβ”€β”€ EditorImageDialog.vue
β”‚   β”‚   β”œβ”€β”€ FilePicker.vue
β”‚   β”‚   β”œβ”€β”€ ImageUploader.vue
β”‚   β”‚   β”œβ”€β”€ PageBlocksEditor.vue
β”‚   β”‚   β”œβ”€β”€ StatCard.vue
β”‚   β”‚   └── Toast.vue
β”‚   └── blocks/                   # Page content blocks
β”‚       β”œβ”€β”€ BlockHero.vue
β”‚       β”œβ”€β”€ BlockFeatures.vue
β”‚       β”œβ”€β”€ BlockCta.vue
β”‚       β”œβ”€β”€ BlockText.vue
β”‚       β”œβ”€β”€ BlockGallery.vue
β”‚       β”œβ”€β”€ BlockTestimonials.vue
β”‚       β”œβ”€β”€ BlockFaq.vue
β”‚       β”œβ”€β”€ BlockStats.vue
β”‚       β”œβ”€β”€ BlockVideo.vue
β”‚       └── BlockCustom.vue
β”œβ”€β”€ composables/                  # Reusable composition functions
β”‚   β”œβ”€β”€ useAuth.ts               # Authentication composable
β”‚   β”œβ”€β”€ useFormatDate.ts         # Date formatting
β”‚   β”œβ”€β”€ useFormValidation.ts     # Form validation
β”‚   β”œβ”€β”€ useNotification.ts       # Toast notifications
β”‚   └── useSiteConfig.ts         # Site configuration
β”œβ”€β”€ layouts/                      # Layout templates
β”‚   β”œβ”€β”€ default.vue              # Default layout
β”‚   └── admin.vue                # Admin layout
β”œβ”€β”€ pages/                        # Application pages
β”‚   β”œβ”€β”€ index.vue                # Home page
β”‚   β”œβ”€β”€ about.vue                # About page
β”‚   β”œβ”€β”€ setup.vue                # Setup wizard
β”‚   β”œβ”€β”€ [slug].vue               # Dynamic page route
β”‚   β”œβ”€β”€ blog/                    # Blog routes
β”‚   β”‚   β”œβ”€β”€ index.vue            # Blog list
β”‚   β”‚   β”œβ”€β”€ [slug].vue           # Blog post detail
β”‚   β”‚   β”œβ”€β”€ categories/
β”‚   β”‚   β”‚   └── index.vue
β”‚   β”‚   β”œβ”€β”€ category/
β”‚   β”‚   β”‚   └── [name].vue
β”‚   β”‚   β”œβ”€β”€ tags/
β”‚   β”‚   β”‚   └── index.vue
β”‚   β”‚   └── tag/
β”‚   β”‚       └── [name].vue
β”‚   └── admin/                   # Admin dashboard
β”‚       β”œβ”€β”€ index.vue            # Admin dashboard
β”‚       β”œβ”€β”€ login.vue            # Admin login
β”‚       β”œβ”€β”€ profile.vue          # User profile
β”‚       β”œβ”€β”€ users.vue            # User management
β”‚       β”œβ”€β”€ tokens.vue           # API token management
β”‚       β”œβ”€β”€ authors.vue          # Authors management
β”‚       β”œβ”€β”€ categories.vue       # Categories management
β”‚       β”œβ”€β”€ tags.vue             # Tags management
β”‚       β”œβ”€β”€ files.vue            # Files management
β”‚       β”œβ”€β”€ site.vue             # Site settings
β”‚       β”œβ”€β”€ pages/               # Page management
β”‚       β”‚   β”œβ”€β”€ index.vue
β”‚       β”‚   β”œβ”€β”€ new.vue
β”‚       β”‚   └── [id]/
β”‚       β”‚       └── edit.vue
β”‚       └── posts/               # Post management
β”‚           β”œβ”€β”€ index.vue
β”‚           β”œβ”€β”€ new.vue
β”‚           └── [id]/
β”‚               └── edit.vue
β”œβ”€β”€ server/                      # Backend server code
β”‚   β”œβ”€β”€ api/                    # API routes
β”‚   β”‚   β”œβ”€β”€ posts/              # Post endpoints
β”‚   β”‚   β”‚   β”œβ”€β”€ index.get.ts
β”‚   β”‚   β”‚   └── [id].get.ts
β”‚   β”‚   β”œβ”€β”€ pages/              # Page endpoints
β”‚   β”‚   β”‚   β”œβ”€β”€ index.get.ts
β”‚   β”‚   β”‚   └── [slug].get.ts
β”‚   β”‚   β”œβ”€β”€ categories.get.ts   # Category endpoints
β”‚   β”‚   β”œβ”€β”€ tags.get.ts         # Tag endpoints
β”‚   β”‚   β”œβ”€β”€ site.get.ts         # Site config endpoint
β”‚   β”‚   β”œβ”€β”€ auth/               # Authentication
β”‚   β”‚   β”‚   β”œβ”€β”€ login.post.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ logout.post.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ me.get.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ user.get.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ profile.put.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ password.put.ts
β”‚   β”‚   β”‚   └── account.delete.ts
β”‚   β”‚   └── admin/              # Admin endpoints
β”‚   β”‚       β”œβ”€β”€ files/
β”‚   β”‚       β”‚   β”œβ”€β”€ upload.post.ts
β”‚   β”‚       β”‚   β”œβ”€β”€ index.get.ts
β”‚   β”‚       β”‚   └── [id].delete.ts
β”‚   β”‚       β”œβ”€β”€ posts/
β”‚   β”‚       β”œβ”€β”€ pages/
β”‚   β”‚       β”œβ”€β”€ users/
β”‚   β”‚       β”œβ”€β”€ authors/
β”‚   β”‚       β”œβ”€β”€ categories/
β”‚   β”‚       β”œβ”€β”€ tags/
β”‚   β”‚       └── dashboard/
β”‚   β”‚           └── stats.get.ts
β”‚   β”œβ”€β”€ middleware/             # Server middleware
β”‚   β”‚   β”œβ”€β”€ apiAuth.ts         # API authentication
β”‚   β”‚   └── db-check.ts        # Database connection check
β”‚   β”œβ”€β”€ utils/                 # Utility functions
β”‚   β”‚   β”œβ”€β”€ r2.ts             # Cloudflare R2 functions
β”‚   β”‚   β”œβ”€β”€ dbApi.ts          # D1 SQL Studio API
β”‚   β”‚   β”œβ”€β”€ auth.ts           # Authentication utilities
β”‚   β”‚   └── apiToken.ts       # API token utilities
β”‚   └── types/
β”‚       └── dbTypes.ts        # Database TypeScript types
β”œβ”€β”€ types/                      # Shared TypeScript types
β”‚   └── blog.ts               # Blog-related types
β”œβ”€β”€ public/                     # Static assets
β”‚   β”œβ”€β”€ robots.txt
β”‚   └── site.webmanifest
β”œβ”€β”€ .env.local                  # Local environment variables (git-ignored)
β”œβ”€β”€ .env.example                # Environment variables template
β”œβ”€β”€ nuxt.config.ts             # Nuxt configuration
β”œβ”€β”€ tailwind.config.ts         # Tailwind CSS configuration
β”œβ”€β”€ tsconfig.json              # TypeScript configuration
β”œβ”€β”€ package.json               # Dependencies and scripts
└── README.md                  # This file

πŸ”Œ API Endpoints

Public APIs

Posts

  • GET /api/posts - Get all posts (supports pagination, category, and tag filters)
  • GET /api/posts/:id - Get post by ID or slug

Pages

  • GET /api/pages - List all published pages with pagination
  • GET /api/pages/:slug - Get single page by slug

Content

  • GET /api/categories - Get all categories with post counts
  • GET /api/tags - Get all tags with post counts
  • GET /api/site - Get site configuration

Admin APIs (Authentication Required)

Authentication

  • POST /api/auth/login - Login with credentials
  • POST /api/auth/logout - Logout current session
  • GET /api/auth/me - Get current user info
  • PUT /api/auth/profile - Update user profile
  • PUT /api/auth/password - Change password
  • DELETE /api/auth/account - Delete account

File Management

  • POST /api/admin/files/upload - Upload files to R2
  • GET /api/admin/files - List files with pagination and filtering
  • DELETE /api/admin/files/:id - Delete file

Content Management

  • GET /api/admin/posts - List all posts (with draft support)

  • POST /api/admin/posts - Create new post

  • PUT /api/admin/posts/:id - Update post

  • DELETE /api/admin/posts/:id - Delete post

  • GET /api/admin/pages - List all pages

  • POST /api/admin/pages - Create new page

  • PUT /api/admin/pages/:id - Update page

  • DELETE /api/admin/pages/:id - Delete page

  • GET /api/admin/categories - List all categories

  • POST /api/admin/categories - Create category

  • PUT /api/admin/categories/:id - Update category

  • DELETE /api/admin/categories/:id - Delete category

  • GET /api/admin/tags - List all tags

  • POST /api/admin/tags - Create tag

  • PUT /api/admin/tags/:id - Update tag

  • DELETE /api/admin/tags/:id - Delete tag

User Management

  • GET /api/admin/users - List all users
  • POST /api/admin/users - Create user
  • PUT /api/admin/users/:id - Update user
  • DELETE /api/admin/users/:id - Delete user

Dashboard

  • GET /api/admin/dashboard/stats - Get dashboard statistics

Query Parameters

GET /api/posts

Parameter Type Default Description
page number 1 Page number for pagination
limit number 10 Posts per page
category string - Filter by category name
tag string - Filter by tag name
search string - Search in title and excerpt

GET /api/admin/files

Parameter Type Default Description
page number 1 Page number
limit number 20 Files per page
search string - Search by file name
mime_type string - Filter by MIME type

Example Requests:

# Get posts with pagination and category filter
GET /api/posts?page=1&limit=10&category=Tutorial

# Search files by name and type
GET /api/admin/files?page=1&limit=20&search=avatar&mime_type=image/jpeg

🎨 Features Deep Dive

Authentication & Authorization

The blog includes a complete authentication system with:

  • Secure Login: Username/password authentication with session management
  • JWT Tokens: API tokens for programmatic access
  • User Roles: Support for different user roles and permissions
  • Protected Routes: Admin pages require authentication
  • Session Timeout: Automatic session expiration for security

Content Management System

Blog Posts

  • Full CRUD operations for posts
  • Draft and published status support
  • Rich text editor with Markdown support
  • Featured posts functionality
  • Author and category assignment
  • Auto-generated read time estimation

Custom Pages

Two Content Modes

  1. HTML Content Mode: Use the content field for simple pages with raw HTML
  2. Block-Based Mode: Build pages using reusable content blocks for complex layouts

Available Block Types

The system includes 10 pre-built block types:

  • BlockHero - Hero section with title, subtitle, and CTA buttons
  • BlockFeatures - Feature showcase grid
  • BlockCta - Call-to-action section
  • BlockText - Simple text/content block
  • BlockGallery - Image gallery
  • BlockTestimonials - Customer testimonials
  • BlockFaq - FAQ accordion
  • BlockStats - Statistics/metrics display
  • BlockVideo - Video embed
  • BlockCustom - Custom HTML block

Page Customization Options

Layout & Theme:

  • layout: 'wide', 'narrow', or 'default' - Controls content width
  • theme: 'light' or 'dark' - Page color scheme
  • template: Page template name (e.g., 'minimal', 'standard')

Display Settings:

  • show_header - Show/hide header
  • show_footer - Show/hide footer
  • show_breadcrumb - Show/hide breadcrumb navigation
  • cover_image_url - Hero cover image URL

Advanced Features:

  • custom_css - Inject custom CSS styles
  • custom_js - Add custom JavaScript
  • enable_comments - Enable comment section
  • enable_sharing - Show social sharing buttons
  • is_password_protected - Protect page with password

SEO Optimization:

  • meta_title, meta_description, meta_keywords - Standard SEO tags
  • og_title, og_description, og_image - Open Graph tags
  • canonical_url - Canonical URL

API Endpoints for Pages

GET /api/pages

  • List all pages with pagination
  • Query parameters:
    • page - Page number (default: 1)
    • limit - Results per page (default: 100)
    • status - Filter by status: 'draft', 'published', or 'archived'

GET /api/pages/[slug]

  • Get single page by slug or ID
  • Add ?preview=true to view draft pages

GET /api/pages/[id]/blocks

  • Fetch all blocks for a specific page
  • Returns blocks sorted by display order

Creating Custom Pages

Pages are stored in the database and managed through the D1 SQL Studio REST API. Each page requires:

{
  title: 'Page Title',
  slug: 'page-url-slug',
  status: 'published', // 'draft', 'published', or 'archived'
  template: 'standard',
  theme: 'light',
  layout: 'default',
  // ... additional fields
}

Pages are automatically accessible at /{slug} (e.g., /about, /contact).

Styling

Modify tailwind.config.ts to customize:

  • Colors (primary palette)
  • Fonts
  • Spacing
  • Other design tokens

Configuration

Update nuxt.config.ts for:

  • SEO defaults
  • Image optimization settings
  • Build configurations

🌐 Deployment to Cloudflare Pages

Build Configuration

  • Build command: npm run build
  • Build output directory: dist
  • Node version: 20

Deployment Steps

  1. Push to Git: Push your code to GitHub, GitLab, or Bitbucket

  2. Connect to Cloudflare:

  3. Configure Build:

    • Framework preset: Nuxt.js
    • Build command: npm run build
    • Build output directory: dist
  4. Set Environment Variables:

    • Go to Pages β†’ Your project β†’ Settings β†’ Environment variables
    • Add all required variables for Preview and Production:
      • DB_API_KEY, DB_API_URL
      • R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET_NAME, R2_PUBLIC_URL
      • SESSION_SECRET
  5. Deploy: Click Save and Deploy

Your site will be live on Cloudflare's global CDN!

Environment Variables Checklist

Before deploying, ensure you have configured all required variables:

Database:
- [ ] DB_API_KEY
- [ ] DB_API_URL

File Storage (R2):
- [ ] R2_ACCOUNT_ID
- [ ] R2_ACCESS_KEY_ID
- [ ] R2_SECRET_ACCESS_KEY
- [ ] R2_BUCKET_NAME
- [ ] R2_PUBLIC_URL

Session:
- [ ] SESSION_SECRET (minimum 32 characters)

πŸš€ Performance Optimization

Server-Side Rendering (SSR)

  • All pages are server-side rendered for optimal SEO and initial load performance
  • Automatic code splitting for faster page transitions

Image Optimization

  • Automatic image optimization through Nuxt Image
  • Lazy loading for images below the fold
  • Responsive image serving
  • WebP format support for modern browsers

Content Delivery

  • Global CDN distribution via Cloudflare Pages
  • Edge caching for static assets
  • Real-time invalidation on updates

Database Performance

  • Efficient pagination to avoid loading large datasets
  • Indexed queries for fast filtering and search
  • Connection pooling through D1 SQL Studio REST API

πŸ”’ Security Features

  • Input Validation: All form inputs are validated on both client and server
  • SQL Injection Prevention: Parameterized queries through D1 SQL Studio API
  • CSRF Protection: Built-in CSRF token handling
  • XSS Prevention: Automatic HTML escaping in templates
  • Secure Headers: Content-Security-Policy and other security headers configured
  • Rate Limiting: API endpoints protected with rate limiting
  • File Upload Security:
    • File type validation (MIME type checking)
    • File size limits
    • Unique filename generation
    • Isolated storage in R2

πŸ“š Documentation & Resources

Official Documentation

Project References

🀝 Contributing

Contributions are welcome! To contribute:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Please ensure:

  • Code follows the existing style and conventions
  • TypeScript types are properly defined
  • New features include appropriate documentation
  • Tests are added for new functionality where applicable

πŸ› Reporting Issues

Found a bug? Please open an issue on GitHub with:

  • Clear description of the problem
  • Steps to reproduce the issue
  • Expected vs actual behavior
  • Your environment (OS, Node version, etc.)

⭐ Show Your Support

If you find this project helpful, please consider:

  • ⭐ Starring the repository - Show your appreciation
  • πŸ”— Sharing it with others - Help spread the word
  • 🀝 Contributing improvements - Make it better together
  • πŸ› Reporting bugs - Help us fix issues
  • πŸ’‘ Suggesting features - Share your ideas

Live site: https://blog.404401.xyz

πŸ“„ License

MIT

This means you can use this project for personal and commercial purposes, modify it, distribute it, and use it privately, as long as you include a copy of the license.

About

A modern, feature-rich blog built with Nuxt 3, Tailwind CSS, and deployed on Cloudflare Pages.

Topics

Resources

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors