|
| 1 | +"use client"; |
| 2 | + |
| 3 | +import React, { useState, useCallback, useEffect } from 'react'; |
1 | 4 | import SwaggerUI from 'swagger-ui-react'; |
2 | 5 | import 'swagger-ui-react/swagger-ui.css'; |
3 | 6 |
|
4 | | -export default function Home() { |
| 7 | +interface ApiUrls { |
| 8 | + [key: string]: string; |
| 9 | +} |
| 10 | + |
| 11 | +export default function Home(): React.ReactElement { |
| 12 | + const [version, setVersion] = useState<string>('4.0'); |
| 13 | + const [isDarkMode, setIsDarkMode] = useState<boolean>(false); |
| 14 | + |
| 15 | + // Initialize dark mode based on system preference |
| 16 | + useEffect(() => { |
| 17 | + const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; |
| 18 | + setIsDarkMode(prefersDark); |
| 19 | + |
| 20 | + // Apply dark mode to the document |
| 21 | + if (prefersDark) { |
| 22 | + document.documentElement.classList.add('dark'); |
| 23 | + } |
| 24 | + }, []); |
| 25 | + |
| 26 | + const handleVersionChange = useCallback((event: React.ChangeEvent<HTMLSelectElement>) => { |
| 27 | + setVersion(event.target.value); |
| 28 | + }, []); |
| 29 | + |
| 30 | + const handleDarkModeToggle = useCallback(() => { |
| 31 | + setIsDarkMode(prev => { |
| 32 | + const newMode = !prev; |
| 33 | + if (newMode) { |
| 34 | + document.documentElement.classList.add('dark'); |
| 35 | + } else { |
| 36 | + document.documentElement.classList.remove('dark'); |
| 37 | + } |
| 38 | + return newMode; |
| 39 | + }); |
| 40 | + }, []); |
| 41 | + |
| 42 | + const apiUrls: ApiUrls = { |
| 43 | + '4.0': 'https://raw.githubusercontent.com/thorsten/phpMyFAQ/4.0/docs/openapi.json', |
| 44 | + '4.1': 'https://raw.githubusercontent.com/thorsten/phpMyFAQ/main/docs/openapi.json', |
| 45 | + }; |
| 46 | + |
5 | 47 | return ( |
6 | | - <SwaggerUI url="https://raw.githubusercontent.com/thorsten/phpMyFAQ/4.0/docs/openapi.json" /> |
| 48 | + <div className={`min-h-screen transition-colors duration-300 ${ |
| 49 | + isDarkMode |
| 50 | + ? 'bg-gray-900' |
| 51 | + : 'bg-gray-50' |
| 52 | + }`}> |
| 53 | + <div className="swagger-ui mx-auto px-4 py-8"> |
| 54 | + {/* Main Swagger UI Container with integrated controls */} |
| 55 | + <div className={`${ |
| 56 | + isDarkMode ? 'bg-gray-800 border-gray-700' : 'bg-white border-gray-200' |
| 57 | + } rounded-lg border shadow-lg overflow-hidden wrapper`}> |
| 58 | + |
| 59 | + {/* Controls Header inside Swagger container */} |
| 60 | + <div className={`${ |
| 61 | + isDarkMode ? 'bg-gray-700 border-gray-600' : 'bg-gray-50 border-gray-200' |
| 62 | + } mx-4 mt-4 mb-2 px-6 py-4 border rounded-lg flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4`}> |
| 63 | + |
| 64 | + {/* Version Selector */} |
| 65 | + <div className="flex items-center space-x-3"> |
| 66 | + <label htmlFor="api-version" className={`font-medium ${ |
| 67 | + isDarkMode ? 'text-gray-200' : 'text-gray-700' |
| 68 | + }`}> |
| 69 | + API Version: |
| 70 | + </label> |
| 71 | + <select |
| 72 | + id="api-version" |
| 73 | + value={version} |
| 74 | + onChange={handleVersionChange} |
| 75 | + className={`${ |
| 76 | + isDarkMode |
| 77 | + ? 'bg-gray-600 border-gray-500 text-white focus:border-blue-400' |
| 78 | + : 'bg-white border-gray-300 text-gray-900 focus:border-blue-500' |
| 79 | + } px-3 py-1.5 rounded-md border focus:outline-none focus:ring-2 focus:ring-blue-500/20 transition-colors text-sm`} |
| 80 | + aria-label="Select API version" |
| 81 | + > |
| 82 | + <option value="4.0">Version 4.0</option> |
| 83 | + <option value="4.1">Version 4.1</option> |
| 84 | + </select> |
| 85 | + </div> |
| 86 | + |
| 87 | + {/* Dark Mode Toggle */} |
| 88 | + <div className="flex items-center space-x-3"> |
| 89 | + <span className={`font-medium text-sm ${ |
| 90 | + isDarkMode ? 'text-gray-200' : 'text-gray-700' |
| 91 | + }`}> |
| 92 | + Theme: |
| 93 | + </span> |
| 94 | + <button |
| 95 | + onClick={handleDarkModeToggle} |
| 96 | + className={`${ |
| 97 | + isDarkMode |
| 98 | + ? 'bg-blue-600 hover:bg-blue-700' |
| 99 | + : 'bg-gray-600 hover:bg-gray-700' |
| 100 | + } relative inline-flex h-5 w-9 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2`} |
| 101 | + aria-label="Toggle dark mode" |
| 102 | + > |
| 103 | + <span |
| 104 | + className={`${ |
| 105 | + isDarkMode ? 'translate-x-5' : 'translate-x-1' |
| 106 | + } inline-block h-3 w-3 transform rounded-full bg-white transition-transform`} |
| 107 | + /> |
| 108 | + </button> |
| 109 | + <span className={`text-xs ${ |
| 110 | + isDarkMode ? 'text-gray-300' : 'text-gray-600' |
| 111 | + }`}> |
| 112 | + {isDarkMode ? '🌙' : '☀️'} |
| 113 | + </span> |
| 114 | + </div> |
| 115 | + </div> |
| 116 | + |
| 117 | + {/* Swagger UI Content */} |
| 118 | + <div className={`${ |
| 119 | + isDarkMode ? 'swagger-container-dark' : 'swagger-container-light' |
| 120 | + }`}> |
| 121 | + <SwaggerUI |
| 122 | + url={apiUrls[version]} |
| 123 | + deepLinking={true} |
| 124 | + displayOperationId={false} |
| 125 | + defaultModelsExpandDepth={1} |
| 126 | + defaultModelExpandDepth={1} |
| 127 | + defaultModelRendering="example" |
| 128 | + displayRequestDuration={true} |
| 129 | + docExpansion="list" |
| 130 | + filter={true} |
| 131 | + showExtensions={true} |
| 132 | + showCommonExtensions={true} |
| 133 | + tryItOutEnabled={true} |
| 134 | + /> |
| 135 | + </div> |
| 136 | + </div> |
| 137 | + </div> |
| 138 | + </div> |
7 | 139 | ); |
8 | 140 | } |
0 commit comments