snapshot of https://github.com/ThreeDotsLabs/watermill.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
master / ci (push) Failing after 0s

This commit is contained in:
upstream-mirror
2026-09-15 21:27:46 +05:00
commit ce933d1277
538 changed files with 46504 additions and 0 deletions

View File

@@ -0,0 +1 @@
<a href="{{ .Destination | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }}{{ if or (strings.HasPrefix .Destination "http") (strings.HasPrefix .Destination "https") }} target="_blank"{{ end }} >{{ .Text | safeHTML }}</a>

View File

@@ -0,0 +1,38 @@
{{ define "main" }}
<div class="learn-container">
<div class="learn-header">
<h1 class="learn-main-title">Learn Watermill</h1>
</div>
<div class="learn-section">
<h2 class="learn-section-title">How do you like to learn?</h2>
<div class="learn-row">
{{ range $index, $option := .Params.learning_options }}
<a href="{{ .link }}" class="learn-card">
<div class="learn-card-icon">
{{ .icon | safeHTML }}
</div>
<h3>{{ .title }}</h3>
<span class="learn-card-secondary">{{ .subtitle }}</span>
<p>{{ .description }}</p>
</a>
{{ end }}
</div>
</div>
<div class="learn-section">
<h2 class="learn-section-title">Dive Deeper</h2>
<div class="learn-row">
{{ range .Params.deeper_options }}
<a href="{{ .link }}" class="learn-card" {{ if .external }}target="_blank" rel="noopener"{{ end }}>
<div class="learn-card-icon">
{{ .icon | safeHTML }}
</div>
<h3>{{ .title }}</h3>
<p>{{ .description }}</p>
</a>
{{ end }}
</div>
</div>
</div>
{{ end }}

View File

@@ -0,0 +1,12 @@
{{ define "main" }}
<div class="quickstart-container">
<div class="quickstart-header">
<h1 class="quickstart-main-title">{{ .Title }}</h1>
<p class="quickstart-subtitle">{{ .Params.description }}</p>
</div>
<div class="quickstart-content">
{{ .Content }}
</div>
</div>
{{ end }}

217
docs/layouts/index.html Normal file
View File

