Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,27 @@ import rehypeAutolinkHeadings from 'rehype-autolink-headings';
import { lastModified, pageReleases, pageSources } from './src/lib/lastmod.ts';
import { getReleases } from './src/lib/github.ts';

/**
* Wraps every markdown table in a container that scrolls sideways. The page
* clips horizontal overflow (global.css), so a table wider than a phone screen
* would otherwise be cut off rather than scroll.
*/
function rehypeScrollingTables() {
/** @param {any} node */
const visit = (node) => {
if (!Array.isArray(node.children)) return;
node.children = node.children.map((/** @type {any} */ child) => {
if (child.type === 'element' && child.tagName === 'table') {
// Focusable, like the code blocks, so that it can be scrolled from the keyboard.
return { type: 'element', tagName: 'div', properties: { className: ['table-scroll'], tabIndex: 0 }, children: [child] };
}
visit(child);
return child;
});
};
return (/** @type {any} */ tree) => visit(tree);
}

// https://astro.build/config
export default defineConfig({
site: 'https://thinkwat.ch',
Expand Down Expand Up @@ -87,6 +108,7 @@ export default defineConfig({
wrap: false,
},
rehypePlugins: [
rehypeScrollingTables,
rehypeSlug,
[
rehypeAutolinkHeadings,
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"pagefind": "pagefind --site dist --output-path dist/pagefind",
"preview": "astro preview",
"releases": "node scripts/update-releases.mjs",
"core-docs": "node scripts/update-core-docs.mjs",
"favicons": "node scripts/generate-favicons.mjs",
"astro": "astro"
},
Expand Down
18 changes: 18 additions & 0 deletions scripts/update-core-docs.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Refresh src/data/core-docs, the committed copy of the ThinkWatch Core
// documents this site publishes (the configuration reference and the server
// deployment guide), from the latest Core release. The build always fetches
// the documents itself and uses this copy only when GitHub cannot be reached;
// it warns when the copy no longer matches. See src/lib/core-docs.mjs.
//
// Run with: pnpm core-docs (GITHUB_TOKEN is used when set; CORE_DOCS_REF
// takes another tag).
import { fileURLToPath } from "node:url";

// Paths in core-docs.mjs are relative to the project root.
process.chdir(fileURLToPath(new URL("..", import.meta.url)));
const { coreDocsRef, fetchCoreDocs, SNAPSHOT_DIR, writeSnapshot } = await import("../src/lib/core-docs.mjs");

const ref = await coreDocsRef();
const docs = await fetchCoreDocs(ref);
await writeSnapshot(docs);
console.log(`✓ Wrote ${SNAPSHOT_DIR} from ThinkWatch Core ${ref} (${Object.keys(docs.files).join(", ")})`);
58 changes: 58 additions & 0 deletions src/components/CopyCommand.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
// A shell command with a copy button: the command scrolls, the button stays.
// Used for the twcore install command on the Core page and on the home page.
import { getLang, t } from "~/i18n";

interface Props {
command: string;
/** Colour and size of the command text */
class?: string;
}

const { command, class: className = "text-[#e6ebf2] text-[15px] sm:text-base" } = Astro.props;
const ui = t(getLang(Astro)).common;
---

<div
class="flex min-w-0 items-center rounded-[14px] border border-[var(--color-border-strong)] bg-[var(--color-surface)] font-mono leading-relaxed"
data-copy-command
>
<code class:list={["min-w-0 flex-1 overflow-x-auto whitespace-nowrap p-5 sm:p-6", className]}>
<span class="select-none text-[var(--color-dim)]">$ </span><span data-cmd>{command}</span>
</code>
<button type="button" class="copy-button" data-copy={command} data-copied-label={ui.copied}>{ui.copy}</button>
</div>

<script>
for (const btn of document.querySelectorAll<HTMLButtonElement>("[data-copy-command] [data-copy]")) {
const label = btn.textContent;
btn.addEventListener("click", async () => {
try {
await navigator.clipboard.writeText(btn.dataset.copy ?? "");
} catch {
// No clipboard access: select the command so it can be copied by hand.
const cmd = btn.parentElement?.querySelector("[data-cmd]");
if (cmd) getSelection()?.selectAllChildren(cmd);
return;
}
btn.textContent = btn.dataset.copiedLabel ?? label;
setTimeout(() => (btn.textContent = label), 1500);
});
}
</script>

<style>
.copy-button {
flex-shrink: 0;
align-self: stretch;
border-left: 1px solid var(--color-border-strong);
padding: 0 1.25rem;
font-family: var(--font-sans);
font-size: 0.875rem;
color: var(--color-muted);
transition: color 150ms;
}
.copy-button:hover {
color: var(--color-brand-1);
}
</style>
21 changes: 18 additions & 3 deletions src/components/home/CoreStrip.astro
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
---
// ThinkWatch Core on the home page: what the two products share, and the
// command that installs twcore on a Linux server (see the /core page).
import CopyCommand from "~/components/CopyCommand.astro";
import { getLang, localePath } from "~/i18n";
import { homeCopy } from "~/i18n/pages/home";

const lang = getLang(Astro);
const c = homeCopy[lang].core;

const installCommand =
"curl -fsSL https://raw.githubusercontent.com/ThinkWatchProject/ThinkWatch-Core/main/scripts/install.sh | sudo sh";
---

<div class="border-y border-[var(--color-border)]">
<div class="container-page flex flex-col gap-5 py-10 md:flex-row md:items-center md:justify-between md:gap-12 md:py-12">
<p class="max-w-3xl text-base leading-relaxed text-[#cbd5e1] sm:text-xl">
<div class="container-page grid gap-6 py-10 md:py-12 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)] lg:items-center lg:gap-12">
<p class="m-0 max-w-3xl text-base leading-relaxed text-[#cbd5e1] sm:text-xl">
{c.a}<a href={localePath(lang, "/core")} class="font-semibold text-white underline decoration-[var(--color-brand-1)]/50 underline-offset-4 hover:text-[var(--color-brand-1)]">{c.name}</a>{c.b}
</p>
<code class="shrink-0 self-start rounded-[10px] border border-[var(--color-border-strong)] bg-[var(--color-surface)] px-5 py-4 font-mono text-sm text-[var(--color-brand-1)] md:self-auto sm:text-[15px]">cargo run -p twcore -- serve</code>
<div class="flex min-w-0 flex-col gap-3">
<p class="m-0 font-mono text-[13px] uppercase tracking-[0.08em] text-[var(--color-muted)]">{c.commandLabel}</p>
<CopyCommand command={installCommand} class="text-[var(--color-brand-1)] text-sm sm:text-[15px]" />
<a
href={localePath(lang, "/docs/core/server-deployment")}
class="inline-flex min-h-11 items-center self-start text-[17px] font-medium text-[var(--color-brand-1)] transition-colors hover:text-[var(--color-brand-2)]"
>
{c.docs}
</a>
</div>
</div>
</div>
Loading
Loading