diff --git a/.DS_Store b/.DS_Store index 4de7a02..13bff6e 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Cargo.lock b/Cargo.lock index c903f86..b9f570b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -94,12 +94,6 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" -[[package]] -name = "arc-swap" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" - [[package]] name = "arg_enum_proc_macro" version = "0.3.4" @@ -503,12 +497,6 @@ dependencies = [ "bitcoin_hashes 0.14.0", ] -[[package]] -name = "base62" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fa474cf7492f9a299ba6019fb99ec673e1739556d48e8a90eabaea282ef0e4" - [[package]] name = "base64" version = "0.22.1" @@ -868,7 +856,7 @@ dependencies = [ "serde_json", "syn 2.0.90", "tempfile", - "toml 0.8.19", + "toml", ] [[package]] @@ -1118,15 +1106,29 @@ dependencies = [ "smol", "tokio", "tracing-subscriber", - "ui", ] [[package]] name = "coop-ui" version = "0.1.0" dependencies = [ + "anyhow", + "chrono", "gpui", - "ui", + "image", + "itertools 0.13.0", + "once_cell", + "paste", + "regex", + "resvg", + "rust-embed", + "serde", + "serde_json", + "smallvec", + "smol", + "unicode-segmentation", + "usvg", + "uuid", ] [[package]] @@ -1510,7 +1512,7 @@ dependencies = [ "cc", "memchr", "rustc_version", - "toml 0.8.19", + "toml", "vswhom", "winreg", ] @@ -2045,17 +2047,6 @@ dependencies = [ "regex-syntax", ] -[[package]] -name = "globwalk" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" -dependencies = [ - "bitflags 1.3.2", - "ignore", - "walkdir", -] - [[package]] name = "gloo-timers" version = "0.3.0" @@ -2648,22 +2639,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "ignore" -version = "0.4.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" -dependencies = [ - "crossbeam-deque", - "globset", - "log", - "memchr", - "regex-automata", - "same-file", - "walkdir", - "winapi-util", -] - [[package]] name = "image" version = "0.25.5" @@ -2788,15 +2763,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.12.1" @@ -2961,12 +2927,6 @@ dependencies = [ "libc", ] -[[package]] -name = "libyml" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64804cc6a5042d4f05379909ba25b503ec04e2c082151d62122d5dcaa274b961" - [[package]] name = "linkme" version = "0.3.31" @@ -3271,15 +3231,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" -[[package]] -name = "normpath" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "nostr" version = "0.37.0" @@ -3897,7 +3848,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.22.22", + "toml_edit", ] [[package]] @@ -4389,60 +4340,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "rust-i18n" -version = "3.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "039f57d22229db401af3458ca939300178e99e88b938573cea12b7c2b0f09724" -dependencies = [ - "globwalk", - "once_cell", - "regex", - "rust-i18n-macro", - "rust-i18n-support", - "smallvec", -] - -[[package]] -name = "rust-i18n-macro" -version = "3.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde5c022360a2e54477882843d56b6f9bcb4bc62f504b651a2f497f0028d174f" -dependencies = [ - "glob", - "once_cell", - "proc-macro2", - "quote", - "rust-i18n-support", - "serde", - "serde_json", - "serde_yml", - "syn 2.0.90", -] - -[[package]] -name = "rust-i18n-support" -version = "3.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75d2844d36f62b5d6b66f9cf8f8cbdbbbdcdb5fd37a473a9cc2fb45fdcf485d2" -dependencies = [ - "arc-swap", - "base62", - "globwalk", - "itertools 0.11.0", - "lazy_static", - "normpath", - "once_cell", - "proc-macro2", - "regex", - "serde", - "serde_json", - "serde_yml", - "siphasher 1.0.1", - "toml 0.7.8", - "triomphe", -] - [[package]] name = "rustc-demangle" version = "0.1.24" @@ -4862,23 +4759,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_yml" -version = "0.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e76bab63c3fd98d27c17f9cbce177f64a91f5e69ac04cafe04e1bb25d1dc3c" -dependencies = [ - "indexmap", - "itoa", - "libyml", - "log", - "memchr", - "ryu", - "serde", - "serde_json", - "tempfile", -] - [[package]] name = "sha1" version = "0.10.6" @@ -5310,7 +5190,7 @@ dependencies = [ "cfg-expr", "heck 0.5.0", "pkg-config", - "toml 0.8.19", + "toml", "version-compare", ] @@ -5573,18 +5453,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "toml" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.19.15", -] - [[package]] name = "toml" version = "0.8.19" @@ -5594,7 +5462,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.22", + "toml_edit", ] [[package]] @@ -5606,19 +5474,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow 0.5.40", -] - [[package]] name = "toml_edit" version = "0.22.22" @@ -5629,7 +5484,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.20", + "winnow", ] [[package]] @@ -5695,17 +5550,6 @@ dependencies = [ "tracing-log", ] -[[package]] -name = "triomphe" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8f7726da4807b58ea5c96fdc122f80702030edc33b35aff9190a51148ccc85" -dependencies = [ - "arc-swap", - "serde", - "stable_deref_trait", -] - [[package]] name = "try-lock" version = "0.2.5" @@ -5770,31 +5614,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "ui" -version = "0.1.0" -source = "git+https://github.com/lumehq/gpui-component#ca5232d1e7e66defe02271781ceadf2a81ed0e3d" -dependencies = [ - "anyhow", - "chrono", - "gpui", - "image", - "itertools 0.13.0", - "once_cell", - "paste", - "regex", - "resvg", - "rust-embed", - "rust-i18n", - "serde", - "serde_json", - "smallvec", - "smol", - "unicode-segmentation", - "usvg", - "uuid", -] - [[package]] name = "unicase" version = "2.8.0" @@ -6575,15 +6394,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - [[package]] name = "winnow" version = "0.6.20" @@ -6829,7 +6639,7 @@ dependencies = [ "tracing", "uds_windows", "windows-sys 0.59.0", - "winnow 0.6.20", + "winnow", "xdg-home", "zbus_macros 5.1.1", "zbus_names 4.1.0", @@ -6883,7 +6693,7 @@ checksum = "856b7a38811f71846fd47856ceee8bccaec8399ff53fb370247e66081ace647b" dependencies = [ "serde", "static_assertions", - "winnow 0.6.20", + "winnow", "zvariant 5.1.0", ] @@ -7025,7 +6835,7 @@ dependencies = [ "serde", "static_assertions", "url", - "winnow 0.6.20", + "winnow", "zvariant_derive 5.1.0", "zvariant_utils 3.0.2", ] @@ -7078,5 +6888,5 @@ dependencies = [ "serde", "static_assertions", "syn 2.0.90", - "winnow 0.6.20", + "winnow", ] diff --git a/Cargo.toml b/Cargo.toml index 9218e2f..f9f8599 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ coop = { path = "crates/*" } # UI gpui = { git = "https://github.com/zed-industries/zed" } reqwest_client = { git = "https://github.com/zed-industries/zed" } -components = { package = "ui", git = "https://github.com/lumehq/gpui-component" } # Nostr nostr-relay-builder = { git = "https://github.com/rust-nostr/nostr" } @@ -18,6 +17,7 @@ nostr-sdk = { git = "https://github.com/rust-nostr/nostr", features = [ "all-nips", ] } +smol = "1" tokio = { version = "1", features = ["full"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" @@ -28,6 +28,7 @@ chrono = "0.4.38" tracing = "0.1.40" anyhow = "1.0.44" smallvec = "1.13.2" +rust-embed = "8.5.0" keyring-search = "1.2.0" keyring = { version = "3", features = [ "apple-native", diff --git a/crates/.DS_Store b/crates/.DS_Store new file mode 100644 index 0000000..e7d927b Binary files /dev/null and b/crates/.DS_Store differ diff --git a/crates/app/Cargo.toml b/crates/app/Cargo.toml index 1069879..f9a2c6a 100644 --- a/crates/app/Cargo.toml +++ b/crates/app/Cargo.toml @@ -12,7 +12,6 @@ path = "src/main.rs" coop-ui = { path = "../ui" } gpui.workspace = true -components.workspace = true reqwest_client.workspace = true tokio.workspace = true @@ -25,7 +24,7 @@ serde_json.workspace = true itertools.workspace = true chrono.workspace = true dirs.workspace = true +rust-embed.workspace = true +smol.workspace = true tracing-subscriber = { version = "0.3.18", features = ["fmt"] } -rust-embed = "8.5.0" -smol = "1" diff --git a/crates/app/src/main.rs b/crates/app/src/main.rs index 89ec862..fb71539 100644 --- a/crates/app/src/main.rs +++ b/crates/app/src/main.rs @@ -1,5 +1,5 @@ use asset::Assets; -use components::Root; +use coop_ui::Root; use dirs::config_dir; use gpui::*; use nostr_sdk::prelude::*; @@ -76,7 +76,7 @@ async fn main() { AccountState::set_global(cx); // Initialize components - components::init(cx); + coop_ui::init(cx); // Set quit action cx.on_action(quit); diff --git a/crates/app/src/views/app.rs b/crates/app/src/views/app.rs index 69a8663..122b617 100644 --- a/crates/app/src/views/app.rs +++ b/crates/app/src/views/app.rs @@ -1,4 +1,4 @@ -use components::{ +use coop_ui::{ dock::{DockArea, DockItem, DockPlacement, PanelStyle}, theme::{ActiveTheme, Theme}, Root, TitleBar, diff --git a/crates/app/src/views/dock/chat/mod.rs b/crates/app/src/views/dock/chat/mod.rs index 7614497..f4960d5 100644 --- a/crates/app/src/views/dock/chat/mod.rs +++ b/crates/app/src/views/dock/chat/mod.rs @@ -1,4 +1,4 @@ -use components::{ +use coop_ui::{ button::Button, button_group::ButtonGroup, dock::{DockItemState, Panel, PanelEvent, TitleStyle}, diff --git a/crates/app/src/views/dock/inbox/chat.rs b/crates/app/src/views/dock/inbox/chat.rs index 47004b4..28e50cd 100644 --- a/crates/app/src/views/dock/inbox/chat.rs +++ b/crates/app/src/views/dock/inbox/chat.rs @@ -1,4 +1,4 @@ -use components::{theme::ActiveTheme, Collapsible, Selectable, StyledExt}; +use coop_ui::{theme::ActiveTheme, Collapsible, Selectable, StyledExt}; use gpui::*; use nostr_sdk::prelude::*; use prelude::FluentBuilder; diff --git a/crates/app/src/views/dock/inbox/mod.rs b/crates/app/src/views/dock/inbox/mod.rs index 004c657..33f7818 100644 --- a/crates/app/src/views/dock/inbox/mod.rs +++ b/crates/app/src/views/dock/inbox/mod.rs @@ -1,5 +1,5 @@ use chat::{Chat, ChatDelegate}; -use components::{theme::ActiveTheme, v_flex, StyledExt}; +use coop_ui::{theme::ActiveTheme, v_flex, StyledExt}; use gpui::*; use itertools::Itertools; use nostr_sdk::prelude::*; diff --git a/crates/app/src/views/dock/left_dock.rs b/crates/app/src/views/dock/left_dock.rs index 4fc75ae..13ea581 100644 --- a/crates/app/src/views/dock/left_dock.rs +++ b/crates/app/src/views/dock/left_dock.rs @@ -1,4 +1,4 @@ -use components::{ +use coop_ui::{ button::Button, dock::{DockItemState, Panel, PanelEvent, TitleStyle}, popup_menu::PopupMenu, diff --git a/crates/app/src/views/dock/welcome.rs b/crates/app/src/views/dock/welcome.rs index 3103a24..fce2478 100644 --- a/crates/app/src/views/dock/welcome.rs +++ b/crates/app/src/views/dock/welcome.rs @@ -1,4 +1,4 @@ -use components::{ +use coop_ui::{ button::Button, dock::{DockItemState, Panel, PanelEvent, TitleStyle}, popup_menu::PopupMenu, diff --git a/crates/app/src/views/onboarding.rs b/crates/app/src/views/onboarding.rs index 0c7f8cc..bd43333 100644 --- a/crates/app/src/views/onboarding.rs +++ b/crates/app/src/views/onboarding.rs @@ -1,5 +1,5 @@ use async_utility::task::spawn; -use components::{ +use coop_ui::{ input::{InputEvent, TextInput}, label::Label, }; @@ -17,7 +17,7 @@ impl Onboarding { pub fn new(cx: &mut ViewContext<'_, Self>) -> Self { let input = cx.new_view(|cx| { let mut input = TextInput::new(cx); - input.set_size(components::Size::Medium, cx); + input.set_size(coop_ui::Size::Medium, cx); input }); diff --git a/crates/ui/.DS_Store b/crates/ui/.DS_Store new file mode 100644 index 0000000..d7921e0 Binary files /dev/null and b/crates/ui/.DS_Store differ diff --git a/crates/ui/Cargo.toml b/crates/ui/Cargo.toml index 819f4a3..763b37d 100644 --- a/crates/ui/Cargo.toml +++ b/crates/ui/Cargo.toml @@ -6,4 +6,21 @@ publish = false [dependencies] gpui.workspace = true -components.workspace = true + +rust-embed.workspace = true +smol.workspace = true +serde.workspace = true +serde_json.workspace = true +smallvec.workspace = true +anyhow.workspace = true +itertools.workspace = true +chrono.workspace = true + +paste = "1" +regex = "1" +unicode-segmentation = "1.11.0" +uuid = "1.10" +once_cell = "1.19.0" +image = "0.25.1" +usvg = { version = "0.44.0", default-features = false, features = ["system-fonts", "text"] } +resvg = { version = "0.44.0", default-features = false, features = ["system-fonts", "text"] } diff --git a/crates/ui/LICENSE b/crates/ui/LICENSE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/crates/ui/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/crates/ui/README.md b/crates/ui/README.md new file mode 100644 index 0000000..e69de29 diff --git a/crates/ui/colors.json b/crates/ui/colors.json new file mode 100644 index 0000000..66d9f60 --- /dev/null +++ b/crates/ui/colors.json @@ -0,0 +1,2000 @@ +{ + "_doc": "https://github.com/shadcn-ui/ui/blob/main/apps/www/public/registry/colors/index.json", + "inherit": "inherit", + "current": "currentColor", + "transparent": "transparent", + "black": { + "hex": "#000000", + "rgb": "rgb(0,0,0)", + "hsl": "hsl(0,0%,0%)", + "rgbChannel": "0 0 0", + "hslChannel": "0 0% 0%" + }, + "white": { + "hex": "#ffffff", + "rgb": "rgb(255,255,255)", + "hsl": "hsl(0,0%,100%)", + "rgbChannel": "255 255 255", + "hslChannel": "0 0% 100%" + }, + "slate": [ + { + "scale": 50, + "hex": "#f8fafc", + "rgb": "rgb(248,250,252)", + "hsl": "hsl(210,40%,98%)", + "rgbChannel": "248 250 252", + "hslChannel": "210 40% 98%" + }, + { + "scale": 100, + "hex": "#f1f5f9", + "rgb": "rgb(241,245,249)", + "hsl": "hsl(210,40%,96.1%)", + "rgbChannel": "241 245 249", + "hslChannel": "210 40% 96.1%" + }, + { + "scale": 200, + "hex": "#e2e8f0", + "rgb": "rgb(226,232,240)", + "hsl": "hsl(214.3,31.8%,91.4%)", + "rgbChannel": "226 232 240", + "hslChannel": "214.3 31.8% 91.4%" + }, + { + "scale": 300, + "hex": "#cbd5e1", + "rgb": "rgb(203,213,225)", + "hsl": "hsl(212.7,26.8%,83.9%)", + "rgbChannel": "203 213 225", + "hslChannel": "212.7 26.8% 83.9%" + }, + { + "scale": 400, + "hex": "#94a3b8", + "rgb": "rgb(148,163,184)", + "hsl": "hsl(215,20.2%,65.1%)", + "rgbChannel": "148 163 184", + "hslChannel": "215 20.2% 65.1%" + }, + { + "scale": 500, + "hex": "#64748b", + "rgb": "rgb(100,116,139)", + "hsl": "hsl(215.4,16.3%,46.9%)", + "rgbChannel": "100 116 139", + "hslChannel": "215.4 16.3% 46.9%" + }, + { + "scale": 600, + "hex": "#475569", + "rgb": "rgb(71,85,105)", + "hsl": "hsl(215.3,19.3%,34.5%)", + "rgbChannel": "71 85 105", + "hslChannel": "215.3 19.3% 34.5%" + }, + { + "scale": 700, + "hex": "#334155", + "rgb": "rgb(51,65,85)", + "hsl": "hsl(215.3,25%,26.7%)", + "rgbChannel": "51 65 85", + "hslChannel": "215.3 25% 26.7%" + }, + { + "scale": 800, + "hex": "#1e293b", + "rgb": "rgb(30,41,59)", + "hsl": "hsl(217.2,32.6%,17.5%)", + "rgbChannel": "30 41 59", + "hslChannel": "217.2 32.6% 17.5%" + }, + { + "scale": 900, + "hex": "#0f172a", + "rgb": "rgb(15,23,42)", + "hsl": "hsl(222.2,47.4%,11.2%)", + "rgbChannel": "15 23 42", + "hslChannel": "222.2 47.4% 11.2%" + }, + { + "scale": 950, + "hex": "#020617", + "rgb": "rgb(2,6,23)", + "hsl": "hsl(222.2,84%,4.9%)", + "rgbChannel": "2 6 23", + "hslChannel": "222.2 84% 4.9%" + } + ], + "gray": [ + { + "scale": 50, + "hex": "#f9fafb", + "rgb": "rgb(249,250,251)", + "hsl": "hsl(210,20%,98%)", + "rgbChannel": "249 250 251", + "hslChannel": "210 20% 98%" + }, + { + "scale": 100, + "hex": "#f3f4f6", + "rgb": "rgb(243,244,246)", + "hsl": "hsl(220,14.3%,95.9%)", + "rgbChannel": "243 244 246", + "hslChannel": "220 14.3% 95.9%" + }, + { + "scale": 200, + "hex": "#e5e7eb", + "rgb": "rgb(229,231,235)", + "hsl": "hsl(220,13%,91%)", + "rgbChannel": "229 231 235", + "hslChannel": "220 13% 91%" + }, + { + "scale": 300, + "hex": "#d1d5db", + "rgb": "rgb(209,213,219)", + "hsl": "hsl(216,12.2%,83.9%)", + "rgbChannel": "209 213 219", + "hslChannel": "216 12.2% 83.9%" + }, + { + "scale": 400, + "hex": "#9ca3af", + "rgb": "rgb(156,163,175)", + "hsl": "hsl(217.9,10.6%,64.9%)", + "rgbChannel": "156 163 175", + "hslChannel": "217.9 10.6% 64.9%" + }, + { + "scale": 500, + "hex": "#6b7280", + "rgb": "rgb(107,114,128)", + "hsl": "hsl(220,8.9%,46.1%)", + "rgbChannel": "107 114 128", + "hslChannel": "220 8.9% 46.1%" + }, + { + "scale": 600, + "hex": "#4b5563", + "rgb": "rgb(75,85,99)", + "hsl": "hsl(215,13.8%,34.1%)", + "rgbChannel": "75 85 99", + "hslChannel": "215 13.8% 34.1%" + }, + { + "scale": 700, + "hex": "#374151", + "rgb": "rgb(55,65,81)", + "hsl": "hsl(216.9,19.1%,26.7%)", + "rgbChannel": "55 65 81", + "hslChannel": "216.9 19.1% 26.7%" + }, + { + "scale": 800, + "hex": "#1f2937", + "rgb": "rgb(31,41,55)", + "hsl": "hsl(215,27.9%,16.9%)", + "rgbChannel": "31 41 55", + "hslChannel": "215 27.9% 16.9%" + }, + { + "scale": 900, + "hex": "#111827", + "rgb": "rgb(17,24,39)", + "hsl": "hsl(220.9,39.3%,11%)", + "rgbChannel": "17 24 39", + "hslChannel": "220.9 39.3% 11%" + }, + { + "scale": 950, + "hex": "#030712", + "rgb": "rgb(3,7,18)", + "hsl": "hsl(224,71.4%,4.1%)", + "rgbChannel": "3 7 18", + "hslChannel": "224 71.4% 4.1%" + } + ], + "zinc": [ + { + "scale": 50, + "hex": "#fafafa", + "rgb": "rgb(250,250,250)", + "hsl": "hsl(0,0%,98%)", + "rgbChannel": "250 250 250", + "hslChannel": "0 0% 98%" + }, + { + "scale": 100, + "hex": "#f4f4f5", + "rgb": "rgb(244,244,245)", + "hsl": "hsl(240,4.8%,95.9%)", + "rgbChannel": "244 244 245", + "hslChannel": "240 4.8% 95.9%" + }, + { + "scale": 200, + "hex": "#e4e4e7", + "rgb": "rgb(228,228,231)", + "hsl": "hsl(240,5.9%,90%)", + "rgbChannel": "228 228 231", + "hslChannel": "240 5.9% 90%" + }, + { + "scale": 300, + "hex": "#d4d4d8", + "rgb": "rgb(212,212,216)", + "hsl": "hsl(240,4.9%,83.9%)", + "rgbChannel": "212 212 216", + "hslChannel": "240 4.9% 83.9%" + }, + { + "scale": 400, + "hex": "#a1a1aa", + "rgb": "rgb(161,161,170)", + "hsl": "hsl(240,5%,64.9%)", + "rgbChannel": "161 161 170", + "hslChannel": "240 5% 64.9%" + }, + { + "scale": 500, + "hex": "#71717a", + "rgb": "rgb(113,113,122)", + "hsl": "hsl(240,3.8%,46.1%)", + "rgbChannel": "113 113 122", + "hslChannel": "240 3.8% 46.1%" + }, + { + "scale": 600, + "hex": "#52525b", + "rgb": "rgb(82,82,91)", + "hsl": "hsl(240,5.2%,33.9%)", + "rgbChannel": "82 82 91", + "hslChannel": "240 5.2% 33.9%" + }, + { + "scale": 700, + "hex": "#3f3f46", + "rgb": "rgb(63,63,70)", + "hsl": "hsl(240,5.3%,26.1%)", + "rgbChannel": "63 63 70", + "hslChannel": "240 5.3% 26.1%" + }, + { + "scale": 800, + "hex": "#27272a", + "rgb": "rgb(39,39,42)", + "hsl": "hsl(240,3.7%,15.9%)", + "rgbChannel": "39 39 42", + "hslChannel": "240 3.7% 15.9%" + }, + { + "scale": 900, + "hex": "#18181b", + "rgb": "rgb(24,24,27)", + "hsl": "hsl(240,5.9%,10%)", + "rgbChannel": "24 24 27", + "hslChannel": "240 5.9% 10%" + }, + { + "scale": 950, + "hex": "#09090b", + "rgb": "rgb(9,9,11)", + "hsl": "hsl(240,10%,3.9%)", + "rgbChannel": "9 9 11", + "hslChannel": "240 10% 3.9%" + } + ], + "neutral": [ + { + "scale": 50, + "hex": "#fafafa", + "rgb": "rgb(250,250,250)", + "hsl": "hsl(0,0%,98%)", + "rgbChannel": "250 250 250", + "hslChannel": "0 0% 98%" + }, + { + "scale": 100, + "hex": "#f5f5f5", + "rgb": "rgb(245,245,245)", + "hsl": "hsl(0,0%,96.1%)", + "rgbChannel": "245 245 245", + "hslChannel": "0 0% 96.1%" + }, + { + "scale": 200, + "hex": "#e5e5e5", + "rgb": "rgb(229,229,229)", + "hsl": "hsl(0,0%,89.8%)", + "rgbChannel": "229 229 229", + "hslChannel": "0 0% 89.8%" + }, + { + "scale": 300, + "hex": "#d4d4d4", + "rgb": "rgb(212,212,212)", + "hsl": "hsl(0,0%,83.1%)", + "rgbChannel": "212 212 212", + "hslChannel": "0 0% 83.1%" + }, + { + "scale": 400, + "hex": "#a3a3a3", + "rgb": "rgb(163,163,163)", + "hsl": "hsl(0,0%,63.9%)", + "rgbChannel": "163 163 163", + "hslChannel": "0 0% 63.9%" + }, + { + "scale": 500, + "hex": "#737373", + "rgb": "rgb(115,115,115)", + "hsl": "hsl(0,0%,45.1%)", + "rgbChannel": "115 115 115", + "hslChannel": "0 0% 45.1%" + }, + { + "scale": 600, + "hex": "#525252", + "rgb": "rgb(82,82,82)", + "hsl": "hsl(0,0%,32.2%)", + "rgbChannel": "82 82 82", + "hslChannel": "0 0% 32.2%" + }, + { + "scale": 700, + "hex": "#404040", + "rgb": "rgb(64,64,64)", + "hsl": "hsl(0,0%,25.1%)", + "rgbChannel": "64 64 64", + "hslChannel": "0 0% 25.1%" + }, + { + "scale": 800, + "hex": "#262626", + "rgb": "rgb(38,38,38)", + "hsl": "hsl(0,0%,14.9%)", + "rgbChannel": "38 38 38", + "hslChannel": "0 0% 14.9%" + }, + { + "scale": 900, + "hex": "#171717", + "rgb": "rgb(23,23,23)", + "hsl": "hsl(0,0%,9%)", + "rgbChannel": "23 23 23", + "hslChannel": "0 0% 9%" + }, + { + "scale": 950, + "hex": "#0a0a0a", + "rgb": "rgb(10,10,10)", + "hsl": "hsl(0,0%,3.9%)", + "rgbChannel": "10 10 10", + "hslChannel": "0 0% 3.9%" + } + ], + "stone": [ + { + "scale": 50, + "hex": "#fafaf9", + "rgb": "rgb(250,250,249)", + "hsl": "hsl(60,9.1%,97.8%)", + "rgbChannel": "250 250 249", + "hslChannel": "60 9.1% 97.8%" + }, + { + "scale": 100, + "hex": "#f5f5f4", + "rgb": "rgb(245,245,244)", + "hsl": "hsl(60,4.8%,95.9%)", + "rgbChannel": "245 245 244", + "hslChannel": "60 4.8% 95.9%" + }, + { + "scale": 200, + "hex": "#e7e5e4", + "rgb": "rgb(231,229,228)", + "hsl": "hsl(20,5.9%,90%)", + "rgbChannel": "231 229 228", + "hslChannel": "20 5.9% 90%" + }, + { + "scale": 300, + "hex": "#d6d3d1", + "rgb": "rgb(214,211,209)", + "hsl": "hsl(24,5.7%,82.9%)", + "rgbChannel": "214 211 209", + "hslChannel": "24 5.7% 82.9%" + }, + { + "scale": 400, + "hex": "#a8a29e", + "rgb": "rgb(168,162,158)", + "hsl": "hsl(24,5.4%,63.9%)", + "rgbChannel": "168 162 158", + "hslChannel": "24 5.4% 63.9%" + }, + { + "scale": 500, + "hex": "#78716c", + "rgb": "rgb(120,113,108)", + "hsl": "hsl(25,5.3%,44.7%)", + "rgbChannel": "120 113 108", + "hslChannel": "25 5.3% 44.7%" + }, + { + "scale": 600, + "hex": "#57534e", + "rgb": "rgb(87,83,78)", + "hsl": "hsl(33.3,5.5%,32.4%)", + "rgbChannel": "87 83 78", + "hslChannel": "33.3 5.5% 32.4%" + }, + { + "scale": 700, + "hex": "#44403c", + "rgb": "rgb(68,64,60)", + "hsl": "hsl(30,6.3%,25.1%)", + "rgbChannel": "68 64 60", + "hslChannel": "30 6.3% 25.1%" + }, + { + "scale": 800, + "hex": "#292524", + "rgb": "rgb(41,37,36)", + "hsl": "hsl(12,6.5%,15.1%)", + "rgbChannel": "41 37 36", + "hslChannel": "12 6.5% 15.1%" + }, + { + "scale": 900, + "hex": "#1c1917", + "rgb": "rgb(28,25,23)", + "hsl": "hsl(24,9.8%,10%)", + "rgbChannel": "28 25 23", + "hslChannel": "24 9.8% 10%" + }, + { + "scale": 950, + "hex": "#0c0a09", + "rgb": "rgb(12,10,9)", + "hsl": "hsl(20,14.3%,4.1%)", + "rgbChannel": "12 10 9", + "hslChannel": "20 14.3% 4.1%" + } + ], + "red": [ + { + "scale": 50, + "hex": "#fef2f2", + "rgb": "rgb(254,242,242)", + "hsl": "hsl(0,85.7%,97.3%)", + "rgbChannel": "254 242 242", + "hslChannel": "0 85.7% 97.3%" + }, + { + "scale": 100, + "hex": "#fee2e2", + "rgb": "rgb(254,226,226)", + "hsl": "hsl(0,93.3%,94.1%)", + "rgbChannel": "254 226 226", + "hslChannel": "0 93.3% 94.1%" + }, + { + "scale": 200, + "hex": "#fecaca", + "rgb": "rgb(254,202,202)", + "hsl": "hsl(0,96.3%,89.4%)", + "rgbChannel": "254 202 202", + "hslChannel": "0 96.3% 89.4%" + }, + { + "scale": 300, + "hex": "#fca5a5", + "rgb": "rgb(252,165,165)", + "hsl": "hsl(0,93.5%,81.8%)", + "rgbChannel": "252 165 165", + "hslChannel": "0 93.5% 81.8%" + }, + { + "scale": 400, + "hex": "#f87171", + "rgb": "rgb(248,113,113)", + "hsl": "hsl(0,90.6%,70.8%)", + "rgbChannel": "248 113 113", + "hslChannel": "0 90.6% 70.8%" + }, + { + "scale": 500, + "hex": "#ef4444", + "rgb": "rgb(239,68,68)", + "hsl": "hsl(0,84.2%,60.2%)", + "rgbChannel": "239 68 68", + "hslChannel": "0 84.2% 60.2%" + }, + { + "scale": 600, + "hex": "#dc2626", + "rgb": "rgb(220,38,38)", + "hsl": "hsl(0,72.2%,50.6%)", + "rgbChannel": "220 38 38", + "hslChannel": "0 72.2% 50.6%" + }, + { + "scale": 700, + "hex": "#b91c1c", + "rgb": "rgb(185,28,28)", + "hsl": "hsl(0,73.7%,41.8%)", + "rgbChannel": "185 28 28", + "hslChannel": "0 73.7% 41.8%" + }, + { + "scale": 800, + "hex": "#991b1b", + "rgb": "rgb(153,27,27)", + "hsl": "hsl(0,70%,35.3%)", + "rgbChannel": "153 27 27", + "hslChannel": "0 70% 35.3%" + }, + { + "scale": 900, + "hex": "#7f1d1d", + "rgb": "rgb(127,29,29)", + "hsl": "hsl(0,62.8%,30.6%)", + "rgbChannel": "127 29 29", + "hslChannel": "0 62.8% 30.6%" + }, + { + "scale": 950, + "hex": "#450a0a", + "rgb": "rgb(69,10,10)", + "hsl": "hsl(0,74.7%,15.5%)", + "rgbChannel": "69 10 10", + "hslChannel": "0 74.7% 15.5%" + } + ], + "orange": [ + { + "scale": 50, + "hex": "#fff7ed", + "rgb": "rgb(255,247,237)", + "hsl": "hsl(33.3,100%,96.5%)", + "rgbChannel": "255 247 237", + "hslChannel": "33.3 100% 96.5%" + }, + { + "scale": 100, + "hex": "#ffedd5", + "rgb": "rgb(255,237,213)", + "hsl": "hsl(34.3,100%,91.8%)", + "rgbChannel": "255 237 213", + "hslChannel": "34.3 100% 91.8%" + }, + { + "scale": 200, + "hex": "#fed7aa", + "rgb": "rgb(254,215,170)", + "hsl": "hsl(32.1,97.7%,83.1%)", + "rgbChannel": "254 215 170", + "hslChannel": "32.1 97.7% 83.1%" + }, + { + "scale": 300, + "hex": "#fdba74", + "rgb": "rgb(253,186,116)", + "hsl": "hsl(30.7,97.2%,72.4%)", + "rgbChannel": "253 186 116", + "hslChannel": "30.7 97.2% 72.4%" + }, + { + "scale": 400, + "hex": "#fb923c", + "rgb": "rgb(251,146,60)", + "hsl": "hsl(27,96%,61%)", + "rgbChannel": "251 146 60", + "hslChannel": "27 96% 61%" + }, + { + "scale": 500, + "hex": "#f97316", + "rgb": "rgb(249,115,22)", + "hsl": "hsl(24.6,95%,53.1%)", + "rgbChannel": "249 115 22", + "hslChannel": "24.6 95% 53.1%" + }, + { + "scale": 600, + "hex": "#ea580c", + "rgb": "rgb(234,88,12)", + "hsl": "hsl(20.5,90.2%,48.2%)", + "rgbChannel": "234 88 12", + "hslChannel": "20.5 90.2% 48.2%" + }, + { + "scale": 700, + "hex": "#c2410c", + "rgb": "rgb(194,65,12)", + "hsl": "hsl(17.5,88.3%,40.4%)", + "rgbChannel": "194 65 12", + "hslChannel": "17.5 88.3% 40.4%" + }, + { + "scale": 800, + "hex": "#9a3412", + "rgb": "rgb(154,52,18)", + "hsl": "hsl(15,79.1%,33.7%)", + "rgbChannel": "154 52 18", + "hslChannel": "15 79.1% 33.7%" + }, + { + "scale": 900, + "hex": "#7c2d12", + "rgb": "rgb(124,45,18)", + "hsl": "hsl(15.3,74.6%,27.8%)", + "rgbChannel": "124 45 18", + "hslChannel": "15.3 74.6% 27.8%" + }, + { + "scale": 950, + "hex": "#431407", + "rgb": "rgb(67,20,7)", + "hsl": "hsl(13,81.1%,14.5%)", + "rgbChannel": "67 20 7", + "hslChannel": "13 81.1% 14.5%" + } + ], + "amber": [ + { + "scale": 50, + "hex": "#fffbeb", + "rgb": "rgb(255,251,235)", + "hsl": "hsl(48,100%,96.1%)", + "rgbChannel": "255 251 235", + "hslChannel": "48 100% 96.1%" + }, + { + "scale": 100, + "hex": "#fef3c7", + "rgb": "rgb(254,243,199)", + "hsl": "hsl(48,96.5%,88.8%)", + "rgbChannel": "254 243 199", + "hslChannel": "48 96.5% 88.8%" + }, + { + "scale": 200, + "hex": "#fde68a", + "rgb": "rgb(253,230,138)", + "hsl": "hsl(48,96.6%,76.7%)", + "rgbChannel": "253 230 138", + "hslChannel": "48 96.6% 76.7%" + }, + { + "scale": 300, + "hex": "#fcd34d", + "rgb": "rgb(252,211,77)", + "hsl": "hsl(45.9,96.7%,64.5%)", + "rgbChannel": "252 211 77", + "hslChannel": "45.9 96.7% 64.5%" + }, + { + "scale": 400, + "hex": "#fbbf24", + "rgb": "rgb(251,191,36)", + "hsl": "hsl(43.3,96.4%,56.3%)", + "rgbChannel": "251 191 36", + "hslChannel": "43.3 96.4% 56.3%" + }, + { + "scale": 500, + "hex": "#f59e0b", + "rgb": "rgb(245,158,11)", + "hsl": "hsl(37.7,92.1%,50.2%)", + "rgbChannel": "245 158 11", + "hslChannel": "37.7 92.1% 50.2%" + }, + { + "scale": 600, + "hex": "#d97706", + "rgb": "rgb(217,119,6)", + "hsl": "hsl(32.1,94.6%,43.7%)", + "rgbChannel": "217 119 6", + "hslChannel": "32.1 94.6% 43.7%" + }, + { + "scale": 700, + "hex": "#b45309", + "rgb": "rgb(180,83,9)", + "hsl": "hsl(26,90.5%,37.1%)", + "rgbChannel": "180 83 9", + "hslChannel": "26 90.5% 37.1%" + }, + { + "scale": 800, + "hex": "#92400e", + "rgb": "rgb(146,64,14)", + "hsl": "hsl(22.7,82.5%,31.4%)", + "rgbChannel": "146 64 14", + "hslChannel": "22.7 82.5% 31.4%" + }, + { + "scale": 900, + "hex": "#78350f", + "rgb": "rgb(120,53,15)", + "hsl": "hsl(21.7,77.8%,26.5%)", + "rgbChannel": "120 53 15", + "hslChannel": "21.7 77.8% 26.5%" + }, + { + "scale": 950, + "hex": "#451a03", + "rgb": "rgb(69,26,3)", + "hsl": "hsl(20.9,91.7%,14.1%)", + "rgbChannel": "69 26 3", + "hslChannel": "20.9 91.7% 14.1%" + } + ], + "yellow": [ + { + "scale": 50, + "hex": "#fefce8", + "rgb": "rgb(254,252,232)", + "hsl": "hsl(54.5,91.7%,95.3%)", + "rgbChannel": "254 252 232", + "hslChannel": "54.5 91.7% 95.3%" + }, + { + "scale": 100, + "hex": "#fef9c3", + "rgb": "rgb(254,249,195)", + "hsl": "hsl(54.9,96.7%,88%)", + "rgbChannel": "254 249 195", + "hslChannel": "54.9 96.7% 88%" + }, + { + "scale": 200, + "hex": "#fef08a", + "rgb": "rgb(254,240,138)", + "hsl": "hsl(52.8,98.3%,76.9%)", + "rgbChannel": "254 240 138", + "hslChannel": "52.8 98.3% 76.9%" + }, + { + "scale": 300, + "hex": "#fde047", + "rgb": "rgb(253,224,71)", + "hsl": "hsl(50.4,97.8%,63.5%)", + "rgbChannel": "253 224 71", + "hslChannel": "50.4 97.8% 63.5%" + }, + { + "scale": 400, + "hex": "#facc15", + "rgb": "rgb(250,204,21)", + "hsl": "hsl(47.9,95.8%,53.1%)", + "rgbChannel": "250 204 21", + "hslChannel": "47.9 95.8% 53.1%" + }, + { + "scale": 500, + "hex": "#eab308", + "rgb": "rgb(234,179,8)", + "hsl": "hsl(45.4,93.4%,47.5%)", + "rgbChannel": "234 179 8", + "hslChannel": "45.4 93.4% 47.5%" + }, + { + "scale": 600, + "hex": "#ca8a04", + "rgb": "rgb(202,138,4)", + "hsl": "hsl(40.6,96.1%,40.4%)", + "rgbChannel": "202 138 4", + "hslChannel": "40.6 96.1% 40.4%" + }, + { + "scale": 700, + "hex": "#a16207", + "rgb": "rgb(161,98,7)", + "hsl": "hsl(35.5,91.7%,32.9%)", + "rgbChannel": "161 98 7", + "hslChannel": "35.5 91.7% 32.9%" + }, + { + "scale": 800, + "hex": "#854d0e", + "rgb": "rgb(133,77,14)", + "hsl": "hsl(31.8,81%,28.8%)", + "rgbChannel": "133 77 14", + "hslChannel": "31.8 81% 28.8%" + }, + { + "scale": 900, + "hex": "#713f12", + "rgb": "rgb(113,63,18)", + "hsl": "hsl(28.4,72.5%,25.7%)", + "rgbChannel": "113 63 18", + "hslChannel": "28.4 72.5% 25.7%" + }, + { + "scale": 950, + "hex": "#422006", + "rgb": "rgb(66,32,6)", + "hsl": "hsl(26,83.3%,14.1%)", + "rgbChannel": "66 32 6", + "hslChannel": "26 83.3% 14.1%" + } + ], + "lime": [ + { + "scale": 50, + "hex": "#f7fee7", + "rgb": "rgb(247,254,231)", + "hsl": "hsl(78.3,92%,95.1%)", + "rgbChannel": "247 254 231", + "hslChannel": "78.3 92% 95.1%" + }, + { + "scale": 100, + "hex": "#ecfccb", + "rgb": "rgb(236,252,203)", + "hsl": "hsl(79.6,89.1%,89.2%)", + "rgbChannel": "236 252 203", + "hslChannel": "79.6 89.1% 89.2%" + }, + { + "scale": 200, + "hex": "#d9f99d", + "rgb": "rgb(217,249,157)", + "hsl": "hsl(80.9,88.5%,79.6%)", + "rgbChannel": "217 249 157", + "hslChannel": "80.9 88.5% 79.6%" + }, + { + "scale": 300, + "hex": "#bef264", + "rgb": "rgb(190,242,100)", + "hsl": "hsl(82,84.5%,67.1%)", + "rgbChannel": "190 242 100", + "hslChannel": "82 84.5% 67.1%" + }, + { + "scale": 400, + "hex": "#a3e635", + "rgb": "rgb(163,230,53)", + "hsl": "hsl(82.7,78%,55.5%)", + "rgbChannel": "163 230 53", + "hslChannel": "82.7 78% 55.5%" + }, + { + "scale": 500, + "hex": "#84cc16", + "rgb": "rgb(132,204,22)", + "hsl": "hsl(83.7,80.5%,44.3%)", + "rgbChannel": "132 204 22", + "hslChannel": "83.7 80.5% 44.3%" + }, + { + "scale": 600, + "hex": "#65a30d", + "rgb": "rgb(101,163,13)", + "hsl": "hsl(84.8,85.2%,34.5%)", + "rgbChannel": "101 163 13", + "hslChannel": "84.8 85.2% 34.5%" + }, + { + "scale": 700, + "hex": "#4d7c0f", + "rgb": "rgb(77,124,15)", + "hsl": "hsl(85.9,78.4%,27.3%)", + "rgbChannel": "77 124 15", + "hslChannel": "85.9 78.4% 27.3%" + }, + { + "scale": 800, + "hex": "#3f6212", + "rgb": "rgb(63,98,18)", + "hsl": "hsl(86.3,69%,22.7%)", + "rgbChannel": "63 98 18", + "hslChannel": "86.3 69% 22.7%" + }, + { + "scale": 900, + "hex": "#365314", + "rgb": "rgb(54,83,20)", + "hsl": "hsl(87.6,61.2%,20.2%)", + "rgbChannel": "54 83 20", + "hslChannel": "87.6 61.2% 20.2%" + }, + { + "scale": 950, + "hex": "#1a2e05", + "rgb": "rgb(26,46,5)", + "hsl": "hsl(89.3,80.4%,10%)", + "rgbChannel": "26 46 5", + "hslChannel": "89.3 80.4% 10%" + } + ], + "green": [ + { + "scale": 50, + "hex": "#f0fdf4", + "rgb": "rgb(240,253,244)", + "hsl": "hsl(138.5,76.5%,96.7%)", + "rgbChannel": "240 253 244", + "hslChannel": "138.5 76.5% 96.7%" + }, + { + "scale": 100, + "hex": "#dcfce7", + "rgb": "rgb(220,252,231)", + "hsl": "hsl(140.6,84.2%,92.5%)", + "rgbChannel": "220 252 231", + "hslChannel": "140.6 84.2% 92.5%" + }, + { + "scale": 200, + "hex": "#bbf7d0", + "rgb": "rgb(187,247,208)", + "hsl": "hsl(141,78.9%,85.1%)", + "rgbChannel": "187 247 208", + "hslChannel": "141 78.9% 85.1%" + }, + { + "scale": 300, + "hex": "#86efac", + "rgb": "rgb(134,239,172)", + "hsl": "hsl(141.7,76.6%,73.1%)", + "rgbChannel": "134 239 172", + "hslChannel": "141.7 76.6% 73.1%" + }, + { + "scale": 400, + "hex": "#4ade80", + "rgb": "rgb(74,222,128)", + "hsl": "hsl(141.9,69.2%,58%)", + "rgbChannel": "74 222 128", + "hslChannel": "141.9 69.2% 58%" + }, + { + "scale": 500, + "hex": "#22c55e", + "rgb": "rgb(34,197,94)", + "hsl": "hsl(142.1,70.6%,45.3%)", + "rgbChannel": "34 197 94", + "hslChannel": "142.1 70.6% 45.3%" + }, + { + "scale": 600, + "hex": "#16a34a", + "rgb": "rgb(22,163,74)", + "hsl": "hsl(142.1,76.2%,36.3%)", + "rgbChannel": "22 163 74", + "hslChannel": "142.1 76.2% 36.3%" + }, + { + "scale": 700, + "hex": "#15803d", + "rgb": "rgb(21,128,61)", + "hsl": "hsl(142.4,71.8%,29.2%)", + "rgbChannel": "21 128 61", + "hslChannel": "142.4 71.8% 29.2%" + }, + { + "scale": 800, + "hex": "#166534", + "rgb": "rgb(22,101,52)", + "hsl": "hsl(142.8,64.2%,24.1%)", + "rgbChannel": "22 101 52", + "hslChannel": "142.8 64.2% 24.1%" + }, + { + "scale": 900, + "hex": "#14532d", + "rgb": "rgb(20,83,45)", + "hsl": "hsl(143.8,61.2%,20.2%)", + "rgbChannel": "20 83 45", + "hslChannel": "143.8 61.2% 20.2%" + }, + { + "scale": 950, + "hex": "#052e16", + "rgb": "rgb(5,46,22)", + "hsl": "hsl(144.9,80.4%,10%)", + "rgbChannel": "5 46 22", + "hslChannel": "144.9 80.4% 10%" + } + ], + "emerald": [ + { + "scale": 50, + "hex": "#ecfdf5", + "rgb": "rgb(236,253,245)", + "hsl": "hsl(151.8,81%,95.9%)", + "rgbChannel": "236 253 245", + "hslChannel": "151.8 81% 95.9%" + }, + { + "scale": 100, + "hex": "#d1fae5", + "rgb": "rgb(209,250,229)", + "hsl": "hsl(149.3,80.4%,90%)", + "rgbChannel": "209 250 229", + "hslChannel": "149.3 80.4% 90%" + }, + { + "scale": 200, + "hex": "#a7f3d0", + "rgb": "rgb(167,243,208)", + "hsl": "hsl(152.4,76%,80.4%)", + "rgbChannel": "167 243 208", + "hslChannel": "152.4 76% 80.4%" + }, + { + "scale": 300, + "hex": "#6ee7b7", + "rgb": "rgb(110,231,183)", + "hsl": "hsl(156.2,71.6%,66.9%)", + "rgbChannel": "110 231 183", + "hslChannel": "156.2 71.6% 66.9%" + }, + { + "scale": 400, + "hex": "#34d399", + "rgb": "rgb(52,211,153)", + "hsl": "hsl(158.1,64.4%,51.6%)", + "rgbChannel": "52 211 153", + "hslChannel": "158.1 64.4% 51.6%" + }, + { + "scale": 500, + "hex": "#10b981", + "rgb": "rgb(16,185,129)", + "hsl": "hsl(160.1,84.1%,39.4%)", + "rgbChannel": "16 185 129", + "hslChannel": "160.1 84.1% 39.4%" + }, + { + "scale": 600, + "hex": "#059669", + "rgb": "rgb(5,150,105)", + "hsl": "hsl(161.4,93.5%,30.4%)", + "rgbChannel": "5 150 105", + "hslChannel": "161.4 93.5% 30.4%" + }, + { + "scale": 700, + "hex": "#047857", + "rgb": "rgb(4,120,87)", + "hsl": "hsl(162.9,93.5%,24.3%)", + "rgbChannel": "4 120 87", + "hslChannel": "162.9 93.5% 24.3%" + }, + { + "scale": 800, + "hex": "#065f46", + "rgb": "rgb(6,95,70)", + "hsl": "hsl(163.1,88.1%,19.8%)", + "rgbChannel": "6 95 70", + "hslChannel": "163.1 88.1% 19.8%" + }, + { + "scale": 900, + "hex": "#064e3b", + "rgb": "rgb(6,78,59)", + "hsl": "hsl(164.2,85.7%,16.5%)", + "rgbChannel": "6 78 59", + "hslChannel": "164.2 85.7% 16.5%" + }, + { + "scale": 950, + "hex": "#022c22", + "rgb": "rgb(2,44,34)", + "hsl": "hsl(165.7,91.3%,9%)", + "rgbChannel": "2 44 34", + "hslChannel": "165.7 91.3% 9%" + } + ], + "teal": [ + { + "scale": 50, + "hex": "#f0fdfa", + "rgb": "rgb(240,253,250)", + "hsl": "hsl(166.2,76.5%,96.7%)", + "rgbChannel": "240 253 250", + "hslChannel": "166.2 76.5% 96.7%" + }, + { + "scale": 100, + "hex": "#ccfbf1", + "rgb": "rgb(204,251,241)", + "hsl": "hsl(167.2,85.5%,89.2%)", + "rgbChannel": "204 251 241", + "hslChannel": "167.2 85.5% 89.2%" + }, + { + "scale": 200, + "hex": "#99f6e4", + "rgb": "rgb(153,246,228)", + "hsl": "hsl(168.4,83.8%,78.2%)", + "rgbChannel": "153 246 228", + "hslChannel": "168.4 83.8% 78.2%" + }, + { + "scale": 300, + "hex": "#5eead4", + "rgb": "rgb(94,234,212)", + "hsl": "hsl(170.6,76.9%,64.3%)", + "rgbChannel": "94 234 212", + "hslChannel": "170.6 76.9% 64.3%" + }, + { + "scale": 400, + "hex": "#2dd4bf", + "rgb": "rgb(45,212,191)", + "hsl": "hsl(172.5,66%,50.4%)", + "rgbChannel": "45 212 191", + "hslChannel": "172.5 66% 50.4%" + }, + { + "scale": 500, + "hex": "#14b8a6", + "rgb": "rgb(20,184,166)", + "hsl": "hsl(173.4,80.4%,40%)", + "rgbChannel": "20 184 166", + "hslChannel": "173.4 80.4% 40%" + }, + { + "scale": 600, + "hex": "#0d9488", + "rgb": "rgb(13,148,136)", + "hsl": "hsl(174.7,83.9%,31.6%)", + "rgbChannel": "13 148 136", + "hslChannel": "174.7 83.9% 31.6%" + }, + { + "scale": 700, + "hex": "#0f766e", + "rgb": "rgb(15,118,110)", + "hsl": "hsl(175.3,77.4%,26.1%)", + "rgbChannel": "15 118 110", + "hslChannel": "175.3 77.4% 26.1%" + }, + { + "scale": 800, + "hex": "#115e59", + "rgb": "rgb(17,94,89)", + "hsl": "hsl(176.1,69.4%,21.8%)", + "rgbChannel": "17 94 89", + "hslChannel": "176.1 69.4% 21.8%" + }, + { + "scale": 900, + "hex": "#134e4a", + "rgb": "rgb(19,78,74)", + "hsl": "hsl(175.9,60.8%,19%)", + "rgbChannel": "19 78 74", + "hslChannel": "175.9 60.8% 19%" + }, + { + "scale": 950, + "hex": "#042f2e", + "rgb": "rgb(4,47,46)", + "hsl": "hsl(178.6,84.3%,10%)", + "rgbChannel": "4 47 46", + "hslChannel": "178.6 84.3% 10%" + } + ], + "cyan": [ + { + "scale": 50, + "hex": "#ecfeff", + "rgb": "rgb(236,254,255)", + "hsl": "hsl(183.2,100%,96.3%)", + "rgbChannel": "236 254 255", + "hslChannel": "183.2 100% 96.3%" + }, + { + "scale": 100, + "hex": "#cffafe", + "rgb": "rgb(207,250,254)", + "hsl": "hsl(185.1,95.9%,90.4%)", + "rgbChannel": "207 250 254", + "hslChannel": "185.1 95.9% 90.4%" + }, + { + "scale": 200, + "hex": "#a5f3fc", + "rgb": "rgb(165,243,252)", + "hsl": "hsl(186.2,93.5%,81.8%)", + "rgbChannel": "165 243 252", + "hslChannel": "186.2 93.5% 81.8%" + }, + { + "scale": 300, + "hex": "#67e8f9", + "rgb": "rgb(103,232,249)", + "hsl": "hsl(187,92.4%,69%)", + "rgbChannel": "103 232 249", + "hslChannel": "187 92.4% 69%" + }, + { + "scale": 400, + "hex": "#22d3ee", + "rgb": "rgb(34,211,238)", + "hsl": "hsl(187.9,85.7%,53.3%)", + "rgbChannel": "34 211 238", + "hslChannel": "187.9 85.7% 53.3%" + }, + { + "scale": 500, + "hex": "#06b6d4", + "rgb": "rgb(6,182,212)", + "hsl": "hsl(188.7,94.5%,42.7%)", + "rgbChannel": "6 182 212", + "hslChannel": "188.7 94.5% 42.7%" + }, + { + "scale": 600, + "hex": "#0891b2", + "rgb": "rgb(8,145,178)", + "hsl": "hsl(191.6,91.4%,36.5%)", + "rgbChannel": "8 145 178", + "hslChannel": "191.6 91.4% 36.5%" + }, + { + "scale": 700, + "hex": "#0e7490", + "rgb": "rgb(14,116,144)", + "hsl": "hsl(192.9,82.3%,31%)", + "rgbChannel": "14 116 144", + "hslChannel": "192.9 82.3% 31%" + }, + { + "scale": 800, + "hex": "#155e75", + "rgb": "rgb(21,94,117)", + "hsl": "hsl(194.4,69.6%,27.1%)", + "rgbChannel": "21 94 117", + "hslChannel": "194.4 69.6% 27.1%" + }, + { + "scale": 900, + "hex": "#164e63", + "rgb": "rgb(22,78,99)", + "hsl": "hsl(196.4,63.6%,23.7%)", + "rgbChannel": "22 78 99", + "hslChannel": "196.4 63.6% 23.7%" + }, + { + "scale": 950, + "hex": "#083344", + "rgb": "rgb(8,51,68)", + "hsl": "hsl(197,78.9%,14.9%)", + "rgbChannel": "8 51 68", + "hslChannel": "197 78.9% 14.9%" + } + ], + "sky": [ + { + "scale": 50, + "hex": "#f0f9ff", + "rgb": "rgb(240,249,255)", + "hsl": "hsl(204,100%,97.1%)", + "rgbChannel": "240 249 255", + "hslChannel": "204 100% 97.1%" + }, + { + "scale": 100, + "hex": "#e0f2fe", + "rgb": "rgb(224,242,254)", + "hsl": "hsl(204,93.8%,93.7%)", + "rgbChannel": "224 242 254", + "hslChannel": "204 93.8% 93.7%" + }, + { + "scale": 200, + "hex": "#bae6fd", + "rgb": "rgb(186,230,253)", + "hsl": "hsl(200.6,94.4%,86.1%)", + "rgbChannel": "186 230 253", + "hslChannel": "200.6 94.4% 86.1%" + }, + { + "scale": 300, + "hex": "#7dd3fc", + "rgb": "rgb(125,211,252)", + "hsl": "hsl(199.4,95.5%,73.9%)", + "rgbChannel": "125 211 252", + "hslChannel": "199.4 95.5% 73.9%" + }, + { + "scale": 400, + "hex": "#38bdf8", + "rgb": "rgb(56,189,248)", + "hsl": "hsl(198.4,93.2%,59.6%)", + "rgbChannel": "56 189 248", + "hslChannel": "198.4 93.2% 59.6%" + }, + { + "scale": 500, + "hex": "#0ea5e9", + "rgb": "rgb(14,165,233)", + "hsl": "hsl(198.6,88.7%,48.4%)", + "rgbChannel": "14 165 233", + "hslChannel": "198.6 88.7% 48.4%" + }, + { + "scale": 600, + "hex": "#0284c7", + "rgb": "rgb(2,132,199)", + "hsl": "hsl(200.4,98%,39.4%)", + "rgbChannel": "2 132 199", + "hslChannel": "200.4 98% 39.4%" + }, + { + "scale": 700, + "hex": "#0369a1", + "rgb": "rgb(3,105,161)", + "hsl": "hsl(201.3,96.3%,32.2%)", + "rgbChannel": "3 105 161", + "hslChannel": "201.3 96.3% 32.2%" + }, + { + "scale": 800, + "hex": "#075985", + "rgb": "rgb(7,89,133)", + "hsl": "hsl(201,90%,27.5%)", + "rgbChannel": "7 89 133", + "hslChannel": "201 90% 27.5%" + }, + { + "scale": 900, + "hex": "#0c4a6e", + "rgb": "rgb(12,74,110)", + "hsl": "hsl(202,80.3%,23.9%)", + "rgbChannel": "12 74 110", + "hslChannel": "202 80.3% 23.9%" + }, + { + "scale": 950, + "hex": "#082f49", + "rgb": "rgb(8,47,73)", + "hsl": "hsl(204,80.2%,15.9%)", + "rgbChannel": "8 47 73", + "hslChannel": "204 80.2% 15.9%" + } + ], + "blue": [ + { + "scale": 50, + "hex": "#eff6ff", + "rgb": "rgb(239,246,255)", + "hsl": "hsl(213.8,100%,96.9%)", + "rgbChannel": "239 246 255", + "hslChannel": "213.8 100% 96.9%" + }, + { + "scale": 100, + "hex": "#dbeafe", + "rgb": "rgb(219,234,254)", + "hsl": "hsl(214.3,94.6%,92.7%)", + "rgbChannel": "219 234 254", + "hslChannel": "214.3 94.6% 92.7%" + }, + { + "scale": 200, + "hex": "#bfdbfe", + "rgb": "rgb(191,219,254)", + "hsl": "hsl(213.3,96.9%,87.3%)", + "rgbChannel": "191 219 254", + "hslChannel": "213.3 96.9% 87.3%" + }, + { + "scale": 300, + "hex": "#93c5fd", + "rgb": "rgb(147,197,253)", + "hsl": "hsl(211.7,96.4%,78.4%)", + "rgbChannel": "147 197 253", + "hslChannel": "211.7 96.4% 78.4%" + }, + { + "scale": 400, + "hex": "#60a5fa", + "rgb": "rgb(96,165,250)", + "hsl": "hsl(213.1,93.9%,67.8%)", + "rgbChannel": "96 165 250", + "hslChannel": "213.1 93.9% 67.8%" + }, + { + "scale": 500, + "hex": "#3b82f6", + "rgb": "rgb(59,130,246)", + "hsl": "hsl(217.2,91.2%,59.8%)", + "rgbChannel": "59 130 246", + "hslChannel": "217.2 91.2% 59.8%" + }, + { + "scale": 600, + "hex": "#2563eb", + "rgb": "rgb(37,99,235)", + "hsl": "hsl(221.2,83.2%,53.3%)", + "rgbChannel": "37 99 235", + "hslChannel": "221.2 83.2% 53.3%" + }, + { + "scale": 700, + "hex": "#1d4ed8", + "rgb": "rgb(29,78,216)", + "hsl": "hsl(224.3,76.3%,48%)", + "rgbChannel": "29 78 216", + "hslChannel": "224.3 76.3% 48%" + }, + { + "scale": 800, + "hex": "#1e40af", + "rgb": "rgb(30,64,175)", + "hsl": "hsl(225.9,70.7%,40.2%)", + "rgbChannel": "30 64 175", + "hslChannel": "225.9 70.7% 40.2%" + }, + { + "scale": 900, + "hex": "#1e3a8a", + "rgb": "rgb(30,58,138)", + "hsl": "hsl(224.4,64.3%,32.9%)", + "rgbChannel": "30 58 138", + "hslChannel": "224.4 64.3% 32.9%" + }, + { + "scale": 950, + "hex": "#172554", + "rgb": "rgb(23,37,84)", + "hsl": "hsl(226.2,57%,21%)", + "rgbChannel": "23 37 84", + "hslChannel": "226.2 57% 21%" + } + ], + "indigo": [ + { + "scale": 50, + "hex": "#eef2ff", + "rgb": "rgb(238,242,255)", + "hsl": "hsl(225.9,100%,96.7%)", + "rgbChannel": "238 242 255", + "hslChannel": "225.9 100% 96.7%" + }, + { + "scale": 100, + "hex": "#e0e7ff", + "rgb": "rgb(224,231,255)", + "hsl": "hsl(226.5,100%,93.9%)", + "rgbChannel": "224 231 255", + "hslChannel": "226.5 100% 93.9%" + }, + { + "scale": 200, + "hex": "#c7d2fe", + "rgb": "rgb(199,210,254)", + "hsl": "hsl(228,96.5%,88.8%)", + "rgbChannel": "199 210 254", + "hslChannel": "228 96.5% 88.8%" + }, + { + "scale": 300, + "hex": "#a5b4fc", + "rgb": "rgb(165,180,252)", + "hsl": "hsl(229.7,93.5%,81.8%)", + "rgbChannel": "165 180 252", + "hslChannel": "229.7 93.5% 81.8%" + }, + { + "scale": 400, + "hex": "#818cf8", + "rgb": "rgb(129,140,248)", + "hsl": "hsl(234.5,89.5%,73.9%)", + "rgbChannel": "129 140 248", + "hslChannel": "234.5 89.5% 73.9%" + }, + { + "scale": 500, + "hex": "#6366f1", + "rgb": "rgb(99,102,241)", + "hsl": "hsl(238.7,83.5%,66.7%)", + "rgbChannel": "99 102 241", + "hslChannel": "238.7 83.5% 66.7%" + }, + { + "scale": 600, + "hex": "#4f46e5", + "rgb": "rgb(79,70,229)", + "hsl": "hsl(243.4,75.4%,58.6%)", + "rgbChannel": "79 70 229", + "hslChannel": "243.4 75.4% 58.6%" + }, + { + "scale": 700, + "hex": "#4338ca", + "rgb": "rgb(67,56,202)", + "hsl": "hsl(244.5,57.9%,50.6%)", + "rgbChannel": "67 56 202", + "hslChannel": "244.5 57.9% 50.6%" + }, + { + "scale": 800, + "hex": "#3730a3", + "rgb": "rgb(55,48,163)", + "hsl": "hsl(243.7,54.5%,41.4%)", + "rgbChannel": "55 48 163", + "hslChannel": "243.7 54.5% 41.4%" + }, + { + "scale": 900, + "hex": "#312e81", + "rgb": "rgb(49,46,129)", + "hsl": "hsl(242.2,47.4%,34.3%)", + "rgbChannel": "49 46 129", + "hslChannel": "242.2 47.4% 34.3%" + }, + { + "scale": 950, + "hex": "#1e1b4b", + "rgb": "rgb(30,27,75)", + "hsl": "hsl(243.8,47.1%,20%)", + "rgbChannel": "30 27 75", + "hslChannel": "243.8 47.1% 20%" + } + ], + "violet": [ + { + "scale": 50, + "hex": "#f5f3ff", + "rgb": "rgb(245,243,255)", + "hsl": "hsl(250,100%,97.6%)", + "rgbChannel": "245 243 255", + "hslChannel": "250 100% 97.6%" + }, + { + "scale": 100, + "hex": "#ede9fe", + "rgb": "rgb(237,233,254)", + "hsl": "hsl(251.4,91.3%,95.5%)", + "rgbChannel": "237 233 254", + "hslChannel": "251.4 91.3% 95.5%" + }, + { + "scale": 200, + "hex": "#ddd6fe", + "rgb": "rgb(221,214,254)", + "hsl": "hsl(250.5,95.2%,91.8%)", + "rgbChannel": "221 214 254", + "hslChannel": "250.5 95.2% 91.8%" + }, + { + "scale": 300, + "hex": "#c4b5fd", + "rgb": "rgb(196,181,253)", + "hsl": "hsl(252.5,94.7%,85.1%)", + "rgbChannel": "196 181 253", + "hslChannel": "252.5 94.7% 85.1%" + }, + { + "scale": 400, + "hex": "#a78bfa", + "rgb": "rgb(167,139,250)", + "hsl": "hsl(255.1,91.7%,76.3%)", + "rgbChannel": "167 139 250", + "hslChannel": "255.1 91.7% 76.3%" + }, + { + "scale": 500, + "hex": "#8b5cf6", + "rgb": "rgb(139,92,246)", + "hsl": "hsl(258.3,89.5%,66.3%)", + "rgbChannel": "139 92 246", + "hslChannel": "258.3 89.5% 66.3%" + }, + { + "scale": 600, + "hex": "#7c3aed", + "rgb": "rgb(124,58,237)", + "hsl": "hsl(262.1,83.3%,57.8%)", + "rgbChannel": "124 58 237", + "hslChannel": "262.1 83.3% 57.8%" + }, + { + "scale": 700, + "hex": "#6d28d9", + "rgb": "rgb(109,40,217)", + "hsl": "hsl(263.4,70%,50.4%)", + "rgbChannel": "109 40 217", + "hslChannel": "263.4 70% 50.4%" + }, + { + "scale": 800, + "hex": "#5b21b6", + "rgb": "rgb(91,33,182)", + "hsl": "hsl(263.4,69.3%,42.2%)", + "rgbChannel": "91 33 182", + "hslChannel": "263.4 69.3% 42.2%" + }, + { + "scale": 900, + "hex": "#4c1d95", + "rgb": "rgb(76,29,149)", + "hsl": "hsl(263.5,67.4%,34.9%)", + "rgbChannel": "76 29 149", + "hslChannel": "263.5 67.4% 34.9%" + }, + { + "scale": 950, + "hex": "#1e1b4b", + "rgb": "rgb(46,16,101)", + "hsl": "hsl(261.2,72.6%,22.9%)", + "rgbChannel": "46 16 101", + "hslChannel": "261.2 72.6% 22.9%" + } + ], + "purple": [ + { + "scale": 50, + "hex": "#faf5ff", + "rgb": "rgb(250,245,255)", + "hsl": "hsl(270,100%,98%)", + "rgbChannel": "250 245 255", + "hslChannel": "270 100% 98%" + }, + { + "scale": 100, + "hex": "#f3e8ff", + "rgb": "rgb(243,232,255)", + "hsl": "hsl(268.7,100%,95.5%)", + "rgbChannel": "243 232 255", + "hslChannel": "268.7 100% 95.5%" + }, + { + "scale": 200, + "hex": "#e9d5ff", + "rgb": "rgb(233,213,255)", + "hsl": "hsl(268.6,100%,91.8%)", + "rgbChannel": "233 213 255", + "hslChannel": "268.6 100% 91.8%" + }, + { + "scale": 300, + "hex": "#d8b4fe", + "rgb": "rgb(216,180,254)", + "hsl": "hsl(269.2,97.4%,85.1%)", + "rgbChannel": "216 180 254", + "hslChannel": "269.2 97.4% 85.1%" + }, + { + "scale": 400, + "hex": "#c084fc", + "rgb": "rgb(192,132,252)", + "hsl": "hsl(270,95.2%,75.3%)", + "rgbChannel": "192 132 252", + "hslChannel": "270 95.2% 75.3%" + }, + { + "scale": 500, + "hex": "#a855f7", + "rgb": "rgb(168,85,247)", + "hsl": "hsl(270.7,91%,65.1%)", + "rgbChannel": "168 85 247", + "hslChannel": "270.7 91% 65.1%" + }, + { + "scale": 600, + "hex": "#9333ea", + "rgb": "rgb(147,51,234)", + "hsl": "hsl(271.5,81.3%,55.9%)", + "rgbChannel": "147 51 234", + "hslChannel": "271.5 81.3% 55.9%" + }, + { + "scale": 700, + "hex": "#7e22ce", + "rgb": "rgb(126,34,206)", + "hsl": "hsl(272.1,71.7%,47.1%)", + "rgbChannel": "126 34 206", + "hslChannel": "272.1 71.7% 47.1%" + }, + { + "scale": 800, + "hex": "#6b21a8", + "rgb": "rgb(107,33,168)", + "hsl": "hsl(272.9,67.2%,39.4%)", + "rgbChannel": "107 33 168", + "hslChannel": "272.9 67.2% 39.4%" + }, + { + "scale": 900, + "hex": "#581c87", + "rgb": "rgb(88,28,135)", + "hsl": "hsl(273.6,65.6%,32%)", + "rgbChannel": "88 28 135", + "hslChannel": "273.6 65.6% 32%" + }, + { + "scale": 950, + "hex": "#3b0764", + "rgb": "rgb(59,7,100)", + "hsl": "hsl(273.5,86.9%,21%)", + "rgbChannel": "59 7 100", + "hslChannel": "273.5 86.9% 21%" + } + ], + "fuchsia": [ + { + "scale": 50, + "hex": "#fdf4ff", + "rgb": "rgb(253,244,255)", + "hsl": "hsl(289.1,100%,97.8%)", + "rgbChannel": "253 244 255", + "hslChannel": "289.1 100% 97.8%" + }, + { + "scale": 100, + "hex": "#fae8ff", + "rgb": "rgb(250,232,255)", + "hsl": "hsl(287,100%,95.5%)", + "rgbChannel": "250 232 255", + "hslChannel": "287 100% 95.5%" + }, + { + "scale": 200, + "hex": "#f5d0fe", + "rgb": "rgb(245,208,254)", + "hsl": "hsl(288.3,95.8%,90.6%)", + "rgbChannel": "245 208 254", + "hslChannel": "288.3 95.8% 90.6%" + }, + { + "scale": 300, + "hex": "#f0abfc", + "rgb": "rgb(240,171,252)", + "hsl": "hsl(291.1,93.1%,82.9%)", + "rgbChannel": "240 171 252", + "hslChannel": "291.1 93.1% 82.9%" + }, + { + "scale": 400, + "hex": "#e879f9", + "rgb": "rgb(232,121,249)", + "hsl": "hsl(292,91.4%,72.5%)", + "rgbChannel": "232 121 249", + "hslChannel": "292 91.4% 72.5%" + }, + { + "scale": 500, + "hex": "#d946ef", + "rgb": "rgb(217,70,239)", + "hsl": "hsl(292.2,84.1%,60.6%)", + "rgbChannel": "217 70 239", + "hslChannel": "292.2 84.1% 60.6%" + }, + { + "scale": 600, + "hex": "#c026d3", + "rgb": "rgb(192,38,211)", + "hsl": "hsl(293.4,69.5%,48.8%)", + "rgbChannel": "192 38 211", + "hslChannel": "293.4 69.5% 48.8%" + }, + { + "scale": 700, + "hex": "#a21caf", + "rgb": "rgb(162,28,175)", + "hsl": "hsl(294.7,72.4%,39.8%)", + "rgbChannel": "162 28 175", + "hslChannel": "294.7 72.4% 39.8%" + }, + { + "scale": 800, + "hex": "#86198f", + "rgb": "rgb(134,25,143)", + "hsl": "hsl(295.4,70.2%,32.9%)", + "rgbChannel": "134 25 143", + "hslChannel": "295.4 70.2% 32.9%" + }, + { + "scale": 900, + "hex": "#701a75", + "rgb": "rgb(112,26,117)", + "hsl": "hsl(296.7,63.6%,28%)", + "rgbChannel": "112 26 117", + "hslChannel": "296.7 63.6% 28%" + }, + { + "scale": 950, + "hex": "#4a044e", + "rgb": "rgb(74,4,78)", + "hsl": "hsl(296.8,90.2%,16.1%)", + "rgbChannel": "74 4 78", + "hslChannel": "296.8 90.2% 16.1%" + } + ], + "pink": [ + { + "scale": 50, + "hex": "#fdf2f8", + "rgb": "rgb(253,242,248)", + "hsl": "hsl(327.3,73.3%,97.1%)", + "rgbChannel": "253 242 248", + "hslChannel": "327.3 73.3% 97.1%" + }, + { + "scale": 100, + "hex": "#fce7f3", + "rgb": "rgb(252,231,243)", + "hsl": "hsl(325.7,77.8%,94.7%)", + "rgbChannel": "252 231 243", + "hslChannel": "325.7 77.8% 94.7%" + }, + { + "scale": 200, + "hex": "#fbcfe8", + "rgb": "rgb(251,207,232)", + "hsl": "hsl(325.9,84.6%,89.8%)", + "rgbChannel": "251 207 232", + "hslChannel": "325.9 84.6% 89.8%" + }, + { + "scale": 300, + "hex": "#f9a8d4", + "rgb": "rgb(249,168,212)", + "hsl": "hsl(327.4,87.1%,81.8%)", + "rgbChannel": "249 168 212", + "hslChannel": "327.4 87.1% 81.8%" + }, + { + "scale": 400, + "hex": "#f472b6", + "rgb": "rgb(244,114,182)", + "hsl": "hsl(328.6,85.5%,70.2%)", + "rgbChannel": "244 114 182", + "hslChannel": "328.6 85.5% 70.2%" + }, + { + "scale": 500, + "hex": "#ec4899", + "rgb": "rgb(236,72,153)", + "hsl": "hsl(330.4,81.2%,60.4%)", + "rgbChannel": "236 72 153", + "hslChannel": "330.4 81.2% 60.4%" + }, + { + "scale": 600, + "hex": "#db2777", + "rgb": "rgb(219,39,119)", + "hsl": "hsl(333.3,71.4%,50.6%)", + "rgbChannel": "219 39 119", + "hslChannel": "333.3 71.4% 50.6%" + }, + { + "scale": 700, + "hex": "#be185d", + "rgb": "rgb(190,24,93)", + "hsl": "hsl(335.1,77.6%,42%)", + "rgbChannel": "190 24 93", + "hslChannel": "335.1 77.6% 42%" + }, + { + "scale": 800, + "hex": "#9d174d", + "rgb": "rgb(157,23,77)", + "hsl": "hsl(335.8,74.4%,35.3%)", + "rgbChannel": "157 23 77", + "hslChannel": "335.8 74.4% 35.3%" + }, + { + "scale": 900, + "hex": "#831843", + "rgb": "rgb(131,24,67)", + "hsl": "hsl(335.9,69%,30.4%)", + "rgbChannel": "131 24 67", + "hslChannel": "335.9 69% 30.4%" + }, + { + "scale": 950, + "hex": "#500724", + "rgb": "rgb(80,7,36)", + "hsl": "hsl(336.2,83.9%,17.1%)", + "rgbChannel": "80 7 36", + "hslChannel": "336.2 83.9% 17.1%" + } + ], + "rose": [ + { + "scale": 50, + "hex": "#fff1f2", + "rgb": "rgb(255,241,242)", + "hsl": "hsl(355.7,100%,97.3%)", + "rgbChannel": "255 241 242", + "hslChannel": "355.7 100% 97.3%" + }, + { + "scale": 100, + "hex": "#ffe4e6", + "rgb": "rgb(255,228,230)", + "hsl": "hsl(355.6,100%,94.7%)", + "rgbChannel": "255 228 230", + "hslChannel": "355.6 100% 94.7%" + }, + { + "scale": 200, + "hex": "#fecdd3", + "rgb": "rgb(254,205,211)", + "hsl": "hsl(352.7,96.1%,90%)", + "rgbChannel": "254 205 211", + "hslChannel": "352.7 96.1% 90%" + }, + { + "scale": 300, + "hex": "#fda4af", + "rgb": "rgb(253,164,175)", + "hsl": "hsl(352.6,95.7%,81.8%)", + "rgbChannel": "253 164 175", + "hslChannel": "352.6 95.7% 81.8%" + }, + { + "scale": 400, + "hex": "#fb7185", + "rgb": "rgb(251,113,133)", + "hsl": "hsl(351.3,94.5%,71.4%)", + "rgbChannel": "251 113 133", + "hslChannel": "351.3 94.5% 71.4%" + }, + { + "scale": 500, + "hex": "#f43f5e", + "rgb": "rgb(244,63,94)", + "hsl": "hsl(349.7,89.2%,60.2%)", + "rgbChannel": "244 63 94", + "hslChannel": "349.7 89.2% 60.2%" + }, + { + "scale": 600, + "hex": "#e11d48", + "rgb": "rgb(225,29,72)", + "hsl": "hsl(346.8,77.2%,49.8%)", + "rgbChannel": "225 29 72", + "hslChannel": "346.8 77.2% 49.8%" + }, + { + "scale": 700, + "hex": "#be123c", + "rgb": "rgb(190,18,60)", + "hsl": "hsl(345.3,82.7%,40.8%)", + "rgbChannel": "190 18 60", + "hslChannel": "345.3 82.7% 40.8%" + }, + { + "scale": 800, + "hex": "#9f1239", + "rgb": "rgb(159,18,57)", + "hsl": "hsl(343.4,79.7%,34.7%)", + "rgbChannel": "159 18 57", + "hslChannel": "343.4 79.7% 34.7%" + }, + { + "scale": 900, + "hex": "#881337", + "rgb": "rgb(136,19,55)", + "hsl": "hsl(341.5,75.5%,30.4%)", + "rgbChannel": "136 19 55", + "hslChannel": "341.5 75.5% 30.4%" + }, + { + "scale": 950, + "hex": "#4c0519", + "rgb": "rgb(76,5,25)", + "hsl": "hsl(343.1,87.7%,15.9%)", + "rgbChannel": "76 5 25", + "hslChannel": "343.1 87.7% 15.9%" + } + ] +} diff --git a/crates/ui/src/.DS_Store b/crates/ui/src/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/crates/ui/src/.DS_Store differ diff --git a/crates/ui/src/accordion.rs b/crates/ui/src/accordion.rs new file mode 100644 index 0000000..bbf9d2d --- /dev/null +++ b/crates/ui/src/accordion.rs @@ -0,0 +1,300 @@ +use std::{cell::Cell, rc::Rc, sync::Arc}; + +use gpui::{ + div, prelude::FluentBuilder as _, rems, AnyElement, Div, ElementId, InteractiveElement as _, + IntoElement, ParentElement, RenderOnce, SharedString, StatefulInteractiveElement as _, Styled, + WindowContext, +}; + +use crate::{h_flex, theme::ActiveTheme as _, v_flex, Icon, IconName, Sizable, Size}; + +/// An AccordionGroup is a container for multiple Accordion elements. +#[derive(IntoElement)] +pub struct Accordion { + id: ElementId, + base: Div, + multiple: bool, + size: Size, + bordered: bool, + disabled: bool, + children: Vec, + on_toggle_click: Option>, +} + +impl Accordion { + pub fn new(id: impl Into) -> Self { + Self { + id: id.into(), + base: v_flex().gap_1(), + multiple: false, + size: Size::default(), + bordered: true, + children: Vec::new(), + disabled: false, + on_toggle_click: None, + } + } + + pub fn multiple(mut self, multiple: bool) -> Self { + self.multiple = multiple; + self + } + + pub fn bordered(mut self, bordered: bool) -> Self { + self.bordered = bordered; + self + } + + pub fn disabled(mut self, disabled: bool) -> Self { + self.disabled = disabled; + self + } + + pub fn item(mut self, child: F) -> Self + where + F: FnOnce(AccordionItem) -> AccordionItem, + { + let item = child(AccordionItem::new()); + self.children.push(item); + self + } + + /// Sets the on_toggle_click callback for the AccordionGroup. + /// + /// The first argument `Vec` is the indices of the open accordions. + pub fn on_toggle_click( + mut self, + on_toggle_click: impl Fn(&[usize], &mut WindowContext) + Send + Sync + 'static, + ) -> Self { + self.on_toggle_click = Some(Arc::new(on_toggle_click)); + self + } +} + +impl Sizable for Accordion { + fn with_size(mut self, size: impl Into) -> Self { + self.size = size.into(); + self + } +} + +impl RenderOnce for Accordion { + fn render(self, _: &mut WindowContext) -> impl IntoElement { + let mut open_ixs: Vec = Vec::new(); + let multiple = self.multiple; + let state = Rc::new(Cell::new(None)); + + self.children + .iter() + .enumerate() + .for_each(|(ix, accordion)| { + if accordion.open { + open_ixs.push(ix); + } + }); + + self.base + .id(self.id) + .children( + self.children + .into_iter() + .enumerate() + .map(|(ix, accordion)| { + let state = Rc::clone(&state); + accordion + .with_size(self.size) + .bordered(self.bordered) + .when(self.disabled, |this| this.disabled(true)) + .on_toggle_click(move |_, _| { + state.set(Some(ix)); + }) + }), + ) + .when_some( + self.on_toggle_click.filter(|_| !self.disabled), + move |this, on_toggle_click| { + this.on_click(move |_, cx| { + let mut open_ixs = open_ixs.clone(); + if let Some(ix) = state.get() { + if multiple { + if let Some(pos) = open_ixs.iter().position(|&i| i == ix) { + open_ixs.remove(pos); + } else { + open_ixs.push(ix); + } + } else { + let was_open = open_ixs.iter().any(|&i| i == ix); + open_ixs.clear(); + if !was_open { + open_ixs.push(ix); + } + } + } + + on_toggle_click(&open_ixs, cx); + }) + }, + ) + } +} + +/// An Accordion is a vertically stacked list of items, each of which can be expanded to reveal the content associated with it. +#[derive(IntoElement)] +pub struct AccordionItem { + icon: Option, + title: AnyElement, + content: AnyElement, + open: bool, + size: Size, + bordered: bool, + disabled: bool, + on_toggle_click: Option>, +} + +impl AccordionItem { + pub fn new() -> Self { + Self { + icon: None, + title: SharedString::default().into_any_element(), + content: SharedString::default().into_any_element(), + open: false, + disabled: false, + on_toggle_click: None, + size: Size::default(), + bordered: true, + } + } + + pub fn icon(mut self, icon: impl Into) -> Self { + self.icon = Some(icon.into()); + self + } + + pub fn title(mut self, title: impl IntoElement) -> Self { + self.title = title.into_any_element(); + self + } + + pub fn content(mut self, content: impl IntoElement) -> Self { + self.content = content.into_any_element(); + self + } + + pub fn bordered(mut self, bordered: bool) -> Self { + self.bordered = bordered; + self + } + + pub fn open(mut self, open: bool) -> Self { + self.open = open; + self + } + + pub fn disabled(mut self, disabled: bool) -> Self { + self.disabled = disabled; + self + } + + fn on_toggle_click( + mut self, + on_toggle_click: impl Fn(&bool, &mut WindowContext) + 'static, + ) -> Self { + self.on_toggle_click = Some(Arc::new(on_toggle_click)); + self + } +} + +impl Sizable for AccordionItem { + fn with_size(mut self, size: impl Into) -> Self { + self.size = size.into(); + self + } +} + +impl RenderOnce for AccordionItem { + fn render(self, cx: &mut WindowContext) -> impl IntoElement { + let text_size = match self.size { + Size::XSmall => rems(0.875), + Size::Small => rems(0.875), + _ => rems(1.0), + }; + + v_flex() + .bg(cx.theme().accordion) + .overflow_hidden() + .when(self.bordered, |this| { + this.border_1().border_color(cx.theme().border).rounded_md() + }) + .text_size(text_size) + .child( + h_flex() + .id("accordion-title") + .justify_between() + .map(|this| match self.size { + Size::XSmall => this.py_0().px_1p5(), + Size::Small => this.py_0p5().px_2(), + Size::Large => this.py_1p5().px_4(), + _ => this.py_1().px_3(), + }) + .when(self.open, |this| { + this.when(self.bordered, |this| { + this.bg(cx.theme().accordion_active) + .text_color(cx.theme().foreground) + .border_b_1() + .border_color(cx.theme().border) + }) + }) + .child( + h_flex() + .items_center() + .map(|this| match self.size { + Size::XSmall => this.gap_1(), + Size::Small => this.gap_1(), + _ => this.gap_2(), + }) + .when_some(self.icon, |this, icon| { + this.child( + icon.with_size(self.size) + .text_color(cx.theme().muted_foreground), + ) + }) + .child(self.title), + ) + .when(!self.disabled, |this| { + this.cursor_pointer() + .hover(|this| this.bg(cx.theme().accordion_hover)) + .child( + Icon::new(if self.open { + IconName::ChevronUp + } else { + IconName::ChevronDown + }) + .xsmall() + .text_color(cx.theme().muted_foreground), + ) + }) + .when_some( + self.on_toggle_click.filter(|_| !self.disabled), + |this, on_toggle_click| { + this.on_click({ + move |_, cx| { + on_toggle_click(&!self.open, cx); + } + }) + }, + ), + ) + .when(self.open, |this| { + this.child( + div() + .map(|this| match self.size { + Size::XSmall => this.p_1p5(), + Size::Small => this.p_2(), + Size::Large => this.p_4(), + _ => this.p_3(), + }) + .child(self.content), + ) + }) + } +} diff --git a/crates/ui/src/animation.rs b/crates/ui/src/animation.rs new file mode 100644 index 0000000..be3539e --- /dev/null +++ b/crates/ui/src/animation.rs @@ -0,0 +1,19 @@ +/// A cubic bezier function like CSS `cubic-bezier`. +/// +/// Builder: +/// +/// https://cubic-bezier.com +pub fn cubic_bezier(x1: f32, y1: f32, x2: f32, y2: f32) -> impl Fn(f32) -> f32 { + move |t: f32| { + let one_t = 1.0 - t; + let one_t2 = one_t * one_t; + let t2 = t * t; + let t3 = t2 * t; + + // The Bezier curve function for x and y, where x0 = 0, y0 = 0, x3 = 1, y3 = 1 + let _x = 3.0 * x1 * one_t2 * t + 3.0 * x2 * one_t * t2 + t3; + let y = 3.0 * y1 * one_t2 * t + 3.0 * y2 * one_t * t2 + t3; + + y + } +} diff --git a/crates/ui/src/badge.rs b/crates/ui/src/badge.rs new file mode 100644 index 0000000..0e7e0f1 --- /dev/null +++ b/crates/ui/src/badge.rs @@ -0,0 +1,123 @@ +use crate::{theme::ActiveTheme as _, Sizable, Size}; +use gpui::{ + div, prelude::FluentBuilder as _, relative, Div, Hsla, InteractiveElement as _, IntoElement, + ParentElement, RenderOnce, Styled, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum BadgeVariant { + #[default] + Primary, + Secondary, + Outline, + Destructive, + Custom { + color: Hsla, + foreground: Hsla, + border: Hsla, + }, +} +impl BadgeVariant { + fn bg(&self, cx: &gpui::WindowContext) -> Hsla { + match self { + Self::Primary => cx.theme().primary, + Self::Secondary => cx.theme().secondary, + Self::Outline => gpui::transparent_black(), + Self::Destructive => cx.theme().destructive, + Self::Custom { color, .. } => *color, + } + } + + fn border(&self, cx: &gpui::WindowContext) -> Hsla { + match self { + Self::Primary => cx.theme().primary, + Self::Secondary => cx.theme().secondary, + Self::Outline => cx.theme().border, + Self::Destructive => cx.theme().destructive, + Self::Custom { border, .. } => *border, + } + } + + fn fg(&self, cx: &gpui::WindowContext) -> Hsla { + match self { + Self::Primary => cx.theme().primary_foreground, + Self::Secondary => cx.theme().secondary_foreground, + Self::Outline => cx.theme().foreground, + Self::Destructive => cx.theme().destructive_foreground, + Self::Custom { foreground, .. } => *foreground, + } + } +} + +/// Badge is a small status indicator for UI elements. +/// +/// Only support: Medium, Small +#[derive(IntoElement)] +pub struct Badge { + base: Div, + veriant: BadgeVariant, + size: Size, +} +impl Badge { + fn new() -> Self { + Self { + base: div().flex().items_center().rounded_md().border_1(), + veriant: BadgeVariant::default(), + size: Size::Medium, + } + } + + pub fn with_variant(mut self, variant: BadgeVariant) -> Self { + self.veriant = variant; + self + } + + pub fn primary() -> Self { + Self::new().with_variant(BadgeVariant::Primary) + } + + pub fn secondary() -> Self { + Self::new().with_variant(BadgeVariant::Secondary) + } + + pub fn outline() -> Self { + Self::new().with_variant(BadgeVariant::Outline) + } + + pub fn destructive() -> Self { + Self::new().with_variant(BadgeVariant::Destructive) + } + + pub fn custom(color: Hsla, foreground: Hsla, border: Hsla) -> Self { + Self::new().with_variant(BadgeVariant::Custom { + color, + foreground, + border, + }) + } +} +impl Sizable for Badge { + fn with_size(mut self, size: impl Into) -> Self { + self.size = size.into(); + self + } +} +impl ParentElement for Badge { + fn extend(&mut self, elements: impl IntoIterator) { + self.base.extend(elements); + } +} +impl RenderOnce for Badge { + fn render(self, cx: &mut gpui::WindowContext) -> impl IntoElement { + self.base + .line_height(relative(1.3)) + .map(|this| match self.size { + Size::XSmall | Size::Small => this.text_xs().px_1p5().py_0(), + _ => this.text_xs().px_2p5().py_0p5(), + }) + .bg(self.veriant.bg(cx)) + .text_color(self.veriant.fg(cx)) + .border_color(self.veriant.border(cx)) + .hover(|this| this.opacity(0.9)) + } +} diff --git a/crates/ui/src/breadcrumb.rs b/crates/ui/src/breadcrumb.rs new file mode 100644 index 0000000..4751e93 --- /dev/null +++ b/crates/ui/src/breadcrumb.rs @@ -0,0 +1,118 @@ +use std::rc::Rc; + +use gpui::{ + div, prelude::FluentBuilder as _, ClickEvent, ElementId, InteractiveElement as _, IntoElement, + ParentElement, RenderOnce, SharedString, StatefulInteractiveElement, Styled, WindowContext, +}; + +use crate::{h_flex, theme::ActiveTheme, Icon, IconName}; + +#[derive(IntoElement)] +pub struct Breadcrumb { + items: Vec, +} + +#[derive(IntoElement)] +pub struct BreadcrumbItem { + id: ElementId, + text: SharedString, + on_click: Option>, + disabled: bool, + is_last: bool, +} + +impl BreadcrumbItem { + pub fn new(id: impl Into, text: impl Into) -> Self { + Self { + id: id.into(), + text: text.into(), + on_click: None, + disabled: false, + is_last: false, + } + } + + pub fn disabled(mut self, disabled: bool) -> Self { + self.disabled = disabled; + self + } + + pub fn on_click( + mut self, + on_click: impl Fn(&ClickEvent, &mut WindowContext) + 'static, + ) -> Self { + self.on_click = Some(Rc::new(on_click)); + self + } + + /// For internal use only. + fn is_last(mut self, is_last: bool) -> Self { + self.is_last = is_last; + self + } +} + +impl RenderOnce for BreadcrumbItem { + fn render(self, cx: &mut WindowContext) -> impl IntoElement { + div() + .id(self.id) + .child(self.text) + .text_color(cx.theme().muted_foreground) + .when(self.is_last, |this| this.text_color(cx.theme().foreground)) + .when(self.disabled, |this| { + this.text_color(cx.theme().muted_foreground) + }) + .when(!self.disabled, |this| { + this.when_some(self.on_click, |this, on_click| { + this.cursor_pointer().on_click(move |event, cx| { + on_click(event, cx); + }) + }) + }) + } +} + +impl Breadcrumb { + pub fn new() -> Self { + Self { items: Vec::new() } + } + + /// Add an item to the breadcrumb. + pub fn item(mut self, item: BreadcrumbItem) -> Self { + self.items.push(item); + self + } +} + +#[derive(IntoElement)] +struct BreadcrumbSeparator; +impl RenderOnce for BreadcrumbSeparator { + fn render(self, cx: &mut WindowContext) -> impl IntoElement { + Icon::new(IconName::ChevronRight) + .text_color(cx.theme().muted_foreground) + .size_3p5() + .into_any_element() + } +} + +impl RenderOnce for Breadcrumb { + fn render(self, cx: &mut WindowContext) -> impl IntoElement { + let items_count = self.items.len(); + + let mut children = vec![]; + for (ix, item) in self.items.into_iter().enumerate() { + let is_last = ix == items_count - 1; + + children.push(item.is_last(is_last).into_any_element()); + if !is_last { + children.push(BreadcrumbSeparator.into_any_element()); + } + } + + h_flex() + .gap_1p5() + .text_sm() + .text_color(cx.theme().muted_foreground) + .children(children) + } +} diff --git a/crates/ui/src/button.rs b/crates/ui/src/button.rs new file mode 100644 index 0000000..53883bf --- /dev/null +++ b/crates/ui/src/button.rs @@ -0,0 +1,667 @@ +use crate::{ + h_flex, + indicator::Indicator, + theme::{ActiveTheme, Colorize as _}, + tooltip::Tooltip, + Disableable, Icon, Selectable, Sizable, Size, +}; +use gpui::{ + div, prelude::FluentBuilder as _, px, relative, AnyElement, ClickEvent, Corners, Div, Edges, + ElementId, Hsla, InteractiveElement, IntoElement, MouseButton, ParentElement, Pixels, + RenderOnce, SharedString, StatefulInteractiveElement as _, Styled, WindowContext, +}; + +pub enum ButtonRounded { + None, + Small, + Medium, + Large, + Size(Pixels), +} + +impl From for ButtonRounded { + fn from(px: Pixels) -> Self { + ButtonRounded::Size(px) + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct ButtonCustomVariant { + color: Hsla, + foreground: Hsla, + border: Hsla, + shadow: bool, + hover: Hsla, + active: Hsla, +} + +pub trait ButtonVariants: Sized { + fn with_variant(self, variant: ButtonVariant) -> Self; + + /// With the primary style for the Button. + fn primary(self) -> Self { + self.with_variant(ButtonVariant::Primary) + } + + /// With the danger style for the Button. + fn danger(self) -> Self { + self.with_variant(ButtonVariant::Danger) + } + + /// With the outline style for the Button. + fn outline(self) -> Self { + self.with_variant(ButtonVariant::Outline) + } + + /// With the ghost style for the Button. + fn ghost(self) -> Self { + self.with_variant(ButtonVariant::Ghost) + } + + /// With the link style for the Button. + fn link(self) -> Self { + self.with_variant(ButtonVariant::Link) + } + + /// With the text style for the Button, it will no padding look like a normal text. + fn text(self) -> Self { + self.with_variant(ButtonVariant::Text) + } + + /// With the custom style for the Button. + fn custom(self, style: ButtonCustomVariant) -> Self { + self.with_variant(ButtonVariant::Custom(style)) + } +} + +impl ButtonCustomVariant { + pub fn new(cx: &WindowContext) -> Self { + Self { + color: cx.theme().secondary, + foreground: cx.theme().secondary_foreground, + border: cx.theme().border, + hover: cx.theme().secondary_hover, + active: cx.theme().secondary_active, + shadow: true, + } + } + + pub fn color(mut self, color: Hsla) -> Self { + self.color = color; + self + } + + pub fn foreground(mut self, color: Hsla) -> Self { + self.foreground = color; + self + } + + pub fn border(mut self, color: Hsla) -> Self { + self.border = color; + self + } + + pub fn hover(mut self, color: Hsla) -> Self { + self.hover = color; + self + } + + pub fn active(mut self, color: Hsla) -> Self { + self.active = color; + self + } + + pub fn shadow(mut self, shadow: bool) -> Self { + self.shadow = shadow; + self + } +} + +/// The veriant of the Button. +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum ButtonVariant { + Primary, + Secondary, + Danger, + Outline, + Ghost, + Link, + Text, + Custom(ButtonCustomVariant), +} + +impl Default for ButtonVariant { + fn default() -> Self { + Self::Secondary + } +} + +impl ButtonVariant { + fn is_link(&self) -> bool { + matches!(self, Self::Link) + } + + fn is_text(&self) -> bool { + matches!(self, Self::Text) + } + + fn no_padding(&self) -> bool { + self.is_link() || self.is_text() + } +} + +/// A Button element. +#[derive(IntoElement)] +pub struct Button { + pub base: Div, + id: ElementId, + icon: Option, + label: Option, + children: Vec, + disabled: bool, + pub(crate) selected: bool, + variant: ButtonVariant, + rounded: ButtonRounded, + border_corners: Corners, + border_edges: Edges, + size: Size, + compact: bool, + tooltip: Option, + on_click: Option>, + pub(crate) stop_propagation: bool, + loading: bool, + loading_icon: Option, +} + +impl From