@@ -0,0 +1,217 @@
{{ define "main" }}
<section class="section container-fluid mt-n3 pb-3">
<div class="row justify-content-center">
<div class="text-center mb-4">
<img src="/img/gopher.svg" alt="Logo" style="width: 220px" />
</div>
<div class="col-lg-12 text-center">
<h1>{{ .Title }}</h1>
</div>
<div class="col-lg-9 col-xl-8 text-center">
<p class="lead">{{ .Params.lead | safeHTML }}</p>
<a class="btn btn-primary btn-cta rounded-pill btn-lg m-3" href="/learn/" role="button">
Get Started
</a>
<a class="btn btn-outline-primary btn-cta rounded-pill btn-lg my-3" href="https://github.com/ThreeDotsLabs/watermill" role="button">
See on GitHub
</a>
{{ .Content }}
</div>
</div>
</section>
<section class="section py-5 homepage-features">
<div class="container">
<!-- EventBus Section -->
<div class="row justify-content-center mb-5 pb-5 homepage-section-gradient">
<div class="col-lg-11 col-xl-10 text-center">
<h2 class="display-4 fw-bold mb-4 gradient-text-1">Publish Events</h2>
<p class="lead text-muted mb-5">Work with Go structs.<br/>
Decouple your services with asynchronous processing.
</p>
<div class="expressive-code homepage-code-block">
<figure class="frame not-content">
{{ highlight `event := UserRegistered{
UserID: id,
Email: email,
JoinedAt: time.Now(),
}
err := eventBus.Publish(ctx, event)` "go" "" }}
</figure>
</div>
</div>
</div>
<!-- EventProcessor Section -->
<div class="row justify-content-center mb-5 pb-5 homepage-section-gradient">
<div class="col-lg-11 col-xl-10 text-center">
<h2 class="display-4 fw-bold mb-4 gradient-text-1">Handle Events</h2>
<p class="lead text-muted mb-5">Focus on the business logic.<br/>
Watermill handles routing, serialization and low-level details.
</p>
<div class="expressive-code homepage-code-block">
<figure class="frame not-content">
{{ highlight `eventProcessor.AddHandlers(
cqrs.NewEventHandler("SendWelcomeEmail", sendWelcomeEmail),
)
func sendWelcomeEmail(ctx context.Context, event *UserRegistered) error {
return emailService.Send(event.Email, "Welcome!")
}` "go" "" }}
</figure>
</div>
</div>
</div>
<!-- Router Middleware Section -->
<div class="row justify-content-center mb-5 pb-5 homepage-section-gradient">
<div class="col-lg-11 col-xl-10 text-center">
<h2 class="display-4 fw-bold mb-4 gradient-text-1">Simple API you already know</h2>
<p class="lead text-muted mb-5">Use the familiar concepts, similar to an HTTP Router with support for middleware.</p>
<div class="expressive-code homepage-code-block">
<figure class="frame not-content">
{{ highlight `router.AddMiddleware(
middleware.Recoverer,
middleware.CorrelationID,
middleware.Timeout(30 * time.Second),
)` "go" "" }}
</figure>
</div>
</div>
</div>
<!-- Pub/Sub Support Section -->
<div class="row justify-content-center pb-5 homepage-section-gradient">
<div class="col-lg-11 col-xl-10 text-center">
<h2 class="display-4 fw-bold mb-4 gradient-text-1">Use your favorite Pub/Sub</h2>
<p class="lead text-muted mb-5">Work with Kafka, RabbitMQ, PostgreSQL, Redis, and more Pub/Subs with the same API. Switch providers without changing your application code.</p>
<!-- Pub/Sub Logos Collage -->
<div class="pubsub-logos-container mb-5">
<div class="pubsub-logos-grid">
<a href="/pubsubs/aws/" class="pubsub-logo-item">
<img src="/img/pubsub-logos/aws.png" alt="AWS SQS/SNS" />
<span>AWS SNS/SQS</span>
</a>
<a href="/pubsubs/bolt/" class="pubsub-logo-item">
<img src="/img/pubsub-logos/bolt.png" alt="BoltDB" />
<span>BoltDB</span>
</a>
<a href="/pubsubs/firestore/" class="pubsub-logo-item">
<img src="/img/pubsub-logos/firestore.png" alt="Google Firestore" />
<span>Firestore</span>
</a>
<a href="/pubsubs/gochannel/" class="pubsub-logo-item">
<img src="/img/pubsub-logos/gochannel.png" alt="Go Channel" />
<span>Go Channel</span>
</a>
<a href="/pubsubs/googlecloud/" class="pubsub-logo-item">
<img src="/img/pubsub-logos/gcp.png" alt="Google Cloud Pub/Sub" />
<span>Google Cloud Pub/Sub</span>
</a>
<a href="/pubsubs/http/" class="pubsub-logo-item">
<img src="/img/pubsub-logos/http.png" alt="HTTP" />
<span>HTTP</span>
</a>
<a href="/pubsubs/io/" class="pubsub-logo-item">
<img src="/img/pubsub-logos/io.png" alt="I/O" />
<span>I/O</span>
</a>
<a href="/pubsubs/kafka/" class="pubsub-logo-item">
<img src="/img/pubsub-logos/kafka.png" alt="Apache Kafka" />
<span>Kafka</span>
</a>
<a href="/pubsubs/sql/" class="pubsub-logo-item">
<img src="/img/pubsub-logos/mysql.png" alt="MySQL" />
<span>MySQL</span>
</a>
<a href="/pubsubs/nats/" class="pubsub-logo-item">
<img src="/img/pubsub-logos/nats.png" alt="NATS" />
<span>NATS</span>
</a>
<a href="/pubsubs/sql/" class="pubsub-logo-item">
<img src="/img/pubsub-logos/postgresql.png" alt="PostgreSQL" />
<span>PostgreSQL</span>
</a>
<a href="/pubsubs/amqp/" class="pubsub-logo-item">
<img src="/img/pubsub-logos/rabbitmq.png" alt="RabbitMQ" />
<span>RabbitMQ</span>
</a>
<a href="/pubsubs/redisstream/" class="pubsub-logo-item">
<img src="/img/pubsub-logos/redis.png" alt="Redis" />
<span>Redis</span>
</a>
<a href="/pubsubs/sqlite/" class="pubsub-logo-item">
<img src="/img/pubsub-logos/sqlite.png" alt="SQLite" />
<span>SQLite</span>
</a>
</div>
</div>
</div>
</div>
<!-- Library vs Framework Section -->
<div class="row justify-content-center mb-5 pb-5 homepage-section-gradient">
<div class="col-md-12 col-lg-11 col-xl-10 text-center">
<h2 class="display-4 fw-bold mb-4 gradient-text-1">Library ≠ Framework</h2>
<p class="lead text-muted mb-5">Use any architecture you want. No vendor lock-in.</p>
<div class="expressive-code homepage-code-block">
<figure class="frame not-content">
{{ highlight `func (h *Handler) RegisterUser(w http.ResponseWriter, r *http.Request) {
user := createUser(r)
// Your existing business logic
err := h.userRepo.Save(user)
if err != nil {
// ...
}
// Publish an event using Watermill
err := h.eventBus.Publish(r.Context(), &UserRegistered{...})
// ...
}` "go" "" }}
</figure>
</div>
</div>
</div>
<!-- Get Started Section -->
<div class="row justify-content-center text-center pt-5 mt-5 homepage-section-gradient">
<div class="col-lg-11 col-xl-10">
<img src="/img/gopher.svg" alt="Watermill Logo" style="width: 160px;" class="mb-2" />
<h2 class="display-5 fw-bold mb-4">Start building</h2>
<div class="mt-3">
<a class="btn btn-primary btn-cta rounded-pill btn-lg" href="/learn/" role="button">
Get Started
</a>
</div>
</div>
</div>
</div>
</section>
{{ end }}
{{ define "sidebar-prefooter" }}
{{ if site.Params.doks.backgroundDots -}}
<div class="d-flex justify-content-start">
<div class="bg-dots"></div>
</div>
{{ end -}}
{{ end }}
{{ define "sidebar-footer" }}
{{ if site.Params.doks.sectionFooter -}}
<section class="section section-md container-fluid bg-light">
<div class="row justify-content-center text-center">
<div class="col-lg-7">
<h2 class="mt-2">Start building with Doks today</h2>
<a class="btn btn-primary rounded-pill px-4 my-2" href="/docs/{{ if site.Params.doks.docsVersioning }}{{ site.Params.doks.docsVersion }}/{{ end }}prologue/introduction/" role="button">{{ i18n "get-started" }}</a>
</div>
</div>
</section>
{{ end -}}
{{ end }}

