lospec_cli/cmd/
search.rs

1use colored::Colorize;
2use thiserror::Error;
3
4use crate::{cli::Sorting, palette::Palettes};
5
6#[derive(Debug, Error)]
7pub enum Error {
8    #[error(transparent)]
9    RequestError(#[from] reqwest::Error),
10
11    #[error(transparent)]
12    DeserializationError(#[from] serde_json::Error),
13}
14
15/// Color search filter.
16#[derive(Clone)]
17pub enum Filter {
18    /// Palettes with any number of colors.
19    Any,
20    /// Palettes with N maximum colors.
21    Max(u16),
22    /// Palettes with N minimum colors.
23    Min(u16),
24    /// Palettes with exactly N colors.
25    Exact(u16),
26}
27
28pub struct Search {
29    /// Which page to show.
30    pub page: u16,
31    /// Search filter.
32    pub filter: Filter,
33    /// Search results sorting.
34    pub sorting: Sorting,
35    /// Search tag (empty if no tag is being searched).
36    pub tag: String,
37}
38
39impl Search {
40    pub fn new(page: Option<u16>, filter: Filter, sorting: Sorting, tag: Option<String>) -> Self {
41        Self {
42            page: page.unwrap_or(1),
43            filter,
44            sorting,
45            tag: tag.unwrap_or("".to_string()),
46        }
47    }
48
49    /// Generate query parameters for the request.
50    fn to_query(self) -> Vec<(&'static str, String)> {
51        let mut params = vec![
52            ("page", format!("{}", self.page)),
53            ("sortingType", self.sorting.to_string()),
54            ("tag", self.tag),
55        ];
56
57        match self.filter {
58            Filter::Any => params.push(("colorNumberFilterType", "any".to_string())),
59            Filter::Max(n) => {
60                params.push(("colorNumberFilterType", "max".to_string()));
61                params.push(("colorNumber", format!("{}", n)));
62            }
63            Filter::Min(n) => {
64                params.push(("colorNumberFilterType", "min".to_string()));
65                params.push(("colorNumber", format!("{}", n)));
66            }
67            Filter::Exact(n) => {
68                params.push(("colorNumberFilterType", "exact".to_string()));
69                params.push(("colorNumber", format!("{}", n)));
70            }
71        }
72
73        params
74    }
75
76    /// Execute the search request.
77    pub async fn execute(self) -> Result<(), Error> {
78        let client = reqwest::Client::new();
79
80        let response = client
81            .get("https://lospec.com/palette-list/load")
82            .query(&self.to_query())
83            .send()
84            .await?;
85
86        let json: Palettes =
87            serde_json::from_slice(&response.bytes().await.map_err(Error::RequestError)?)?;
88
89        for palette in &json.palettes {
90            if let Some(user) = &palette.user {
91                println!("{} ({}) by {}", palette.title, palette.slug, user.name);
92            } else {
93                println!("{}", palette.title);
94            }
95
96            for color in &palette.colors {
97                let colored_string = "  ".on_truecolor(color.red, color.green, color.blue);
98                print!("{}", colored_string);
99            }
100            println!();
101            println!();
102        }
103
104        Ok(())
105    }
106}