1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
mod common;

use self::common::CommonTheme;
use crate::{
    mobile::{NavBarTheme, TabbarTheme},
    AlertTheme, AutoCompleteTheme, AvatarTheme, BreadcrumbTheme, ButtonTheme, CalendarTheme,
    CollapseTheme, ColorPickerTheme, DatePickerTheme, InputTheme, MenuTheme, MessageTheme,
    PopoverTheme, ProgressTheme, SelectTheme, SkeletionTheme, SliderTheme, SpinnerTheme,
    SwitchTheme, TableTheme, TagTheme, TimePickerTheme, TypographyTheme, UploadTheme,
};
use leptos::*;

pub trait ThemeMethod {
    fn light() -> Self;
    fn dark() -> Self;
}

#[derive(Clone)]
pub struct Theme {
    pub name: String,
    pub common: CommonTheme,
    pub button: ButtonTheme,
    pub input: InputTheme,
    pub menu: MenuTheme,
    pub table: TableTheme,
    pub alert: AlertTheme,
    pub skeletion: SkeletionTheme,
    pub tag: TagTheme,
    pub avatar: AvatarTheme,
    pub message: MessageTheme,
    pub select: SelectTheme,
    pub slider: SliderTheme,
    pub switch: SwitchTheme,
    pub spinner: SpinnerTheme,
    pub upload: UploadTheme,
    pub nav_bar: NavBarTheme,
    pub tabbar: TabbarTheme,
    pub auto_complete: AutoCompleteTheme,
    pub color_picker: ColorPickerTheme,
    pub breadcrumb: BreadcrumbTheme,
    pub progress: ProgressTheme,
    pub typograph: TypographyTheme,
    pub calendar: CalendarTheme,
    pub time_picker: TimePickerTheme,
    pub date_picker: DatePickerTheme,
    pub popover: PopoverTheme,
    pub collapse: CollapseTheme,
}

impl Theme {
    pub fn light() -> Self {
        Self {
            name: "light".into(),
            common: CommonTheme::light(),
            button: ButtonTheme::light(),
            input: InputTheme::light(),
            menu: MenuTheme::light(),
            table: TableTheme::light(),
            alert: AlertTheme::light(),
            skeletion: SkeletionTheme::light(),
            tag: TagTheme::light(),
            avatar: AvatarTheme::light(),
            message: MessageTheme::light(),
            select: SelectTheme::light(),
            slider: SliderTheme::light(),
            switch: SwitchTheme::light(),
            spinner: SpinnerTheme::light(),
            upload: UploadTheme::light(),
            nav_bar: NavBarTheme::light(),
            tabbar: TabbarTheme::light(),
            auto_complete: AutoCompleteTheme::light(),
            color_picker: ColorPickerTheme::light(),
            breadcrumb: BreadcrumbTheme::light(),
            progress: ProgressTheme::light(),
            typograph: TypographyTheme::light(),
            calendar: CalendarTheme::light(),
            time_picker: TimePickerTheme::light(),
            date_picker: DatePickerTheme::light(),
            popover: PopoverTheme::light(),
            collapse: CollapseTheme::light(),
        }
    }
    pub fn dark() -> Self {
        Self {
            name: "dark".into(),
            common: CommonTheme::dark(),
            button: ButtonTheme::dark(),
            input: InputTheme::dark(),
            menu: MenuTheme::dark(),
            table: TableTheme::dark(),
            alert: AlertTheme::dark(),
            skeletion: SkeletionTheme::dark(),
            tag: TagTheme::dark(),
            avatar: AvatarTheme::dark(),
            message: MessageTheme::dark(),
            select: SelectTheme::dark(),
            slider: SliderTheme::dark(),
            switch: SwitchTheme::dark(),
            spinner: SpinnerTheme::dark(),
            upload: UploadTheme::dark(),
            nav_bar: NavBarTheme::dark(),
            tabbar: TabbarTheme::dark(),
            auto_complete: AutoCompleteTheme::dark(),
            color_picker: ColorPickerTheme::dark(),
            breadcrumb: BreadcrumbTheme::dark(),
            progress: ProgressTheme::dark(),
            typograph: TypographyTheme::dark(),
            calendar: CalendarTheme::dark(),
            time_picker: TimePickerTheme::dark(),
            date_picker: DatePickerTheme::dark(),
            popover: PopoverTheme::dark(),
            collapse: CollapseTheme::dark(),
        }
    }
}

impl ThemeMethod for Theme {
    fn light() -> Self {
        Theme::light()
    }
    fn dark() -> Self {
        Theme::dark()
    }
}

#[component]
pub fn ThemeProvider(
    #[prop(optional, into)] theme: Option<RwSignal<Theme>>,
    children: Children,
) -> impl IntoView {
    let theme = if let Some(theme) = theme {
        theme
    } else {
        create_rw_signal(Theme::light())
    };

    view! { <Provider value=theme children/> }
}

pub fn use_theme(default: impl Fn() -> Theme) -> ReadSignal<Theme> {
    use_context::<RwSignal<Theme>>()
        .unwrap_or_else(|| create_rw_signal(default()))
        .split()
        .0
}

pub fn use_rw_theme() -> RwSignal<Theme> {
    expect_context::<RwSignal<Theme>>()
}

#[cfg(test)]
mod tests {
    use super::{use_theme, Theme};

    fn _t_use_theme() {
        use_theme(Theme::dark);
    }
}