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
9 changes: 1 addition & 8 deletions site/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export default defineConfig({
// Modal header title (defaults to "Echo Docs AI" from the project name).
'data-modal-title': 'Ask AI',
'data-project-color': '#00afd1',
// Modal header logo — the same sparkle as the "Ask AI" header pill
// Modal header logo — the same star as the "Ask AI" header pill
// (not the Echo cube). The floating launcher that also used this is hidden.
'data-project-logo': '/ask-ai.svg',
// Sync the widget's light/dark with the site (we set data-theme on <html>).
Expand All @@ -88,13 +88,6 @@ export default defineConfig({
href: 'https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700;800&family=Fragment+Mono&display=swap',
},
},
{
tag: 'link',
attrs: {
rel: 'stylesheet',
href: 'https://unpkg.com/@phosphor-icons/web@2.1.1/src/regular/style.css',
},
},
// Default social card. Starlight already emits og:title/description/url
// and twitter:card=summary_large_image, but no image — add a site-wide
// default so shares aren't imageless. Absolute URLs are required by
Expand Down
36 changes: 16 additions & 20 deletions site/performance-baseline.json
Original file line number Diff line number Diff line change
@@ -1,65 +1,61 @@
{
"/": {
"html": {
"raw": 27523,
"gzip": 8601
"raw": 51106,
"gzip": 11580
},
"firstLoadAssets": {
"raw": 94854,
"gzip": 19546
"raw": 121132,
"gzip": 27418
},
"externalDomains": [
"fonts.googleapis.com",
"github.com",
"unpkg.com",
"widget.kapa.ai",
"www.googletagmanager.com"
]
},
"/middleware/cors/": {
"html": {
"raw": 60522,
"gzip": 11390
"raw": 64337,
"gzip": 12671
},
"firstLoadAssets": {
"raw": 118355,
"gzip": 26052
"raw": 123856,
"gzip": 28794
},
"externalDomains": [
"fonts.googleapis.com",
"unpkg.com",
"widget.kapa.ai",
"www.googletagmanager.com"
]
},
"/next/": {
"html": {
"raw": 27645,
"gzip": 8615
"raw": 50213,
"gzip": 11409
},
"firstLoadAssets": {
"raw": 94869,
"gzip": 19549
"raw": 121152,
"gzip": 27425
},
"externalDomains": [
"fonts.googleapis.com",
"github.com",
"unpkg.com",
"www.googletagmanager.com"
]
},
"/next/middleware/cors/": {
"html": {
"raw": 60976,
"gzip": 11405
"raw": 64150,
"gzip": 12326
},
"firstLoadAssets": {
"raw": 118370,
"gzip": 26055
"raw": 123876,
"gzip": 28801
},
"externalDomains": [
"fonts.googleapis.com",
"unpkg.com",
"www.googletagmanager.com"
]
}
Expand Down
2 changes: 1 addition & 1 deletion site/public/ask-ai.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions site/src/components/ConfigReference.astro
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import prometheusManifest from '../generated/prometheus.json';
import telemetryManifest from '../generated/open-telemetry.json';
import externalSources from '../../external-sources.json';
import { formatRevision } from '../data/source.mjs';
import { Badge } from '@astrojs/starlight/components';

interface Props {
name: string;
Expand Down Expand Up @@ -43,7 +44,7 @@ const sourceUrl = (file: string, line: number) => `${repository}/blob/${manifest
<thead><tr><th scope="col">{labels.field}</th><th scope="col">{labels.type}</th><th scope="col">{labels.description}</th><th scope="col">{labels.source}</th></tr></thead>
<tbody>
{config.fields.map((field) => <tr>
<th scope="row"><code>{field.name}</code>{field.deprecated && <span class="deprecated">{labels.deprecated}</span>}</th>
<th scope="row"><code>{field.name}</code>{field.deprecated && <Badge text={labels.deprecated} variant="caution" size="small" class="deprecated" />}</th>
<td><code>{field.type}</code></td>
<td class="field-description">{field.doc || '—'}</td>
<td><a href={sourceUrl(config.file, field.line)} aria-label={`${field.name} ${labels.source}`}>L{field.line}</a></td>
Expand Down Expand Up @@ -76,5 +77,5 @@ const sourceUrl = (file: string, line: number) => `${repository}/blob/${manifest
tbody th { font-weight: 500; }
code { overflow-wrap: anywhere; white-space: pre-wrap; }
.field-description { min-width: 16rem; white-space: pre-line; overflow-wrap: anywhere; }
.deprecated { display: inline-block; margin-inline-start: .5rem; font-size: .75em; color: var(--sl-color-text-accent); }
.deprecated { margin-inline-start: .5rem; }
</style>
53 changes: 53 additions & 0 deletions site/src/components/FeatureCard.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
// Starlight's <Card> markup with an <h3> title: Card renders its title as a <p>,
// which drops homepage feature titles out of the heading outline.
import { Icon } from '@astrojs/starlight/components';
import type { StarlightIcon } from '@astrojs/starlight/types';

interface Props {
icon: StarlightIcon;
title: string;
}

const { icon, title } = Astro.props;
---

<article class="card sl-flex">
<h3 class="title sl-flex">
<Icon name={icon} class="icon" size="1.333em" />
<span>{title}</span>
</h3>
<div class="body"><slot /></div>
</article>

<style>
/* .card .title outranks the theme's global .sl-markdown-content heading rule. */
.card {
flex-direction: column;
gap: clamp(0.5rem, calc(0.125rem + 1vw), 1rem);
border: 1px solid var(--sl-color-hairline);
border-radius: 13px;
background: var(--sl-color-bg-sidebar);
padding: 20px;
}
.card .title {
align-items: center;
gap: 0.7rem;
font-family: var(--sl-font);
font-size: 1.05rem;
font-weight: 600;
letter-spacing: normal;
line-height: var(--sl-line-height-headings);
color: var(--sl-color-white);
}
.icon {
flex-shrink: 0;
color: var(--echo-cyan-text);
}
.body {
margin: 0;
font-size: 0.9rem;
line-height: 1.62;
color: var(--sl-color-gray-3);
}
</style>
5 changes: 3 additions & 2 deletions site/src/components/Footer.astro
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
import Default from '@astrojs/starlight/components/Footer.astro';
import { Icon } from '@astrojs/starlight/components';

const year = new Date().getFullYear();
---
Expand All @@ -8,10 +9,10 @@ const year = new Date().getFullYear();
<span>© {year} LabStack LLC. Released under the MIT License.</span>
<div class="echo-social">
<a href="https://x.com/labstack" target="_blank" rel="noopener noreferrer" aria-label="LabStack on X">
<i class="ph ph-x-logo"></i>
<Icon name="x.com" />
</a>
<a href="https://github.com/labstack/echo" target="_blank" rel="noopener noreferrer" aria-label="Echo on GitHub">
<i class="ph ph-github-logo"></i>
<Icon name="github" />
</a>
</div>
</footer>
61 changes: 16 additions & 45 deletions site/src/components/HomeHero.astro
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,40 @@
// static final-state fallback for reduced motion.
import { starsLabel } from '../data/github.ts';
import stable from '../generated/echo-source.json';
import { Code } from 'astro:components';
import { Code, Icon, LinkButton } from '@astrojs/starlight/components';
import helloWorldSource from '../../../cookbook/hello-world/server.go?raw';
import { sourceSnippet } from '../../plugins/remark-source-code.mjs';
const next = process.env.DOCS_CHANNEL === 'next';
const helloWorldCode = sourceSnippet(helloWorldSource, 'hero', 'cookbook/hello-world/server.go');
// The code window is aria-hidden, so Shiki's <pre> must not be a tab stop.
const notFocusable = { pre(node: { properties: Record<string, unknown> }) { delete node.properties.tabindex; } };
---

<section class="hh">
<section class="hh not-content">
<div class="hh-left">
<span class="hh-eyebrow"><i class="ph ph-sparkle"></i> {next ? 'Echo next — preview documentation' : `Echo ${stable.release} — release documentation`}</span>
<span class="hh-eyebrow"><Icon name="star" /> {next ? 'Echo next — preview documentation' : `Echo ${stable.release} — release documentation`}</span>
<h1>Build fast Go APIs.<br /><span class="g">Without the bloat.</span></h1>
<p class="hh-sub">
A high-performance, minimalist Go web framework — a zero-allocation
router, batteries-included middleware, and an expressive API. Ship
production services in minutes.
</p>
<div class="hh-cta">
<a class="hh-btn pri" href="/guide/quickstart/">Get Started <i class="ph ph-arrow-right"></i></a>
<a class="hh-btn sec" href="https://github.com/labstack/echo" target="_blank" rel="noopener noreferrer"><i class="ph ph-star"></i> {starsLabel} on GitHub</a>
<LinkButton class="hh-btn pri" href="/guide/quickstart/" icon="right-arrow">Get Started</LinkButton>
<LinkButton class="hh-btn sec" variant="secondary" icon="github" iconPlacement="start" href="https://github.com/labstack/echo" target="_blank" rel="noopener noreferrer">{starsLabel} on GitHub</LinkButton>
</div>
<button class="hh-install" type="button" data-copy="go get github.com/labstack/echo/v5" aria-label="Copy install command">
<span class="p">$</span> go get github.com/labstack/echo/v5 <i class="ph ph-copy cp"></i>
</button>
<div class="hh-install"><Code code="go get github.com/labstack/echo/v5" lang="bash" frame="none" wrap /></div>
</div>

<div class="hh-win" aria-hidden="true">
<div class="bar">
<i style="background:#ff5f57"></i><i style="background:#febc2e"></i><i style="background:#28c840"></i>
<span class="fn">server.go · excerpt</span>
</div>
<Code code={helloWorldCode} lang="go" style="background: transparent" transformers={[notFocusable]} />
<div class="hh-term" data-term>
<div><span class="pr">~/echo $</span> <span data-cmd></span><span class="hh-cur" data-cur></span></div>
<div data-out></div>
<div class="hh-win">
<Code code={helloWorldCode} lang="go" title="server.go · excerpt" frame="code" wrap />
<div class="hh-term" data-term aria-hidden="true">
<script is:inline>document.currentScript.parentElement.setAttribute('data-js', '');</script>
<div><span class="pr">~/echo $</span> <span data-cmd>curl localhost:1323</span><span class="hh-cur" data-cur style="display:none"></span></div>
<div data-out><div class="dim">HTTP/1.1 200 OK</div><div class="response">Hello, World!</div></div>
</div>
</div>
</section>

<script>
// --- install copy button ---
document.querySelectorAll<HTMLButtonElement>('.hh-install').forEach((btn) => {
btn.addEventListener('click', async () => {
const text = btn.dataset.copy || '';
try {
await navigator.clipboard.writeText(text);
const icon = btn.querySelector('.cp');
if (icon) {
icon.classList.remove('ph-copy');
icon.classList.add('ph-check');
setTimeout(() => {
icon.classList.remove('ph-check');
icon.classList.add('ph-copy');
}, 1400);
}
} catch {}
});
});

// --- terminal typing animation ---
const term = document.querySelector('[data-term]');
if (term) {
Expand All @@ -72,17 +46,14 @@ const notFocusable = { pre(node: { properties: Record<string, unknown> }) { dele
const curEl = term.querySelector('[data-cur]') as HTMLElement;
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

const response =
'<span class="dim">HTTP/1.1 200 OK</span>\n' +
'<span class="json">Hello, World!</span>';
const cmd = 'curl localhost:1323';
const cmd = cmdEl.textContent ?? '';

const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

async function run() {
while (true) {
cmdEl.textContent = '';
outEl.innerHTML = '';
outEl.hidden = true;
curEl.style.display = 'inline-block';
await sleep(900);
for (const ch of cmd) {
Expand All @@ -91,16 +62,16 @@ const notFocusable = { pre(node: { properties: Record<string, unknown> }) { dele
}
await sleep(450);
curEl.style.display = 'none';
outEl.innerHTML = '<pre style="margin:6px 0 0;padding:0;background:none;font:inherit">' + response + '</pre>';
outEl.hidden = false;
await sleep(3600);
}
}

if (reduce) {
cmdEl.textContent = cmd;
curEl.style.display = 'none';
outEl.innerHTML = '<pre style="margin:6px 0 0;padding:0;background:none;font:inherit">' + response + '</pre>';
} else {
term.setAttribute('data-typing', '');
run();
}
}
Expand Down
Loading
Loading