---
import { ClientRouter } from 'astro:transitions';
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';
import SearchDialog from '../components/SearchDialog.astro';
import stats from '../data/stats.json';
import '../styles/global.css';
interface Props {
title: string;
description: string;
noindex?: boolean;
/**
* Path the canonical/og:url should point at. Defaults to the route being
* rendered; the 404 page overrides it with `/` so it never advertises a
* canonical URL that does not exist.
*/
canonicalPath?: string;
}
const { title, description, noindex = false, canonicalPath } = Astro.props;
const base = import.meta.env.BASE_URL;
const normalizedBase = base.endsWith('/') ? base : `${base}/`;
const site = Astro.site ?? new URL('https://grr-cli.pages.dev');
const relativePath = Astro.url.pathname.startsWith(normalizedBase)
? Astro.url.pathname.slice(normalizedBase.length)
: Astro.url.pathname.replace(/^\/+/, '');
const canonical = new URL(`${normalizedBase}${canonicalPath ?? relativePath}`, site).toString();
// Social crawlers do not render SVG, so the rasterised card is the share image.
const socialImage = new URL(`${normalizedBase}og.png`, site).toString();
const socialImageAlt = 'grr pixel-art crab mascot beside a terminal running grr commands';
// The commit the deploy came from, when Cloudflare Pages built it (see the
// build-sha meta below). Empty in local and preview builds.
const commitSha = process.env.CF_PAGES_COMMIT_SHA ?? '';
// The home page passes `title="grr"` so it renders the exact brand title; every
// other route passes a real title and gets the `${title} · Rust Rewrite (grr)`
// suffix form. Both strings are verification-critical, so neither is derived
// from page copy.
const fullTitle = title === 'grr' ? 'Rust Rewrite (grr) — Google tools from the terminal' : `${title} · Rust Rewrite (grr)`;
const jsonLd = JSON.stringify({
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: 'Rust Rewrite',
alternateName: 'grr',
applicationCategory: 'DeveloperApplication',
applicationSubCategory: 'Command line utility',
operatingSystem: 'macOS, Linux, Windows',
license: 'https://opensource.org/licenses/MIT',
url: site.toString(),
image: socialImage,
author: {
'@type': 'Organization',
name: 'grr project',
url: 'https://github.com/debanjanbasu/grr-cli',
},
softwareVersion: stats.version,
datePublished: '2026-09-22',
isAccessibleForFree: true,
sameAs: ['https://github.com/debanjanbasu/grr-cli', 'https://crates.io/crates/grr-cli'],
codeRepository: 'https://github.com/debanjanbasu/grr-cli',
description,
offers: {
'@type': 'Offer',
price: 0,
priceCurrency: 'USD',
},
});
---
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<ClientRouter />
<script is:inline>
(function () {
var applyStoredTheme = function () {
try {
var theme = localStorage.getItem('grr-theme');
if (theme === 'bumblebee' || theme === 'dim') {
document.documentElement.setAttribute('data-theme', theme);
} else if (theme === 'light' || theme === 'dark') {
document.documentElement.setAttribute('data-theme', theme === 'light' ? 'bumblebee' : 'dim');
}
} catch (error) {
}
};
applyStoredTheme();
document.addEventListener('astro:after-swap', applyStoredTheme);
})();
</script>
<meta name="viewport" content="width=device-width" />
<meta name="description" content={description} />
<meta name="author" content="grr project" />
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#fbf7f1" />
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#1b130e" />
<meta name="color-scheme" content="light dark" />
<meta name="google-site-verification" content="eOuATr6yw8ALdCuyHxA_fan3dXicCibqOyHg1ZORrYo" />
{commitSha && <meta name="build-sha" content={commitSha} />}
<meta name="robots" content={noindex ? 'noindex, nofollow' : 'index, follow'} />
<link rel="preload" href={`${normalizedBase}fonts/3270-Regular.woff2`} as="font" type="font/woff2" crossorigin />
<link rel="canonical" href={canonical} />
<link rel="icon" type="image/svg+xml" href={`${normalizedBase}favicon.svg`} sizes="any" />
<link rel="icon" type="image/svg+xml" href={`${normalizedBase}favicon-32.svg`} sizes="32x32" />
<link rel="icon" type="image/svg+xml" href={`${normalizedBase}favicon-16.svg`} sizes="16x16" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Rust Rewrite" />
<meta property="og:locale" content="en_US" />
<meta property="og:title" content={fullTitle} />
<meta property="og:description" content={description} />
<meta property="og:url" content={canonical} />
<meta property="og:image" content={socialImage} />
<meta property="og:image:secure_url" content={socialImage} />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content={socialImageAlt} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={fullTitle} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={socialImage} />
<meta name="twitter:image:alt" content={socialImageAlt} />
<script type="application/ld+json" set:html={jsonLd}></script>
<title>{fullTitle}</title>
</head>
<body>
<a class="skip-link" href="#main-content">Skip to content</a>
<div class="backdrop" aria-hidden="true"><span class="backdrop-stars-back"></span><span class="backdrop-stars-mid"></span></div>
<div class="scroll-progress" aria-hidden="true"></div>
<div class="site-shell">
<Header />
{/* Pagefind indexes only the elements carrying data-pagefind-body, so
marking <main> keeps the header, nav and footer chrome out of the
search index while every page's real content stays in. */}
<main id="main-content" data-pagefind-body>
<slot />
</main>
<Footer />
</div>
<SearchDialog />
<script is:inline type="module">
(function () {
var root = document.documentElement;
var query = window.matchMedia('(prefers-color-scheme: dark)');
var isDark = function () {
return root.dataset.theme === 'dim' || (query.matches && root.dataset.theme !== 'bumblebee');
};
var sync = function () {
var button = document.querySelector('[data-theme-toggle]');
if (button) button.setAttribute('aria-pressed', String(isDark()));
};
var initThemeToggle = function () {
if (window.__grrThemeBound) return;
window.__grrThemeBound = true;
document.addEventListener('click', function (event) {
var target = event.target;
var button = target && target.closest ? target.closest('[data-theme-toggle]') : null;
if (!button) return;
var next = isDark() ? 'bumblebee' : 'dim';
root.dataset.theme = next;
try {
localStorage.setItem('grr-theme', next);
} catch (error) {
}
sync();
});
if (query.addEventListener) {
query.addEventListener('change', sync);
}
};
var initCopy = function () {
if (window.__grrCopyBound) return;
window.__grrCopyBound = true;
function flash(button, label) {
var state = button.querySelector('[data-copy-state]');
if (!state) return;
if (button.dataset.copyReset) clearTimeout(button.dataset.copyReset);
state.textContent = label;
button.classList.add('is-copied');
button.dataset.copyReset = setTimeout(function () {
state.textContent = 'Copy';
button.classList.remove('is-copied');
}, 1600);
}
function selectForManualCopy(code) {
var range = document.createRange();
range.selectNodeContents(code);
var selection = window.getSelection();
if (!selection) return;
selection.removeAllRanges();
selection.addRange(range);
}
document.addEventListener('click', function (event) {
var button = event.target.closest ? event.target.closest('[data-copy]') : null;
if (!button) return;
var block = button.closest('.code-window');
var code = block && block.querySelector('pre code');
if (!code) return;
var text = code.textContent.replace(/\s+$/, '');
event.preventDefault();
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(
function () {
flash(button, 'Copied');
},
function () {
selectForManualCopy(code);
flash(button, 'Press Ctrl+C');
},
);
} else {
selectForManualCopy(code);
flash(button, 'Press Ctrl+C');
}
});
};
var init = function () {
initThemeToggle();
initCopy();
sync();
};
init();
document.addEventListener('astro:page-load', init);
})();
</script>
</body>
</html>