This commit is contained in:
+3
-3
@@ -7,14 +7,14 @@ import { ThemeScript } from "@/components/ThemeScript";
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL("https://vantage.hostxtra.co.uk"),
|
||||
title: {
|
||||
default: "Vantage — one control plane for the whole fleet",
|
||||
template: "%s — Vantage",
|
||||
default: "Vantage one control plane for the whole fleet",
|
||||
template: "%s Vantage",
|
||||
},
|
||||
description: "Self-hosted fleet control: SSH key assignment, workflow execution, service monitoring, a secrets vault and a browser console, across every server you manage.",
|
||||
openGraph: {
|
||||
type: "website",
|
||||
siteName: "Vantage",
|
||||
title: "Vantage — one control plane for the whole fleet",
|
||||
title: "Vantage one control plane for the whole fleet",
|
||||
description: "Self-hosted fleet control: SSH keys, workflows, monitors, secrets and consoles, over one outbound agent connection.",
|
||||
},
|
||||
icons: { icon: "/images/vantage_logo.svg" },
|
||||
|
||||
@@ -29,8 +29,8 @@ export default function PlatformPage() {
|
||||
</p>
|
||||
<p>
|
||||
Key state is polled on a 30-second interval, because 30 seconds is fine for access control and polling
|
||||
is simple to reason about. Everything that should not wait — running a step, opening a console, applying
|
||||
updates — is pushed down a bidirectional command stream the agent holds open.
|
||||
is simple to reason about. Everything that should not wait running a step, opening a console, applying
|
||||
updates is pushed down a bidirectional command stream the agent holds open.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -76,19 +76,19 @@ export default function PlatformPage() {
|
||||
and renames it over the real one. A machine that loses power mid-write keeps the file it had.
|
||||
</p>
|
||||
<pre className="code">
|
||||
<i>// agent poll, simplified</i>
|
||||
<i>
|
||||
{"\n"}
|
||||
desired := client.SyncKeys(serverID, token){"\n"}
|
||||
current := keys.ReadAuthorizedKeys(){"\n\n"}
|
||||
<b>if</b> !keys.StateChanged(current, desired) {"{"}
|
||||
{"\n "}
|
||||
<i>// nothing to do</i>
|
||||
<i>
|
||||
{"\n "}
|
||||
<b>return</b> nil{"\n"}
|
||||
{"}"}
|
||||
{"\n\n"}
|
||||
keys.WriteAuthorizedKeys(desired){"\n"}
|
||||
<i>// write .tmp, os.Rename(), chmod 0600</i>
|
||||
<i>
|
||||
</pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -13,11 +13,11 @@ const COMPARISON: [string, string, string, string][] = [
|
||||
["SSH key assignment", "Yes", "Yes", "Yes"],
|
||||
["Workflows and step library", "Yes", "Yes", "Yes"],
|
||||
["Monitors", "3", "Unlimited", "Unlimited"],
|
||||
["Secrets vault", "—", "Yes", "Yes"],
|
||||
["Browser console", "—", "Yes", "Yes"],
|
||||
["OIDC single sign-on", "—", "Yes", "Yes"],
|
||||
["Secrets vault", "No", "Yes", "Yes"],
|
||||
["Browser console", "No", "Yes", "Yes"],
|
||||
["OIDC single sign-on", "No", "Yes", "Yes"],
|
||||
["Audit history", "30 days", "Forever", "Forever"],
|
||||
["Runs on your hardware", "—", "—", "Yes"],
|
||||
["Runs on your hardware", "No", "No", "Yes"],
|
||||
["Support", "Community", "Next business day", "Priority"],
|
||||
];
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ export function Footer() {
|
||||
return (
|
||||
<footer className="foot">
|
||||
<div className="rail foot__in">
|
||||
<p>Vantage — self-hosted fleet control for people who own their servers.</p>
|
||||
<p>Vantage self-hosted fleet control for people who own their servers.</p>
|
||||
{NAV_LINKS.map((link) => (
|
||||
<Link key={link.href} href={link.href}>
|
||||
{link.label}
|
||||
|
||||
@@ -64,7 +64,7 @@ export function InstrumentPanel() {
|
||||
if (effect === "revoked") setRevoked(true);
|
||||
};
|
||||
|
||||
// Reduced motion gets the finished state immediately rather than no state.
|
||||
|
||||
if (reduced) {
|
||||
setLines([FIRST_LINE, ...BEATS.map((b) => b.line)].slice(-MAX_LINES));
|
||||
BEATS.forEach((b) => apply(b.effect));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Traced from web/public/images/vantage_logo.svg. The fill is currentColor so
|
||||
// the mark follows the --logo token in both themes.
|
||||
|
||||
|
||||
export function Logo({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg viewBox="246 207 533 610" className={className} aria-hidden="true" focusable="false">
|
||||
|
||||
@@ -11,7 +11,7 @@ export function Nav() {
|
||||
const pathname = usePathname();
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
// A route change should never leave the drawer hanging open behind the new page.
|
||||
|
||||
useEffect(() => {
|
||||
setOpen(false);
|
||||
}, [pathname]);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Applies the stored theme before first paint. Without this the page renders in
|
||||
// the OS theme for a frame and then snaps to the stored one.
|
||||
|
||||
|
||||
const script = `
|
||||
(function(){
|
||||
try {
|
||||
|
||||
@@ -26,8 +26,8 @@ export function ThemeToggle() {
|
||||
setTheme(next);
|
||||
}
|
||||
|
||||
// Until mounted the rendered label would disagree with the server output, so
|
||||
// the button carries a neutral label on first paint.
|
||||
|
||||
|
||||
const label = theme === null ? "Theme" : theme === "dark" ? "Light" : "Dark";
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user