bim 0.1.0

A content-first static site generator for blogs, digital gardens, and knowledge bases
Documentation
# bim

A content-first, convention-over-configuration static site generator written in Rust.

Designed to support blogs, digital gardens, code snippets, recipes, talks, and slides in a single coherent knowledge base.

## Philosophy

- **Markdown** as the primary authoring format
- **Filesystem structure** as the source of truth
- **No front matter** - metadata extracted from filenames and git
- **Lenient behavior** - warnings instead of hard errors
- **Fast** - parallel processing with Rayon

## Installation

```bash
cargo install bim
```

Or build from source:

```bash
cargo build --release
./target/release/bim --help
```

## Quick Start

```bash
# Create a new site
mkdir my-site && cd my-site

# Create some content
mkdir blog
echo "# Hello World" > blog/2024-01-15-hello-world.md
echo "# About" > index.md

# Build the site
bim build

# Serve locally with live reload
bim serve --watch
```

## CLI Commands

### `bim build`

Build the static site.

```bash
bim build                  # Build to ./dist
bim build --output public  # Build to ./public
bim build --drafts         # Include draft content
bim build --clean          # Clean output directory first
```

### `bim serve`

Build and serve the site locally.

```bash
bim serve                  # Serve on http://127.0.0.1:3000
bim serve --port 8080      # Custom port
bim serve --host 0.0.0.0   # Bind to all interfaces
bim serve --watch          # Watch for changes and rebuild
bim serve --drafts         # Include draft content
```

### `bim watch`

Watch for changes and rebuild.

```bash
bim watch                  # Watch and rebuild to ./dist
bim watch --drafts         # Include draft content
```

### `bim prep-images`

Process images without building the full site.

```bash
bim prep-images            # Process images
bim prep-images --force    # Force reprocessing all images
```

## Directory Structure

```
my-site/
├── index.md              # Homepage
├── nav.md                # Navigation menu
├── blog/                 # Blog posts (date-sorted, RSS feed)
│   ├── 2024-01-15-hello.md
│   └── 2024-02-01-update.md
├── notes/                # Hierarchical notes (auto-indexes)
│   ├── getting-started/
│   │   ├── index.md
│   │   └── installation.md
│   └── features/
│       └── backlinks.md
├── snippets/             # Code snippets (syntax highlighted)
│   ├── rust/
│   │   └── error_handling.rs
│   └── python/
│       └── decorators.py
├── talks/                # Conference talks
├── projects/             # Project pages
├── recipes/              # Recipes or tutorials
├── slides/               # Presentation slides
├── tags/                 # Custom tag pages (optional)
│   └── rust.md
├── contexts/             # Custom context pages (optional)
│   └── linux.md
├── layouts/              # Custom HTML layouts
│   └── default.html
├── static/               # Static files (copied as-is)
│   ├── css/
│   └── robots.txt
└── images/               # Images (processed/optimized)
    └── hero.jpg
```

## Collections

| Collection | URL Base | Features |
|------------|----------|----------|
| blog | /blog/ | Date-sorted, RSS feed, flat structure |
| notes | /notes/ | Hierarchical, auto-indexes for directories |
| snippets | /snippets/ | Syntax highlighting, language detection |
| talks | /talks/ | Flat structure |
| projects | /projects/ | Flat structure |
| recipes | /recipes/ | Flat structure |
| slides | /slides/ | Flat structure, no backlinks |
| tags | /tags/ | Auto-generated from content |
| contexts | /contexts/ | Auto-generated from content |

## Content Features

### Dates from Filenames

Prefix filenames with `YYYY-MM-DD-` to set the date:

```
blog/2024-01-15-my-post.md  →  /blog/my-post/
```

If no date prefix, the git commit date is used.

### Titles from Headings

The first `# Heading` in your markdown becomes the page title:

```markdown
# My Awesome Post

Content here...
```

### Drafts

Files starting with `_` or in `_drafts/` directories are drafts:

```
blog/_work-in-progress.md   # Draft (underscore prefix)
blog/_drafts/ideas.md       # Draft (in _drafts directory)
```

