1use serde::{Deserialize, Serialize};
6use std::str::FromStr;
7
8use crate::types::ViewportConfig;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(rename_all = "lowercase")]
13pub enum ViewportPreset {
14 Desktop,
16 DesktopHd,
17 Desktop4k,
18
19 TabletPortrait,
21 TabletLandscape,
22 IpadPro,
23
24 Mobile,
26 MobileLandscape,
27 IphoneSe,
28 Iphone14,
29 Iphone14Pro,
30 Iphone14ProMax,
31 Pixel7,
32
33 Custom,
35}
36
37impl ViewportPreset {
38 #[inline]
40 pub const fn config(&self) -> ViewportConfig {
41 match self {
42 Self::Desktop => ViewportConfig {
44 width: 1280,
45 height: 720,
46 device_scale_factor: Some(1.0),
47 },
48 Self::DesktopHd => ViewportConfig {
49 width: 1920,
50 height: 1080,
51 device_scale_factor: Some(1.0),
52 },
53 Self::Desktop4k => ViewportConfig {
54 width: 3840,
55 height: 2160,
56 device_scale_factor: Some(1.0),
57 },
58
59 Self::TabletPortrait => ViewportConfig {
61 width: 768,
62 height: 1024,
63 device_scale_factor: Some(2.0),
64 },
65 Self::TabletLandscape => ViewportConfig {
66 width: 1024,
67 height: 768,
68 device_scale_factor: Some(2.0),
69 },
70 Self::IpadPro => ViewportConfig {
71 width: 1024,
72 height: 1366,
73 device_scale_factor: Some(2.0),
74 },
75
76 Self::Mobile => ViewportConfig {
78 width: 375,
79 height: 667,
80 device_scale_factor: Some(2.0),
81 },
82 Self::MobileLandscape => ViewportConfig {
83 width: 667,
84 height: 375,
85 device_scale_factor: Some(2.0),
86 },
87 Self::IphoneSe => ViewportConfig {
88 width: 375,
89 height: 667,
90 device_scale_factor: Some(2.0),
91 },
92 Self::Iphone14 => ViewportConfig {
93 width: 390,
94 height: 844,
95 device_scale_factor: Some(3.0),
96 },
97 Self::Iphone14Pro => ViewportConfig {
98 width: 393,
99 height: 852,
100 device_scale_factor: Some(3.0),
101 },
102 Self::Iphone14ProMax => ViewportConfig {
103 width: 430,
104 height: 932,
105 device_scale_factor: Some(3.0),
106 },
107 Self::Pixel7 => ViewportConfig {
108 width: 412,
109 height: 915,
110 device_scale_factor: Some(2.625),
111 },
112
113 Self::Custom => ViewportConfig {
115 width: 1280,
116 height: 720,
117 device_scale_factor: Some(1.0),
118 },
119 }
120 }
121
122 pub const fn name(&self) -> &'static str {
124 match self {
125 Self::Desktop => "desktop",
126 Self::DesktopHd => "desktop-hd",
127 Self::Desktop4k => "desktop-4k",
128 Self::TabletPortrait => "tablet-portrait",
129 Self::TabletLandscape => "tablet-landscape",
130 Self::IpadPro => "ipad-pro",
131 Self::Mobile => "mobile",
132 Self::MobileLandscape => "mobile-landscape",
133 Self::IphoneSe => "iphone-se",
134 Self::Iphone14 => "iphone-14",
135 Self::Iphone14Pro => "iphone-14-pro",
136 Self::Iphone14ProMax => "iphone-14-pro-max",
137 Self::Pixel7 => "pixel-7",
138 Self::Custom => "custom",
139 }
140 }
141}
142
143impl FromStr for ViewportPreset {
144 type Err = ();
145
146 fn from_str(s: &str) -> Result<Self, Self::Err> {
147 match s.to_lowercase().as_str() {
148 "desktop" => Ok(Self::Desktop),
149 "desktop-hd" | "desktophd" => Ok(Self::DesktopHd),
150 "desktop-4k" | "desktop4k" => Ok(Self::Desktop4k),
151 "tablet" | "tablet-portrait" => Ok(Self::TabletPortrait),
152 "tablet-landscape" => Ok(Self::TabletLandscape),
153 "ipad-pro" | "ipadpro" => Ok(Self::IpadPro),
154 "mobile" => Ok(Self::Mobile),
155 "mobile-landscape" => Ok(Self::MobileLandscape),
156 "iphone-se" | "iphonese" => Ok(Self::IphoneSe),
157 "iphone-14" | "iphone14" => Ok(Self::Iphone14),
158 "iphone-14-pro" | "iphone14pro" => Ok(Self::Iphone14Pro),
159 "iphone-14-pro-max" | "iphone14promax" => Ok(Self::Iphone14ProMax),
160 "pixel-7" | "pixel7" => Ok(Self::Pixel7),
161 _ => Err(()),
162 }
163 }
164}
165
166impl From<ViewportPreset> for ViewportConfig {
167 #[inline]
168 fn from(preset: ViewportPreset) -> Self {
169 preset.config()
170 }
171}
172
173pub const PRESET_VIEWPORTS: &[ViewportPreset] = &[
175 ViewportPreset::Desktop,
176 ViewportPreset::DesktopHd,
177 ViewportPreset::Desktop4k,
178 ViewportPreset::TabletPortrait,
179 ViewportPreset::TabletLandscape,
180 ViewportPreset::IpadPro,
181 ViewportPreset::Mobile,
182 ViewportPreset::MobileLandscape,
183 ViewportPreset::IphoneSe,
184 ViewportPreset::Iphone14,
185 ViewportPreset::Iphone14Pro,
186 ViewportPreset::Iphone14ProMax,
187 ViewportPreset::Pixel7,
188];
189
190#[cfg(test)]
191mod tests {
192 use super::{PRESET_VIEWPORTS, ViewportPreset};
193 use crate::types::ViewportConfig;
194 use std::str::FromStr;
195
196 #[test]
197 fn test_desktop_preset() {
198 let config = ViewportPreset::Desktop.config();
199 assert_eq!(config.width, 1280);
200 assert_eq!(config.height, 720);
201 }
202
203 #[test]
204 fn test_mobile_preset() {
205 let config = ViewportPreset::Mobile.config();
206 assert_eq!(config.width, 375);
207 assert_eq!(config.height, 667);
208 }
209
210 #[test]
211 fn test_preset_from_str() {
212 assert_eq!(
213 ViewportPreset::from_str("desktop"),
214 Ok(ViewportPreset::Desktop)
215 );
216 assert_eq!(
217 ViewportPreset::from_str("mobile"),
218 Ok(ViewportPreset::Mobile)
219 );
220 assert_eq!(
221 ViewportPreset::from_str("iphone-14-pro"),
222 Ok(ViewportPreset::Iphone14Pro)
223 );
224 assert_eq!(ViewportPreset::from_str("unknown"), Err(()));
225 }
226
227 #[test]
228 fn test_preset_into_config() {
229 let config: ViewportConfig = ViewportPreset::Iphone14.into();
230 assert_eq!(config.width, 390);
231 assert_eq!(config.height, 844);
232 assert_eq!(config.device_scale_factor, Some(3.0));
233 }
234
235 #[test]
236 fn test_preset_viewports_count() {
237 assert_eq!(PRESET_VIEWPORTS.len(), 13);
238 }
239}