View File

@@ -0,0 +1,37 @@
{{- if not (or .IsHome .Params.HideBanner) -}}
<div class="text-center mb-5 event-driven-banner">
<a href="https://threedots.tech/event-driven/?utm_source=watermill-docs">
<img width="400" src="https://threedots.tech/event-driven-banner.png">
<br>
Check our online hands-on training
</a>
</div>
{{- end -}}
<footer class="footer text-muted">
<div class="container-{{ site.Params.doks.containerBreakpoint | default "lg" }}">
<div class="row">
<div class="col-lg-8 text-center text-lg-start">
<a href="https://threedots.tech">
<img class="only-dark" fetchpriority="high" decoding="async" width="200" height="31" src="https://threedots.tech/images/logo-darkmode.svg" alt="Three Dots Labs">
<img class="only-light" fetchpriority="high" decoding="async" width="200" height="31" src="https://threedots.tech/images/logo.svg" alt="Three Dots Labs">
</a>
</div>
<div class="col-lg-8 text-center text-lg-end">
<p>© Three Dots Labs 2014 — {{ dateFormat "2006" now }}</p>
</div>
</div>
</div>
<div class="text-center mt-5">
<p>
</p>
<p><small>
Watermill is open-source software and is not backed by venture capital.
<br>
We are an independent, bootstrapped company.
</small>
</p>
</div>
</footer>

View File

@@ -0,0 +1,16 @@
{{/* Put your custom <script></script> tags here */}}
{{/* EXAMPLE - only load script for production
{{ if eq (hugo.Environment) "production" -}}
{{ partial "footer/esbuild" (dict "src" "js/instantpage.js" "load" "async" "transpile" false) -}}
{{ end -}}
*/}}
{{/* EXAMPLE - only load script for a page type e.g. contact or gallery
{{ if eq .Type "gallery" -}}
{{ partial "footer/esbuild" (dict "src" "js/gallery.js" "load" "async" "transpile" false) -}}
{{ end -}}
*/}}
<script defer data-domain="watermill.io" src="https://threedots.tech/js/po.js"></script>
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>

View File

@@ -0,0 +1,16 @@
<!-- Custom head -->
<!-- google fonts -->
{{ $pf:= "Heebo:wght@400;600" }}
{{ $sf:= "Quicksand:wght@700" }}
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<script>
(function () {
const googleFont = document.createElement("link");
googleFont.href = "https://fonts.googleapis.com/css2?family={{$pf | safeURL}}{{with $sf}}&family={{. | safeURL}}{{end}}&display=swap";
googleFont.type = "text/css";
googleFont.rel = "stylesheet";
document.head.appendChild(googleFont);
})();
</script>

View File

@@ -0,0 +1,3 @@
<link rel="preload" href="{{ "fonts/quicksand/quicksand-v31-latin-regular.woff2" | absURL }}" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="{{ "fonts/quicksand/quicksand-v31-latin-500.woff2" | absURL }}" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="{{ "fonts/quicksand/quicksand-v31-latin-700.woff2" | absURL }}" as="font" type="font/woff2" crossorigin>

View File

@@ -0,0 +1 @@
<!-- Insert scripts NOT needed by stylesheets here -->

View File