Include drafts with `--drafts` flag.

### Tags

Use `[#tag name]` syntax to tag content:

```markdown
This post is about [#rust] and [#web development].
```

Tags are automatically converted to links and aggregated at `/tags/`.

### Contexts

Use `[@context name]` syntax to specify contexts:

```markdown
This applies to [@linux] and [@docker] environments.
```

Contexts are automatically converted to links and aggregated at `/contexts/`.

### Backlinks

Internal links are tracked and backlinks are displayed automatically. Link to other pages:

```markdown
See also [my other post](/blog/other-post/).
```

The linked page will show a backlink to this page.

### Directives

Use directives to embed dynamic content:

```markdown
## Recent Posts

{{recent blog 5}}

## Latest Notes

{{recent notes 3}}
```

Available directives:
- `{{recent collection count}}` - List recent items from a collection

## Navigation

Create `nav.md` to define the site navigation:

```markdown
- [Home]/
- [Blog]/blog/
- [Notes]/notes/
- [Snippets]/snippets/
```

## Layouts

Create custom layouts in the `layouts/` directory. Layouts are HTML files with placeholders:

```html
<!DOCTYPE html>
<html lang="{{lang}}" dir="{{dir}}">
<head>
    <title>{{title}}</title>
</head>
<body>
    {{nav}}
    <main>{{content}}</main>
    {{backlinks}}
    <footer>Last modified: {{last_modified}}</footer>
</body>
</html>
```

### Available Placeholders

| Placeholder | Description |
|-------------|-------------|
| `{{title}}` | Page title |
| `{{content}}` | Rendered HTML content |
| `{{nav}}` | Navigation HTML |
| `{{backlinks}}` | Backlinks section HTML |
| `{{last_modified}}` | Last modification date |
| `{{lang}}` | Content language (e.g., "en", "ar") |
| `{{dir}}` | Text direction ("ltr" or "rtl") |

### Layout Selection

Layouts are selected by collection:

- `layouts/blog.html` - Blog posts
- `layouts/notes.html` - Notes
- `layouts/snippets.html` - Code snippets
- `layouts/slides.html` - Slides
- `layouts/default.html` - Fallback for all collections

## Code Snippets

Place code files in `snippets/` to create syntax-highlighted pages:

```
snippets/
├── rust/
│   └── error_handling.rs
├── python/
│   └── decorators.py
└── bash/
    └── git_aliases.sh
```

Each file becomes a page with:
- Title from filename
- Syntax highlighting
- Backlink support

## Language Detection

Content language is automatically detected:
- English content: `lang="en"` `dir="ltr"`
- Arabic content: `lang="ar"` `dir="rtl"`
- Other RTL languages supported

## RSS Feed

An RSS feed is automatically generated at `/feed.xml` for the blog collection.

## Sitemap

A sitemap is automatically generated at `/sitemap.xml` with all pages.

## Image Processing

Images in the `images/` directory are:
- Copied to output
- Optimized for web (future: resize, compress)

## Static Files

Files in `static/` are copied as-is to the output:

```
static/css/custom.css  →  dist/css/custom.css
static/robots.txt      →  dist/robots.txt
```

## Git Integration

If your site is in a git repository:
- File modification dates come from git history
- Uncommitted files use current time

## Dark Mode

The default layout includes automatic dark mode support using `prefers-color-scheme` media query.

## Example Site

See [bim.gumx.cc](https://bim.gumx.cc) for a complete example site demonstrating all features.

## Using as a Library

bim can also be used as a library in your Rust projects:

```rust
use bim::{config::Config, discovery, render};

fn main() -> anyhow::Result<()> {
    let config = Config::default();
    let site = discovery::discover_site(&config)?;
    render::build_site(&site, &config)?;
    Ok(())
}
```

## Environment Variables

- `RUST_LOG=bim=info` - Enable info logging
- `RUST_LOG=bim=debug` - Enable debug logging

## Links

- Repository: https://git.sr.ht/~gumx/bim
- Website: https://bim.gumx.cc

## License

MIT