Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/sureshamal/markview/llms.txt

Use this file to discover all available pages before exploring further.

Tech Stack

MarkView is built with a modern hybrid desktop architecture combining web technologies with native Rust code.

Frontend

Next.js 16 + React 19
  • App Router with static export
  • Client-side rendering only
  • Tailwind CSS for styling

Desktop Framework

Tauri v2
  • Rust-based backend
  • Native file system access
  • Lightweight webview rendering

Markdown Rendering

react-markdown ecosystem
  • GitHub Flavored Markdown
  • Syntax highlighting
  • Mermaid diagram support

Build Tool

Bun
  • Fast package management
  • Quick script execution
  • Node.js compatible

Project Structure

MarkView follows a monorepo-style structure with separate frontend and backend directories:
Project Layout
markview/
├── app/                    # Next.js App Router
   ├── page.tsx           # Main application component
   ├── layout.tsx         # Root layout wrapper
   └── globals.css        # Global styles and theme CSS variables
├── public/                # Static assets
├── src-tauri/             # Tauri Rust backend
   ├── src/
   ├── lib.rs        # Core Tauri commands and logic
   ├── main.rs       # Application entry point
   └── build.rs      # Build-time code generation
   ├── Cargo.toml        # Rust dependencies
   ├── tauri.conf.json   # Tauri configuration
   └── target/           # Build output (gitignored)
├── out/                   # Next.js static export (gitignored)
├── package.json          # Node dependencies and scripts
├── next.config.ts        # Next.js configuration
└── tailwind.config.ts    # Tailwind CSS configuration

Tauri Commands Architecture

The Rust backend exposes three Tauri commands that the React frontend can invoke for file operations.

Command: get_cli_args

Location: src-tauri/src/lib.rs:12-25 Retrieves command-line arguments passed to the application and converts relative paths to absolute paths.
#[tauri::command]
fn get_cli_args() -> Vec<String> {
    let mut args: Vec<String> = Vec::new();
    if let Ok(current_dir) = env::current_dir() {
        for arg in env::args().skip(1) {
            let path = std::path::Path::new(&arg);
            if path.is_absolute() {
                args.push(arg.clone());
            } else {
                args.push(current_dir.join(path).to_string_lossy().into_owned());
            }
        }
    }
    args
}
Usage: Called on application startup to open files/directories passed via CLI.

Command: read_markdown_file

Location: src-tauri/src/lib.rs:28-41 Reads a single markdown file from the file system.
#[tauri::command]
fn read_markdown_file(path: String) -> Result<FileData, String> {
    let path = Path::new(&path);
    if path.is_file() {
        if let Ok(content) = fs::read_to_string(path) {
            let name = path
                .file_name()
                .unwrap_or_default()
                .to_string_lossy()
                .into_owned();
            return Ok(FileData { name, content });
        }
    }
    Err("Could not read file".to_string())
}
Returns: FileData struct with name and content fields.

Command: read_markdown_dir

Location: src-tauri/src/lib.rs:44-69 Reads all markdown files (.md or .markdown) from a directory.
#[tauri::command]
fn read_markdown_dir(path: String) -> Result<Vec<FileData>, String> {
    let mut files = Vec::new();
    let path = Path::new(&path);
    if path.is_dir() {
        if let Ok(entries) = fs::read_dir(path) {
            for entry in entries.flatten() {
                let entry_path = entry.path();
                if entry_path.is_file() {
                    if let Some(ext) = entry_path.extension() {
                        if ext == "md" || ext == "markdown" {
                            // Read file and add to vector
                        }
                    }
                }
            }
        }
    }
    Ok(files)
}
Returns: Vector of FileData structs.

Tauri Plugins

MarkView uses several official Tauri plugins for enhanced functionality:
PluginPurposeUsed For
tauri-plugin-dialogNative file dialogsFile/folder picker
tauri-plugin-fsFile system accessReading markdown files
tauri-plugin-shellShell command executionOpening external URLs
tauri-plugin-logLogging infrastructureDebug and error logs

React Component Structure

The main application is a single-page React component with multiple sub-components.

Main Component: Home

Location: app/page.tsx:333-1155 The root component manages:
  • File state (loaded markdown files)
  • Theme state (7 built-in themes)
  • Search state (file and theme search)
  • UI modals (command palettes)

Key Sub-Components

CodeBlock

Location: app/page.tsx:16-99 Custom code block renderer with:
  • Syntax highlighting via react-syntax-highlighter
  • Copy-to-clipboard functionality
  • Language detection
  • Mermaid diagram support
  • Theme-aware styling (light/dark mode)
Location: app/page.tsx:107-247 Custom link component with:
  • Internal file navigation (relative paths)
  • External URL handling (opens in browser)
  • Link preview on hover
  • Anchor link scrolling

CommandPalette

