Coverage for src / lexigram / ui / atoms / theme_toggle.py: 100%

6 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-08-10 04:11 +0800

1"""Dark mode theme toggle component.""" 

2 

3from __future__ import annotations 

4 

5from typing import Any 

6 

7from lexigram.ui.core.base import Component, el 

8 

9 

10class ThemeToggle(Component): 

11 """Theme toggle with light/dark/system modes. 

12 

13 Persists preference in localStorage. Falls back to system 

14 ``prefers-color-scheme`` when no preference is stored. 

15 Renders as an icon button that cycles through modes. 

16 """ 

17 

18 def render(self) -> Any: 

19 return el( 

20 "button", 

21 {"x-on:click": "cycleTheme()"}, 

22 el( 

23 "svg", 

24 el( 

25 "path", 

26 d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z", 

27 ), 

28 aria_hidden="true", 

29 fill="none", 

30 viewBox="0 0 24 24", 

31 stroke="currentColor", 

32 stroke_width="2", 

33 x_show="theme === 'light'", 

34 class_="h-5 w-5", 

35 ), 

36 el( 

37 "svg", 

38 el("path", d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"), 

39 aria_hidden="true", 

40 fill="currentColor", 

41 viewBox="0 0 24 24", 

42 x_show="theme === 'dark'", 

43 class_="h-5 w-5", 

44 ), 

45 el( 

46 "svg", 

47 el( 

48 "path", 

49 d="M3 5a2 2 0 012-2h14a2 2 0 012 2v10a2 2 0 01-2 2h-3l-1 3H9l-1-3H5a2 2 0 01-2-2V5z", 

50 ), 

51 aria_hidden="true", 

52 fill="none", 

53 viewBox="0 0 24 24", 

54 stroke="currentColor", 

55 stroke_width="2", 

56 x_show="theme === 'system'", 

57 class_="h-5 w-5 opacity-50", 

58 ), 

59 type="button", 

60 class_="inline-flex items-center justify-center rounded-md p-2 text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", 

61 aria_label="Toggle theme", 

62 x_data="themeToggle()", 

63 x_init="$store.theme = localStorage.getItem('theme')", 

64 )