@@ -0,0 +1,276 @@
{{ if site.Params.doks.alert -}}
{{ partial "header/alert.html" . }}
{{ end -}}
{{ if site.Params.doks.navbarSticky -}}
<div class="sticky-top">
{{ end -}}
{{ if site.Params.doks.headerBar -}}
<div class="header-bar"></div>
{{ end -}}
<header class="navbar navbar-expand-lg">
{{ with site.Params.doks.containerBreakpoint -}}
<div class="container-{{ . }}">
{{ else -}}
<div class="container">
{{ end -}}
<!-- Site title -->
<a class="navbar-brand me-auto me-lg-3" href="{{ relLangURL "" }}">{{ .Site.Title }}</a>
<!-- FlexSearch mobile -->
{{ partial "main/showFlexSearch" . }}
{{ $showFlexSearch := .Scratch.Get "showFlexSearch" -}}
{{ if $showFlexSearch -}}
<button type="button" id="searchToggleMobile" class="btn btn-link nav-link mx-2 d-lg-none" aria-label="Search website">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-search" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<circle cx="10" cy="10" r="7"></circle>
<line x1="21" y1="21" x2="15" y2="15"></line>
</svg>
</button>
{{ end -}}
<!-- Section navigation -->
{{ if (in site.Params.doks.sectionNav .Section) -}}
<button class="btn btn-link d-lg-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasNavSection" aria-controls="offcanvasNavSection" aria-label="Open section navigation menu">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-dots-vertical" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 12m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path>
<path d="M12 19m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path>
<path d="M12 5m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path>
</svg>
</button>
<div class="offcanvas offcanvas-start d-lg-none" tabindex="-1" id="offcanvasNavSection" aria-labelledby="offcanvasNavSectionLabel">
{{ if site.Params.doks.headerBar -}}
<div class="header-bar"></div>
{{ end -}}
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasNavSectionLabel">{{ .Section | humanize }}</h5>
<button type="button" class="btn btn-link nav-link p-0 ms-auto" data-bs-dismiss="offcanvas" aria-label="Close">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-x" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M18 6l-12 12"></path>
<path d="M6 6l12 12"></path>
</svg>
</button>
</div>
<div class="offcanvas-body">
<aside class="doks-sidebar mt-n3">
<nav id="doks-docs-nav" aria-label="Tertiary navigation">
{{ partial "sidebar/section-menu.html" . }}
</nav>
</aside>
</div>
</div>
{{ end -}}
<!-- Main navigation button -->
<button class="btn btn-link nav-link mx-2 order-3 d-lg-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasNavMain" aria-controls="offcanvasNavMain" aria-label="Open main navigation menu">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-menu" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<line x1="4" y1="8" x2="20" y2="8"></line>
<line x1="4" y1="16" x2="20" y2="16"></line>
</svg>
</button>
<!-- Main navigation -->
<div class="offcanvas offcanvas-end h-auto" tabindex="-1" id="offcanvasNavMain" aria-labelledby="offcanvasNavMainLabel">
{{ if site.Params.doks.headerBar -}}
<div class="header-bar d-lg-none"></div>
{{ end -}}
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasNavMainLabel">{{ site.Title }}</h5>
<button type="button" class="btn btn-link nav-link p-0 ms-auto" data-bs-dismiss="offcanvas" aria-label="Close">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-x" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M18 6l-12 12"></path>
<path d="M6 6l12 12"></path>
</svg>
</button>
</div>
<!--
<div class="offcanvas-header">
<h5 class="offcanvas-title fw-bold" id="offcanvasNavMainLabel">{{ .Site.Params.Title }}</h5>
<button class="btn btn-link nav-link ms-auto" type="button" data-bs-dismiss="offcanvas" aria-label="Close menu">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-x" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M18 6l-12 12"></path>
<path d="M6 6l12 12"></path>
</svg>
</button>
</div>
-->
<div class="offcanvas-body d-flex flex-column flex-lg-row justify-content-between">
<ul class="navbar-nav flex-grow-1">
{{- $current := . -}}
{{- $section := $current.Section -}}
{{ range .Site.Menus.main -}}
{{- $active := or ($current.IsMenuCurrent "main" .) ($current.HasMenuCurrent "main" .) -}}
{{- $active = or $active (eq .Name $current.Title) -}}
{{- $active = or $active (and (eq .Name ($section | humanize)) (eq $current.Section $section)) -}}
{{- $active = or $active (and (eq .Name "Blog") (eq $current.Section "blog" "authors")) -}}
{{ if .HasChildren -}}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
{{ .Name -}}
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-down" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M6 9l6 6l6 -6"></path>
</svg>
</a>
<ul class="dropdown-menu shadow rounded border-0">
{{ range .Children -}}
{{- $active = eq .Name $current.Title -}}
<li><a class="dropdown-item{{ if $active }} active{{ end }}" href="{{ .URL | absURL }}"{{ if $active }} aria-current="true"{{ end }}>{{ .Name }}</a></li>
{{ end -}}
</ul>
</li>
{{ else -}}
<li class="nav-item">
<a class="nav-link{{ if $active }} active{{ end }}" href="{{ .URL | absURL }}"{{ if $active }} aria-current="true"{{ end }}>{{ .Name }}{{ .Post | safeHTML }}</a>
</li>
{{ end -}}
{{ end -}}
</ul>
<!-- FlexSearch desktop -->
{{ partial "main/showFlexSearch" . }}
{{ $showFlexSearch := .Scratch.Get "showFlexSearch" -}}
{{ if $showFlexSearch -}}
<button type="button" id="searchToggleDesktop" class="btn btn-link nav-link p-2 d-none d-lg-block" aria-label="Search website">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-search" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<circle cx="10" cy="10" r="7"></circle>
<line x1="21" y1="21" x2="15" y2="15"></line>
</svg>
</button>
{{ end -}}
<!-- Language dropdown -->
{{ if eq site.Params.doks.multilingualMode true -}}
<div class="dropdown mt-1 order-lg-2">
<button class="btn btn-dropdown dropdown-toggle" id="doks-languages" data-bs-toggle="dropdown" aria-expanded="false" data-bs-display="static">
<span class="dropdown-caret">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-language" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M4 5h7"></path>
<path d="M9 3v2c0 4.418 -2.239 8 -5 8"></path>
<path d="M5 9c0 2.144 2.952 3.908 6.7 4"></path>
<path d="M12 20l4 -9l4 9"></path>
<path d="M19.1 18h-6.2"></path>
</svg>
<span id="doks-language-current">{{ .Site.Language.LanguageName }}</span>
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-down" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M6 9l6 6l6 -6"></path>
</svg>
</span>
</button>
<ul class="dropdown-menu dropdown-menu-lg-end me-lg-2 shadow rounded border-0" aria-labelledby="doks-languages">
<li><span class="dropdown-item current" aria-current="true">{{ .Site.Language.LanguageName }}</span></li>
<li><hr class="dropdown-divider"></li>
{{ if site.Params.doks.showMissingLanguages -}}
{{ $translatedLangs := slice -}}
{{ range .Translations -}}
{{ $translatedLangs = $translatedLangs | append .Lang }}
{{- end }}
{{ range site.Languages -}}
{{ if and (ne $.Lang .Lang) (not (in $.Params.skipTranslations .Lang)) -}}
{{ $isTranslated := in $translatedLangs .Lang -}}
<li><a class="dropdown-item {{ if not $isTranslated }}untranslated{{ end }}" rel="alternate" href="{{ if $isTranslated }}{{ (index (where $.Translations "Lang" .Lang) 0).RelPermalink }}{{ else }}{{ .Lang | relURL }}{{ end }}" hreflang="{{ .Lang }}" lang="{{ .Lang }}">{{ .LanguageName }}</a></li>
{{- end }}
{{- end }}
{{ else -}}
{{ range .Translations -}}
<li><a class="dropdown-item" rel="alternate" href="{{ .RelPermalink }}" hreflang="{{ .Lang }}" lang="{{ .Lang }}">{{ .Language.LanguageName }}</a></li>
{{- end }}
{{- end }}
<!--
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="/docs/contributing/how-to-contribute/">Help Translate</a></li>
-->
</ul>
</div>
{{ end -}}
<!-- Versioning dropdown -->
{{ if eq site.Params.doks.docsVersioning true -}}
<div class="dropdown mt-1 order-lg-3">
<button class="btn btn-dropdown dropdown-toggle" id="doks-versions" data-bs-toggle="dropdown" aria-expanded="false" data-bs-display="static" aria-label="Toggle version menu">
<span class="d-none">Doks</span> v{{ site.Params.doks.docsVersion }}
<span class="dropdown-caret">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-down" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M6 9l6 6l6 -6"></path>
</svg>
</span>
</button>
<ul class="dropdown-menu dropdown-menu-lg-end me-lg-2 shadow rounded border-0" aria-labelledby="doks-versions">
<li><a class="dropdown-item current" aria-current="true" href="/docs/{{ site.Params.doks.docsVersion }}/prologue/introduction/">Latest ({{ site.Params.doks.docsVersion }}.x)</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="/docs/0.2/prologue/introduction/">v0.2.x</a></li>
<li><a class="dropdown-item" href="/docs/0.1/prologue/introduction/">v0.1.x</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="/docs/versions/">All versions</a></li>
</ul>
</div>
{{ end -}}
<!-- Color mode toggler -->
{{ if and (eq site.Params.doks.colorMode "auto") site.Params.doks.colorModeToggler -}}
<button id="buttonColorMode" class="btn btn-link mx-auto nav-link p-0 ms-lg-2 me-lg-1" type="button" aria-label="Toggle theme">
<svg data-bs-theme-value="dark" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-moon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
<svg data-bs-theme-value="light" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-sun" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 12m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0m-5 0h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7"></path>
</svg>
</button>
{{ end -}}
<!-- Social menu -->
{{ if .Site.Menus.social -}}
<ul id="socialMenu" class="nav mx-auto flex-row order-lg-4">
{{ range .Site.Menus.social -}}
<li class="nav-item">
<a class="nav-link social-link" href="{{ .URL | relURL }}">{{ .Pre | safeHTML }}<small class="ms-2 visually-hidden">{{ .Name | safeHTML }}</small></a>
</li>
{{ end -}}
</ul>
{{ end -}}
<!-- Navbar button mobile -->
{{ if site.Params.doks.navBarButton -}}
<a class="btn btn-primary rounded-pill mt-2 btn-block d-lg-none" href="{{ site.Params.doks.navBarButtonUrl | absURL }}" role="button">{{ site.Params.doks.navBarButtonText }}</a>
{{ end -}}
</div>
</div>
<!-- Navbar button desktop -->
{{ if site.Params.doks.navBarButton -}}
<a class="btn btn-primary rounded-pill ms-3 me-2 px-4 order-lg-3 d-none d-lg-block" href="{{ site.Params.doks.navBarButtonUrl | absURL }}" role="button">{{ site.Params.doks.navBarButtonText }}</a>
{{ end -}}
</div>
</header>
{{ if site.Params.doks.navbarSticky -}}
</div>
{{ end -}}
<!-- Search modal -->
{{ if site.Params.doks.flexSearch -}}
{{ partial "header/search-modal" . }}
{{ end -}}

