@@ -336,6 +336,78 @@ const structuredData = {
336336 </div >
337337 </section >
338338
339+ <!-- Try it with a preset -->
340+ <section class =" py-32 px-6 sm:px-8" >
341+ <div class =" max-w-4xl mx-auto text-center" >
342+ <p class =" section-reveal text-sm font-semibold tracking-widest uppercase text-purple-400 mb-4" >Try It With a Preset</p >
343+ <h2 class =" section-reveal text-3xl md:text-5xl font-bold mb-8" >Test the API your app calls.</h2 >
344+ <p class =" section-reveal text-lg md:text-xl mb-12" style =" color: var(--text-muted);" >
345+ Install Dev Proxy, download the preset for your API, and run your app as usual. It keeps calling the real API URLs.
346+ </p >
347+ <p class =" section-reveal text-left text-sm font-semibold mb-3" style =" color: var(--text-muted);" >1. Install Dev Proxy</p >
348+ <div class =" section-reveal rounded-2xl border overflow-hidden text-left" style =" background: var(--bg-secondary); border-color: var(--border-primary);" data-os-tabs >
349+ <div class =" flex border-b" role =" tablist" aria-label =" Operating system" style =" border-color: var(--border-primary);" >
350+ { [
351+ { id: ' windows' , label: ' Windows' },
352+ { id: ' macos' , label: ' macOS' },
353+ { id: ' linux' , label: ' Linux' },
354+ ].map ((tab , i ) => (
355+ <button
356+ type = " button"
357+ role = " tab"
358+ id = { ` os-tab-${tab .id } ` }
359+ aria-controls = { ` os-panel-${tab .id } ` }
360+ aria-selected = { i === 0 ? ' true' : ' false' }
361+ tabindex = { i === 0 ? 0 : - 1 }
362+ data-os = { tab .id }
363+ class = " -mb-px px-5 py-3 text-sm font-semibold border-b-2 border-transparent transition-colors hover:text-purple-400 aria-selected:border-purple-500 aria-selected:text-purple-400 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-purple-500"
364+ >{ tab .label } </button >
365+ ))}
366+ </div >
367+ { [
368+ { id: ' windows' , lines: [' winget install DevProxy.DevProxy --silent' ], note: ' After the installation finishes, open a new terminal.' },
369+ { id: ' macos' , lines: [' brew tap dotnet/dev-proxy' , ' brew install dev-proxy' ] },
370+ { id: ' linux' , lines: [' bash -c "$(curl -sL https://aka.ms/devproxy/setup.sh)"' ] },
371+ ].map ((panel , i ) => (
372+ <div role = " tabpanel" id = { ` os-panel-${panel .id } ` } aria-labelledby = { ` os-tab-${panel .id } ` } hidden = { i !== 0 } class = " p-4 sm:p-6" >
373+ <div class = " font-mono text-xs sm:text-sm space-y-1" >
374+ { panel .lines .map ((line ) => <p class = " break-words" style = " color: var(--text-secondary);" >{ line } </p >)}
375+ </div >
376+ { panel .note && <p class = " mt-3 text-xs" style = " color: var(--text-faint);" >{ panel .note } </p >}
377+ </div >
378+ ))}
379+ </div >
380+ <p class =" section-reveal mt-8 text-left text-sm font-semibold mb-3" style =" color: var(--text-muted);" >2. Download a preset and start Dev Proxy with it</p >
381+ <div class =" section-reveal rounded-2xl border overflow-hidden text-left font-mono text-xs sm:text-sm" style =" background: var(--bg-secondary); border-color: var(--border-primary);" >
382+ <div class =" p-4 sm:p-6 space-y-1" >
383+ <p class =" break-words" style =" color: var(--text-secondary);" >devproxy config get <span class =" text-purple-400" >github-rate-limiting</span ></p >
384+ <p class =" break-words" style =" color: var(--text-secondary);" >devproxy --config-file "~dataFolder/configs/<span class =" text-purple-400" >github-rate-limiting</span >/.devproxy/devproxyrc.json"</p >
385+ </div >
386+ </div >
387+ <p class =" section-reveal mt-8 text-left text-sm font-semibold mb-3" style =" color: var(--text-muted);" >Presets for popular APIs</p >
388+ <div class =" section-reveal grid grid-cols-2 md:grid-cols-4 gap-4" >
389+ { [
390+ { api: ' GitHub' , preset: ' github-rate-limiting' },
391+ { api: ' OpenAI' , preset: ' openai-throttling' },
392+ { api: ' Anthropic' , preset: ' anthropic-throttling' },
393+ { api: ' Microsoft Graph' , preset: ' microsoft-graph-rate-limiting' },
394+ ].map ((item ) => (
395+ <a
396+ href = { ` ${import .meta .env .BASE_URL }samples/${item .preset }/ ` }
397+ class = " rounded-xl border p-4 text-left transition-all duration-300 hover:border-purple-500/50"
398+ style = " background: var(--bg-secondary); border-color: var(--border-primary);"
399+ >
400+ <p class = " text-sm font-semibold mb-1" >{ item .api } </p >
401+ <p class = " text-xs font-mono break-words" style = " color: var(--text-faint);" >{ item .preset } </p >
402+ </a >
403+ ))}
404+ </div >
405+ <p class =" section-reveal mt-8 text-sm" style =" color: var(--text-faint);" >
406+ The first time you start Dev Proxy, you trust its certificate. <a href =" https://aka.ms/devproxy/start" target =" _blank" rel =" noopener" class =" text-purple-400 hover:text-purple-300" >Step-by-step setup</a > · <a href ={ ` ${import .meta .env .BASE_URL }samples/ ` } class =" text-purple-400 hover:text-purple-300" >More presets</a >
407+ </p >
408+ </div >
409+ </section >
410+
339411 <!-- Getting started video -->
340412 <section class =" py-32 px-6 sm:px-8" >
341413 <div class =" max-w-4xl mx-auto text-center" >
@@ -543,4 +615,35 @@ const structuredData = {
543615 );
544616
545617 document.querySelectorAll('.section-reveal').forEach((el) => observer.observe(el));
618+
619+ document.querySelectorAll<HTMLElement>('[data-os-tabs]').forEach((root) => {
620+ const tabs = Array.from(root.querySelectorAll<HTMLButtonElement>('[role="tab"]'));
621+ const select = (tab: HTMLButtonElement, focus = false, persist = false) => {
622+ tabs.forEach((t) => {
623+ const selected = t === tab;
624+ t.setAttribute('aria-selected', String(selected));
625+ t.tabIndex = selected ? 0 : -1;
626+ root.querySelector<HTMLElement>(`#${t.getAttribute('aria-controls')}`)!.hidden = !selected;
627+ });
628+ if (focus) tab.focus();
629+ if (persist) {
630+ const url = new URL(window.location.href);
631+ url.searchParams.set('os', tab.dataset.os!);
632+ history.replaceState(null, '', url);
633+ }
634+ };
635+ tabs.forEach((tab, i) => {
636+ tab.addEventListener('click', () => select(tab, false, true));
637+ tab.addEventListener('keydown', (e) => {
638+ const next = e.key === 'ArrowRight' ? 1 : e.key === 'ArrowLeft' ? -1 : 0;
639+ if (next) select(tabs[(i + next + tabs.length) % tabs.length], true, true);
640+ });
641+ });
642+ // A shared ?os= link wins over the visitor's own OS.
643+ const fromUrl = new URLSearchParams(window.location.search).get('os');
644+ const platform = (navigator.userAgent || '').toLowerCase();
645+ const detected = platform.includes('mac') ? 'macos' : platform.includes('linux') && !platform.includes('android') ? 'linux' : 'windows';
646+ const initial = tabs.find((t) => t.dataset.os === fromUrl) ?? tabs.find((t) => t.dataset.os === detected);
647+ if (initial) select(initial);
648+ });
546649</script >
0 commit comments