skill_web/components/
icons.rs

1//! SVG icon components
2//!
3//! Icons from Heroicons (https://heroicons.com)
4
5use yew::prelude::*;
6
7/// Common props for all icons
8#[derive(Properties, PartialEq, Clone)]
9pub struct IconProps {
10    #[prop_or("w-5 h-5".into())]
11    pub class: AttrValue,
12}
13
14/// Dashboard icon (home)
15#[function_component(DashboardIcon)]
16pub fn dashboard_icon(props: &IconProps) -> Html {
17    html! {
18        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
19            <path stroke-linecap="round" stroke-linejoin="round" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
20        </svg>
21    }
22}
23
24/// Skills icon (cube)
25#[function_component(SkillsIcon)]
26pub fn skills_icon(props: &IconProps) -> Html {
27    html! {
28        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
29            <path stroke-linecap="round" stroke-linejoin="round" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
30        </svg>
31    }
32}
33
34/// Play icon (for run)
35#[function_component(PlayIcon)]
36pub fn play_icon(props: &IconProps) -> Html {
37    html! {
38        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
39            <path stroke-linecap="round" stroke-linejoin="round" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" />
40            <path stroke-linecap="round" stroke-linejoin="round" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
41        </svg>
42    }
43}
44
45/// History icon (clock)
46#[function_component(HistoryIcon)]
47pub fn history_icon(props: &IconProps) -> Html {
48    html! {
49        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
50            <path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
51        </svg>
52    }
53}
54
55/// Settings icon (cog)
56#[function_component(SettingsIcon)]
57pub fn settings_icon(props: &IconProps) -> Html {
58    html! {
59        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
60            <path stroke-linecap="round" stroke-linejoin="round" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
61            <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
62        </svg>
63    }
64}
65
66/// Search icon
67#[function_component(SearchIcon)]
68pub fn search_icon(props: &IconProps) -> Html {
69    html! {
70        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
71            <path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
72        </svg>
73    }
74}
75
76/// Plus icon
77#[function_component(PlusIcon)]
78pub fn plus_icon(props: &IconProps) -> Html {
79    html! {
80        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
81            <path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m8-8H4" />
82        </svg>
83    }
84}
85
86/// Check icon
87#[function_component(CheckIcon)]
88pub fn check_icon(props: &IconProps) -> Html {
89    html! {
90        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
91            <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
92        </svg>
93    }
94}
95
96/// X icon (close)
97#[function_component(XIcon)]
98pub fn x_icon(props: &IconProps) -> Html {
99    html! {
100        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
101            <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
102        </svg>
103    }
104}
105
106/// Chevron right icon
107#[function_component(ChevronRightIcon)]
108pub fn chevron_right_icon(props: &IconProps) -> Html {
109    html! {
110        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
111            <path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7" />
112        </svg>
113    }
114}
115
116/// External link icon
117#[function_component(ExternalLinkIcon)]
118pub fn external_link_icon(props: &IconProps) -> Html {
119    html! {
120        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
121            <path stroke-linecap="round" stroke-linejoin="round" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
122        </svg>
123    }
124}
125
126/// Copy icon
127#[function_component(CopyIcon)]
128pub fn copy_icon(props: &IconProps) -> Html {
129    html! {
130        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
131            <path stroke-linecap="round" stroke-linejoin="round" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
132        </svg>
133    }
134}
135
136/// Refresh icon
137#[function_component(RefreshIcon)]
138pub fn refresh_icon(props: &IconProps) -> Html {
139    html! {
140        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
141            <path stroke-linecap="round" stroke-linejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
142        </svg>
143    }
144}
145
146/// Terminal icon
147#[function_component(TerminalIcon)]
148pub fn terminal_icon(props: &IconProps) -> Html {
149    html! {
150        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
151            <path stroke-linecap="round" stroke-linejoin="round" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
152        </svg>
153    }
154}
155
156/// Lightning bolt icon (for skills/power)
157#[function_component(LightningIcon)]
158pub fn lightning_icon(props: &IconProps) -> Html {
159    html! {
160        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
161            <path stroke-linecap="round" stroke-linejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z" />
162        </svg>
163    }
164}
165
166/// Folder icon
167#[function_component(FolderIcon)]
168pub fn folder_icon(props: &IconProps) -> Html {
169    html! {
170        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
171            <path stroke-linecap="round" stroke-linejoin="round" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
172        </svg>
173    }
174}
175
176/// Download icon
177#[function_component(DownloadIcon)]
178pub fn download_icon(props: &IconProps) -> Html {
179    html! {
180        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
181            <path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
182        </svg>
183    }
184}
185
186/// Analytics/Chart icon
187#[function_component(AnalyticsIcon)]
188pub fn analytics_icon(props: &IconProps) -> Html {
189    html! {
190        <svg class={&props.class} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
191            <path stroke-linecap="round" stroke-linejoin="round" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
192        </svg>
193    }
194}