diff --git a/content/docs/introduction.md b/content/docs/introduction.md index 508af32..35307a9 100644 --- a/content/docs/introduction.md +++ b/content/docs/introduction.md @@ -1,15 +1,19 @@ # Introduction -**echoIRCd** is a modern IRC daemon and a full services suite, written from scratch in Rust. It is -original code — not a fork of another ircd — and the entire tree compiles with -`#![forbid(unsafe_code)]`. +**echoIRCd** is a modern IRC daemon, written from scratch in Rust. It is original code — not a fork +of another ircd — and the entire tree compiles with `#![forbid(unsafe_code)]`. + +Accounts and channels are handled by **echo services**, a *separate* companion package that links +to the daemon over the server-to-server protocol — the daemon itself is a pure ircd and does not +have services built in. ## What you get -- **echoIRCd** — the server: a single-threaded core with an epoll reactor pool, the full channel - and user mode set, host cloaking, connection classes, and an operator privilege model. -- **echo services** — NickServ, ChanServ, OperServ, MemoServ and more, linked over a standard - server-to-server protocol and backed by an event-sourced store. +- **echoIRCd** — the daemon: a single-threaded core with an epoll reactor pool, the full channel + and user mode set, host cloaking, connection classes, and an operator privilege model. It exposes + the account and SASL *interface* that services plug into. +- **echo services** — a separate package (NickServ, ChanServ, OperServ, MemoServ and more), linked + over the server-to-server protocol and backed by an event-sourced store. ## Highlights diff --git a/src/main.rs b/src/main.rs index cdb48a7..561a957 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,6 +54,12 @@ struct ConnectTemplate { active: &'static str, } +#[derive(Template)] +#[template(path = "services.html")] +struct ServicesTemplate { + active: &'static str, +} + struct SidePage { slug: &'static str, title: &'static str, @@ -95,6 +101,9 @@ async fn features() -> Response { async fn connect() -> Response { page(ConnectTemplate { active: "connect" }) } +async fn services() -> Response { + page(ServicesTemplate { active: "services" }) +} async fn docs_index() -> Response { Redirect::permanent(&format!("/docs/{}", docs::first_slug())).into_response() @@ -177,6 +186,7 @@ async fn main() { .route("/", get(index)) .route("/features", get(features)) .route("/connect", get(connect)) + .route("/services", get(services)) .route("/docs", get(docs_index)) .route("/docs/search.json", get(docs_search)) .route("/docs/:slug", get(docs_page)) diff --git a/static/style.css b/static/style.css index 270b672..3e9f8fb 100644 --- a/static/style.css +++ b/static/style.css @@ -127,6 +127,13 @@ code{font-family:var(--mono);font-size:.9em;background:rgba(18,165,148,.09);colo .foot-links a{color:#aeb8c0;font-size:.9rem} .foot-links a:hover{color:#fff} +/* services flow diagram */ +.flow{display:flex;align-items:center;gap:.55rem;flex-wrap:wrap;margin:1.3rem 0 .3rem} +.flow .node{background:#fff;border:1px solid var(--line2);border-radius:9px;padding:.45rem .85rem;font-weight:500;font-size:.92rem} +.flow .node.accent{border-color:var(--teal);color:var(--teal-dd);background:var(--teal-t)} +.flow .node.accent2{border-color:#c6b6ec;color:#5a3fb0;background:#f3edfd} +.flow .arrow{color:var(--faint);font-family:var(--mono);font-size:.82rem} + @media(max-width:820px){ .hero-in{grid-template-columns:1fr;gap:1.6rem} .statuscard{max-width:26rem} diff --git a/templates/base.html b/templates/base.html index 2ddf32e..62e5d0f 100644 --- a/templates/base.html +++ b/templates/base.html @@ -4,7 +4,7 @@