Add a custom Hero banner to langing page with install instructions and remove overly prominent roadmap (still in docs).

This commit is contained in:
Sebastian Jeltsch
2025-07-17 13:54:11 +02:00
parent 02c0b8e28a
commit b9eb39ad37
8 changed files with 205 additions and 29 deletions

3
.gitignore vendored
View File

@@ -8,9 +8,6 @@ node_modules/
# jetbrains setting folder
.idea/
# Dev artifacts
public/
# Avoid `pnpm-lock.yaml` files when not in the root. They are produced when
# building with `--ignore-worspace`.
**/pnpm-lock.yaml

View File

@@ -14,6 +14,8 @@ const openApiBase = "api";
// https://astro.build/config
export default defineConfig({
site: "https://trailbase.io",
// NOTE: Since we're serving static content, these redirects are actual
// pages with a meta refresh tag rather than redirect HTTP responses.
redirects: {
// Stable docs path independent of documentation structure.
"/docs": "/getting-started/install",
@@ -146,6 +148,7 @@ export default defineConfig({
],
components: {
Footer: "./src/components/Footer.astro",
Hero: "./src/components/Hero.astro",
},
}),
],

1
docs/public/install.sh Symbolic link
View File

@@ -0,0 +1 @@
../../install.sh

View File

@@ -0,0 +1,198 @@
---
// Hero component inspired from starlight's original:
// https://github.com/withastro/starlight/blob/8cf8ac79213a69eae8a04c848de9570b9fd1408f/packages/starlight/components/Hero.astro
import { Image } from "astro:assets";
import { Code, LinkButton } from "@astrojs/starlight/components";
import type { ImageMetadata } from "astro";
export const PAGE_TITLE_ID = "_top";
const { data } = Astro.locals.starlightRoute.entry;
const { title = data.title, image, actions = [] } = data.hero || {};
const imageAttrs = {
loading: "eager" as const,
decoding: "async" as const,
width: 400,
height: 400,
alt: image?.alt || "",
};
let darkImage: ImageMetadata | undefined;
let lightImage: ImageMetadata | undefined;
let rawHtml: string | undefined;
if (image) {
if ("file" in image) {
darkImage = image.file;
} else if ("dark" in image) {
darkImage = image.dark;
lightImage = image.light;
} else {
rawHtml = image.html;
}
}
---
<div class="hero">
{
darkImage && (
<Image
src={darkImage}
{...imageAttrs}
class:list={{ "light:sl-hidden": Boolean(lightImage) }}
/>
)
}
{
lightImage && (
<Image src={lightImage} {...imageAttrs} class="dark:sl-hidden" />
)
}
{rawHtml && <div class="hero-html sl-flex" set:html={rawHtml} />}
<div class="sl-flex stack">
<div class="sl-flex copy">
<h1 id={PAGE_TITLE_ID} data-page-title set:html={title} />
<div class="tagline">
<p>
An open, blazingly fast, single-executable Firebase alternative with
type-safe REST & realtime APIs, built-in JS/ES6/TS runtime, SSR, auth
and admin UI built on Rust, SQLite & V8.
</p>
<br />
<p>
Simplify with fewer moving parts&colon; an easy to self-host
single-executable with everything you need to focus on your mobile,
web or desktop application. Sub-millisecond latencies eliminate the
need for dedicated caches, no more stale or inconsistent data.
</p>
<br />
<Code
class=""
lang="sh"
code={"curl -sSL https://trailbase.io/install.sh | bash"}
frame={false}
/>
</div>
</div>
{
actions.length > 0 && (
<div class="sl-flex actions">
{actions.map(
({
attrs: { class: className, ...attrs } = {},
icon,
link: href,
text,
variant,
}) => (
<LinkButton
{href}
{variant}
icon={icon?.name}
class:list={[className]}
{...attrs}
>
{text}
{icon?.html && <Fragment set:html={icon.html} />}
</LinkButton>
),
)}
</div>
)
}
</div>
</div>
<style>
@layer starlight.core {
.hero {
display: grid;
align-items: center;
gap: 1rem;
padding-bottom: 1rem;
}
.hero > img,
.hero > .hero-html {
object-fit: contain;
width: min(70%, 20rem);
height: auto;
margin-inline: auto;
}
.stack {
flex-direction: column;
gap: clamp(1.5rem, calc(1.5rem + 1vw), 2rem);
text-align: center;
}
.copy {
flex-direction: column;
gap: 1rem;
align-items: center;
}
.copy > * {
max-width: 50ch;
}
h1 {
font-size: clamp(
var(--sl-text-3xl),
calc(0.25rem + 5vw),
var(--sl-text-6xl)
);
line-height: var(--sl-line-height-headings);
font-weight: 600;
color: var(--sl-color-white);
}
.tagline {
font-size: clamp(
var(--sl-text-base),
calc(0.0625rem + 2vw),
var(--sl-text-xl)
);
color: var(--sl-color-gray-2);
}
.actions {
gap: 1rem 2rem;
flex-wrap: wrap;
justify-content: center;
}
@media (min-width: 50rem) {
.hero {
grid-template-columns: 7fr 4fr;
gap: 3%;
padding-block: clamp(2.5rem, calc(1rem + 10vmin), 10rem);
}
.hero > img,
.hero > .hero-html {
order: 2;
width: min(100%, 25rem);
}
.stack {
text-align: start;
}
.copy {
align-items: flex-start;
}
.actions {
justify-content: flex-start;
}
}
}
</style>

View File

@@ -1,6 +1,6 @@
---
import { Card } from "@astrojs/starlight/components";
import { type StarlightIcon } from "@astrojs/starlight/types";
import type { StarlightIcon } from "@astrojs/starlight/types";
export interface Props {
title: string;

View File

@@ -9,6 +9,7 @@ For context, some larger features we have on our Roadmap:
Also, service-accounts to auth other backends as opposed to end-users.
- Many SQLite databases: imagine a separate database by tenant or user. Note
that while joins are available across databases, foreign keys are not.
- Point-in-time-recovery via checkpointing or SQLite sessions.
- A message queue system to deal with slow tasks or bursty workloads.
- We might want to address fan-out and the integration of external resources
through GraphQL or similar.

View File

@@ -4,18 +4,6 @@ description: >
A blazingly fast, open-source, single-executable, featureful Firebase alternative.
template: splash
hero:
tagline: >
An open, blazingly fast, single-executable Firebase alternative with
type-safe REST & realtime APIs, built-in JS/ES6/TS runtime, SSR,
auth and admin UI built on Rust, SQLite & V8.
<br />
<br />
Simplify with fewer moving parts&colon; an easy to self-host
single-executable with everything you need to focus on your mobile, web or
desktop application.
Sub-millisecond latencies eliminate the need for dedicated caches, no more
stale or inconsistent data.
image:
file: ../../assets/logo_512.webp
actions:
@@ -41,8 +29,6 @@ import { Aside, Card, CardGrid } from "@astrojs/starlight/components";
import SplitCard from "@/components/SplitCard.astro";
import Footer from "@/components/Footer.astro";
import Roadmap from "./_roadmap.md";
import shelve from "@/assets/shelve.webp";
import dotnetLogo from "@/assets/dotnet_logo.svg";
@@ -186,14 +172,3 @@ import { Duration100kInsertsChart } from "./reference/_benchmarks/benchmarks.tsx
</CardGrid>
</div>
<div class="h-8" />
<div class="flex justify-center">
<div class="md:w-[80%] flex flex-col items-center gap-4">
<Aside type="tip" title="Roadmap">
<Roadmap />
</Aside>
</div>
</div>

View File

@@ -0,0 +1 @@
../../../assets/favicon.svg