initial commit: reforgermods.net launcher 0.1.0

A desktop server browser for Arma Reforger, built on the reforgermods.net v2
API. Live server list with search, sort and filters; a detail inspector with
population history and mod readiness; measured ICMP latency; favorites, recents
and settings; and direct joining through Steam.

Tauri 2 and Rust, with a Preact frontend that builds to 80 KB of JavaScript in
one chunk. Logic lives in rfm-core, which has no Tauri dependency and is tested
directly; src-tauri is the window, the command surface and the wiring.

Packaged for the public beta: a per-user NSIS installer, a portable .exe and an
Arch package, with signature-verified background updates on Windows and a
release pipeline that builds from a tag. The artifacts are not yet
Authenticode-signed — that is wired and waiting on an Azure Trusted Signing
identity, and docs/distribution.md says so plainly rather than letting anyone
discover it at the SmartScreen dialog.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
SowinskiBraedenandClaude Opus 5 committed 2026-09-24 20:29:00 -07:00
commit 377f3a31b3
91 files changed
+24994

No files matched your search

+74
View File
@@ -0,0 +1,74 @@
/**
* Population history for the selected server.
*
* One inline SVG, no charting library: a min–max band, an average line, and a
* range switcher. The paths come from `lib/chart.ts`, which is pure and tested.
*/
import { historyLoading, historyRange, historySeries, setHistoryRange } from "../lib/state";
import { buildChart } from "../lib/chart";
import { HISTORY_RANGES } from "../lib/types";
/** Drawing box. `preserveAspectRatio="none"` stretches it to the panel width. */
const WIDTH = 300;
const HEIGHT = 56;
export function HistoryChart() {
const series = historySeries.value;
const loading = historyLoading.value;
const range = historyRange.value;
const geometry = series ? buildChart(series.points, WIDTH, HEIGHT) : null;
return (
<div class="section">
<div class="section__h">
<span>Population</span>
<div class="rangeswitch">
{HISTORY_RANGES.map((option) => (
<button
key={option.value}
data-on={option.value === range}
onClick={() => setHistoryRange(option.value)}
>
{option.label}
</button>
))}
</div>
</div>
{geometry ? (
<>
<svg
class="chart"
viewBox={`0 0 ${WIDTH} ${HEIGHT}`}
preserveAspectRatio="none"
role="img"
aria-label={`Population over the last ${range}: peak ${geometry.peak}, average ${geometry.mean}`}
>
{/* Band first so the average line sits on top of it. */}
<path class="chart__band" d={geometry.band} />
{/* non-scaling-stroke keeps the line 1px despite the stretched viewBox. */}
<path class="chart__line" d={geometry.line} vector-effect="non-scaling-stroke" />
</svg>
<div class="chart__legend">
<span>
peak <b>{geometry.peak}</b>
</span>
<span>
avg <b>{geometry.mean}</b>
</span>
<span>
low <b>{geometry.low}</b>
</span>
{geometry.cap > 0 && <span>of {geometry.cap}</span>}
<span class="chart__bucket">{series?.bucket} buckets</span>
</div>
</>
) : (
<p class="state__hint" style={{ margin: 0 }}>
{loading ? "Loading history…" : "No recorded history for this range."}
</p>
)}
</div>
);
}