View File

@@ -0,0 +1,39 @@
{{ $parts := slice site.Params.doks.docsRepo }}
{{ if (eq site.Params.doks.repoHost "GitHub") }}
{{ $parts = $parts | append "edit" site.Params.doks.docsRepoBranch }}
{{ else if (eq site.Params.doks.repoHost "Gitea") }}
{{ $parts = $parts | append "_edit" site.Params.doks.docsRepoBranch }}
{{ else if (eq site.Params.doks.repoHost "GitLab") }}
{{ $parts = $parts | append "-/blob" site.Params.doks.docsRepoBranch }}
{{ else if (eq site.Params.doks.repoHost "Bitbucket") }}
{{ $parts = $parts | append "src" site.Params.doks.docsRepoBranch }}
{{ else if (eq site.Params.doks.repoHost "BitbucketServer") }}
{{ $parts = $parts | append "browse" site.Params.doks.docsRepoBranch }}
{{ end }}
{{ if isset .Site.Params "docsRepoSubPath" }}
{{ if not (eq site.Params.doks.docsRepoSubPath "") }}
{{ $parts = $parts | append site.Params.doks.docsRepoSubPath }}
{{ end }}
{{ end }}
{{ $filePath := replace .File.Path "\\" "/" }}
{{ $lang := "" }}
{{ if site.Params.doks.multilingualMode }}
{{ $lang = .Lang }}
{{ end }}
{{ $parts = $parts | append "docs/content" $filePath }}
{{ $url := delimit $parts "/" }}
<div class="edit-page">
<a href="{{ $url }}">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-edit-2">
<path d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z"></path>
</svg>
Help us improve this page
</a>
</div>

