From 8533aefbf9610c0f0afd70e6a4751b48b0e1335d Mon Sep 17 00:00:00 2001 From: Zhiben Chen Date: Tue, 8 Sep 2026 21:07:32 -0400 Subject: [PATCH] Add Markdown page actions and consistent documentation controls --- astro.config.mjs | 2 +- src/components/PageActions.astro | 50 ++++++++++++++++ src/components/PageTitle.astro | 10 +++- src/pages/index.astro | 4 +- src/pages/markdown/[...slug].txt.ts | 13 ++++ src/styles/controls.css | 93 +++++++++++++++++++++++++++++ src/styles/site.css | 8 +-- 7 files changed, 169 insertions(+), 11 deletions(-) create mode 100644 src/components/PageActions.astro create mode 100644 src/pages/markdown/[...slug].txt.ts create mode 100644 src/styles/controls.css diff --git a/astro.config.mjs b/astro.config.mjs index 78bde6b..b391880 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -10,7 +10,7 @@ export default defineConfig({ title: 'FluxServe', description: 'A serving engine for diffusion language models.', favicon: '/fluxserve-icon.png', - customCss: ['./src/styles/site.css'], + customCss: ['./src/styles/site.css', './src/styles/controls.css'], credits: false, disable404Route: true, components: { diff --git a/src/components/PageActions.astro b/src/components/PageActions.astro new file mode 100644 index 0000000..2b12a23 --- /dev/null +++ b/src/components/PageActions.astro @@ -0,0 +1,50 @@ +--- +import { Icon } from '@astrojs/starlight/components'; +interface Props { id: string; } +const { id } = Astro.props; +const markdownURL = '/markdown/' + id.split('/').map(encodeURIComponent).join('/') + '.txt'; +--- +
+
+ +
+ + +
+
+ +
+ + diff --git a/src/components/PageTitle.astro b/src/components/PageTitle.astro index 48f6933..a535dd7 100644 --- a/src/components/PageTitle.astro +++ b/src/components/PageTitle.astro @@ -1,4 +1,12 @@ --- import DefaultPageTitle from '@astrojs/starlight/components/PageTitle.astro'; +import PageActions from './PageActions.astro'; +const { hasSidebar, entry } = Astro.locals.starlightRoute; --- -{Astro.url.pathname !== '/' && } +{Astro.url.pathname !== '/' && ( + hasSidebar ?
: +)} + diff --git a/src/pages/index.astro b/src/pages/index.astro index 929a4d5..c097de2 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -2,7 +2,7 @@ import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro'; import { Code } from '@astrojs/starlight/components'; import BenchmarkChart from '../components/BenchmarkChart.astro'; -const install = 'git clone https://github.com/FLX-OSS/FluxServe\ncd FluxServe\nexport PIP_BREAK_SYSTEM_PACKAGES=1\npip install -e flux-kernel/python/ --no-build-isolation\npip install -e flux-scheduler\npip install -e .'; +const install = 'docker pull flxoss/fluxserve:v0.1-cu130-fa4'; ---
@@ -15,7 +15,7 @@ const install = 'git clone https://github.com/FLX-OSS/FluxServe\ncd FluxServe\ne Get started View on GitHub
-

Install from source inside the FluxServe CUDA container ↗

+ diff --git a/src/pages/markdown/[...slug].txt.ts b/src/pages/markdown/[...slug].txt.ts new file mode 100644 index 0000000..8e4cbcd --- /dev/null +++ b/src/pages/markdown/[...slug].txt.ts @@ -0,0 +1,13 @@ +import { getCollection, type CollectionEntry } from 'astro:content'; +import type { APIRoute } from 'astro'; + +export async function getStaticPaths() { + return (await getCollection('docs')).map(page => ({ params: { slug: page.id }, props: { page } })); +} + +export const GET: APIRoute = ({ props }) => { + const page = props.page as CollectionEntry<'docs'>; + return new Response(`# ${page.data.title}\n\n${page.body ?? ''}`, { + headers: { 'Content-Type': 'text/plain; charset=utf-8' }, + }); +}; diff --git a/src/styles/controls.css b/src/styles/controls.css new file mode 100644 index 0000000..d8fb5bf --- /dev/null +++ b/src/styles/controls.css @@ -0,0 +1,93 @@ +/* Shared neutral controls, including Starlight's search and contents controls. */ +:root { + --control-height: 40px; + --control-radius: 6px; + --control-icon: 20px; + --control-hover: var(--sl-color-gray-6); +} +.header-tools site-search > button, +mobile-starlight-toc .toggle, +.page-actions .action-buttons, +.header-tools .theme-toggle, +.header-tools .github-link { + box-sizing: border-box; + height: var(--control-height); + min-height: var(--control-height); + border: 1px solid var(--line); + border-radius: var(--control-radius); + background: transparent; + color: var(--sl-color-gray-2); + box-shadow: none; + font-size: .875rem; +} +.header-tools site-search > button, +mobile-starlight-toc .toggle { padding: 0 12px; gap: 8px; } +.header-tools .theme-toggle, +.header-tools .github-link { width: var(--control-height); display: grid; place-items: center; padding: 0; } +.page-actions .copy-page, +.page-actions summary { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + height: calc(var(--control-height) - 2px); + min-height: 0; + padding: 0 12px; + border: 0; + background: transparent; + color: var(--sl-color-gray-2); + font: inherit; + cursor: pointer; +} +.page-actions .copy-page { border-radius: calc(var(--control-radius) - 1px) 0 0 calc(var(--control-radius) - 1px); } +.page-actions summary { + width: calc(var(--control-height) - 1px); + padding: 0; + border-left: 1px solid var(--line); + border-radius: 0 calc(var(--control-radius) - 1px) calc(var(--control-radius) - 1px) 0; + list-style: none; +} +.header-tools site-search > button:hover, +mobile-starlight-toc details .toggle:hover, +mobile-starlight-toc details[open] .toggle, +.page-actions .copy-page:hover, +.page-actions summary:hover, +.page-actions details[open] summary, +.header-tools .theme-toggle:hover, +.header-tools .github-link:hover { + color: var(--sl-color-white); + background: var(--control-hover); + border-color: var(--line); + box-shadow: none; +} +.header-tools :is(button, a):focus-visible, +.page-actions :is(button, summary, a):focus-visible, +mobile-starlight-toc summary:focus-visible, +.sidebar-content :is(summary, a):focus-visible { + outline: 2px solid var(--brand); + outline-offset: 2px; +} +.header-tools :is(button, a) svg, +.page-actions :is(button, summary) svg, +mobile-starlight-toc .caret, +.sidebar-content summary .caret { + width: var(--control-icon); + height: var(--control-icon); + font-size: var(--control-icon); + flex-shrink: 0; +} +/* Use the same right chevron, rotated consistently to indicate open state. */ +.page-actions summary svg { transform: rotate(90deg); } +.page-actions details[open] summary svg { transform: rotate(-90deg); } +.sidebar-content summary { border-radius: var(--control-radius); } +.sidebar-content summary:hover, +.sidebar-content a:not([aria-current='page']):hover, +.page-actions .page-menu a:hover { + background: var(--control-hover); + color: var(--sl-color-white); +} +.page-actions .page-menu a { border-radius: calc(var(--control-radius) - 1px); } +.header-tools .theme-toggle { flex-shrink: 0; cursor: pointer; } +.theme-toggle span:not([hidden]) { display: flex; } +@media(max-width: 49.99rem) { .header-tools .github-link { display: none; } } diff --git a/src/styles/site.css b/src/styles/site.css index 65e32cc..5f8f4d0 100644 --- a/src/styles/site.css +++ b/src/styles/site.css @@ -56,8 +56,7 @@ a:focus-visible, button:focus-visible, select:focus-visible { outline: 2px solid .primary-nav a:hover, .primary-nav a[aria-current] { color: var(--brand); } .header-tools { display: flex; align-items: center; gap: 1rem; margin-left: auto; } .header-tools site-search { min-width: 0; } -.header-tools site-search > button { width: 11rem; border-color: var(--line); background: var(--surface); border-radius: 7px; } -.github-link { color: var(--sl-color-white); display: flex; } +.header-tools site-search > button { width: 11rem; } html:not([data-has-sidebar]) { --sl-content-width: 72rem; } html:not([data-has-sidebar]) .content-panel + .content-panel { border-top: 0; padding-top: 0; } html:has(.landing) .content-panel:first-child { display: none; } @@ -125,8 +124,3 @@ html:has(.landing) main { padding-top: 0; } @media(prefers-reduced-motion: reduce) { *,*::before,*::after { scroll-behavior: auto !important; animation: none !important; transition: none !important; } } .sidebar-content summary .large { text-transform: capitalize; } - -.theme-toggle { display: grid; place-items: center; flex-shrink: 0; width: 2.5rem; height: 2.5rem; padding: 0; border: 0; border-radius: .5rem; background: transparent; color: var(--sl-color-gray-2); cursor: pointer; } -.theme-toggle:hover { background: var(--surface); color: var(--sl-color-white); } -.theme-toggle:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; } -.theme-toggle span:not([hidden]) { display: flex; font-size: 1.125rem; }