icon.rs
| 1 | use leptos::prelude::*; |
| 2 | |
| 3 | #[derive(Clone, Copy, PartialEq, Debug)] |
| 4 | // Several variants are used from later milestones (context menu icons). |
| 5 | #[allow(dead_code)] |
| 6 | pub enum IconName { |
| 7 | Folder, |
| 8 | File, |
| 9 | Image, |
| 10 | Video, |
| 11 | Audio, |
| 12 | Text, |
| 13 | Code, |
| 14 | Archive, |
| 15 | Pdf, |
| 16 | Grid, |
| 17 | List, |
| 18 | Refresh, |
| 19 | Upload, |
| 20 | FolderPlus, |
| 21 | Download, |
| 22 | Pencil, |
| 23 | Move, |
| 24 | Copy, |
| 25 | Share, |
| 26 | Info, |
| 27 | Trash, |
| 28 | } |
| 29 | |
| 30 | /// Pick the icon for a file name based on its extension. |
| 31 | pub fn icon_for(name: &str, is_dir: bool) -> IconName { |
| 32 | if is_dir { |
| 33 | return IconName::Folder; |
| 34 | } |
| 35 | let ext = name.rsplit('.').next().unwrap_or("").to_lowercase(); |
| 36 | match ext.as_str() { |
| 37 | "png" | "jpg" | "jpeg" | "gif" | "webp" | "svg" | "bmp" | "ico" | "avif" => { |
| 38 | IconName::Image |
| 39 | } |
| 40 | "mp4" | "webm" | "mkv" | "mov" | "avi" => IconName::Video, |
| 41 | "mp3" | "wav" | "ogg" | "flac" | "m4a" | "opus" => IconName::Audio, |
| 42 | "pdf" => IconName::Pdf, |
| 43 | "zip" | "tar" | "gz" | "tgz" | "zst" | "bz2" | "xz" | "7z" | "rar" => { |
| 44 | IconName::Archive |
| 45 | } |
| 46 | "rs" | "js" | "ts" | "tsx" | "jsx" | "py" | "rb" | "go" | "c" | "cpp" |
| 47 | | "h" | "hpp" | "json" | "toml" | "yaml" | "yml" | "sh" | "html" | "css" |
| 48 | | "wasm" | "sql" => IconName::Code, |
| 49 | "txt" | "md" | "log" | "csv" | "ini" | "conf" | "xml" => IconName::Text, |
| 50 | _ => IconName::File, |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | fn icon_d(name: IconName) -> &'static str { |
| 55 | match name { |
| 56 | IconName::Folder => { |
| 57 | "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" |
| 58 | } |
| 59 | IconName::File => "M6 2h8l5 5v13a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2z M13 2v6h6", |
| 60 | IconName::Image => "M3 5h18v14H3z M10 10a1.5 1.5 0 1 1-3 0a1.5 1.5 0 0 1 3 0z M21 15l-5-5-9 9", |
| 61 | IconName::Video => "M3 5h18v14H3z M10 9l5 3-5 3z", |
| 62 | IconName::Audio => { |
| 63 | "M9 18V6l10-2v10 M9 18a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0z M19 15a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0z" |
| 64 | } |
| 65 | IconName::Text => "M5 3h14v18H5z M9 8h6 M9 12h6 M9 16h4", |
| 66 | IconName::Code => "M8 8l-4 4 4 4 M16 8l4 4-4 4", |
| 67 | IconName::Archive => "M4 4h16v16H4z M12 4v2 M12 8v2 M12 12v2 M9 16h6v4H9z", |
| 68 | IconName::Pdf => "M6 2h8l5 5v13a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2z M13 2v6h6 M8 13h8 M8 17h8", |
| 69 | IconName::Grid => "M4 4h7v7H4z M13 4h7v7h-7z M4 13h7v7H4z M13 13h7v7h-7z", |
| 70 | IconName::List => "M4 6h2 M9 6h11 M4 12h2 M9 12h11 M4 18h2 M9 18h11", |
| 71 | IconName::Refresh => "M21 12a9 9 0 1 1-3-6.7 M21 3v6h-6", |
| 72 | IconName::Upload => "M12 16V4 M7 9l5-5 5 5 M4 20h16", |
| 73 | IconName::FolderPlus => { |
| 74 | "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z M12 11v6 M9 14h6" |
| 75 | } |
| 76 | IconName::Download => "M12 4v12 M7 11l5 5 5-5 M4 20h16", |
| 77 | IconName::Pencil => "M4 20l1-4L16 5l3 3L8 19z M13 8l3 3", |
| 78 | IconName::Move => "M20 7H6 M9 4L6 7l3 3 M4 17h14 M15 14l3 3-3 3", |
| 79 | IconName::Copy => "M8 8h12v12H8z M4 16V4h12", |
| 80 | IconName::Share => "M4 13v6a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-6 M12 3v11 M8 7l4-4 4 4", |
| 81 | IconName::Info => "M12 3a9 9 0 1 0 .01 0z M12 11v5 M12 8h.01", |
| 82 | IconName::Trash => "M4 7h16 M9 7V4h6v3 M6 7l1 13h10l1-13 M10 11v6 M14 11v6", |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | fn icon_class(name: IconName) -> &'static str { |
| 87 | match name { |
| 88 | IconName::Folder | IconName::FolderPlus => "ic-folder", |
| 89 | _ => "ic-muted", |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | #[component] |
| 94 | pub fn Icon(name: IconName, class: Option<String>) -> impl IntoView { |
| 95 | let mut cls = String::from("icon "); |
| 96 | cls.push_str(icon_class(name)); |
| 97 | if let Some(extra) = class { |
| 98 | cls.push(' '); |
| 99 | cls.push_str(&extra); |
| 100 | } |
| 101 | view! { |
| 102 | <svg |
| 103 | class=cls |
| 104 | viewBox="0 0 24 24" |
| 105 | fill="none" |
| 106 | stroke="currentColor" |
| 107 | stroke_width="1.8" |
| 108 | stroke_linecap="round" |
| 109 | stroke_linejoin="round" |
| 110 | aria-hidden="true" |
| 111 | > |
| 112 | <path d=icon_d(name)/> |
| 113 | </svg> |
| 114 | } |
| 115 | } |
| 116 |