View File

@@ -0,0 +1,5 @@
{{ $hasHeadings := false }}
{{ if (isset .Fragments "Headings") }}
{{ $hasHeadings = gt (len .Fragments.Headings) 0 }}
{{ end }}
{{ $hasHeadings }}

View File

@@ -0,0 +1,50 @@
{{/* Based on: https://github.com/gohugoio/hugo/blob/master/tpl/tplimpl/embedded/templates/opengraph.html */}}
<meta property="og:title" content="{{ .Title }}">
<meta property="og:description" content="{{ with .Description }}{{ . }}{{ else }}{{if .IsPage}}{{ .Summary }}{{ else }}{{ with .Site.Params.description }}{{ . }}{{ end }}{{ end }}{{ end }}">
<meta property="og:type" content="{{ if .IsPage }}article{{ else }}website{{ end }}">
<meta property="og:url" content="{{ .Permalink }}">
{{ $imagePermalink := (printf "https://academy-api.threedots.tech/ssr/image.png?%s" (collections.Querify "url" .Permalink) ) }}
<meta property="og:image" content="{{ $imagePermalink }}">
{{- if .IsPage }}
{{- $iso8601 := "2006-01-02T15:04:05-07:00" -}}
<meta property="article:section" content="{{ .Section }}">
{{ with .PublishDate }}<meta property="article:published_time" {{ .Format $iso8601 | printf "content=%q" | safeHTMLAttr }}>{{ end }}
{{ with .Lastmod }}<meta property="article:modified_time" {{ .Format $iso8601 | printf "content=%q" | safeHTMLAttr }}>{{ end }}
{{- end -}}
{{- with .Params.audio }}<meta property="og:audio" content="{{ . }}">{{ end }}
{{- with .Params.locale }}<meta property="og:locale" content="{{ . }}">{{ end }}
{{- with .Site.Params.title }}<meta property="og:site_name" content="{{ . }}">{{ end }}
{{- with .Params.videos }}{{- range . }}
<meta property="og:video" content="{{ . | absURL }}">
{{ end }}{{ end }}
{{- /* If it is part of a series, link to related articles */}}
{{- $permalink := .Permalink }}
{{- $siteSeries := .Site.Taxonomies.series }}
{{- if $siteSeries }}
{{ with .Params.series }}{{- range $name := . }}
{{- $series := index $siteSeries ($name | urlize) }}
{{- range $page := first 6 $series.Pages }}
{{- if ne $page.Permalink $permalink }}<meta property="og:see_also" content="{{ $page.Permalink }}">{{ end }}
{{- end }}
{{ end }}{{ end }}
{{- end }}
{{- /* Deprecate site.Social.facebook_admin in favor of site.Params.social.facebook_admin */}}
{{- $facebookAdmin := "" }}
{{- with site.Params.social }}
{{- if reflect.IsMap . }}
{{- $facebookAdmin = .facebook_admin }}
{{- end }}
{{- else }}
{{- with site.Social.facebook_admin }}
{{- $facebookAdmin = . }}
{{- warnf "The social key in site configuration is deprecated. Use params.social.facebook_admin instead." }}
{{- end }}
{{- end }}
{{- /* Facebook Page Admin ID for Domain Insights */}}
{{ with $facebookAdmin }}<meta property="fb:admins" content="{{ . }}">{{ end }}

