diff --git a/src/components/dark-mode-toggle.tsx b/src/components/dark-mode-toggle.tsx index 571ac0b..5b83a54 100644 --- a/src/components/dark-mode-toggle.tsx +++ b/src/components/dark-mode-toggle.tsx @@ -1,9 +1,14 @@ import { SunIcon, MoonIcon } from '@heroicons/react/24/outline'; -import { useDarkMode } from '../utils/hooks'; +import { useTheme } from '../utils/hooks'; import classNames from 'classnames'; export function DarkModeToggle() { - const { isDark, toggleDarkMode } = useDarkMode(); + const { isDark, currentTheme, toggleMode } = useTheme(); + + const toggleDarkMode = () => { + // Toggle between light and dark variants of current theme family + toggleMode(); + }; return ( + + {/* Theme Selector */} + { + const newThemeId = `${baseThemeId}-${currentTheme.mode}`; + handleThemeChange(newThemeId); + }}> +
+ + + Theme selector + + + + + {Array.from(themesByBase.entries()).map(([baseThemeId, variants]) => { + const lightTheme = variants.light; + const darkTheme = variants.dark; + const displayTheme = currentTheme.mode === 'light' ? lightTheme : darkTheme; + + if (!displayTheme) return null; + + return ( + + classNames( + 'relative cursor-pointer select-none py-3 pl-10 pr-4', + active + ? 'bg-sky-100 dark:bg-sky-900 text-sky-900 dark:text-sky-100' + : 'text-gray-900 dark:text-gray-100' + ) + } + value={baseThemeId} + > + {({ selected }) => ( + <> +
+
+ + {displayTheme.name.replace(' Light', '').replace(' Dark', '')} + +
+ {lightTheme && ( +
+ +
+
+
+
+
+
+ )} + {darkTheme && ( +
+ +
+
+
+
+
+
+ )} +
+
+ + {displayTheme.description.replace(' (Light mode)', '').replace(' (Dark mode)', '')} + +
+ Font: {displayTheme.typography.fontFamilyPrimary.split(',')[0].replace(/"/g, '')} + + Radius: {displayTheme.spacing.radiusMd} +
+
+ {selected ? ( + + + ) : null} + + )} + + ); + })} + + +
+ +
+ ); +} \ No newline at end of file diff --git a/src/mdx/api-playground.tsx b/src/mdx/api-playground.tsx index d5751a1..4e8b3b9 100644 --- a/src/mdx/api-playground.tsx +++ b/src/mdx/api-playground.tsx @@ -5,7 +5,7 @@ import { PencilIcon, TrashIcon, XIcon } from 'lucide-react' import { useCallback, useEffect, useRef, useState } from 'preact/hooks' import { Highlight, themes } from 'prism-react-renderer' import Dropdown from '../components/dropdown' -import { useDarkMode } from '../utils/hooks' +import { useTheme } from '../utils/hooks' import { Fence } from './fence' import { Tag } from './tag' @@ -154,8 +154,8 @@ export const HeadersTab = ({ requestConfig, setRequestConfig }: HeadersTabProps) return (
- Key - Value + Key + Value
{headersList.map((hdr, idx) => (
@@ -166,37 +166,37 @@ export const HeadersTab = ({ requestConfig, setRequestConfig }: HeadersTabProps) value={hdr.key} onChange={e => updateHeader(idx, 'key', (e.target as HTMLInputElement).value)} placeholder="Header name" - className="w-32 rounded-lg bg-zinc-800 border border-zinc-600 px-2 py-1 text-sm text-white" + className="w-32 rounded-lg api-playground-input px-2 py-1 text-sm" /> updateHeader(idx, 'value', (e.target as HTMLInputElement).value)} placeholder="Header value" - className="flex-1 rounded-lg bg-zinc-800 border border-zinc-600 px-2 py-1 text-sm text-white" + className="flex-1 rounded-lg api-playground-input px-2 py-1 text-sm" /> - - ) : ( <> - {hdr.key} - {hdr.value} - - )}
))} -
@@ -274,37 +274,37 @@ export const ParamsTab = ({ queryParams, setQueryParams }: ParamsTabProps) => { return (
- Name - Value + Name + Value
{paramsList.map((p, i) => (
{p.isEditing ? ( <> - updateParam(i, 'name', (e.target as HTMLInputElement).value)} placeholder="Param name" className="w-32 rounded-lg bg-zinc-800 border border-zinc-600 px-2 py-1 text-sm text-white" /> - updateParam(i, 'value', (e.target as HTMLInputElement).value)} placeholder="Param value" className="flex-1 rounded-lg bg-zinc-800 border border-zinc-600 px-2 py-1 text-sm text-white" /> - - ) : ( <> - {p.name} - {p.value} - - )}
))} -
@@ -327,7 +327,7 @@ export function APIPlayground({ const [isLoading, setIsLoading] = useState(false) const [response, setResponse] = useState(null) const [error, setError] = useState(null) - const { isDark } = useDarkMode(); + const { isDark } = useTheme(); const [selectedServer, setSelectedServer] = useState(servers?.[0] || null) // Request configuration state @@ -428,12 +428,12 @@ export function APIPlayground({ ] return ( -
+
{/* Header */} -
+
{method.toUpperCase()} - {title || url} + {title || url}
{description && ( -
-

{description}

+
+

{description}

)}
- + ({ label: server.description || server.url, onClick: () => setSelectedServer(server) }))} @@ -471,18 +471,18 @@ export function APIPlayground({
{/* Request Configuration */} -
+
- + {tabs.map((tab) => ( classNames( - 'px-4 py-3 text-sm font-medium transition border-b-2', + 'px-4 py-3 text-sm font-medium transition border-b-2 api-playground-tab', selected - ? 'border-sky-500 text-sky-400' - : 'border-transparent text-zinc-400 hover:text-zinc-300' + ? 'active' + : '' ) } > @@ -510,7 +510,7 @@ export function APIPlayground({ {['POST', 'PUT', 'PATCH'].includes(method.toUpperCase()) ? (
- + setRequestConfig(prev => ({ ...prev, body: (e.target as HTMLTextAreaElement).value }))} placeholder="Enter JSON body..." rows={8} - className={`w-full rounded-lg bg-zinc-800 border border-zinc-600 px-3 py-2 text-sm text-white placeholder-zinc-400 focus:border-sky-500 focus:outline-none font-mono ${className}`} + className={`w-full rounded-lg api-playground-input px-3 py-2 text-sm font-mono ${className}`} style={style} /> )}
) : ( -

Request body not applicable for {method.toUpperCase()} requests.

+

Request body not applicable for {method.toUpperCase()} requests.

)}
{/* Auth Tab */}
- + - + setAuth(prev => ({ ...prev, token: (e.target as HTMLInputElement).value }))} placeholder="Enter bearer token..." - className="w-full rounded-lg bg-zinc-800 border border-zinc-600 px-3 py-2 text-sm text-white placeholder-zinc-400 focus:border-sky-500 focus:outline-none" + className="w-full rounded-lg api-playground-input px-3 py-2 text-sm" />
)} {auth.type === 'apiKey' && (
- + setAuth(prev => ({ ...prev, apiKey: (e.target as HTMLInputElement).value }))} placeholder="Enter API key..." - className="w-full rounded-lg bg-zinc-800 border border-zinc-600 px-3 py-2 text-sm text-white placeholder-zinc-400 focus:border-sky-500 focus:outline-none" + className="w-full rounded-lg api-playground-input px-3 py-2 text-sm" />
)} @@ -577,23 +577,23 @@ export function APIPlayground({ {auth.type === 'basic' && (
- + setAuth(prev => ({ ...prev, username: (e.target as HTMLInputElement).value }))} placeholder="Enter username..." - className="w-full rounded-lg bg-zinc-800 border border-zinc-600 px-3 py-2 text-sm text-white placeholder-zinc-400 focus:border-sky-500 focus:outline-none" + className="w-full rounded-lg api-playground-input px-3 py-2 text-sm" />
- + setAuth(prev => ({ ...prev, password: (e.target as HTMLInputElement).value }))} placeholder="Enter password..." - className="w-full rounded-lg bg-zinc-800 border border-zinc-600 px-3 py-2 text-sm text-white placeholder-zinc-400 focus:border-sky-500 focus:outline-none" + className="w-full rounded-lg api-playground-input px-3 py-2 text-sm" />
@@ -605,8 +605,8 @@ export function APIPlayground({ {/* Response */}
-
-

Response

+
+

Response

@@ -627,18 +627,18 @@ export function APIPlayground({ = 200 && response.status < 300 - ? 'bg-sky-500/10 text-sky-400 ring-sky-500/20' + ? 'bg-success text-success' : response.status >= 400 - ? 'bg-rose-500/10 text-rose-400 ring-rose-500/20' - : 'bg-yellow-500/10 text-yellow-400 ring-yellow-500/20' + ? 'bg-error text-error' + : 'bg-warning text-warning' )}> {response.status} {response.statusText} - {response.duration}ms + {response.duration}ms
-

Response Body

+

Response Body

{typeof response.data === 'string' ? response.data @@ -648,12 +648,12 @@ export function APIPlayground({
-

Response Headers

+

Response Headers

{Object.entries(response.headers).map(([key, value]) => (
- {key}: - {value} + {key}: + {value}
))}
@@ -661,7 +661,7 @@ export function APIPlayground({
) : (
-
+
Click "Send Request" to see the response
diff --git a/src/mdx/open-api.tsx b/src/mdx/open-api.tsx index 9711a4b..efdd27c 100644 --- a/src/mdx/open-api.tsx +++ b/src/mdx/open-api.tsx @@ -169,7 +169,7 @@ export function OpenAPI({ openAPIJson, method: selectedMethod, path: selectedPat } return ( -
+
{ showPlayground &&

API Playground