React useState toggle 的 hover 按鈕在mobile device 無法作用

AI 詠唱出來的第一版 UI, 如果是只有使用 desktop device only, 是沒問題, 只使用 hover 處理 switch 的功能在 desktop 上更實用, 但hover 在 mobile device 無法使用.

Changes:

  • State-based Toggle: Replaced the CSS-only group-hover behavior with a React useState toggle. This ensures the dropdown opens and closes reliably on touch screens where hover states are inconsistent.
  • Click-Away Support: Added a transparent backdrop that automatically closes the language menu when you click or tap anywhere else on the screen.
  • Improved Mobile UX: The dropdown now responds immediately to taps, providing a much smoother experience for mobile users.

異動的程式碼:

const Header = ({ onHome, onSettings, onManagement, language, onLanguageChange, currentView }: { 
  onHome: () => void; 
  onSettings: () => void;
  onManagement: () => void;
  language: 'zh' | 'en';
  onLanguageChange: (lang: 'zh' | 'en') => void;
  currentView: View;
}) => {
  const t = translations[language];
  const [isLangOpen, setIsLangOpen] = useState(false);

說明: 增加 useState(false) 在 Header


-            <div className="relative group">
-              <button className="flex items-center space-x-1 hover:text-slate-900 transition-colors py-2">
+            <div className="relative">
+              <button
+                onClick={() => setIsLangOpen(!isLangOpen)}
+                className="flex items-center space-x-1 hover:text-slate-900 transition-colors py-2"
+              >

說明: button 增加 onClick={() => setIsLangOpen(!isLangOpen)} 的 event.

-              <div className="absolute right-0 top-full mt-1 w-32 bg-white border border-slate-200 rounded-lg shadow-lg
 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all z-50">
-                <button
-                  onClick={() => onLanguageChange('zh')}
-                  className={`w-full text-left px-4 py-2 text-sm hover:bg-slate-50 first:rounded-t-lg ${language === 'zh' ? 'text-slate-900 font-bold' : 'text-slate-600'}`}
-                >
-                  {t.zh}
-                </button>
-                <button
-                  onClick={() => onLanguageChange('en')}
-                  className={`w-full text-left px-4 py-2 text-sm hover:bg-slate-50 last:rounded-b-lg ${language === 'en' ? 'text-slate-900 font-bold' : 'text-slate-600'}`}
-                >
-                  {t.en}
-                </button>
-              </div>
+              {isLangOpen && (
+                <>
+                  <div
+                    className="fixed inset-0 z-40"
+                    onClick={() => setIsLangOpen(false)}
+                  />
+                  <div className="absolute right-0 top-full mt-1 w-32 bg-white border border-slate-200 rounded-lg shadow-lg z-50 overflow-hidden">
+                    <button
+                      onClick={() => {
+                        onLanguageChange('zh');
+                        setIsLangOpen(false);
+                      }}
+                  />
+                  <div className="absolute right-0 top-full mt-1 w-32 bg-white border border-slate-200 rounded-lg shadow-lg z-50 overflow-hidden">
+                    <button
+                      onClick={() => {
+                        onLanguageChange('zh');
+                        setIsLangOpen(false);
+                      }}
+                      className={`w-full text-left px-4 py-2 text-sm hover:bg-slate-50 ${language === 'zh' ? 'text-slate-900 font-bold bg-slate-50' : 'text-slate-600'}`}
+                    >
+                      {t.zh}
+                    </button>
+                    <button
+                      onClick={() => {
+                        onLanguageChange('en');
+                        setIsLangOpen(false);
+                      }}
+                      className={`w-full text-left px-4 py-2 text-sm hover:bg-slate-50 ${language === 'en' ? 'text-slate-900 font-bold bg-slate-50' : 'text-slate-600'}`}
+                    >
+                      {t.en}
+                    </button>
+                  </div>
+                </>
+              )}

說明: button 增加判斷 isLangOpen 的 flag 來彈出語言切換的 popup menu.

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *