diff --git a/README.md b/README.md index 87e4d17..773e8c8 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,195 @@ -# Contribute -Create content for your site from existing sources. +
+
+
Create content for your site from existing sources.
+ + + +--- + +## What is Contribute? + +Static site generators are great for blog posts you write by hand — but most of a site's content already lives somewhere else: a YouTube channel, RSS feeds, a newsletter archive, an old CMS export. **Contribute turns those source items into clean markdown files with YAML front matter**, ready to drop into your generator's content folder. + +It does this with one small, reusable shape so you don't write a bespoke importer per source. You write two tiny conformances per source; the fetch + extract + write pipeline stays the same. + +> **Scope:** Contribute does **not** fetch from APIs. You bring the already-decoded source models — use [SyndiKit](https://github.com/brightdigit/SyndiKit) for RSS, a client for the YouTube API, your CMS's export, etc. Contribute's job starts there: **source model → markdown file.** + +`brightdigit.com` uses Contribute to import its podcast episodes, videos, and newsletters into a Swift static site generator. + +## The core idea: one trio + +Two protocols do the per-source work, and a third binds them to a single source model. + +| Protocol | Responsibility | +| --- | --- | +| `FrontMatterTranslator` | Map a source item's fields onto your site's (`Encodable`) front matter. | +| `MarkdownExtractor` | Render a source item's body into markdown, using an injected HTML→markdown function. | +| `ContentType` | Bind one `SourceType` to *its* translator and extractor — and get a generic `write(...)` for free. | + +```swift +public protocol FrontMatterTranslator { + associatedtype SourceType + associatedtype FrontMatterType: Encodable + init() + func frontMatter(from source: SourceType) -> FrontMatterType +} + +public protocol MarkdownExtractor { + associatedtype SourceType + init() + func markdown( + from source: SourceType, + using htmlToMarkdown: @escaping (String) throws -> String + ) throws -> String +} + +public protocol ContentType { + associatedtype SourceType + associatedtype MarkdownExtractorType: MarkdownExtractor + where MarkdownExtractorType.SourceType == SourceType + associatedtype FrontMatterTranslatorType: FrontMatterTranslator + where FrontMatterTranslatorType.SourceType == SourceType +} +``` + +`SourceType` is *your* model — Contribute never defines it and never fetches it. That seam is what keeps the library source-agnostic. + +## Installation + +Add Contribute to your `Package.swift`: + +```swift +dependencies: [ + .package(url: "https://github.com/brightdigit/Contribute.git", from: "1.0.0") +] +``` + +Then add it to a target: + +```swift +.target( + name: "MySite", + dependencies: [.product(name: "Contribute", package: "Contribute")] +) +``` + +## Quick start + +Say you've already fetched an RSS feed into an array of your own `RSSItem` values and want one markdown file per entry. + +```swift +import Contribute +import Foundation + +// 1. Your site's front matter — anything Encodable. +struct PostFrontMatter: Encodable { + let title: String + let date: Date + let tags: [String] +} + +// 2. Your already-decoded source model. Conform to HTMLSource to reuse the +// built-in FilteredHTMLMarkdownExtractor for the body. +struct RSSItem: HTMLSource { + let title: String + let published: Date + let categories: [String] + let html: String // satisfies HTMLSource +} + +// 3. A ContentType binds the source to its translator + extractor. +enum RSSContent: ContentType { + typealias SourceType = RSSItem + typealias FrontMatterTranslatorType = FrontMatter + typealias MarkdownExtractorType = FilteredHTMLMarkdownExtractor