{% import "macros.html" as macros %}
<!DOCTYPE html>
<html lang="en">
<head>
<script>
// 1Password extension bug workaround: MUST be first script in document.
// 1Password injects Prism.js targeting [class*="language-"], stripping our
// syntect spans. Fix: rename language-* to lang-* before 1Password sees them.
// https://1password.community/discussion/165597
(function() {
function fix(el) {
if (el.className && el.className.replace) {
el.className = el.className.replace(/\blanguage-\S*/g, '');
}
if (el.dataset && el.dataset.lang) el.removeAttribute('data-lang');
}
new MutationObserver(function(mutations) {
for (var i = 0; i < mutations.length; i++) {
var nodes = mutations[i].addedNodes;
for (var j = 0; j < nodes.length; j++) {
var n = nodes[j];
if (n.nodeType === 1) {
if (n.className && n.className.includes && n.className.includes('language-')) fix(n);
var els = n.querySelectorAll ? n.querySelectorAll('[class*="language-"]') : [];
for (var k = 0; k < els.length; k++) fix(els[k]);
}
}
}
}).observe(document.documentElement, { childList: true, subtree: true });
})();
</script>
<meta charset="UTF-8">
<title>{% block title %}{{ config.title }}{% endblock title %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<link rel="icon" type="image/png" sizes="48x48" href="/favicon-48.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
{% include "_variables.html" %}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Plus+Jakarta+Sans:wght@500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<link rel="preload" href="{{ get_url(path='logo@2x.png') }}" as="image" media="(-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi)">
<link rel="preload" href="{{ get_url(path='logo.png') }}" as="image" media="not all and (-webkit-min-device-pixel-ratio: 2), not all and (min-resolution: 192dpi)">
<script>
// iOS viewport jank fix: Firefox/Chrome iOS have broken svh/lvh units that
// behave like dvh, causing the hero to resize when browser chrome appears.
// Root cause: Missing WebKit minimumViewportInset/maximumViewportInset APIs.
// https://github.com/mozilla-mobile/firefox-ios/issues/11574
//
// Solution: Capture height ONCE on load, set --vh-full CSS variable.
// CSS uses var(--vh-full, 100lvh) so iOS gets stable pixels, others get lvh.
(function() {
var isIOS = /iP(hone|ad|od)/.test(navigator.platform) ||
(/Macintosh/.test(navigator.userAgent) && 'ontouchend' in document);
if (!isIOS) return;
var h = window.innerHeight;
if (h) {
document.documentElement.style.setProperty('--vh-full', h + 'px');
}
window.addEventListener('orientationchange', function() {
setTimeout(function() {
var newH = window.innerHeight;
if (newH) {
document.documentElement.style.setProperty('--vh-full', newH + 'px');
}
}, 100);
});
})();
</script>
<meta name="view-transition" content="same-origin">
{% set page_description = page.description | default(value=config.extra.site_description) %}
<meta name="description" content="{{ page_description }}">
{% if page.extra.canonical %}
<link rel="canonical" href="{{ config.base_url | trim_end_matches(pat='/') }}{{ page.extra.canonical }}">
{% else %}
<link rel="canonical" href="{{ current_url | default(value=config.base_url) }}">
{% endif %}
<!-- OpenGraph -->
{% set og_title = page.title | default(value="") %}
<meta property="og:type" content="website">
<meta property="og:url" content="{% if page.extra.canonical %}{{ config.base_url | trim_end_matches(pat='/') }}{{ page.extra.canonical }}{% else %}{{ current_url | default(value=config.base_url) }}{% endif %}">
{% if og_title %}{% set og_title_full = og_title ~ " | " ~ config.title %}{% else %}{% set og_title_full = config.title ~ " — " ~ config.extra.site_description %}{% endif %}
<meta property="og:title" content="{{ og_title_full }}">
<meta property="og:description" content="{{ page_description }}">
<meta property="og:image" content="{{ config.base_url }}assets/social/social-card.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{{ og_title_full }}">
<meta name="twitter:description" content="{{ page_description }}">
<meta name="twitter:image" content="{{ config.base_url }}assets/social/social-card.png">
<!-- Structured data -->
{% if not page.title %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "Worktrunk",
"url": "https://worktrunk.dev/",
"description": "{{ config.extra.site_description }}"
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "Worktrunk",
"url": "https://worktrunk.dev/",
"description": "{{ config.extra.site_description }}",
"applicationCategory": "DeveloperApplication",
"operatingSystem": "macOS, Linux, Windows",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
},
"codeRepository": "https://github.com/max-sixty/worktrunk",
"license": "https://opensource.org/licenses/Apache-2.0"
}
</script>
{% endif %}
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-6YY8BDJ4QH"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-6YY8BDJ4QH');
</script>
<link rel="stylesheet" href="/normalize.css">
<link rel="preload" href="/custom.css" as="style">
<link rel="stylesheet" href="/custom.css">
<!-- Syntax highlighting themes - preload and load conditionally by color scheme -->
<link rel="preload" href="/giallo-light.css" as="style" media="(prefers-color-scheme: light)">
<link rel="preload" href="/giallo-dark.css" as="style" media="(prefers-color-scheme: dark)">
<link rel="stylesheet" href="/giallo-light.css" media="(prefers-color-scheme: light)">
<link rel="stylesheet" href="/giallo-dark.css" media="(prefers-color-scheme: dark)">
<script src="/elasticlunr.min.js" defer></script>
<script src="/search_index.en.js" defer></script>
<script src="/search.js" defer></script>
<script src="/code-copy.js" defer></script>
<script src="/mobile-menu.js" defer></script>
<script src="//instant.page/5.2.0" type="module" integrity="sha384-jnZyxPjiipYXnSU0ygqeac2q7CVYMbh84q0uHVRRxEtvFPiQYbXWUorga2aqZJ0z"></script>
<script>
// Show demo images with fade-in after they load (hides broken-image icon during loading)
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('figure.demo img').forEach(function(img) {
if (img.complete) {
img.classList.add('loaded');
} else {
img.addEventListener('load', function() { img.classList.add('loaded'); });
}
});
});
</script>
</head>
<body>
<!-- iOS 26 Liquid Glass fix: solid scrim behind translucent browser chrome -->
<div class="ios-chrome-scrim" aria-hidden="true"></div>
<header>
<button class="mobile-menu-toggle" aria-label="Open menu" aria-expanded="false">
<svg class="menu-icon" aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="3" y1="6" x2="21" y2="6"></line>
<line x1="3" y1="12" x2="21" y2="12"></line>
<line x1="3" y1="18" x2="21" y2="18"></line>
</svg>
<svg class="close-icon" aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
<a href="/">
<div class="logo">
<img src="{{ get_url(path=config.extra.logo_path) }}" srcset="{{ get_url(path='logo.png') }} 1x, {{ get_url(path='logo@2x.png') }} 2x" alt="logo" width="44" height="44" decoding="sync" fetchpriority="high">
{{ config.extra.logo_name }}
</div>
</a>
<nav>
<div class="search-container">
<input id="userinput" type="search" placeholder="Search..." aria-label="Search documentation">
<div id="suggestions"></div>
</div>
{% for menu in config.extra.extra_menu %}
<a class="nav-item" href="{{ menu.link | safe }}">{{ menu.title }}</a>
{% endfor %}
</nav>
</header>
<!-- Mobile menu drawer -->
<div class="mobile-menu-overlay" aria-hidden="true"></div>
<nav class="mobile-menu" aria-hidden="true">
<div class="mobile-menu-content">
<div class="mobile-menu-section">
{% for menu in config.extra.extra_menu %}
<a class="mobile-nav-item" href="{{ menu.link | safe }}">{{ menu.title }}</a>
{% endfor %}
</div>
<div class="mobile-menu-divider"></div>
<div class="mobile-menu-section mobile-menu-toc">
{% set docs_section = get_section(path="_index.md") %}
{% set current_group = "" %}
{% for doc_page in docs_section.pages %}
{% set page_group = doc_page.extra.group | default(value="") %}
{% if page_group != current_group and page_group != "" %}
<div class="mobile-toc-group">{{ page_group }}</div>
{% set_global current_group = page_group %}
{% endif %}
<a class="mobile-toc-item" href="{{ doc_page.permalink | safe }}">{{ doc_page.title }}</a>
{% endfor %}
</div>
</div>
</nav>
<div class="hero">
{% block hero %}{% endblock hero %}
</div>
<main>
{% block toc %}
{% set docs_section = get_section(path="_index.md") %}
{{ macros::toc_nav(docs_section=docs_section) }}
{% endblock toc %}
<div class="content" id="{% block content_id %}{% endblock content_id %}">
{% block content %}
{{ section.content | safe }}
{% endblock content %}
</div>
</main>
<footer>
<div class="footer-social">
<a href="https://github.com/max-sixty/worktrunk" aria-label="GitHub" title="GitHub">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/>
</svg>
</a>
<a href="https://crates.io/crates/worktrunk" aria-label="Crates.io" title="Crates.io">
<svg width="20" height="20" viewBox="0 0 512 512" fill="currentColor">
<path d="M239.1 6.3l-208 78c-18.7 7-31.1 25-31.1 45v225.1c0 18.2 10.3 34.8 26.5 42.9l208 104c13.5 6.8 29.4 6.8 42.9 0l208-104c16.3-8.1 26.5-24.8 26.5-42.9V129.3c0-20-12.4-37.9-31.1-44.9l-208-78C262.4 2.2 249.6 2.2 239.1 6.3zM256 68.4l192 72v1.1l-192 78-192-78v-1.1l192-72zm32 356V275.5l160-65v160.4l-160 53.5z"/>
</svg>
</a>
<a href="https://twitter.com/intent/tweet?text=Worktrunk%20%E2%80%94%20CLI%20for%20git%20worktree%20management&url=https%3A%2F%2Fworktrunk.dev" aria-label="Share on X" title="Share on X">
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>
</svg>
</a>
<a href="https://www.reddit.com/submit?url=https%3A%2F%2Fworktrunk.dev&title=Worktrunk%20%E2%80%94%20CLI%20for%20git%20worktree%20management" aria-label="Share on Reddit" title="Share on Reddit">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0zm5.01 4.744c.688 0 1.25.561 1.25 1.249a1.25 1.25 0 0 1-2.498.056l-2.597-.547-.8 3.747c1.824.07 3.48.632 4.674 1.488.308-.309.73-.491 1.207-.491.968 0 1.754.786 1.754 1.754 0 .716-.435 1.333-1.01 1.614a3.111 3.111 0 0 1 .042.52c0 2.694-3.13 4.87-7.004 4.87-3.874 0-7.004-2.176-7.004-4.87 0-.183.015-.366.043-.534A1.748 1.748 0 0 1 4.028 12c0-.968.786-1.754 1.754-1.754.463 0 .898.196 1.207.49 1.207-.883 2.878-1.43 4.744-1.487l.885-4.182a.342.342 0 0 1 .14-.197.35.35 0 0 1 .238-.042l2.906.617a1.214 1.214 0 0 1 1.108-.701zM9.25 12C8.561 12 8 12.562 8 13.25c0 .687.561 1.248 1.25 1.248.687 0 1.248-.561 1.248-1.249 0-.688-.561-1.249-1.249-1.249zm5.5 0c-.687 0-1.248.561-1.248 1.25 0 .687.561 1.248 1.249 1.248.688 0 1.249-.561 1.249-1.249 0-.687-.562-1.249-1.25-1.249zm-5.466 3.99a.327.327 0 0 0-.231.094.33.33 0 0 0 0 .463c.842.842 2.484.913 2.961.913.477 0 2.105-.056 2.961-.913a.361.361 0 0 0 .029-.463.33.33 0 0 0-.464 0c-.547.533-1.684.73-2.512.73-.828 0-1.979-.196-2.512-.73a.326.326 0 0 0-.232-.095z"/>
</svg>
</a>
<a href="https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fworktrunk.dev" aria-label="Share on LinkedIn" title="Share on LinkedIn">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
</svg>
</a>
</div>
</footer>
<script>
// Wrap code blocks in containers SYNCHRONOUSLY before first paint to prevent layout jump.
// The deferred code-copy.js will add copy buttons to these wrappers later.
(function() {
var blocks = document.querySelectorAll('.content pre');
for (var i = 0; i < blocks.length; i++) {
var block = blocks[i];
var wrapper = document.createElement('div');
wrapper.className = 'code-block-wrapper';
block.parentNode.insertBefore(wrapper, block);
wrapper.appendChild(block);
}
})();
</script>
</body>
</html>