View File

@@ -0,0 +1,30 @@
{{/* Based on: https://github.com/gohugoio/hugo/blob/master/tpl/tplimpl/embedded/templates/twitter_cards.html */}}
{{ $imagePermalink := (printf "https://academy-api.threedots.tech/ssr/image.png?%s" (collections.Querify "url" .Permalink) ) }}
<meta name="twitter:image" content="{{ $imagePermalink }}">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{{ .Title }}">
<meta name="twitter:description" content="{{ with .Description }}{{ . }}{{ else }}{{if .IsPage}}{{ .Summary }}{{ else }}{{ with .Site.Params.description }}{{ . }}{{ end }}{{ end }}{{ end -}}">
{{- /* Deprecate site.Social.twitter in favor of site.Params.social.twitter */}}
{{- $twitterSite := "" }}
{{- with site.Params.social }}
{{- if reflect.IsMap . }}
{{- $twitterSite = .twitter }}
{{- end }}
{{- else }}
{{- with site.Social.twitter }}
{{- $twitterSite = . }}
{{- warnf "The social key in site configuration is deprecated. Use params.social.twitter instead." }}
{{- end }}
{{- end }}
{{- with $twitterSite }}
{{- $content := . }}
{{- if not (strings.HasPrefix . "@") }}
{{- $content = printf "@%v" $twitterSite }}
{{- end }}
<meta name="twitter:site" content="{{ $content }}">
{{- end }}

View File

