@@ -5,7 +5,7 @@ import { Check, Copy, Download, X } from "lucide-react";
55
66type Method = "binary" | "docker" | "cargo" ;
77type OS = "linux-x86_64" | "linux-arm64" | "macos-arm64" | "windows" ;
8- type Profile = "full" | "standard" | "minimal" | "tiny" ;
8+ type Profile = "full" | "headless" | " standard" | "minimal" | "tiny" ;
99type Libc = "gnu" | "musl" ;
1010
1111const osLabels : Record < OS , string > = {
@@ -20,6 +20,14 @@ const libcLabels: Record<Libc, string> = {
2020 musl : "musl" ,
2121} ;
2222
23+ const profileLabels : Record < Profile , string > = {
24+ full : "Full" ,
25+ headless : "Headless" ,
26+ standard : "Standard" ,
27+ minimal : "Minimal" ,
28+ tiny : "Tiny" ,
29+ } ;
30+
2331function getTarget ( os : OS , libc : Libc ) : string {
2432 switch ( os ) {
2533 case "linux-x86_64" :
@@ -35,38 +43,42 @@ function getTarget(os: OS, libc: Libc): string {
3543
3644const profileSummaries : Record < Profile , string > = {
3745 full : "Everything" ,
46+ headless : "Full features, no embedded assets (serve frontend separately)" ,
3847 standard : "Production deployment" ,
3948 minimal : "Development and embedded use" ,
4049 tiny : "Stateless proxy" ,
4150} ;
4251
52+ const allProfiles : Profile [ ] = [ "full" , "headless" , "standard" , "minimal" , "tiny" ] ;
53+ const embeddedAssetProfiles : Profile [ ] = [ "minimal" , "standard" , "full" ] ;
54+
4355const featureMatrix : { name : string ; profiles : Profile [ ] } [ ] = [
44- { name : "OpenAI" , profiles : [ "tiny" , "minimal" , "standard" , "full" ] } ,
45- { name : "Anthropic" , profiles : [ "minimal" , "standard" , "full" ] } ,
46- { name : "AWS Bedrock" , profiles : [ "minimal" , "standard" , "full" ] } ,
47- { name : "Google Vertex AI" , profiles : [ "minimal" , "standard" , "full" ] } ,
48- { name : "Azure OpenAI" , profiles : [ "minimal" , "standard" , "full" ] } ,
49- { name : "SQLite" , profiles : [ "minimal" , "standard" , "full" ] } ,
50- { name : "Embedded UI" , profiles : [ "minimal" , "standard" , "full" ] } ,
51- { name : "Model catalog" , profiles : [ "minimal" , "standard" , "full" ] } ,
52- { name : "Setup wizard" , profiles : [ "minimal" , "standard" , "full" ] } ,
53- { name : "PostgreSQL" , profiles : [ "standard" , "full" ] } ,
54- { name : "Redis caching" , profiles : [ "standard" , "full" ] } ,
55- { name : "SSO (OIDC / OAuth)" , profiles : [ "standard" , "full" ] } ,
56- { name : "CEL RBAC" , profiles : [ "standard" , "full" ] } ,
57- { name : "S3 storage" , profiles : [ "standard" , "full" ] } ,
58- { name : "Secrets managers" , profiles : [ "standard" , "full" ] } ,
59- { name : "OTLP & Prometheus" , profiles : [ "standard" , "full" ] } ,
60- { name : "OpenAPI docs" , profiles : [ "standard" , "full" ] } ,
61- { name : "Embedded docs" , profiles : [ "standard" , "full" ] } ,
62- { name : "Doc extraction" , profiles : [ "standard" , "full" ] } ,
63- { name : "Cost forecasting" , profiles : [ "standard" , "full" ] } ,
64- { name : "CSV export" , profiles : [ "standard" , "full" ] } ,
65- { name : "Response validation" , profiles : [ "standard" , "full" ] } ,
66- { name : "JSON schema" , profiles : [ "standard" , "full" ] } ,
67- { name : "SAML SSO" , profiles : [ "full" ] } ,
68- { name : "Kreuzberg OCR" , profiles : [ "full" ] } ,
69- { name : "ClamAV scanning" , profiles : [ "full" ] } ,
56+ { name : "OpenAI" , profiles : allProfiles } ,
57+ { name : "Anthropic" , profiles : [ "minimal" , "standard" , "headless" , " full"] } ,
58+ { name : "AWS Bedrock" , profiles : [ "minimal" , "standard" , "headless" , " full"] } ,
59+ { name : "Google Vertex AI" , profiles : [ "minimal" , "standard" , "headless" , " full"] } ,
60+ { name : "Azure OpenAI" , profiles : [ "minimal" , "standard" , "headless" , " full"] } ,
61+ { name : "SQLite" , profiles : [ "minimal" , "standard" , "headless" , " full"] } ,
62+ { name : "Embedded UI" , profiles : embeddedAssetProfiles } ,
63+ { name : "Model catalog" , profiles : embeddedAssetProfiles } ,
64+ { name : "Setup wizard" , profiles : embeddedAssetProfiles } ,
65+ { name : "PostgreSQL" , profiles : [ "standard" , "headless" , " full"] } ,
66+ { name : "Redis caching" , profiles : [ "standard" , "headless" , " full"] } ,
67+ { name : "SSO (OIDC / OAuth)" , profiles : [ "standard" , "headless" , " full"] } ,
68+ { name : "CEL RBAC" , profiles : [ "standard" , "headless" , " full"] } ,
69+ { name : "S3 storage" , profiles : [ "standard" , "headless" , " full"] } ,
70+ { name : "Secrets managers" , profiles : [ "standard" , "headless" , " full"] } ,
71+ { name : "OTLP & Prometheus" , profiles : [ "standard" , "headless" , " full"] } ,
72+ { name : "OpenAPI docs" , profiles : [ "standard" , "headless" , " full"] } ,
73+ { name : "Embedded docs" , profiles : embeddedAssetProfiles } ,
74+ { name : "Doc extraction" , profiles : [ "standard" , "headless" , " full"] } ,
75+ { name : "Cost forecasting" , profiles : [ "standard" , "headless" , " full"] } ,
76+ { name : "CSV export" , profiles : [ "standard" , "headless" , " full"] } ,
77+ { name : "Response validation" , profiles : [ "standard" , "headless" , " full"] } ,
78+ { name : "JSON schema" , profiles : [ "standard" , "headless" , " full"] } ,
79+ { name : "SAML SSO" , profiles : [ "headless" , " full"] } ,
80+ { name : "Kreuzberg OCR" , profiles : [ "headless" , " full"] } ,
81+ { name : "ClamAV scanning" , profiles : [ "headless" , " full"] } ,
7082] ;
7183
7284function getInstallCommand ( method : Method , os : OS , profile : Profile , libc : Libc ) : string {
@@ -135,7 +147,7 @@ function ToggleGroup<T extends string>({
135147 key = { opt }
136148 onClick = { ( ) => onChange ( opt ) }
137149 disabled = { isDisabled }
138- className = { `rounded-md px-3 py-1.5 text-sm font-medium transition-colors ${
150+ className = { `rounded-md px-2.5 py-1 text-xs font-medium transition-colors sm:px-3 sm:py-1.5 sm:text-sm ${
139151 isDisabled
140152 ? "cursor-not-allowed bg-fd-muted text-fd-muted-foreground/40"
141153 : value === opt
@@ -152,9 +164,10 @@ function ToggleGroup<T extends string>({
152164}
153165
154166function getDisabledProfiles ( os : OS , libc : Libc ) : Set < Profile > | undefined {
155- if ( os === "windows" ) return new Set ( [ "full" , "standard" ] ) ;
156- if ( os === "linux-arm64" ) return new Set ( [ "full" ] ) ;
157- if ( os . startsWith ( "linux-" ) && libc === "musl" ) return new Set ( [ "full" ] ) ;
167+ // headless and full only built for linux-x86_64-gnu and macos-arm64
168+ if ( os === "windows" ) return new Set ( [ "full" , "headless" ] ) ;
169+ if ( os === "linux-arm64" ) return new Set ( [ "full" , "headless" ] ) ;
170+ if ( os . startsWith ( "linux-" ) && libc === "musl" ) return new Set ( [ "full" , "headless" ] ) ;
158171 return undefined ;
159172}
160173
@@ -184,7 +197,7 @@ export function QuickStartSelector() {
184197
185198 const handleLibcChange = ( newLibc : Libc ) => {
186199 setLibc ( newLibc ) ;
187- if ( newLibc === "musl" && profile === "full" ) {
200+ if ( newLibc === "musl" && ( profile === "full" || profile === "headless" ) ) {
188201 setProfile ( "standard" ) ;
189202 }
190203 } ;
@@ -193,27 +206,18 @@ export function QuickStartSelector() {
193206 const downloadUrl = method === "binary" ? getDownloadUrl ( os , profile , libc ) : null ;
194207
195208 const handleCopy = async ( ) => {
196- if ( navigator . clipboard ) {
197- await navigator . clipboard . writeText ( command ) ;
198- } else {
199- const textarea = document . createElement ( "textarea" ) ;
200- textarea . value = command ;
201- textarea . style . position = "fixed" ;
202- textarea . style . opacity = "0" ;
203- document . body . appendChild ( textarea ) ;
204- textarea . select ( ) ;
205- document . execCommand ( "copy" ) ;
206- document . body . removeChild ( textarea ) ;
207- }
209+ await navigator . clipboard . writeText ( command ) ;
208210 setCopied ( true ) ;
209211 setTimeout ( ( ) => setCopied ( false ) , 2000 ) ;
210212 } ;
211213
212214 return (
213215 < div className = "not-prose overflow-hidden rounded-lg border border-fd-border bg-fd-card" >
214216 < div className = "space-y-3 border-b border-fd-border bg-fd-muted/50 p-4" >
215- < div className = "flex flex-wrap items-center gap-3" >
216- < span className = "w-16 shrink-0 text-sm font-medium text-fd-muted-foreground" > Method</ span >
217+ < div className = "flex flex-col gap-1.5 sm:flex-row sm:items-center sm:gap-3" >
218+ < span className = "text-sm font-medium text-fd-muted-foreground sm:w-16 sm:shrink-0" >
219+ Method
220+ </ span >
217221 < ToggleGroup
218222 options = { [ "binary" , "docker" , "cargo" ] as Method [ ] }
219223 value = { method }
@@ -223,8 +227,10 @@ export function QuickStartSelector() {
223227 </ div >
224228 { method === "binary" && (
225229 < >
226- < div className = "flex flex-wrap items-center gap-3" >
227- < span className = "w-16 shrink-0 text-sm font-medium text-fd-muted-foreground" > OS</ span >
230+ < div className = "flex flex-col gap-1.5 sm:flex-row sm:items-center sm:gap-3" >
231+ < span className = "text-sm font-medium text-fd-muted-foreground sm:w-16 sm:shrink-0" >
232+ OS
233+ </ span >
228234 < ToggleGroup
229235 options = { [ "linux-x86_64" , "linux-arm64" , "macos-arm64" , "windows" ] as OS [ ] }
230236 value = { os }
@@ -233,8 +239,8 @@ export function QuickStartSelector() {
233239 />
234240 </ div >
235241 { isLinux && (
236- < div className = "flex flex-wrap items-center gap-3" >
237- < span className = "w-16 shrink-0 text-sm font-medium text-fd-muted-foreground" >
242+ < div className = "flex flex-col gap-1.5 sm:flex-row sm: items-center sm: gap-3" >
243+ < span className = "text-sm font-medium text-fd-muted-foreground sm:w-16 sm:shrink-0 " >
238244 Libc
239245 </ span >
240246 < ToggleGroup
@@ -246,14 +252,15 @@ export function QuickStartSelector() {
246252 />
247253 </ div >
248254 ) }
249- < div className = "flex flex-wrap items-center gap-3" >
250- < span className = "w-16 shrink-0 text-sm font-medium text-fd-muted-foreground" >
255+ < div className = "flex flex-col gap-1.5 sm:flex-row sm: items-center sm: gap-3" >
256+ < span className = "text-sm font-medium text-fd-muted-foreground sm:w-16 sm:shrink-0 " >
251257 Features
252258 </ span >
253259 < ToggleGroup
254- options = { [ "full" , "standard" , "minimal" , "tiny" ] as Profile [ ] }
260+ options = { allProfiles }
255261 value = { profile }
256262 onChange = { setProfile }
263+ labels = { profileLabels }
257264 disabled = { disabledProfiles }
258265 />
259266 </ div >
0 commit comments