diff --git a/packages/web/src/components/DeviceInfoPanel.tsx b/packages/web/src/components/DeviceInfoPanel.tsx
index 6e89a4db..6480cb39 100644
--- a/packages/web/src/components/DeviceInfoPanel.tsx
+++ b/packages/web/src/components/DeviceInfoPanel.tsx
@@ -85,6 +85,12 @@ export const DeviceInfoPanel = ({
];
const actionButtons: ActionButtonConfig[] = [
+ {
+ id: "theme",
+ label: t("theme.changeTheme"),
+ icon: Palette,
+ render: () => ,
+ },
{
id: "changeName",
label: t("sidebar.deviceInfo.deviceName.changeName"),
@@ -97,12 +103,7 @@ export const DeviceInfoPanel = ({
icon: SearchIcon,
onClick: setCommandPaletteOpen,
},
- {
- id: "theme",
- label: t("theme.changeTheme"),
- icon: Palette,
- render: () => ,
- },
+
{
id: "language",
label: t("language.changeLanguage"),
diff --git a/packages/web/src/components/ThemeSwitcher.tsx b/packages/web/src/components/ThemeSwitcher.tsx
index f0900279..a4595079 100644
--- a/packages/web/src/components/ThemeSwitcher.tsx
+++ b/packages/web/src/components/ThemeSwitcher.tsx
@@ -1,7 +1,8 @@
-import { useTheme } from "@core/hooks/useTheme.ts";
-import { cn } from "@core/utils/cn.ts";
import { Monitor, Moon, Sun } from "lucide-react";
import { useTranslation } from "react-i18next";
+import { useTheme } from "../core/hooks/useTheme.ts";
+import { useToggleVisibility } from "../core/hooks/useToggleVisiblility.ts";
+import { cn } from "../core/utils/cn.ts";
import { Button } from "./UI/Button.tsx";
import { Subtle } from "./UI/Typography/Subtle.tsx";
@@ -12,10 +13,16 @@ interface ThemeSwitcherProps {
disableHover?: boolean;
}
+const TOOLTIP_TIMEOUT = 2000; // 2 seconds
+
export default function ThemeSwitcher({
className: passedClassName = "",
disableHover = false,
}: ThemeSwitcherProps) {
+ const [showTooltip, toggleShowTooltip] = useToggleVisibility({
+ timeout: TOOLTIP_TIMEOUT,
+ });
+
const { preference, setPreference } = useTheme();
const { t } = useTranslation("ui");
@@ -35,8 +42,10 @@ export default function ThemeSwitcher({
const toggleTheme = () => {
const preferences: ThemePreference[] = ["light", "dark", "system"];
const currentIndex = preferences.indexOf(preference);
- const nextPreference = preferences[(currentIndex + 1) % preferences.length];
+ const nextPreference =
+ preferences[(currentIndex + 1) % preferences.length] ?? "system";
setPreference(nextPreference);
+ toggleShowTooltip();
};
const preferenceDisplayMap: Record = {
@@ -65,12 +74,12 @@ export default function ThemeSwitcher({
{currentDisplayPreference}
diff --git a/packages/web/src/core/hooks/useToggleVisiblility.ts b/packages/web/src/core/hooks/useToggleVisiblility.ts
new file mode 100644
index 00000000..5f83800e
--- /dev/null
+++ b/packages/web/src/core/hooks/useToggleVisiblility.ts
@@ -0,0 +1,32 @@
+import { useCallback, useEffect, useRef, useState } from "react";
+
+export function useToggleVisibility({ timeout }: { timeout?: number } = {}) {
+ const [isVisible, setIsVisible] = useState(false);
+ const timeoutRef = useRef | null>(null);
+
+ const show = useCallback(() => {
+ setIsVisible(true);
+
+ if (timeout) {
+ if (timeoutRef.current) {
+ clearTimeout(timeoutRef.current);
+ }
+
+ timeoutRef.current = setTimeout(() => {
+ setIsVisible(false);
+ timeoutRef.current = null;
+ }, timeout);
+ }
+ }, [timeout]);
+
+ // Clear timeout on unmount
+ useEffect(() => {
+ return () => {
+ if (timeoutRef.current) {
+ clearTimeout(timeoutRef.current);
+ }
+ };
+ }, []);
+
+ return [isVisible, show] as const;
+}