Coverage for src / local_deep_research / web / themes / schema.py: 100%

16 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-02-25 01:07 +0000

1""" 

2Theme Schema - Data structures for theme metadata. 

3""" 

4 

5from dataclasses import dataclass 

6from pathlib import Path 

7from typing import Literal 

8 

9 

10# Required CSS variables that every theme must define 

11REQUIRED_VARIABLES: list[str] = [ 

12 "--bg-primary", 

13 "--bg-secondary", 

14 "--bg-tertiary", 

15 "--accent-primary", 

16 "--accent-secondary", 

17 "--accent-tertiary", 

18 "--text-primary", 

19 "--text-secondary", 

20 "--text-muted", 

21 "--border-color", 

22 "--success-color", 

23 "--warning-color", 

24 "--error-color", 

25] 

26 

27# RGB variants for rgba() usage 

28REQUIRED_RGB_VARIANTS: list[str] = [ 

29 "--bg-primary-rgb", 

30 "--bg-secondary-rgb", 

31 "--bg-tertiary-rgb", 

32 "--accent-primary-rgb", 

33 "--accent-secondary-rgb", 

34 "--accent-tertiary-rgb", 

35 "--text-primary-rgb", 

36 "--text-secondary-rgb", 

37 "--text-muted-rgb", 

38 "--border-color-rgb", 

39 "--success-color-rgb", 

40 "--warning-color-rgb", 

41 "--error-color-rgb", 

42] 

43 

44# Valid theme groups 

45ThemeGroup = Literal["core", "nature", "dev", "research", "system", "other"] 

46 

47# Valid theme types (for luminance classification) 

48ThemeType = Literal["dark", "light"] 

49 

50 

51@dataclass 

52class ThemeMetadata: 

53 """Theme metadata extracted from CSS frontmatter.""" 

54 

55 id: str # kebab-case identifier (e.g., "nord", "dracula") 

56 label: str # Display label for UI (e.g., "Nord", "Dracula") 

57 icon: str # FontAwesome icon class (e.g., "fa-snowflake") 

58 group: ThemeGroup # Category for grouping in UI 

59 type: ThemeType = "dark" # dark/light for luminance classification 

60 description: str = "" # Optional description 

61 author: str = "" # Optional author attribution 

62 css_path: Path | None = ( 

63 None # Path to CSS file (None for virtual themes like "system") 

64 ) 

65 

66 def to_dict(self) -> dict: 

67 """Convert to dictionary for JSON serialization.""" 

68 return { 

69 "label": self.label, 

70 "icon": self.icon, 

71 "group": self.group, 

72 "type": self.type, 

73 } 

74 

75 

76# Group labels for UI display 

77GROUP_LABELS: dict[str, str] = { 

78 "core": "Core Themes", 

79 "nature": "Nature", 

80 "dev": "Developer Themes", 

81 "research": "Research & Reading", 

82 "system": "System", 

83 "other": "Other", 

84}