@@ -0,0 +1,7 @@
{{- with site.Menus.sidebar }}
{{ partial "sidebar/render-section-menu.html" (dict "currentPage" $ "nodes" .) }}
{{- else }}
{{- with (.Site.GetPage "section" .Section).Sections }}
{{ partial "sidebar/render-section-menu.html" (dict "currentPage" $ "nodes" .) }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,114 @@
{{ $file := (.Get "file") }}
{{ $content := readFile $file }}
{{ $first_line_contains := (.Get "first_line_contains") }}
{{ $last_line_contains := (.Get "last_line_contains") }}
{{ $last_line_equals := (.Get "last_line_equals") }}
{{ $show_line := false }}
{{/*if true, first or last line was not found*/}}
{{ $first_line_found := false}}
{{ $last_line_found := false}}
{{ $padding_after := (.Get "padding_after" | default "0" | int) }}
{{ $first_line_num := 0 }}
{{ $last_line_num := 0 }}
{{ $linkFile := $file }}
{{ $repo := "watermill" }}
{{ if in $file "src-link/watermill-" }}
{{ $repo = index (findRE "watermill-[a-z]+" $linkFile) 0 }}
{{ $linkFile = replace $linkFile $repo "" }}
{{ $linkFile = replace $linkFile "src-link//" "" }}
{{ else if in $linkFile "src-link/" }}
{{ $linkFile = replace $linkFile "src-link/" "" }}
{{ else }}
{{ $linkFile = print "docs/content/" $linkFile }}
{{ end }}
{{ $lines := slice }}
{{ range $elem_key, $elem_val := split $content "\n" }}
{{ $line_num := (add $elem_key 1) }}
{{ if and (not $first_line_found) (in $elem_val $first_line_contains) }}
{{ if ne $elem_key 0 }}
{{ $lines = $lines | append "// ..." }}
{{ end }}
{{ $show_line = true }}
{{ $first_line_found = true}}
{{ $first_line_num = $line_num }}
{{ end }}
{{ if $show_line }}
{{ $lines = $lines | append $elem_val }}
{{ end }}
{{ if and ($first_line_found) (in $elem_val $last_line_contains) (ne $last_line_contains "") }}
{{ $last_line_found = true }}
{{ end }}
{{ if and ($first_line_found) (eq $elem_val $last_line_equals) (ne $last_line_equals "") }}
{{ $last_line_found = true }}
{{ end }}
{{ if and $last_line_found $show_line }}
{{ if gt $padding_after 0 }}
{{ $padding_after = sub $padding_after 1}}
{{ else }}
{{ $lines = $lines | append "// ..." }}
{{ $show_line = false }}
{{ $last_line_num = $line_num }}
{{ end }}
{{ end }}
{{ end }}
{{/* Calculate minimum indentation (common whitespace) */}}
{{ $min_indent := 999999 }}
{{ range $lines }}
{{ if and (ne . "// ...") (ne (trim . " \t") "") }}
{{ $leading := 0 }}
{{ range $i, $char := split . "" }}
{{ if or (eq $char " ") (eq $char "\t") }}
{{ $leading = add $leading 1 }}
{{ else }}
{{ break }}
{{ end }}
{{ end }}
{{ if lt $leading $min_indent }}
{{ $min_indent = $leading }}
{{ end }}
{{ end }}
{{ end }}
{{/* Remove common leading whitespace from all lines */}}
{{ $normalized_lines := slice }}
{{ range $lines }}
{{ if or (eq . "// ...") (eq (trim . " \t") "") }}
{{ $normalized_lines = $normalized_lines | append . }}
{{ else if gt $min_indent 0 }}
{{ $normalized_lines = $normalized_lines | append (substr . $min_indent) }}
{{ else }}
{{ $normalized_lines = $normalized_lines | append . }}
{{ end }}
{{ end }}
<div class="expressive-code">
<figure class="frame not-content">
{{ transform.Highlight (delimit $normalized_lines "\n" | safeHTML) (.Get "type" | default "go") }}
</figure>
</div>
<small class="smaller">Full source: [github.com/ThreeDotsLabs/{{ $repo }}/{{ $linkFile }}](https://github.com/ThreeDotsLabs/{{ $repo }}/tree/master/{{ $linkFile }}{{ if ne $first_line_num 0 }}#L{{ $first_line_num }}{{ end }})</small>
{{if not $first_line_found }}
{{ errorf "`first_line_contains` %s not found in %s snippet" $first_line_contains $file }}
{{end}}
{{if and (not $last_line_found) (ne $last_line_contains "") }}
{{ errorf "`last_line_contains` %s not found in %s snippet" $last_line_contains $file }}
{{end}}

View File

@@ -0,0 +1,37 @@
{{ $file := (.Get "file") }}
{{ $content := readFile $file }}
{{ $start_line := (.Get "start_line") | default "0" }}
{{ $end_line := (.Get "end_line") | default "0" }}
{{ $has_start_line := (ne $start_line "0") }}
{{ $has_end_line := (ne $end_line "0") }}
{{ $lines := slice }}
{{ $linkFile := $file }}
{{ $repo := "watermill" }}
{{ if in $file "src-link/watermill-" }}
{{ $repo = index (findRE "watermill-[a-z]+" $linkFile) 0 }}
{{ $linkFile = replace $linkFile $repo "" }}
{{ $linkFile = replace $linkFile "src-link//" "" }}
{{ else if in $linkFile "src-link/" }}
{{ $linkFile = replace $linkFile "src-link/" "" }}
{{ else }}
{{ $linkFile = print "docs/content/" $linkFile }}
{{ end }}
{{ range $elem_key, $elem_val := split $content "\n" }}
{{if and (or (not $has_start_line) (ge (add $elem_key 1) ($start_line | int))) (or (not $has_end_line) (le (add $elem_key 1) ($end_line | int)))}}
{{ $lines = $lines | append $elem_val }}
{{ end }}
{{ end }}
<div class="expressive-code">
<figure class="frame not-content">
{{ transform.Highlight (delimit $lines "\n" | safeHTML) (.Get "type" | default "go") }}
</figure>
</div>
<small class="smaller">Full source: [{{ $linkFile }}](https://github.com/ThreeDotsLabs/watermill/tree/master/{{ $linkFile }})</small>

View File

@@ -0,0 +1,6 @@
{{$file := .Get "file"}}
{{- if eq (.Get "markdown") "true" -}}
{{- $file | readFile | markdownify -}}
{{- else -}}
{{ $file | readFile | safeHTML }}
{{- end -}}

View File

@@ -0,0 +1,17 @@
<!--
Source: https://github.com/alex-shpak/hugo-book/blob/master/layouts/shortcodes/tab.html
-->
{{ if .Parent -}}
{{ $name := .Get 0 }}
{{ $slug := .Get 1 }}
{{ $group := printf "tabs-%s" (.Parent.Get 0) }}
{{ if not (.Parent.Scratch.Get $group) }}
{{ .Parent.Scratch.Set $group slice }}
{{ end }}
{{ .Parent.Scratch.Add $group (dict "Name" $name "Slug" $slug "Content" .Inner) }}
{{ else -}}
{{ errorf "%q: 'tab' shortcode must be inside 'tabs' shortcode" .Page.Path }}
{{ end -}}

View File

@@ -0,0 +1,25 @@
<!--
Based on: https://github.com/alex-shpak/hugo-book/blob/master/layouts/shortcodes/tabs.html
-->
{{ if .Inner }}{{ end }}
{{ $id := .Get 0 }}
{{ $group := printf "tabs-%s" $id }}
<nav>
<div class="nav nav-tabs" id="nav-tab" role="tablist">
{{ range $index, $tab := .Scratch.Get $group -}}
<button data-toggle-tab="{{ $tab.Slug }}" class="nav-link{{ if not $index }} active{{ end }}" id="{{ printf "%s-%d" $group $index }}-tab" data-bs-toggle="tab" data-bs-target="#{{ printf "%s-%d" $group $index }}" type="button" role="tab" aria-controls="{{ printf "%s-%d" $group $index }}" aria-selected="true">
{{ $tab.Name -}}
</button>
{{ end -}}
</div>
</nav>
<div class="tab-content" id="nav-tabContent">
{{ range $index, $tab := .Scratch.Get $group -}}
<div data-pane="{{ $tab.Slug }}" class="tab-pane fade{{ if not $index }} show active{{ end }}" id="{{ printf "%s-%d" $group $index }}" role="tabpanel" aria-labelledby="{{ printf "%s-%d" $group $index }}-tab" tabindex="0">
{{ .Content | $.Page.RenderString -}}
</div>
{{ end -}}
</div>