diff --git a/assets/themes/catppuccin-frappe.json b/assets/themes/catppuccin-frappe.json deleted file mode 100644 index a5ceeb0..0000000 --- a/assets/themes/catppuccin-frappe.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "id": "catppuccin-frappe", - "name": "Catppuccin Frappé", - "author": "Catppuccin", - "url": "https://github.com/catppuccin/catppuccin", - "light": { - "background": "#303446", - "surface_background": "#292c3c", - "elevated_surface_background": "#232634", - "panel_background": "#303446", - "overlay": "#c6d0f51a", - "title_bar": "#292c3c", - "title_bar_inactive": "#232634", - "window_border": "#737994", - "border": "#626880", - "border_variant": "#51576d", - "border_focused": "#8caaee", - "border_selected": "#8caaee", - "border_transparent": "#00000000", - "border_disabled": "#414559", - "ring": "#8caaee", - "text": "#c6d0f5", - "text_muted": "#b5bfe2", - "text_placeholder": "#a5adce", - "text_accent": "#8caaee", - "icon": "#b5bfe2", - "icon_muted": "#a5adce", - "icon_accent": "#8caaee", - "element_foreground": "#232634", - "element_background": "#8caaee", - "element_hover": "#babbf1", - "element_active": "#7e99d6", - "element_selected": "#7088bf", - "element_disabled": "#8caaee4d", - "secondary_foreground": "#7088bf", - "secondary_background": "#292c3c", - "secondary_hover": "#8caaee33", - "secondary_active": "#232634", - "secondary_selected": "#232634", - "secondary_disabled": "#8caaee4d", - "danger_foreground": "#232634", - "danger_background": "#e78284", - "danger_hover": "#ea999c", - "danger_active": "#d07576", - "danger_selected": "#b96869", - "danger_disabled": "#e782844d", - "warning_foreground": "#232634", - "warning_background": "#e5c890", - "warning_hover": "#ef9f76", - "warning_active": "#ceb482", - "warning_selected": "#b7a074", - "warning_disabled": "#e5c8904d", - "ghost_element_background": "#00000000", - "ghost_element_background_alt": "#414559", - "ghost_element_hover": "#c6d0f533", - "ghost_element_active": "#51576d", - "ghost_element_selected": "#51576d", - "ghost_element_disabled": "#c6d0f50d", - "tab_inactive_background": "#292c3c", - "tab_inactive_foreground": "#b5bfe2", - "tab_active_background": "#303446", - "tab_active_foreground": "#c6d0f5", - "scrollbar_thumb_background": "#c6d0f533", - "scrollbar_thumb_hover_background": "#c6d0f580", - "scrollbar_thumb_border": "#00000000", - "scrollbar_track_background": "#00000000", - "scrollbar_track_border": "#51576d", - "drop_target_background": "#8caaee1a", - "cursor": "#f2d5cf", - "selection": "#949cbb40" - }, - "dark": { - "background": "#303446", - "surface_background": "#292c3c", - "elevated_surface_background": "#232634", - "panel_background": "#303446", - "overlay": "#c6d0f51a", - "title_bar": "#292c3c", - "title_bar_inactive": "#232634", - "window_border": "#737994", - "border": "#626880", - "border_variant": "#51576d", - "border_focused": "#8caaee", - "border_selected": "#8caaee", - "border_transparent": "#00000000", - "border_disabled": "#414559", - "ring": "#8caaee", - "text": "#c6d0f5", - "text_muted": "#b5bfe2", - "text_placeholder": "#a5adce", - "text_accent": "#8caaee", - "icon": "#b5bfe2", - "icon_muted": "#a5adce", - "icon_accent": "#8caaee", - "element_foreground": "#232634", - "element_background": "#8caaee", - "element_hover": "#babbf1", - "element_active": "#7e99d6", - "element_selected": "#7088bf", - "element_disabled": "#8caaee4d", - "secondary_foreground": "#7088bf", - "secondary_background": "#292c3c", - "secondary_hover": "#8caaee33", - "secondary_active": "#232634", - "secondary_selected": "#232634", - "secondary_disabled": "#8caaee4d", - "danger_foreground": "#232634", - "danger_background": "#e78284", - "danger_hover": "#ea999c", - "danger_active": "#d07576", - "danger_selected": "#b96869", - "danger_disabled": "#e782844d", - "warning_foreground": "#232634", - "warning_background": "#e5c890", - "warning_hover": "#ef9f76", - "warning_active": "#ceb482", - "warning_selected": "#b7a074", - "warning_disabled": "#e5c8904d", - "ghost_element_background": "#00000000", - "ghost_element_background_alt": "#414559", - "ghost_element_hover": "#c6d0f533", - "ghost_element_active": "#51576d", - "ghost_element_selected": "#51576d", - "ghost_element_disabled": "#c6d0f50d", - "tab_inactive_background": "#292c3c", - "tab_inactive_foreground": "#b5bfe2", - "tab_active_background": "#303446", - "tab_active_foreground": "#c6d0f5", - "scrollbar_thumb_background": "#c6d0f533", - "scrollbar_thumb_hover_background": "#c6d0f580", - "scrollbar_thumb_border": "#00000000", - "scrollbar_track_background": "#00000000", - "scrollbar_track_border": "#51576d", - "drop_target_background": "#8caaee1a", - "cursor": "#f2d5cf", - "selection": "#949cbb40" - } -} diff --git a/assets/themes/catppuccin-latte.json b/assets/themes/catppuccin-latte.json deleted file mode 100644 index c1dbcad..0000000 --- a/assets/themes/catppuccin-latte.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "id": "catppuccin-latte", - "name": "Catppuccin Latte", - "author": "Catppuccin", - "url": "https://github.com/catppuccin/catppuccin", - "light": { - "background": "#eff1f5", - "surface_background": "#e6e9ef", - "elevated_surface_background": "#dce0e8", - "panel_background": "#eff1f5", - "overlay": "#4c4f691a", - "title_bar": "#e6e9ef", - "title_bar_inactive": "#dce0e8", - "window_border": "#9ca0b0", - "border": "#acb0be", - "border_variant": "#bcc0cc", - "border_focused": "#1e66f5", - "border_selected": "#1e66f5", - "border_transparent": "#00000000", - "border_disabled": "#ccd0da", - "ring": "#1e66f5", - "text": "#4c4f69", - "text_muted": "#5c5f77", - "text_placeholder": "#6c6f85", - "text_accent": "#1e66f5", - "icon": "#5c5f77", - "icon_muted": "#6c6f85", - "icon_accent": "#1e66f5", - "element_foreground": "#eff1f5", - "element_background": "#1e66f5", - "element_hover": "#8839ef", - "element_active": "#1c5ce0", - "element_selected": "#1a52cc", - "element_disabled": "#1e66f54d", - "secondary_foreground": "#1a52cc", - "secondary_background": "#e6e9ef", - "secondary_hover": "#8839ef33", - "secondary_active": "#dce0e8", - "secondary_selected": "#dce0e8", - "secondary_disabled": "#1e66f54d", - "danger_foreground": "#eff1f5", - "danger_background": "#d20f39", - "danger_hover": "#e64553", - "danger_active": "#bd0d33", - "danger_selected": "#a80b2d", - "danger_disabled": "#d20f394d", - "warning_foreground": "#4c4f69", - "warning_background": "#df8e1d", - "warning_hover": "#fe640b", - "warning_active": "#c9801a", - "warning_selected": "#b47217", - "warning_disabled": "#df8e1d4d", - "ghost_element_background": "#00000000", - "ghost_element_background_alt": "#ccd0da", - "ghost_element_hover": "#4c4f6933", - "ghost_element_active": "#bcc0cc", - "ghost_element_selected": "#bcc0cc", - "ghost_element_disabled": "#4c4f690d", - "tab_inactive_background": "#e6e9ef", - "tab_inactive_foreground": "#5c5f77", - "tab_active_background": "#eff1f5", - "tab_active_foreground": "#4c4f69", - "scrollbar_thumb_background": "#4c4f6933", - "scrollbar_thumb_hover_background": "#4c4f6980", - "scrollbar_thumb_border": "#00000000", - "scrollbar_track_background": "#00000000", - "scrollbar_track_border": "#bcc0cc", - "drop_target_background": "#1e66f51a", - "cursor": "#dc8a78", - "selection": "#7c7f9340" - }, - "dark": { - "background": "#eff1f5", - "surface_background": "#e6e9ef", - "elevated_surface_background": "#dce0e8", - "panel_background": "#eff1f5", - "overlay": "#4c4f691a", - "title_bar": "#e6e9ef", - "title_bar_inactive": "#dce0e8", - "window_border": "#9ca0b0", - "border": "#acb0be", - "border_variant": "#bcc0cc", - "border_focused": "#1e66f5", - "border_selected": "#1e66f5", - "border_transparent": "#00000000", - "border_disabled": "#ccd0da", - "ring": "#1e66f5", - "text": "#4c4f69", - "text_muted": "#5c5f77", - "text_placeholder": "#6c6f85", - "text_accent": "#1e66f5", - "icon": "#5c5f77", - "icon_muted": "#6c6f85", - "icon_accent": "#1e66f5", - "element_foreground": "#eff1f5", - "element_background": "#1e66f5", - "element_hover": "#8839ef", - "element_active": "#1c5ce0", - "element_selected": "#1a52cc", - "element_disabled": "#1e66f54d", - "secondary_foreground": "#1a52cc", - "secondary_background": "#e6e9ef", - "secondary_hover": "#8839ef33", - "secondary_active": "#dce0e8", - "secondary_selected": "#dce0e8", - "secondary_disabled": "#1e66f54d", - "danger_foreground": "#eff1f5", - "danger_background": "#d20f39", - "danger_hover": "#e64553", - "danger_active": "#bd0d33", - "danger_selected": "#a80b2d", - "danger_disabled": "#d20f394d", - "warning_foreground": "#4c4f69", - "warning_background": "#df8e1d", - "warning_hover": "#fe640b", - "warning_active": "#c9801a", - "warning_selected": "#b47217", - "warning_disabled": "#df8e1d4d", - "ghost_element_background": "#00000000", - "ghost_element_background_alt": "#ccd0da", - "ghost_element_hover": "#4c4f6933", - "ghost_element_active": "#bcc0cc", - "ghost_element_selected": "#bcc0cc", - "ghost_element_disabled": "#4c4f690d", - "tab_inactive_background": "#e6e9ef", - "tab_inactive_foreground": "#5c5f77", - "tab_active_background": "#eff1f5", - "tab_active_foreground": "#4c4f69", - "scrollbar_thumb_background": "#4c4f6933", - "scrollbar_thumb_hover_background": "#4c4f6980", - "scrollbar_thumb_border": "#00000000", - "scrollbar_track_background": "#00000000", - "scrollbar_track_border": "#bcc0cc", - "drop_target_background": "#1e66f51a", - "cursor": "#dc8a78", - "selection": "#7c7f9340" - } -} diff --git a/assets/themes/catppuccin-macchiato.json b/assets/themes/catppuccin-macchiato.json deleted file mode 100644 index fad7d8b..0000000 --- a/assets/themes/catppuccin-macchiato.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "id": "catppuccin-macchiato", - "name": "Catppuccin Macchiato", - "author": "Catppuccin", - "url": "https://github.com/catppuccin/catppuccin", - "light": { - "background": "#24273a", - "surface_background": "#1e2030", - "elevated_surface_background": "#181926", - "panel_background": "#24273a", - "overlay": "#cad3f51a", - "title_bar": "#1e2030", - "title_bar_inactive": "#181926", - "window_border": "#6e738d", - "border": "#5b6078", - "border_variant": "#494d64", - "border_focused": "#8aadf4", - "border_selected": "#8aadf4", - "border_transparent": "#00000000", - "border_disabled": "#363a4f", - "ring": "#8aadf4", - "text": "#cad3f5", - "text_muted": "#b8c0e0", - "text_placeholder": "#a5adcb", - "text_accent": "#8aadf4", - "icon": "#b8c0e0", - "icon_muted": "#a5adcb", - "icon_accent": "#8aadf4", - "element_foreground": "#181926", - "element_background": "#8aadf4", - "element_hover": "#b7bdf8", - "element_active": "#7c9cdc", - "element_selected": "#6e8bc5", - "element_disabled": "#8aadf44d", - "secondary_foreground": "#6e8bc5", - "secondary_background": "#1e2030", - "secondary_hover": "#8aadf433", - "secondary_active": "#181926", - "secondary_selected": "#181926", - "secondary_disabled": "#8aadf44d", - "danger_foreground": "#181926", - "danger_background": "#ed8796", - "danger_hover": "#ee99a0", - "danger_active": "#d57a87", - "danger_selected": "#be6d78", - "danger_disabled": "#ed87964d", - "warning_foreground": "#181926", - "warning_background": "#eed49f", - "warning_hover": "#f5a97f", - "warning_active": "#d6bf8f", - "warning_selected": "#beaa7f", - "warning_disabled": "#eed49f4d", - "ghost_element_background": "#00000000", - "ghost_element_background_alt": "#363a4f", - "ghost_element_hover": "#cad3f533", - "ghost_element_active": "#494d64", - "ghost_element_selected": "#494d64", - "ghost_element_disabled": "#cad3f50d", - "tab_inactive_background": "#1e2030", - "tab_inactive_foreground": "#b8c0e0", - "tab_active_background": "#24273a", - "tab_active_foreground": "#cad3f5", - "scrollbar_thumb_background": "#cad3f533", - "scrollbar_thumb_hover_background": "#cad3f580", - "scrollbar_thumb_border": "#00000000", - "scrollbar_track_background": "#00000000", - "scrollbar_track_border": "#494d64", - "drop_target_background": "#8aadf41a", - "cursor": "#f4dbd6", - "selection": "#939ab740" - }, - "dark": { - "background": "#24273a", - "surface_background": "#1e2030", - "elevated_surface_background": "#181926", - "panel_background": "#24273a", - "overlay": "#cad3f51a", - "title_bar": "#1e2030", - "title_bar_inactive": "#181926", - "window_border": "#6e738d", - "border": "#5b6078", - "border_variant": "#494d64", - "border_focused": "#8aadf4", - "border_selected": "#8aadf4", - "border_transparent": "#00000000", - "border_disabled": "#363a4f", - "ring": "#8aadf4", - "text": "#cad3f5", - "text_muted": "#b8c0e0", - "text_placeholder": "#a5adcb", - "text_accent": "#8aadf4", - "icon": "#b8c0e0", - "icon_muted": "#a5adcb", - "icon_accent": "#8aadf4", - "element_foreground": "#181926", - "element_background": "#8aadf4", - "element_hover": "#b7bdf8", - "element_active": "#7c9cdc", - "element_selected": "#6e8bc5", - "element_disabled": "#8aadf44d", - "secondary_foreground": "#6e8bc5", - "secondary_background": "#1e2030", - "secondary_hover": "#8aadf433", - "secondary_active": "#181926", - "secondary_selected": "#181926", - "secondary_disabled": "#8aadf44d", - "danger_foreground": "#181926", - "danger_background": "#ed8796", - "danger_hover": "#ee99a0", - "danger_active": "#d57a87", - "danger_selected": "#be6d78", - "danger_disabled": "#ed87964d", - "warning_foreground": "#181926", - "warning_background": "#eed49f", - "warning_hover": "#f5a97f", - "warning_active": "#d6bf8f", - "warning_selected": "#beaa7f", - "warning_disabled": "#eed49f4d", - "ghost_element_background": "#00000000", - "ghost_element_background_alt": "#363a4f", - "ghost_element_hover": "#cad3f533", - "ghost_element_active": "#494d64", - "ghost_element_selected": "#494d64", - "ghost_element_disabled": "#cad3f50d", - "tab_inactive_background": "#1e2030", - "tab_inactive_foreground": "#b8c0e0", - "tab_active_background": "#24273a", - "tab_active_foreground": "#cad3f5", - "scrollbar_thumb_background": "#cad3f533", - "scrollbar_thumb_hover_background": "#cad3f580", - "scrollbar_thumb_border": "#00000000", - "scrollbar_track_background": "#00000000", - "scrollbar_track_border": "#494d64", - "drop_target_background": "#8aadf41a", - "cursor": "#f4dbd6", - "selection": "#939ab740" - } -} diff --git a/assets/themes/catppuccin-mocha.json b/assets/themes/catppuccin-mocha.json deleted file mode 100644 index 87e1e8e..0000000 --- a/assets/themes/catppuccin-mocha.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "id": "catppuccin-mocha", - "name": "Catppuccin Mocha", - "author": "Catppuccin", - "url": "https://github.com/catppuccin/catppuccin", - "light": { - "background": "#1e1e2e", - "surface_background": "#181825", - "elevated_surface_background": "#11111b", - "panel_background": "#1e1e2e", - "overlay": "#cdd6f41a", - "title_bar": "#181825", - "title_bar_inactive": "#11111b", - "window_border": "#6c7086", - "border": "#585b70", - "border_variant": "#45475a", - "border_focused": "#89b4fa", - "border_selected": "#89b4fa", - "border_transparent": "#00000000", - "border_disabled": "#313244", - "ring": "#89b4fa", - "text": "#cdd6f4", - "text_muted": "#bac2de", - "text_placeholder": "#a6adc8", - "text_accent": "#89b4fa", - "icon": "#bac2de", - "icon_muted": "#a6adc8", - "icon_accent": "#89b4fa", - "element_foreground": "#11111b", - "element_background": "#89b4fa", - "element_hover": "#b4befe", - "element_active": "#7ba2e1", - "element_selected": "#6d90c9", - "element_disabled": "#89b4fa4d", - "secondary_foreground": "#6d90c9", - "secondary_background": "#181825", - "secondary_hover": "#89b4fa33", - "secondary_active": "#11111b", - "secondary_selected": "#11111b", - "secondary_disabled": "#89b4fa4d", - "danger_foreground": "#11111b", - "danger_background": "#f38ba8", - "danger_hover": "#eba0ac", - "danger_active": "#db7d98", - "danger_selected": "#c46f88", - "danger_disabled": "#f38ba84d", - "warning_foreground": "#11111b", - "warning_background": "#f9e2af", - "warning_hover": "#fab387", - "warning_active": "#e0cb9e", - "warning_selected": "#c8b48d", - "warning_disabled": "#f9e2af4d", - "ghost_element_background": "#00000000", - "ghost_element_background_alt": "#313244", - "ghost_element_hover": "#cdd6f433", - "ghost_element_active": "#45475a", - "ghost_element_selected": "#45475a", - "ghost_element_disabled": "#cdd6f40d", - "tab_inactive_background": "#181825", - "tab_inactive_foreground": "#bac2de", - "tab_active_background": "#1e1e2e", - "tab_active_foreground": "#cdd6f4", - "scrollbar_thumb_background": "#cdd6f433", - "scrollbar_thumb_hover_background": "#cdd6f580", - "scrollbar_thumb_border": "#00000000", - "scrollbar_track_background": "#00000000", - "scrollbar_track_border": "#45475a", - "drop_target_background": "#89b4fa1a", - "cursor": "#f5e0dc", - "selection": "#9399b240" - }, - "dark": { - "background": "#1e1e2e", - "surface_background": "#181825", - "elevated_surface_background": "#11111b", - "panel_background": "#1e1e2e", - "overlay": "#cdd6f41a", - "title_bar": "#181825", - "title_bar_inactive": "#11111b", - "window_border": "#6c7086", - "border": "#585b70", - "border_variant": "#45475a", - "border_focused": "#89b4fa", - "border_selected": "#89b4fa", - "border_transparent": "#00000000", - "border_disabled": "#313244", - "ring": "#89b4fa", - "text": "#cdd6f4", - "text_muted": "#bac2de", - "text_placeholder": "#a6adc8", - "text_accent": "#89b4fa", - "icon": "#bac2de", - "icon_muted": "#a6adc8", - "icon_accent": "#89b4fa", - "element_foreground": "#11111b", - "element_background": "#89b4fa", - "element_hover": "#b4befe", - "element_active": "#7ba2e1", - "element_selected": "#6d90c9", - "element_disabled": "#89b4fa4d", - "secondary_foreground": "#6d90c9", - "secondary_background": "#181825", - "secondary_hover": "#89b4fa33", - "secondary_active": "#11111b", - "secondary_selected": "#11111b", - "secondary_disabled": "#89b4fa4d", - "danger_foreground": "#11111b", - "danger_background": "#f38ba8", - "danger_hover": "#eba0ac", - "danger_active": "#db7d98", - "danger_selected": "#c46f88", - "danger_disabled": "#f38ba84d", - "warning_foreground": "#11111b", - "warning_background": "#f9e2af", - "warning_hover": "#fab387", - "warning_active": "#e0cb9e", - "warning_selected": "#c8b48d", - "warning_disabled": "#f9e2af4d", - "ghost_element_background": "#00000000", - "ghost_element_background_alt": "#313244", - "ghost_element_hover": "#cdd6f433", - "ghost_element_active": "#45475a", - "ghost_element_selected": "#45475a", - "ghost_element_disabled": "#cdd6f40d", - "tab_inactive_background": "#181825", - "tab_inactive_foreground": "#bac2de", - "tab_active_background": "#1e1e2e", - "tab_active_foreground": "#cdd6f4", - "scrollbar_thumb_background": "#cdd6f433", - "scrollbar_thumb_hover_background": "#cdd6f580", - "scrollbar_thumb_border": "#00000000", - "scrollbar_track_background": "#00000000", - "scrollbar_track_border": "#45475a", - "drop_target_background": "#89b4fa1a", - "cursor": "#f5e0dc", - "selection": "#9399b240" - } -} diff --git a/assets/themes/flexoki.json b/assets/themes/flexoki.json deleted file mode 100644 index 7e71db0..0000000 --- a/assets/themes/flexoki.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "id": "flexoki", - "name": "Flexoki", - "author": "Stephan Ango", - "url": "https://stephango.com/flexoki", - "light": { - "background": "#FFFCF0", - "surface_background": "#F2F0E5", - "elevated_surface_background": "#E6E4D9", - "panel_background": "#FFFCF0", - "overlay": "#100F0F1a", - "title_bar": "#F2F0E5", - "title_bar_inactive": "#E6E4D9", - "window_border": "#B7B5AC", - "border": "#CECDC3", - "border_variant": "#DAD8CE", - "border_focused": "#205EA6", - "border_selected": "#205EA6", - "border_transparent": "#00000000", - "border_disabled": "#E6E4D9", - "ring": "#205EA6", - "text": "#100F0F", - "text_muted": "#6F6E69", - "text_placeholder": "#9F9D96", - "text_accent": "#205EA6", - "icon": "#6F6E69", - "icon_muted": "#9F9D96", - "icon_accent": "#205EA6", - "element_foreground": "#FFFCF0", - "element_background": "#205EA6", - "element_hover": "#1A4F8C", - "element_active": "#163B66", - "element_selected": "#133051", - "element_disabled": "#205EA64d", - "secondary_foreground": "#163B66", - "secondary_background": "#F2F0E5", - "secondary_hover": "#205EA61a", - "secondary_active": "#E6E4D9", - "secondary_selected": "#E6E4D9", - "secondary_disabled": "#205EA64d", - "danger_foreground": "#FFFCF0", - "danger_background": "#D14D41", - "danger_hover": "#C03E35", - "danger_active": "#AF3029", - "danger_selected": "#942822", - "danger_disabled": "#D14D414d", - "warning_foreground": "#100F0F", - "warning_background": "#D0A215", - "warning_hover": "#BE9207", - "warning_active": "#AD8301", - "warning_selected": "#8E6B01", - "warning_disabled": "#D0A2154d", - "ghost_element_background": "#00000000", - "ghost_element_background_alt": "#E6E4D9", - "ghost_element_hover": "#100F0F1a", - "ghost_element_active": "#DAD8CE", - "ghost_element_selected": "#DAD8CE", - "ghost_element_disabled": "#100F0F0d", - "tab_inactive_background": "#F2F0E5", - "tab_inactive_foreground": "#6F6E69", - "tab_active_background": "#FFFCF0", - "tab_active_foreground": "#100F0F", - "scrollbar_thumb_background": "#100F0F33", - "scrollbar_thumb_hover_background": "#100F0F4d", - "scrollbar_thumb_border": "#00000000", - "scrollbar_track_background": "#00000000", - "scrollbar_track_border": "#DAD8CE", - "drop_target_background": "#205EA61a", - "cursor": "#205EA6", - "selection": "#205EA640" - }, - "dark": { - "background": "#100F0F", - "surface_background": "#1C1B1A", - "elevated_surface_background": "#282726", - "panel_background": "#100F0F", - "overlay": "#FFFCF01a", - "title_bar": "#1C1B1A", - "title_bar_inactive": "#282726", - "window_border": "#575653", - "border": "#403E3C", - "border_variant": "#343331", - "border_focused": "#4385BE", - "border_selected": "#4385BE", - "border_transparent": "#00000000", - "border_disabled": "#282726", - "ring": "#4385BE", - "text": "#FFFCF0", - "text_muted": "#878580", - "text_placeholder": "#6F6E69", - "text_accent": "#4385BE", - "icon": "#878580", - "icon_muted": "#6F6E69", - "icon_accent": "#4385BE", - "element_foreground": "#100F0F", - "element_background": "#4385BE", - "element_hover": "#3171B2", - "element_active": "#205EA6", - "element_selected": "#1A4F8C", - "element_disabled": "#4385BE4d", - "secondary_foreground": "#205EA6", - "secondary_background": "#1C1B1A", - "secondary_hover": "#4385BE1a", - "secondary_active": "#282726", - "secondary_selected": "#282726", - "secondary_disabled": "#4385BE4d", - "danger_foreground": "#100F0F", - "danger_background": "#E8705F", - "danger_hover": "#D14D41", - "danger_active": "#C03E35", - "danger_selected": "#AF3029", - "danger_disabled": "#E8705F4d", - "warning_foreground": "#100F0F", - "warning_background": "#DFB431", - "warning_hover": "#D0A215", - "warning_active": "#BE9207", - "warning_selected": "#AD8301", - "warning_disabled": "#DFB4314d", - "ghost_element_background": "#00000000", - "ghost_element_background_alt": "#282726", - "ghost_element_hover": "#FFFCF01a", - "ghost_element_active": "#343331", - "ghost_element_selected": "#343331", - "ghost_element_disabled": "#FFFCF00d", - "tab_inactive_background": "#1C1B1A", - "tab_inactive_foreground": "#878580", - "tab_active_background": "#100F0F", - "tab_active_foreground": "#FFFCF0", - "scrollbar_thumb_background": "#FFFCF033", - "scrollbar_thumb_hover_background": "#FFFCF04d", - "scrollbar_thumb_border": "#00000000", - "scrollbar_track_background": "#00000000", - "scrollbar_track_border": "#343331", - "drop_target_background": "#4385BE1a", - "cursor": "#4385BE", - "selection": "#4385BE40" - } -} diff --git a/assets/themes/rose-pine-dawn.json b/assets/themes/rose-pine-dawn.json deleted file mode 100644 index 79a54f1..0000000 --- a/assets/themes/rose-pine-dawn.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "id": "rose-pine-dawn", - "name": "Rosé Pine Dawn", - "author": "Rosé Pine", - "url": "https://rosepinetheme.com/", - "light": { - "background": "#faf4ed", - "surface_background": "#fffaf3", - "elevated_surface_background": "#f2e9e1", - "panel_background": "#faf4ed", - "overlay": "#5752791a", - "title_bar": "#fffaf3", - "title_bar_inactive": "#f2e9e1", - "window_border": "#cecacd", - "border": "#dfdad9", - "border_variant": "#f4ede8", - "border_focused": "#907aa9", - "border_selected": "#907aa9", - "border_transparent": "#00000000", - "border_disabled": "#f2e9e1", - "ring": "#907aa9", - "text": "#575279", - "text_muted": "#797593", - "text_placeholder": "#9893a5", - "text_accent": "#907aa9", - "icon": "#797593", - "icon_muted": "#9893a5", - "icon_accent": "#907aa9", - "element_foreground": "#faf4ed", - "element_background": "#907aa9", - "element_hover": "#907aa9e6", - "element_active": "#826b95", - "element_selected": "#745c81", - "element_disabled": "#907aa94d", - "secondary_foreground": "#745c81", - "secondary_background": "#fffaf3", - "secondary_hover": "#907aa91a", - "secondary_active": "#f2e9e1", - "secondary_selected": "#f2e9e1", - "secondary_disabled": "#907aa94d", - "danger_foreground": "#faf4ed", - "danger_background": "#b4637a", - "danger_hover": "#a7586e", - "danger_active": "#9a4d62", - "danger_selected": "#8d4256", - "danger_disabled": "#b4637a4d", - "warning_foreground": "#575279", - "warning_background": "#ea9d34", - "warning_hover": "#d98e2f", - "warning_active": "#c87f2a", - "warning_selected": "#b77025", - "warning_disabled": "#ea9d344d", - "ghost_element_background": "#00000000", - "ghost_element_background_alt": "#f2e9e1", - "ghost_element_hover": "#5752791a", - "ghost_element_active": "#dfdad9", - "ghost_element_selected": "#dfdad9", - "ghost_element_disabled": "#5752790d", - "tab_inactive_background": "#fffaf3", - "tab_inactive_foreground": "#797593", - "tab_active_background": "#faf4ed", - "tab_active_foreground": "#575279", - "scrollbar_thumb_background": "#57527933", - "scrollbar_thumb_hover_background": "#5752794d", - "scrollbar_thumb_border": "#00000000", - "scrollbar_track_background": "#00000000", - "scrollbar_track_border": "#dfdad9", - "drop_target_background": "#907aa91a", - "cursor": "#907aa9", - "selection": "#907aa940" - }, - "dark": { - "background": "#faf4ed", - "surface_background": "#fffaf3", - "elevated_surface_background": "#f2e9e1", - "panel_background": "#faf4ed", - "overlay": "#5752791a", - "title_bar": "#fffaf3", - "title_bar_inactive": "#f2e9e1", - "window_border": "#cecacd", - "border": "#dfdad9", - "border_variant": "#f4ede8", - "border_focused": "#907aa9", - "border_selected": "#907aa9", - "border_transparent": "#00000000", - "border_disabled": "#f2e9e1", - "ring": "#907aa9", - "text": "#575279", - "text_muted": "#797593", - "text_placeholder": "#9893a5", - "text_accent": "#907aa9", - "icon": "#797593", - "icon_muted": "#9893a5", - "icon_accent": "#907aa9", - "element_foreground": "#faf4ed", - "element_background": "#907aa9", - "element_hover": "#907aa9e6", - "element_active": "#826b95", - "element_selected": "#745c81", - "element_disabled": "#907aa94d", - "secondary_foreground": "#745c81", - "secondary_background": "#fffaf3", - "secondary_hover": "#907aa91a", - "secondary_active": "#f2e9e1", - "secondary_selected": "#f2e9e1", - "secondary_disabled": "#907aa94d", - "danger_foreground": "#faf4ed", - "danger_background": "#b4637a", - "danger_hover": "#a7586e", - "danger_active": "#9a4d62", - "danger_selected": "#8d4256", - "danger_disabled": "#b4637a4d", - "warning_foreground": "#575279", - "warning_background": "#ea9d34", - "warning_hover": "#d98e2f", - "warning_active": "#c87f2a", - "warning_selected": "#b77025", - "warning_disabled": "#ea9d344d", - "ghost_element_background": "#00000000", - "ghost_element_background_alt": "#f2e9e1", - "ghost_element_hover": "#5752791a", - "ghost_element_active": "#dfdad9", - "ghost_element_selected": "#dfdad9", - "ghost_element_disabled": "#5752790d", - "tab_inactive_background": "#fffaf3", - "tab_inactive_foreground": "#797593", - "tab_active_background": "#faf4ed", - "tab_active_foreground": "#575279", - "scrollbar_thumb_background": "#57527933", - "scrollbar_thumb_hover_background": "#5752794d", - "scrollbar_thumb_border": "#00000000", - "scrollbar_track_background": "#00000000", - "scrollbar_track_border": "#dfdad9", - "drop_target_background": "#907aa91a", - "cursor": "#907aa9", - "selection": "#907aa940" - } -} diff --git a/assets/themes/rose-pine-moon.json b/assets/themes/rose-pine-moon.json deleted file mode 100644 index bfd2c44..0000000 --- a/assets/themes/rose-pine-moon.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "id": "rose-pine-moon", - "name": "Rosé Pine Moon", - "author": "Rosé Pine", - "url": "https://rosepinetheme.com/", - "light": { - "background": "#232136", - "surface_background": "#2a273f", - "elevated_surface_background": "#393552", - "panel_background": "#232136", - "overlay": "#e0def41a", - "title_bar": "#2a273f", - "title_bar_inactive": "#393552", - "window_border": "#56526e", - "border": "#44415a", - "border_variant": "#393552", - "border_focused": "#c4a7e7", - "border_selected": "#c4a7e7", - "border_transparent": "#00000000", - "border_disabled": "#393552", - "ring": "#c4a7e7", - "text": "#e0def4", - "text_muted": "#908caa", - "text_placeholder": "#6e6a86", - "text_accent": "#c4a7e7", - "icon": "#908caa", - "icon_muted": "#6e6a86", - "icon_accent": "#c4a7e7", - "element_foreground": "#232136", - "element_background": "#c4a7e7", - "element_hover": "#c4a7e7e6", - "element_active": "#b296d6", - "element_selected": "#a085c5", - "element_disabled": "#c4a7e74d", - "secondary_foreground": "#a085c5", - "secondary_background": "#393552", - "secondary_hover": "#c4a7e71a", - "secondary_active": "#44415a", - "secondary_selected": "#44415a", - "secondary_disabled": "#c4a7e74d", - "danger_foreground": "#232136", - "danger_background": "#eb6f92", - "danger_hover": "#e55a82", - "danger_active": "#df4572", - "danger_selected": "#d93062", - "danger_disabled": "#eb6f924d", - "warning_foreground": "#232136", - "warning_background": "#f6c177", - "warning_hover": "#f4b35e", - "warning_active": "#f2a545", - "warning_selected": "#f0972c", - "warning_disabled": "#f6c1774d", - "ghost_element_background": "#00000000", - "ghost_element_background_alt": "#393552", - "ghost_element_hover": "#e0def41a", - "ghost_element_active": "#44415a", - "ghost_element_selected": "#44415a", - "ghost_element_disabled": "#e0def40d", - "tab_inactive_background": "#2a273f", - "tab_inactive_foreground": "#908caa", - "tab_active_background": "#232136", - "tab_active_foreground": "#e0def4", - "scrollbar_thumb_background": "#e0def433", - "scrollbar_thumb_hover_background": "#e0def44d", - "scrollbar_thumb_border": "#00000000", - "scrollbar_track_background": "#00000000", - "scrollbar_track_border": "#44415a", - "drop_target_background": "#c4a7e71a", - "cursor": "#c4a7e7", - "selection": "#c4a7e740" - }, - "dark": { - "background": "#232136", - "surface_background": "#2a273f", - "elevated_surface_background": "#393552", - "panel_background": "#232136", - "overlay": "#e0def41a", - "title_bar": "#2a273f", - "title_bar_inactive": "#393552", - "window_border": "#56526e", - "border": "#44415a", - "border_variant": "#393552", - "border_focused": "#c4a7e7", - "border_selected": "#c4a7e7", - "border_transparent": "#00000000", - "border_disabled": "#393552", - "ring": "#c4a7e7", - "text": "#e0def4", - "text_muted": "#908caa", - "text_placeholder": "#6e6a86", - "text_accent": "#c4a7e7", - "icon": "#908caa", - "icon_muted": "#6e6a86", - "icon_accent": "#c4a7e7", - "element_foreground": "#232136", - "element_background": "#c4a7e7", - "element_hover": "#c4a7e7e6", - "element_active": "#b296d6", - "element_selected": "#a085c5", - "element_disabled": "#c4a7e74d", - "secondary_foreground": "#a085c5", - "secondary_background": "#393552", - "secondary_hover": "#c4a7e71a", - "secondary_active": "#44415a", - "secondary_selected": "#44415a", - "secondary_disabled": "#c4a7e74d", - "danger_foreground": "#232136", - "danger_background": "#eb6f92", - "danger_hover": "#e55a82", - "danger_active": "#df4572", - "danger_selected": "#d93062", - "danger_disabled": "#eb6f924d", - "warning_foreground": "#232136", - "warning_background": "#f6c177", - "warning_hover": "#f4b35e", - "warning_active": "#f2a545", - "warning_selected": "#f0972c", - "warning_disabled": "#f6c1774d", - "ghost_element_background": "#00000000", - "ghost_element_background_alt": "#393552", - "ghost_element_hover": "#e0def41a", - "ghost_element_active": "#44415a", - "ghost_element_selected": "#44415a", - "ghost_element_disabled": "#e0def40d", - "tab_inactive_background": "#2a273f", - "tab_inactive_foreground": "#908caa", - "tab_active_background": "#232136", - "tab_active_foreground": "#e0def4", - "scrollbar_thumb_background": "#e0def433", - "scrollbar_thumb_hover_background": "#e0def44d", - "scrollbar_thumb_border": "#00000000", - "scrollbar_track_background": "#00000000", - "scrollbar_track_border": "#44415a", - "drop_target_background": "#c4a7e71a", - "cursor": "#c4a7e7", - "selection": "#c4a7e740" - } -} diff --git a/assets/themes/rose-pine.json b/assets/themes/rose-pine.json deleted file mode 100644 index 3a6c48f..0000000 --- a/assets/themes/rose-pine.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "id": "rose-pine", - "name": "Rosé Pine", - "author": "Rosé Pine", - "url": "https://rosepinetheme.com/", - "light": { - "background": "#191724", - "surface_background": "#1f1d2e", - "elevated_surface_background": "#26233a", - "panel_background": "#191724", - "overlay": "#e0def41a", - "title_bar": "#1f1d2e", - "title_bar_inactive": "#26233a", - "window_border": "#524f67", - "border": "#403d52", - "border_variant": "#26233a", - "border_focused": "#c4a7e7", - "border_selected": "#c4a7e7", - "border_transparent": "#00000000", - "border_disabled": "#26233a", - "ring": "#c4a7e7", - "text": "#e0def4", - "text_muted": "#908caa", - "text_placeholder": "#6e6a86", - "text_accent": "#c4a7e7", - "icon": "#908caa", - "icon_muted": "#6e6a86", - "icon_accent": "#c4a7e7", - "element_foreground": "#191724", - "element_background": "#c4a7e7", - "element_hover": "#c4a7e7e6", - "element_active": "#b296d6", - "element_selected": "#a085c5", - "element_disabled": "#c4a7e74d", - "secondary_foreground": "#a085c5", - "secondary_background": "#26233a", - "secondary_hover": "#c4a7e71a", - "secondary_active": "#403d52", - "secondary_selected": "#403d52", - "secondary_disabled": "#c4a7e74d", - "danger_foreground": "#191724", - "danger_background": "#eb6f92", - "danger_hover": "#e55a82", - "danger_active": "#df4572", - "danger_selected": "#d93062", - "danger_disabled": "#eb6f924d", - "warning_foreground": "#191724", - "warning_background": "#f6c177", - "warning_hover": "#f4b35e", - "warning_active": "#f2a545", - "warning_selected": "#f0972c", - "warning_disabled": "#f6c1774d", - "ghost_element_background": "#00000000", - "ghost_element_background_alt": "#26233a", - "ghost_element_hover": "#e0def41a", - "ghost_element_active": "#403d52", - "ghost_element_selected": "#403d52", - "ghost_element_disabled": "#e0def40d", - "tab_inactive_background": "#1f1d2e", - "tab_inactive_foreground": "#908caa", - "tab_active_background": "#191724", - "tab_active_foreground": "#e0def4", - "scrollbar_thumb_background": "#e0def433", - "scrollbar_thumb_hover_background": "#e0def44d", - "scrollbar_thumb_border": "#00000000", - "scrollbar_track_background": "#00000000", - "scrollbar_track_border": "#403d52", - "drop_target_background": "#c4a7e71a", - "cursor": "#c4a7e7", - "selection": "#c4a7e740" - }, - "dark": { - "background": "#191724", - "surface_background": "#1f1d2e", - "elevated_surface_background": "#26233a", - "panel_background": "#191724", - "overlay": "#e0def41a", - "title_bar": "#1f1d2e", - "title_bar_inactive": "#26233a", - "window_border": "#524f67", - "border": "#403d52", - "border_variant": "#26233a", - "border_focused": "#c4a7e7", - "border_selected": "#c4a7e7", - "border_transparent": "#00000000", - "border_disabled": "#26233a", - "ring": "#c4a7e7", - "text": "#e0def4", - "text_muted": "#908caa", - "text_placeholder": "#6e6a86", - "text_accent": "#c4a7e7", - "icon": "#908caa", - "icon_muted": "#6e6a86", - "icon_accent": "#c4a7e7", - "element_foreground": "#191724", - "element_background": "#c4a7e7", - "element_hover": "#c4a7e7e6", - "element_active": "#b296d6", - "element_selected": "#a085c5", - "element_disabled": "#c4a7e74d", - "secondary_foreground": "#a085c5", - "secondary_background": "#26233a", - "secondary_hover": "#c4a7e71a", - "secondary_active": "#403d52", - "secondary_selected": "#403d52", - "secondary_disabled": "#c4a7e74d", - "danger_foreground": "#191724", - "danger_background": "#eb6f92", - "danger_hover": "#e55a82", - "danger_active": "#df4572", - "danger_selected": "#d93062", - "danger_disabled": "#eb6f924d", - "warning_foreground": "#191724", - "warning_background": "#f6c177", - "warning_hover": "#f4b35e", - "warning_active": "#f2a545", - "warning_selected": "#f0972c", - "warning_disabled": "#f6c1774d", - "ghost_element_background": "#00000000", - "ghost_element_background_alt": "#26233a", - "ghost_element_hover": "#e0def41a", - "ghost_element_active": "#403d52", - "ghost_element_selected": "#403d52", - "ghost_element_disabled": "#e0def40d", - "tab_inactive_background": "#1f1d2e", - "tab_inactive_foreground": "#908caa", - "tab_active_background": "#191724", - "tab_active_foreground": "#e0def4", - "scrollbar_thumb_background": "#e0def433", - "scrollbar_thumb_hover_background": "#e0def44d", - "scrollbar_thumb_border": "#00000000", - "scrollbar_track_background": "#00000000", - "scrollbar_track_border": "#403d52", - "drop_target_background": "#c4a7e71a", - "cursor": "#c4a7e7", - "selection": "#c4a7e740" - } -} diff --git a/crates/coop/src/sidebar/mod.rs b/crates/coop/src/sidebar/mod.rs index 927caec..13969f9 100644 --- a/crates/coop/src/sidebar/mod.rs +++ b/crates/coop/src/sidebar/mod.rs @@ -503,7 +503,7 @@ impl Render for Sidebar { .h(TABBAR_HEIGHT) .border_b_1() .border_color(cx.theme().border) - .bg(cx.theme().elevated_surface_background) + .bg(cx.theme().tab_background) .child( TextInput::new(&self.find_input) .appearance(false) diff --git a/crates/theme/src/colors.rs b/crates/theme/src/colors.rs index 7910ea6..bc84c5b 100644 --- a/crates/theme/src/colors.rs +++ b/crates/theme/src/colors.rs @@ -30,6 +30,8 @@ pub struct ThemeColors { pub text_muted: Hsla, pub text_placeholder: Hsla, pub text_accent: Hsla, + pub text_danger: Hsla, + pub text_warning: Hsla, // Icon colors pub icon: Hsla, @@ -79,6 +81,7 @@ pub struct ThemeColors { // Tab colors pub tab_background: Hsla, pub tab_foreground: Hsla, + pub tab_hover_background: Hsla, pub tab_active_background: Hsla, pub tab_active_foreground: Hsla, @@ -109,8 +112,8 @@ impl ThemeColors { elevated_surface_background: neutral().light().step_3(), panel_background: neutral().light().step_1(), overlay: neutral().light_alpha().step_3(), - title_bar: neutral().light().step_2(), - title_bar_inactive: neutral().light().step_3(), + title_bar: neutral().light().step_3(), + title_bar_inactive: neutral().light().step_1(), window_border: hsl(240.0, 5.9, 78.0), border: neutral().light().step_6(), @@ -124,7 +127,9 @@ impl ThemeColors { text: neutral().light().step_12(), text_muted: neutral().light().step_11(), text_placeholder: neutral().light().step_10(), - text_accent: brand().light().step_11(), + text_accent: brand().light().step_9(), + text_danger: danger().light().step_9(), + text_warning: warning().light().step_10(), icon: neutral().light().step_11(), icon_muted: neutral().light().step_10(), @@ -167,6 +172,7 @@ impl ThemeColors { tab_background: neutral().light().step_3(), tab_foreground: neutral().light().step_11(), + tab_hover_background: neutral().light_alpha().step_4(), tab_active_background: neutral().light().step_1(), tab_active_foreground: neutral().light().step_12(), @@ -174,7 +180,7 @@ impl ThemeColors { scrollbar_thumb_hover_background: neutral().light_alpha().step_4(), scrollbar_thumb_border: gpui::transparent_black(), scrollbar_track_background: gpui::transparent_black(), - scrollbar_track_border: neutral().light().step_5(), + scrollbar_track_border: gpui::transparent_black(), drop_target_background: brand().light_alpha().step_2(), cursor: hsl(200., 100., 50.), @@ -192,7 +198,7 @@ impl ThemeColors { elevated_surface_background: neutral().dark().step_3(), panel_background: gpui::black(), overlay: neutral().dark_alpha().step_3(), - title_bar: gpui::transparent_black(), + title_bar: neutral().dark().step_3(), title_bar_inactive: neutral().dark().step_1(), window_border: hsl(240.0, 3.7, 28.0), @@ -207,7 +213,9 @@ impl ThemeColors { text: neutral().dark().step_12(), text_muted: neutral().dark().step_11(), text_placeholder: neutral().dark().step_10(), - text_accent: brand().dark().step_11(), + text_accent: brand().dark().step_9(), + text_danger: danger().dark().step_9(), + text_warning: warning().dark().step_9(), icon: neutral().dark().step_11(), icon_muted: neutral().dark().step_10(), @@ -250,6 +258,7 @@ impl ThemeColors { tab_background: neutral().dark().step_3(), tab_foreground: neutral().dark().step_11(), + tab_hover_background: neutral().dark_alpha().step_4(), tab_active_background: neutral().dark().step_1(), tab_active_foreground: neutral().dark().step_12(), @@ -257,7 +266,7 @@ impl ThemeColors { scrollbar_thumb_hover_background: neutral().dark_alpha().step_4(), scrollbar_thumb_border: gpui::transparent_black(), scrollbar_track_background: gpui::transparent_black(), - scrollbar_track_border: neutral().dark().step_5(), + scrollbar_track_border: gpui::transparent_black(), drop_target_background: brand().dark_alpha().step_2(), cursor: hsl(200., 100., 50.), diff --git a/crates/theme/src/lib.rs b/crates/theme/src/lib.rs index 4a977af..3a65403 100644 --- a/crates/theme/src/lib.rs +++ b/crates/theme/src/lib.rs @@ -34,7 +34,7 @@ pub const CLIENT_SIDE_DECORATION_BORDER: Pixels = px(1.0); pub const TITLEBAR_HEIGHT: Pixels = px(36.0); /// Defines workspace tabbar height -pub const TABBAR_HEIGHT: Pixels = px(32.0); +pub const TABBAR_HEIGHT: Pixels = px(28.0); /// Defines default sidebar width pub const SIDEBAR_WIDTH: Pixels = px(240.); @@ -207,7 +207,7 @@ impl From for Theme { Theme { font_size: px(15.), font_family: font_family.into(), - radius: px(5.), + radius: px(6.), radius_lg: px(10.), shadow: true, scrollbar_mode: ScrollbarMode::default(), diff --git a/crates/ui/src/dock/dock.rs b/crates/ui/src/dock/dock.rs index c0e7ec5..619385d 100644 --- a/crates/ui/src/dock/dock.rs +++ b/crates/ui/src/dock/dock.rs @@ -4,8 +4,8 @@ use std::sync::Arc; use gpui::prelude::FluentBuilder as _; use gpui::{ App, AppContext, Axis, Context, Element, Empty, Entity, IntoElement, MouseMoveEvent, - MouseUpEvent, ParentElement as _, Pixels, Point, Render, Style, Styled as _, WeakEntity, - Window, div, px, + MouseUpEvent, ParentElement as _, Pixels, Point, Render, Style, StyleRefinement, Styled as _, + WeakEntity, Window, div, px, }; use super::{DockArea, DockItem}; @@ -327,6 +327,8 @@ impl Render for Dock { return div(); } + let cache_style = StyleRefinement::default().absolute().size_full(); + div() .relative() .overflow_hidden() @@ -342,7 +344,7 @@ impl Render for Dock { .map(|this| match &self.panel { DockItem::Split { view, .. } => this.child(view.clone()), DockItem::Tabs { view, .. } => this.child(view.clone()), - DockItem::Panel { view, .. } => this.child(view.clone().view()), + DockItem::Panel { view, .. } => this.child(view.clone().view().cached(cache_style)), }) .child(self.render_resize_handle(window, cx)) .child(DockElement { diff --git a/crates/ui/src/dock/tab_panel.rs b/crates/ui/src/dock/tab_panel.rs index baa2f81..50a8f78 100644 --- a/crates/ui/src/dock/tab_panel.rs +++ b/crates/ui/src/dock/tab_panel.rs @@ -5,7 +5,7 @@ use gpui::{ App, AppContext, Context, Corner, DefiniteLength, DismissEvent, DragMoveEvent, Empty, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement as _, IntoElement, MouseButton, ParentElement, Pixels, Render, ScrollHandle, SharedString, StatefulInteractiveElement, Styled, - WeakEntity, Window, div, rems, + WeakEntity, Window, div, px, rems, }; use theme::{ActiveTheme, AxisExt, CLIENT_SIDE_DECORATION_ROUNDING, Placement, TABBAR_HEIGHT}; @@ -42,22 +42,20 @@ impl DragPanel { impl Render for DragPanel { fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { - div() + h_flex() .id("drag-panel") .cursor_grab() - .py_1() - .px_2() - .w_24() - .flex() - .items_center() + .p_2() + .min_w_24() .justify_center() .overflow_hidden() .whitespace_nowrap() - .rounded(cx.theme().radius_lg) + .rounded(cx.theme().radius) .text_xs() - .when(cx.theme().shadow, |this| this.shadow_lg()) + .text_color(cx.theme().text) + .text_ellipsis() + .when(cx.theme().shadow, |this| this.shadow_xs()) .bg(cx.theme().background) - .text_color(cx.theme().text_accent) .child(self.panel.title(cx)) } } @@ -573,6 +571,7 @@ impl TabPanel { let right_dock_button = self.render_dock_toggle_button(DockPlacement::Right, window, cx); let has_extend_dock_button = left_dock_button.is_some() || bottom_dock_button.is_some(); let tabs_count = self.panels.len(); + let is_bottom_dock = bottom_dock_button.is_some(); if tabs_count == 1 && dock_area.read(cx).panel_style == PanelStyle::Default { let panel = self.panels.first().unwrap(); @@ -641,7 +640,7 @@ impl TabPanel { .into_any_element(); } - TabBar::new() + TabBar::new("tab-bar") .track_scroll(&self.tab_bar_scroll_handle) .h(TABBAR_HEIGHT) .when(has_extend_dock_button, |this| { @@ -649,9 +648,14 @@ impl TabPanel { h_flex() .items_center() .top_0() + .right(-px(1.)) + .border_r_1() + .border_b_1() .h_full() + .border_color(cx.theme().border) .bg(cx.theme().tab_background) - .px_2() + .pl_0p5() + .pr_1() .children(left_dock_button) .children(bottom_dock_button), ) @@ -673,10 +677,37 @@ impl TabPanel { Some( Tab::new() .ix(ix) - .label(panel.title(cx)) - .py_2() + .tab_bar_prefix(has_extend_dock_button) + .child(panel.title(cx)) .selected(active) .disabled(disabled) + .suffix( + Button::new("close-{ix}") + .icon(IconName::Close) + .tooltip("Close panel") + .ghost() + .xsmall() + .on_click(cx.listener({ + let panel = panel.clone(); + move |view, _ev, window, cx| { + view.remove_panel(&panel, window, cx); + } + })), + ) + .on_click(cx.listener({ + let is_collapsed = self.collapsed; + let dock_area = self.dock_area.clone(); + move |view, _, window, cx| { + view.set_active_ix(ix, window, cx); + + // Open dock if clicked on the collapsed bottom dock + if is_bottom_dock && is_collapsed { + _ = dock_area.update(cx, |dock_area, cx| { + dock_area.toggle_dock(DockPlacement::Bottom, window, cx); + }); + } + } + })) .when(!disabled, |this| { this.on_mouse_down( MouseButton::Middle, @@ -713,19 +744,6 @@ impl TabPanel { }, )) }) - .suffix( - Button::new("close-{ix}") - .icon(IconName::Close) - .tooltip("Close panel") - .ghost() - .xsmall() - .on_click(cx.listener({ - let panel = panel.clone(); - move |view, _ev, window, cx| { - view.remove_panel(&panel, window, cx); - } - })), - ) }), ) })) @@ -761,11 +779,15 @@ impl TabPanel { this.suffix( h_flex() .items_center() - .px_2() - .gap_1() .top_0() .right_0() .h_full() + .border_l_1() + .border_b_1() + .px_0p5() + .gap_1() + .border_color(cx.theme().border) + .bg(cx.theme().tab_background) .child(self.render_toolbar(state, window, cx)) .when_some(right_dock_button, |this, btn| this.child(btn)), ) diff --git a/crates/ui/src/styled.rs b/crates/ui/src/styled.rs index 60ec363..8f3f981 100644 --- a/crates/ui/src/styled.rs +++ b/crates/ui/src/styled.rs @@ -1,4 +1,4 @@ -use gpui::{div, px, App, Div, Pixels, Refineable, StyleRefinement, Styled}; +use gpui::{App, DefiniteLength, Div, Edges, Pixels, Refineable, StyleRefinement, Styled, div, px}; use serde::{Deserialize, Serialize}; use theme::ActiveTheme; @@ -46,6 +46,30 @@ pub trait StyledExt: Styled + Sized { self.flex().flex_col() } + /// Apply paddings to the element. + fn paddings(self, paddings: impl Into>) -> Self + where + L: Into + Clone + Default + std::fmt::Debug + PartialEq, + { + let paddings = paddings.into(); + self.pt(paddings.top.into()) + .pb(paddings.bottom.into()) + .pl(paddings.left.into()) + .pr(paddings.right.into()) + } + + /// Apply margins to the element. + fn margins(self, margins: impl Into>) -> Self + where + L: Into + Clone + Default + std::fmt::Debug + PartialEq, + { + let margins = margins.into(); + self.mt(margins.top.into()) + .mb(margins.bottom.into()) + .ml(margins.left.into()) + .mr(margins.right.into()) + } + font_weight!(font_thin, THIN); font_weight!(font_extralight, EXTRA_LIGHT); font_weight!(font_light, LIGHT); diff --git a/crates/ui/src/tab/mod.rs b/crates/ui/src/tab/mod.rs index f53e050..25d0025 100644 --- a/crates/ui/src/tab/mod.rs +++ b/crates/ui/src/tab/mod.rs @@ -1,74 +1,557 @@ -use gpui::prelude::FluentBuilder; -use gpui::{ - AnyElement, App, Div, InteractiveElement, IntoElement, MouseButton, ParentElement, RenderOnce, - StatefulInteractiveElement, Styled, Window, div, px, -}; -use theme::{ActiveTheme, TABBAR_HEIGHT}; +use std::rc::Rc; -use crate::{Selectable, Sizable, Size, h_flex}; +use gpui::prelude::FluentBuilder as _; +use gpui::{ + AnyElement, App, ClickEvent, Div, Edges, Hsla, InteractiveElement, IntoElement, MouseButton, + ParentElement, Pixels, RenderOnce, SharedString, StatefulInteractiveElement, Styled, Window, + div, px, relative, +}; +use theme::ActiveTheme; + +use crate::{Icon, IconName, Selectable, Sizable, Size, StyledExt, h_flex}; pub mod tab_bar; +/// Tab variants. +#[derive(Debug, Clone, Default, Copy, PartialEq, Eq, Hash)] +pub enum TabVariant { + #[default] + Tab, + Outline, + Pill, + Segmented, + Underline, +} + +impl TabVariant { + fn height(&self, size: Size) -> Pixels { + match size { + Size::XSmall => match self { + TabVariant::Underline => px(26.), + _ => px(20.), + }, + Size::Small => match self { + TabVariant::Underline => px(30.), + _ => px(24.), + }, + Size::Large => match self { + TabVariant::Underline => px(44.), + _ => px(36.), + }, + _ => match self { + TabVariant::Underline => px(36.), + _ => px(32.), + }, + } + } + + fn inner_height(&self, size: Size) -> Pixels { + match size { + Size::XSmall => match self { + TabVariant::Tab | TabVariant::Outline | TabVariant::Pill => px(18.), + TabVariant::Segmented => px(16.), + TabVariant::Underline => px(20.), + }, + Size::Small => match self { + TabVariant::Tab | TabVariant::Outline | TabVariant::Pill => px(22.), + TabVariant::Segmented => px(18.), + TabVariant::Underline => px(22.), + }, + Size::Large => match self { + TabVariant::Tab | TabVariant::Outline | TabVariant::Pill => px(36.), + TabVariant::Segmented => px(28.), + TabVariant::Underline => px(32.), + }, + _ => match self { + TabVariant::Tab => px(30.), + TabVariant::Outline | TabVariant::Pill => px(26.), + TabVariant::Segmented => px(24.), + TabVariant::Underline => px(26.), + }, + } + } + + /// Default px(12) to match panel px_3, See [`crate::dock::TabPanel`] + fn inner_paddings(&self, size: Size) -> Edges { + let mut padding_x = match size { + Size::XSmall => px(8.), + Size::Small => px(10.), + Size::Large => px(16.), + _ => px(12.), + }; + + if matches!(self, TabVariant::Underline) { + padding_x = px(0.); + } + + Edges { + left: padding_x, + right: padding_x, + ..Default::default() + } + } + + fn inner_margins(&self, size: Size) -> Edges { + match size { + Size::XSmall => match self { + TabVariant::Underline => Edges { + top: px(1.), + bottom: px(2.), + ..Default::default() + }, + _ => Edges::all(px(0.)), + }, + Size::Small => match self { + TabVariant::Underline => Edges { + top: px(2.), + bottom: px(3.), + ..Default::default() + }, + _ => Edges::all(px(0.)), + }, + Size::Large => match self { + TabVariant::Underline => Edges { + top: px(5.), + bottom: px(6.), + ..Default::default() + }, + _ => Edges::all(px(0.)), + }, + _ => match self { + TabVariant::Underline => Edges { + top: px(3.), + bottom: px(4.), + ..Default::default() + }, + _ => Edges::all(px(0.)), + }, + } + } + + fn normal(&self, cx: &App) -> TabStyle { + match self { + TabVariant::Tab => TabStyle { + fg: cx.theme().tab_foreground, + bg: gpui::transparent_black(), + borders: Edges { + left: px(1.), + right: px(1.), + ..Default::default() + }, + border_color: gpui::transparent_black(), + ..Default::default() + }, + TabVariant::Outline => TabStyle { + fg: cx.theme().tab_foreground, + bg: gpui::transparent_black(), + borders: Edges::all(px(1.)), + border_color: cx.theme().border, + ..Default::default() + }, + TabVariant::Pill => TabStyle { + fg: cx.theme().text, + bg: gpui::transparent_black(), + ..Default::default() + }, + TabVariant::Segmented => TabStyle { + fg: cx.theme().tab_foreground, + bg: gpui::transparent_black(), + ..Default::default() + }, + TabVariant::Underline => TabStyle { + fg: cx.theme().tab_foreground, + bg: gpui::transparent_black(), + inner_bg: gpui::transparent_black(), + borders: Edges { + bottom: px(2.), + ..Default::default() + }, + border_color: gpui::transparent_black(), + ..Default::default() + }, + } + } + + fn hovered(&self, selected: bool, cx: &App) -> TabStyle { + match self { + TabVariant::Tab => TabStyle { + fg: cx.theme().tab_foreground, + bg: gpui::transparent_black(), + borders: Edges { + left: px(1.), + right: px(1.), + ..Default::default() + }, + border_color: gpui::transparent_black(), + ..Default::default() + }, + TabVariant::Outline => TabStyle { + fg: cx.theme().secondary_foreground, + bg: cx.theme().secondary_hover, + borders: Edges::all(px(1.)), + border_color: cx.theme().border, + ..Default::default() + }, + TabVariant::Pill => TabStyle { + fg: cx.theme().secondary_foreground, + bg: cx.theme().secondary_background, + ..Default::default() + }, + TabVariant::Segmented => TabStyle { + fg: cx.theme().tab_foreground, + bg: gpui::transparent_black(), + inner_bg: if selected { + cx.theme().background + } else { + gpui::transparent_black() + }, + ..Default::default() + }, + TabVariant::Underline => TabStyle { + fg: cx.theme().tab_foreground, + bg: gpui::transparent_black(), + inner_bg: gpui::transparent_black(), + borders: Edges { + bottom: px(2.), + ..Default::default() + }, + border_color: gpui::transparent_black(), + ..Default::default() + }, + } + } + + fn selected(&self, cx: &App) -> TabStyle { + match self { + TabVariant::Tab => TabStyle { + fg: cx.theme().tab_active_foreground, + bg: cx.theme().tab_active_background, + borders: Edges { + left: px(1.), + right: px(1.), + ..Default::default() + }, + border_color: cx.theme().border, + ..Default::default() + }, + TabVariant::Outline => TabStyle { + fg: cx.theme().text_accent, + bg: gpui::transparent_black(), + borders: Edges::all(px(1.)), + border_color: cx.theme().element_active, + ..Default::default() + }, + TabVariant::Pill => TabStyle { + fg: cx.theme().element_foreground, + bg: cx.theme().element_background, + ..Default::default() + }, + TabVariant::Segmented => TabStyle { + fg: cx.theme().tab_active_foreground, + bg: gpui::transparent_black(), + inner_bg: cx.theme().background, + shadow: true, + ..Default::default() + }, + TabVariant::Underline => TabStyle { + fg: cx.theme().tab_active_foreground, + bg: gpui::transparent_black(), + borders: Edges { + bottom: px(2.), + ..Default::default() + }, + border_color: cx.theme().element_active, + ..Default::default() + }, + } + } + + fn disabled(&self, selected: bool, cx: &App) -> TabStyle { + match self { + TabVariant::Tab => TabStyle { + fg: cx.theme().text_muted, + bg: gpui::transparent_black(), + border_color: if selected { + cx.theme().border + } else { + gpui::transparent_black() + }, + borders: Edges { + left: px(1.), + right: px(1.), + ..Default::default() + }, + ..Default::default() + }, + TabVariant::Outline => TabStyle { + fg: cx.theme().text_muted, + bg: gpui::transparent_black(), + borders: Edges::all(px(1.)), + border_color: if selected { + cx.theme().element_active + } else { + cx.theme().border + }, + ..Default::default() + }, + TabVariant::Pill => TabStyle { + fg: if selected { + cx.theme().element_foreground.opacity(0.5) + } else { + cx.theme().text_muted + }, + bg: if selected { + cx.theme().element_background.opacity(0.5) + } else { + gpui::transparent_black() + }, + ..Default::default() + }, + TabVariant::Segmented => TabStyle { + fg: cx.theme().text_muted, + bg: cx.theme().tab_background, + inner_bg: if selected { + cx.theme().background + } else { + gpui::transparent_black() + }, + ..Default::default() + }, + TabVariant::Underline => TabStyle { + fg: cx.theme().text_muted, + bg: gpui::transparent_black(), + border_color: if selected { + cx.theme().border + } else { + gpui::transparent_black() + }, + borders: Edges { + bottom: px(2.), + ..Default::default() + }, + ..Default::default() + }, + } + } + + pub(super) fn tab_bar_radius(&self, size: Size, cx: &App) -> Pixels { + if *self != TabVariant::Segmented { + return px(0.); + } + + match size { + Size::XSmall | Size::Small => cx.theme().radius, + Size::Large => cx.theme().radius_lg, + _ => cx.theme().radius_lg, + } + } + + fn radius(&self, size: Size, cx: &App) -> Pixels { + match self { + TabVariant::Outline | TabVariant::Pill => px(99.), + TabVariant::Segmented => match size { + Size::XSmall | Size::Small => cx.theme().radius, + Size::Large => cx.theme().radius_lg, + _ => cx.theme().radius_lg, + }, + _ => px(0.), + } + } + + fn inner_radius(&self, size: Size, cx: &App) -> Pixels { + match self { + TabVariant::Segmented => match size { + Size::Large => self.tab_bar_radius(size, cx) - px(3.), + _ => self.tab_bar_radius(size, cx) - px(2.), + }, + _ => px(0.), + } + } +} + +#[allow(dead_code)] +struct TabStyle { + borders: Edges, + border_color: Hsla, + bg: Hsla, + fg: Hsla, + shadow: bool, + inner_bg: Hsla, +} + +impl Default for TabStyle { + fn default() -> Self { + TabStyle { + borders: Edges::all(px(0.)), + border_color: gpui::transparent_white(), + bg: gpui::transparent_white(), + fg: gpui::transparent_white(), + shadow: false, + inner_bg: gpui::transparent_white(), + } + } +} + +#[allow(clippy::type_complexity)] +/// A Tab element for the [`super::TabBar`]. #[derive(IntoElement)] pub struct Tab { ix: usize, base: Div, - label: Option, + pub(super) label: Option, + icon: Option, prefix: Option, + pub(super) tab_bar_prefix: Option, suffix: Option, - disabled: bool, - selected: bool, + children: Vec, + variant: TabVariant, size: Size, + pub(super) disabled: bool, + pub(super) selected: bool, + on_click: Option>, } -impl Tab { - pub fn new() -> Self { - Self { - ix: 0, - base: div(), - label: None, - disabled: false, - selected: false, - prefix: None, - suffix: None, - size: Size::default(), - } +impl From<&'static str> for Tab { + fn from(label: &'static str) -> Self { + Self::new().label(label) } +} - /// Set label for the tab. - pub fn label(mut self, label: impl Into) -> Self { - self.label = Some(label.into()); - self +impl From for Tab { + fn from(label: String) -> Self { + Self::new().label(label) } +} - /// Set the left side of the tab - pub fn prefix(mut self, prefix: impl Into) -> Self { - self.prefix = Some(prefix.into()); - self +impl From for Tab { + fn from(label: SharedString) -> Self { + Self::new().label(label) } +} - /// Set the right side of the tab - pub fn suffix(mut self, suffix: impl Into) -> Self { - self.suffix = Some(suffix.into()); - self +impl From for Tab { + fn from(icon: Icon) -> Self { + Self::default().icon(icon) } +} - /// Set disabled state to the tab - pub fn disabled(mut self, disabled: bool) -> Self { - self.disabled = disabled; - self - } - - /// Set index to the tab. - pub fn ix(mut self, ix: usize) -> Self { - self.ix = ix; - self +impl From for Tab { + fn from(icon_name: IconName) -> Self { + Self::default().icon(Icon::new(icon_name)) } } impl Default for Tab { fn default() -> Self { - Self::new() + Self { + ix: 0, + base: div(), + label: None, + icon: None, + tab_bar_prefix: None, + children: Vec::new(), + disabled: false, + selected: false, + prefix: None, + suffix: None, + variant: TabVariant::default(), + size: Size::default(), + on_click: None, + } + } +} + +impl Tab { + /// Create a new tab with a label. + pub fn new() -> Self { + Self::default() + } + + /// Set label for the tab. + pub fn label(mut self, label: impl Into) -> Self { + self.label = Some(label.into()); + self + } + + /// Set icon for the tab. + pub fn icon(mut self, icon: impl Into) -> Self { + self.icon = Some(icon.into()); + self + } + + /// Set Tab Variant. + pub fn with_variant(mut self, variant: TabVariant) -> Self { + self.variant = variant; + self + } + + /// Use Pill variant. + pub fn pill(mut self) -> Self { + self.variant = TabVariant::Pill; + self + } + + /// Use outline variant. + pub fn outline(mut self) -> Self { + self.variant = TabVariant::Outline; + self + } + + /// Use Segmented variant. + pub fn segmented(mut self) -> Self { + self.variant = TabVariant::Segmented; + self + } + + /// Use Underline variant. + pub fn underline(mut self) -> Self { + self.variant = TabVariant::Underline; + self + } + + /// Set the left side of the tab + pub fn prefix(mut self, prefix: impl IntoElement) -> Self { + self.prefix = Some(prefix.into_any_element()); + self + } + + /// Set the right side of the tab + pub fn suffix(mut self, suffix: impl IntoElement) -> Self { + self.suffix = Some(suffix.into_any_element()); + self + } + + /// Set disabled state to the tab, default false. + pub fn disabled(mut self, disabled: bool) -> Self { + self.disabled = disabled; + self + } + + /// Set the click handler for the tab. + pub fn on_click( + mut self, + on_click: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static, + ) -> Self { + self.on_click = Some(Rc::new(on_click)); + self + } + + /// Set index to the tab. + pub(crate) fn ix(mut self, ix: usize) -> Self { + self.ix = ix; + self + } + + /// Set if the tab bar has a prefix. + pub(crate) fn tab_bar_prefix(mut self, tab_bar_prefix: bool) -> Self { + self.tab_bar_prefix = Some(tab_bar_prefix); + self + } +} + +impl ParentElement for Tab { + fn extend(&mut self, elements: impl IntoIterator) { + self.children.extend(elements); } } @@ -105,47 +588,115 @@ impl Sizable for Tab { } impl RenderOnce for Tab { - fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { - let (text_color, bg_color) = match (self.selected, self.disabled) { - (true, false) => ( - cx.theme().tab_active_foreground, - cx.theme().tab_active_background, - ), - (false, false) => (cx.theme().tab_foreground, cx.theme().tab_background), - (true, true) => (cx.theme().text_muted, cx.theme().tab_background), - (false, true) => (cx.theme().text_placeholder, cx.theme().tab_background), + fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement { + let mut tab_style = if self.selected { + self.variant.selected(cx) + } else { + self.variant.normal(cx) }; + let mut hover_style = self.variant.hovered(self.selected, cx); + + if self.disabled { + tab_style = self.variant.disabled(self.selected, cx); + hover_style = self.variant.disabled(self.selected, cx); + } + + let tab_bar_prefix = self.tab_bar_prefix.unwrap_or_default(); + + if !tab_bar_prefix && self.ix == 0 && self.variant == TabVariant::Tab { + tab_style.borders.left = px(0.); + hover_style.borders.left = px(0.); + } + + let radius = self.variant.radius(self.size, cx); + let inner_radius = self.variant.inner_radius(self.size, cx); + let inner_paddings = self.variant.inner_paddings(self.size); + let inner_margins = self.variant.inner_margins(self.size); + let inner_height = self.variant.inner_height(self.size); + let height = self.variant.height(self.size); + self.base .id(self.ix) - .group("") - .relative() + .flex() + .flex_wrap() + .gap_1() + .items_center() .flex_shrink_0() + .h(height) .overflow_hidden() + .text_color(tab_style.fg) + .map(|this| match self.size { + Size::XSmall => this.text_xs(), + Size::Large => this.text_base(), + _ => this.text_sm(), + }) + .bg(tab_style.bg) + .border_l(tab_style.borders.left) + .border_r(tab_style.borders.right) + .border_t(tab_style.borders.top) + .border_b(tab_style.borders.bottom) + .border_color(tab_style.border_color) + .rounded(radius) + .when(!self.selected && !self.disabled, |this| { + this.hover(|this| { + this.text_color(hover_style.fg) + .bg(hover_style.bg) + .border_l(hover_style.borders.left) + .border_r(hover_style.borders.right) + .border_t(hover_style.borders.top) + .border_b(hover_style.borders.bottom) + .border_color(hover_style.border_color) + .rounded(radius) + }) + }) + .when_some(self.prefix, |this, prefix| this.child(prefix)) .child( h_flex() - .h(TABBAR_HEIGHT - px(8.)) - .px_1() - .text_xs() - .text_ellipsis() - .text_color(text_color) - .bg(bg_color) - .rounded(cx.theme().radius) - .when(cx.theme().shadow && self.selected, |this| this.shadow_xs()) - .when_some(self.prefix, |this, prefix| this.child(prefix)) - .when_some(self.label, |this, label| this.child(label)) - .when_some(self.suffix, |this, suffix| { - this.child( - div() - .pl_4() - .invisible() - .group_hover("", |this| this.visible()) - .child(suffix), - ) - }), + .flex_1() + .h(inner_height) + .line_height(relative(1.)) + .whitespace_nowrap() + .items_center() + .justify_center() + .overflow_hidden() + .margins(inner_margins) + .flex_shrink_0() + .map(|this| match self.icon { + Some(icon) => { + this.w(inner_height * 1.25) + .child(icon.map(|this| match self.size { + Size::XSmall => this.size_2p5(), + Size::Small => this.size_3p5(), + Size::Large => this.size_4(), + _ => this.size_4(), + })) + } + None => this + .paddings(inner_paddings) + .map(|this| match self.label { + Some(label) => this.child(label), + None => this, + }) + .children(self.children), + }) + .bg(tab_style.inner_bg) + .rounded(inner_radius) + .when(tab_style.shadow, |this| this.shadow_xs()) + .hover(|this| this.bg(hover_style.inner_bg).rounded(inner_radius)), ) - .on_mouse_down(MouseButton::Left, |_ev, _window, cx| { + .when_some(self.suffix, |this, suffix| { + this.child(div().pr_2().child(suffix)) + }) + .on_mouse_down(MouseButton::Left, |_, _, cx| { + // Stop propagation behavior, for works on TitleBar. + // https://github.com/longbridge/gpui-component/issues/1836 cx.stop_propagation(); }) + .when(!self.disabled, |this| { + this.when_some(self.on_click.clone(), |this, on_click| { + this.on_click(move |event, window, cx| on_click(event, window, cx)) + }) + }) } } diff --git a/crates/ui/src/tab/tab_bar.rs b/crates/ui/src/tab/tab_bar.rs index adfebf8..4f5c188 100644 --- a/crates/ui/src/tab/tab_bar.rs +++ b/crates/ui/src/tab/tab_bar.rs @@ -1,41 +1,92 @@ -#[cfg(not(target_os = "windows"))] -use gpui::Pixels; +use std::rc::Rc; + use gpui::prelude::FluentBuilder as _; use gpui::{ - AnyElement, App, Div, InteractiveElement, IntoElement, ParentElement, RenderOnce, ScrollHandle, - StatefulInteractiveElement as _, StyleRefinement, Styled, Window, div, px, + AnyElement, App, Corner, Div, Edges, ElementId, InteractiveElement, IntoElement, ParentElement, + RenderOnce, ScrollHandle, Stateful, StatefulInteractiveElement as _, StyleRefinement, Styled, + Window, div, px, }; use smallvec::SmallVec; use theme::ActiveTheme; -use crate::{Sizable, Size, StyledExt, h_flex}; +use super::{Tab, TabVariant}; +use crate::button::{Button, ButtonVariants as _}; +use crate::menu::{DropdownMenu as _, PopupMenuItem}; +use crate::{IconName, Selectable, Sizable, Size, StyledExt, h_flex}; +#[allow(clippy::type_complexity)] +/// A TabBar element that contains multiple [`Tab`] items. #[derive(IntoElement)] pub struct TabBar { - base: Div, + base: Stateful
, style: StyleRefinement, scroll_handle: Option, prefix: Option, suffix: Option, + children: SmallVec<[Tab; 2]>, last_empty_space: AnyElement, - children: SmallVec<[AnyElement; 2]>, + selected_index: Option, + variant: TabVariant, size: Size, + menu: bool, + on_click: Option>, } impl TabBar { - pub fn new() -> Self { + /// Create a new TabBar. + pub fn new(id: impl Into) -> Self { Self { - base: h_flex().px(px(-1.)), + base: div().id(id).px(px(-1.)), style: StyleRefinement::default(), - scroll_handle: None, children: SmallVec::new(), + scroll_handle: None, prefix: None, suffix: None, + variant: TabVariant::default(), size: Size::default(), last_empty_space: div().w_3().into_any_element(), + selected_index: None, + on_click: None, + menu: false, } } + /// Set the Tab variant, all children will inherit the variant. + pub fn with_variant(mut self, variant: TabVariant) -> Self { + self.variant = variant; + self + } + + /// Set the Tab variant to Pill, all children will inherit the variant. + pub fn pill(mut self) -> Self { + self.variant = TabVariant::Pill; + self + } + + /// Set the Tab variant to Outline, all children will inherit the variant. + pub fn outline(mut self) -> Self { + self.variant = TabVariant::Outline; + self + } + + /// Set the Tab variant to Segmented, all children will inherit the variant. + pub fn segmented(mut self) -> Self { + self.variant = TabVariant::Segmented; + self + } + + /// Set the Tab variant to Underline, all children will inherit the variant. + pub fn underline(mut self) -> Self { + self.variant = TabVariant::Underline; + self + } + + /// Set whether to show the menu button when tabs overflow, default is false. + pub fn menu(mut self, menu: bool) -> Self { + self.menu = menu; + self + } + /// Track the scroll of the TabBar. pub fn track_scroll(mut self, scroll_handle: &ScrollHandle) -> Self { self.scroll_handle = Some(scroll_handle.clone()); @@ -54,27 +105,39 @@ impl TabBar { self } + /// Add children of the TabBar, all children will inherit the variant. + pub fn children(mut self, children: impl IntoIterator>) -> Self { + self.children.extend(children.into_iter().map(Into::into)); + self + } + + /// Add child of the TabBar, tab will inherit the variant. + pub fn child(mut self, child: impl Into) -> Self { + self.children.push(child.into()); + self + } + + /// Set the selected index of the TabBar. + pub fn selected_index(mut self, index: usize) -> Self { + self.selected_index = Some(index); + self + } + /// Set the last empty space element of the TabBar. pub fn last_empty_space(mut self, last_empty_space: impl IntoElement) -> Self { self.last_empty_space = last_empty_space.into_any_element(); self } - #[cfg(not(target_os = "windows"))] - pub fn height(window: &mut Window) -> Pixels { - (1.75 * window.rem_size()).max(px(36.)) - } -} - -impl Default for TabBar { - fn default() -> Self { - Self::new() - } -} - -impl ParentElement for TabBar { - fn extend(&mut self, elements: impl IntoIterator) { - self.children.extend(elements) + /// Set the on_click callback of the TabBar, the first parameter is the index of the clicked tab. + /// + /// When this is set, the children's on_click will be ignored. + pub fn on_click(mut self, on_click: F) -> Self + where + F: Fn(&usize, &mut Window, &mut App) + 'static, + { + self.on_click = Some(Rc::new(on_click)); + self } } @@ -92,14 +155,80 @@ impl Sizable for TabBar { } impl RenderOnce for TabBar { - fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { + fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement { + let default_gap = match self.size { + Size::Small | Size::XSmall => px(8.), + Size::Large => px(16.), + _ => px(12.), + }; + let (bg, paddings, gap) = match self.variant { + TabVariant::Tab => { + let padding = Edges::all(px(0.)); + (cx.theme().tab_background, padding, px(0.)) + } + TabVariant::Outline => { + let padding = Edges::all(px(0.)); + (gpui::transparent_black(), padding, default_gap) + } + TabVariant::Pill => { + let padding = Edges::all(px(0.)); + (gpui::transparent_black(), padding, px(4.)) + } + TabVariant::Segmented => { + let padding_x = match self.size { + Size::XSmall => px(2.), + Size::Small => px(3.), + _ => px(4.), + }; + let padding = Edges { + left: padding_x, + right: padding_x, + ..Default::default() + }; + + (cx.theme().tab_background, padding, px(2.)) + } + TabVariant::Underline => { + // This gap is same as the tab inner_paddings + let gap = match self.size { + Size::XSmall => px(10.), + Size::Small => px(12.), + Size::Large => px(20.), + _ => px(16.), + }; + + (gpui::transparent_black(), Edges::all(px(0.)), gap) + } + }; + + let mut item_labels = Vec::new(); + let selected_index = self.selected_index; + let on_click = self.on_click.clone(); + self.base .group("tab-bar") .relative() .flex() .items_center() - .bg(cx.theme().tab_background) - .text_color(cx.theme().text) + .bg(bg) + .text_color(cx.theme().tab_foreground) + .when( + self.variant == TabVariant::Underline || self.variant == TabVariant::Tab, + |this| { + this.child( + div() + .id("border-b") + .absolute() + .left_0() + .bottom_0() + .size_full() + .border_b_1() + .border_color(cx.theme().border), + ) + }, + ) + .rounded(self.variant.tab_bar_radius(self.size, cx)) + .paddings(paddings) .refine_style(&self.style) .when_some(self.prefix, |this, prefix| this.child(prefix)) .child( @@ -110,11 +239,52 @@ impl RenderOnce for TabBar { .when_some(self.scroll_handle, |this, scroll_handle| { this.track_scroll(&scroll_handle) }) - .children(self.children) - .when(self.suffix.is_some(), |this| { + .gap(gap) + .children(self.children.into_iter().enumerate().map(|(ix, child)| { + item_labels.push((child.label.clone(), child.disabled)); + let tab_bar_prefix = child.tab_bar_prefix.unwrap_or(true); + child + .ix(ix) + .tab_bar_prefix(tab_bar_prefix) + .with_variant(self.variant) + .with_size(self.size) + .when_some(self.selected_index, |this, selected_ix| { + this.selected(selected_ix == ix) + }) + .when_some(self.on_click.clone(), move |this, on_click| { + this.on_click(move |_, window, cx| on_click(&ix, window, cx)) + }) + })) + .when(self.suffix.is_some() || self.menu, |this| { this.child(self.last_empty_space) }), ) + .when(self.menu, |this| { + this.child( + Button::new("more") + .xsmall() + .ghost() + .icon(IconName::ChevronDown) + .dropdown_menu(move |mut this, _, _| { + this = this.scrollable(true); + for (ix, (label, disabled)) in item_labels.iter().enumerate() { + this = this.item( + PopupMenuItem::new(label.clone().unwrap_or_default()) + .checked(selected_index == Some(ix)) + .disabled(*disabled) + .when_some(on_click.clone(), |this, on_click| { + this.on_click(move |_, window, cx| { + on_click(&ix, window, cx) + }) + }), + ) + } + + this + }) + .anchor(Corner::TopRight), + ) + }) .when_some(self.suffix, |this, suffix| this.child(suffix)) } }