Location: app/page.tsx:296-331 Reusable modal wrapper for:
  • Theme selector (Alt+T)
  • File search (Ctrl+K)
  • Keyboard navigation
  • Backdrop overlay

State Management

MarkView uses React hooks for state management:
Key State Variables
const [files, setFiles] = useState<MarkdownFile[]>([]);
const [selectedFile, setSelectedFile] = useState<string>('');
const [theme, setTheme] = useState<Theme>('light');
const [searchQuery, setSearchQuery] = useState('');
const [expandedFolders, setExpandedFolders] = useState<Set<string>>(new Set());
No external state library - uses built-in React state and localStorage for persistence.

Markdown Rendering Pipeline

MarkView transforms raw markdown into rich HTML using a plugin-based pipeline.
1

Input: Raw Markdown

User’s markdown content loaded from file system
2

Parse: react-markdown

Core markdown parser converts markdown to React elementsPackage: react-markdown@10.1.0
3

Transform: remark-gfm

Adds GitHub Flavored Markdown support:
  • Tables
  • Strikethrough
  • Task lists
  • Autolinks
Package: remark-gfm@4.0.1
4

Transform: rehype-raw

Allows raw HTML in markdown (sanitized)Package: rehype-raw@7.0.0
5

Transform: rehype-slug

Auto-generates IDs for headings (for outline navigation)Note: Referenced in code but implemented via custom logic
6

Render: Custom Components

Custom renderers for:
  • Code blocks (syntax highlighting)
  • Links (preview + external handling)
  • Mermaid diagrams
7

Output: Styled HTML

Final themed HTML rendered in the content area

Rendering Configuration

Markdown Component Usage
<ReactMarkdown
  remarkPlugins={[remarkGfm]}
  rehypePlugins={[rehypeRaw]}
  components={{
    code(props) {
      return <CodeBlock theme={theme} {...props} />;
    },
    pre(props) {
      return <>{props.children}</>; // unwrap pre tag
    }
  }}
>
  {selectedContent}
</ReactMarkdown>

Theme System

MarkView implements a CSS variable-based theming system with 7 built-in themes.

Theme Definition

Location: app/globals.css:3-137 Each theme defines CSS custom properties for:
  • Background and foreground colors
  • Card backgrounds and borders
  • Primary and hover colors
  • Code block styling
  • Table styling
  • Blockquote styling
Theme Structure
[data-theme="dark"] {
  --background: #0f172a;
  --foreground: #e2e8f0;
  --card-bg: #1e293b;
  --card-border: #334155;
  --primary: #60a5fa;
  --primary-hover: #3b82f6;
  --text-secondary: #94a3b8;
  /* ... more variables */
}

Available Themes

ThemeBackgroundPrimary ColorUse Case
Light#ffffffBlueDefault bright theme
Dark#0f172aLight blueLow-light environments
Ocean#0c1929CyanBlue-tinted dark theme
Forest#1a2e1aGreenGreen-tinted dark theme
Sunset#2d1f1fOrangeWarm-tinted dark theme
Purple#1a1428PurplePurple-tinted dark theme
Midnight#0a0a12Muted blueUltra-dark theme

Theme Persistence

Themes are saved to localStorage and restored on app launch:
Theme Persistence
// Save theme on change
useEffect(() => {
  localStorage.setItem('markview-theme', theme);
}, [theme]);

// Load saved theme on mount
useEffect(() => {
  const savedTheme = localStorage.getItem('markview-theme');
  if (savedTheme) setTheme(savedTheme);
}, []);

Next.js Configuration

Static Export Mode

Location: next.config.ts:3-5
const nextConfig: NextConfig = {
  output: "export",
};
Purpose: Generates a static HTML/CSS/JS bundle in the out/ directory that Tauri can serve without a Node.js server.

Build Output

The bun run build command:
  1. Runs Next.js build process
  2. Exports static files to out/
  3. Tauri serves these files from the frontendDist path
Static export means no server-side rendering or API routes. All file operations go through Tauri commands.

Development Workflow

Key Design Decisions

  • Smaller bundle size: ~3MB vs 100MB+
  • Lower memory usage: Uses system webview
  • Better security: Rust backend with permission system
  • Native file access: Direct file system operations
  • Tauri requires a static file bundle to serve
  • No need for server-side rendering in a desktop app
  • Faster initial load with pre-rendered HTML
  • Simpler deployment (no Node.js runtime needed)
  • 10-20x faster package installation
  • Built-in TypeScript support
  • Compatible with existing Node.js ecosystem
  • Faster script execution
  • Runtime theme switching without rebuilding
  • Easier to create new themes
  • Better performance (no class recalculation)
  • Works with non-Tailwind CSS

Next Steps

Development Setup

Set up your local development environment

Building for Production

Create production-ready binaries