reworked style tree to use colorScheme instead of old theme. Very limited style for now

This commit is contained in:
K Simmons 2022-09-21 12:39:59 -07:00
parent 0c4c5f9238
commit 56f9543a95
53 changed files with 1017 additions and 1734 deletions

17
Cargo.lock generated
View file

@ -814,22 +814,6 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chat_panel"
version = "0.1.0"
dependencies = [
"client",
"editor",
"gpui",
"menu",
"postage",
"settings",
"theme",
"time 0.3.11",
"util",
"workspace",
]
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.19" version = "0.4.19"
@ -7138,7 +7122,6 @@ dependencies = [
"auto_update", "auto_update",
"backtrace", "backtrace",
"breadcrumbs", "breadcrumbs",
"chat_panel",
"chrono", "chrono",
"cli", "cli",
"client", "client",

View file

@ -1,20 +0,0 @@
[package]
name = "chat_panel"
version = "0.1.0"
edition = "2021"
[lib]
path = "src/chat_panel.rs"
doctest = false
[dependencies]
client = { path = "../client" }
editor = { path = "../editor" }
gpui = { path = "../gpui" }
menu = { path = "../menu" }
settings = { path = "../settings" }
theme = { path = "../theme" }
util = { path = "../util" }
workspace = { path = "../workspace" }
postage = { version = "0.4.1", features = ["futures-traits"] }
time = { version = "0.3", features = ["serde", "serde-well-known"] }

View file

@ -1,433 +0,0 @@
use client::{
channel::{Channel, ChannelEvent, ChannelList, ChannelMessage},
Client,
};
use editor::Editor;
use gpui::{
actions,
elements::*,
platform::CursorStyle,
views::{ItemType, Select, SelectStyle},
AnyViewHandle, AppContext, Entity, ModelHandle, MouseButton, MutableAppContext, RenderContext,
Subscription, Task, View, ViewContext, ViewHandle,
};
use menu::Confirm;
use postage::prelude::Stream;
use settings::{Settings, SoftWrap};
use std::sync::Arc;
use time::{OffsetDateTime, UtcOffset};
use util::{ResultExt, TryFutureExt};
const MESSAGE_LOADING_THRESHOLD: usize = 50;
pub struct ChatPanel {
rpc: Arc<Client>,
channel_list: ModelHandle<ChannelList>,
active_channel: Option<(ModelHandle<Channel>, Subscription)>,
message_list: ListState,
input_editor: ViewHandle<Editor>,
channel_select: ViewHandle<Select>,
local_timezone: UtcOffset,
_observe_status: Task<()>,
}
pub enum Event {}
actions!(chat_panel, [LoadMoreMessages]);
pub fn init(cx: &mut MutableAppContext) {
cx.add_action(ChatPanel::send);
cx.add_action(ChatPanel::load_more_messages);
}
impl ChatPanel {
pub fn new(
rpc: Arc<Client>,
channel_list: ModelHandle<ChannelList>,
cx: &mut ViewContext<Self>,
) -> Self {
let input_editor = cx.add_view(|cx| {
let mut editor =
Editor::auto_height(4, Some(|theme| theme.chat_panel.input_editor.clone()), cx);
editor.set_soft_wrap_mode(SoftWrap::EditorWidth, cx);
editor
});
let channel_select = cx.add_view(|cx| {
let channel_list = channel_list.clone();
Select::new(0, cx, {
move |ix, item_type, is_hovered, cx| {
Self::render_channel_name(
&channel_list,
ix,
item_type,
is_hovered,
&cx.global::<Settings>().theme.chat_panel.channel_select,
cx,
)
}
})
.with_style(move |cx| {
let theme = &cx.global::<Settings>().theme.chat_panel.channel_select;
SelectStyle {
header: theme.header.container,
menu: theme.menu,
}
})
});
let mut message_list = ListState::new(0, Orientation::Bottom, 1000., cx, {
let this = cx.weak_handle();
move |_, ix, cx| {
let this = this.upgrade(cx).unwrap().read(cx);
let message = this.active_channel.as_ref().unwrap().0.read(cx).message(ix);
this.render_message(message, cx)
}
});
message_list.set_scroll_handler(|visible_range, cx| {
if visible_range.start < MESSAGE_LOADING_THRESHOLD {
cx.dispatch_action(LoadMoreMessages);
}
});
let _observe_status = cx.spawn_weak(|this, mut cx| {
let mut status = rpc.status();
async move {
while (status.recv().await).is_some() {
if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |_, cx| cx.notify());
} else {
break;
}
}
}
});
let mut this = Self {
rpc,
channel_list,
active_channel: Default::default(),
message_list,
input_editor,
channel_select,
local_timezone: cx.platform().local_timezone(),
_observe_status,
};
this.init_active_channel(cx);
cx.observe(&this.channel_list, |this, _, cx| {
this.init_active_channel(cx);
})
.detach();
cx.observe(&this.channel_select, |this, channel_select, cx| {
let selected_ix = channel_select.read(cx).selected_index();
let selected_channel = this.channel_list.update(cx, |channel_list, cx| {
let available_channels = channel_list.available_channels()?;
let channel_id = available_channels.get(selected_ix)?.id;
channel_list.get_channel(channel_id, cx)
});
if let Some(selected_channel) = selected_channel {
this.set_active_channel(selected_channel, cx);
}
})
.detach();
this
}
fn init_active_channel(&mut self, cx: &mut ViewContext<Self>) {
let (active_channel, channel_count) = self.channel_list.update(cx, |list, cx| {
let channel_count;
let mut active_channel = None;
if let Some(available_channels) = list.available_channels() {
channel_count = available_channels.len();
if self.active_channel.is_none() {
if let Some(channel_id) = available_channels.first().map(|channel| channel.id) {
active_channel = list.get_channel(channel_id, cx);
}
}
} else {
channel_count = 0;
}
(active_channel, channel_count)
});
if let Some(active_channel) = active_channel {
self.set_active_channel(active_channel, cx);
} else {
self.message_list.reset(0);
self.active_channel = None;
}
self.channel_select.update(cx, |select, cx| {
select.set_item_count(channel_count, cx);
});
}
fn set_active_channel(&mut self, channel: ModelHandle<Channel>, cx: &mut ViewContext<Self>) {
if self.active_channel.as_ref().map(|e| &e.0) != Some(&channel) {
{
let channel = channel.read(cx);
self.message_list.reset(channel.message_count());
let placeholder = format!("Message #{}", channel.name());
self.input_editor.update(cx, move |editor, cx| {
editor.set_placeholder_text(placeholder, cx);
});
}
let subscription = cx.subscribe(&channel, Self::channel_did_change);
self.active_channel = Some((channel, subscription));
}
}
fn channel_did_change(
&mut self,
_: ModelHandle<Channel>,
event: &ChannelEvent,
cx: &mut ViewContext<Self>,
) {
match event {
ChannelEvent::MessagesUpdated {
old_range,
new_count,
} => {
self.message_list.splice(old_range.clone(), *new_count);
}
}
cx.notify();
}
fn render_channel(&self, cx: &mut RenderContext<Self>) -> ElementBox {
let theme = &cx.global::<Settings>().theme;
Flex::column()
.with_child(
Container::new(ChildView::new(&self.channel_select).boxed())
.with_style(theme.chat_panel.channel_select.container)
.boxed(),
)
.with_child(self.render_active_channel_messages())
.with_child(self.render_input_box(cx))
.boxed()
}
fn render_active_channel_messages(&self) -> ElementBox {
let messages = if self.active_channel.is_some() {
List::new(self.message_list.clone()).boxed()
} else {
Empty::new().boxed()
};
FlexItem::new(messages).flex(1., true).boxed()
}
fn render_message(&self, message: &ChannelMessage, cx: &AppContext) -> ElementBox {
let now = OffsetDateTime::now_utc();
let settings = cx.global::<Settings>();
let theme = if message.is_pending() {
&settings.theme.chat_panel.pending_message
} else {
&settings.theme.chat_panel.message
};
Container::new(
Flex::column()
.with_child(
Flex::row()
.with_child(
Container::new(
Label::new(
message.sender.github_login.clone(),
theme.sender.text.clone(),
)
.boxed(),
)
.with_style(theme.sender.container)
.boxed(),
)
.with_child(
Container::new(
Label::new(
format_timestamp(message.timestamp, now, self.local_timezone),
theme.timestamp.text.clone(),
)
.boxed(),
)
.with_style(theme.timestamp.container)
.boxed(),
)
.boxed(),
)
.with_child(Text::new(message.body.clone(), theme.body.clone()).boxed())
.boxed(),
)
.with_style(theme.container)
.boxed()
}
fn render_input_box(&self, cx: &AppContext) -> ElementBox {
let theme = &cx.global::<Settings>().theme;
Container::new(ChildView::new(&self.input_editor).boxed())
.with_style(theme.chat_panel.input_editor.container)
.boxed()
}
fn render_channel_name(
channel_list: &ModelHandle<ChannelList>,
ix: usize,
item_type: ItemType,
is_hovered: bool,
theme: &theme::ChannelSelect,
cx: &AppContext,
) -> ElementBox {
let channel = &channel_list.read(cx).available_channels().unwrap()[ix];
let theme = match (item_type, is_hovered) {
(ItemType::Header, _) => &theme.header,
(ItemType::Selected, false) => &theme.active_item,
(ItemType::Selected, true) => &theme.hovered_active_item,
(ItemType::Unselected, false) => &theme.item,
(ItemType::Unselected, true) => &theme.hovered_item,
};
Container::new(
Flex::row()
.with_child(
Container::new(Label::new("#".to_string(), theme.hash.text.clone()).boxed())
.with_style(theme.hash.container)
.boxed(),
)
.with_child(Label::new(channel.name.clone(), theme.name.clone()).boxed())
.boxed(),
)
.with_style(theme.container)
.boxed()
}
fn render_sign_in_prompt(&self, cx: &mut RenderContext<Self>) -> ElementBox {
let theme = cx.global::<Settings>().theme.clone();
let rpc = self.rpc.clone();
let this = cx.handle();
enum SignInPromptLabel {}
Align::new(
MouseEventHandler::<SignInPromptLabel>::new(0, cx, |mouse_state, _| {
Label::new(
"Sign in to use chat".to_string(),
if mouse_state.hovered {
theme.chat_panel.hovered_sign_in_prompt.clone()
} else {
theme.chat_panel.sign_in_prompt.clone()
},
)
.boxed()
})
.with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, move |_, cx| {
let rpc = rpc.clone();
let this = this.clone();
cx.spawn(|mut cx| async move {
if rpc
.authenticate_and_connect(true, &cx)
.log_err()
.await
.is_some()
{
cx.update(|cx| {
if let Some(this) = this.upgrade(cx) {
if this.is_focused(cx) {
this.update(cx, |this, cx| cx.focus(&this.input_editor));
}
}
})
}
})
.detach();
})
.boxed(),
)
.boxed()
}
fn send(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
if let Some((channel, _)) = self.active_channel.as_ref() {
let body = self.input_editor.update(cx, |editor, cx| {
let body = editor.text(cx);
editor.clear(cx);
body
});
if let Some(task) = channel
.update(cx, |channel, cx| channel.send_message(body, cx))
.log_err()
{
task.detach();
}
}
}
fn load_more_messages(&mut self, _: &LoadMoreMessages, cx: &mut ViewContext<Self>) {
if let Some((channel, _)) = self.active_channel.as_ref() {
channel.update(cx, |channel, cx| {
channel.load_more_messages(cx);
})
}
}
}
impl Entity for ChatPanel {
type Event = Event;
}
impl View for ChatPanel {
fn ui_name() -> &'static str {
"ChatPanel"
}
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
let element = if self.rpc.user_id().is_some() {
self.render_channel(cx)
} else {
self.render_sign_in_prompt(cx)
};
let theme = &cx.global::<Settings>().theme;
ConstrainedBox::new(
Container::new(element)
.with_style(theme.chat_panel.container)
.boxed(),
)
.with_min_width(150.)
.boxed()
}
fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
if matches!(
*self.rpc.status().borrow(),
client::Status::Connected { .. }
) {
cx.focus(&self.input_editor);
}
}
}
fn format_timestamp(
mut timestamp: OffsetDateTime,
mut now: OffsetDateTime,
local_timezone: UtcOffset,
) -> String {
timestamp = timestamp.to_offset(local_timezone);
now = now.to_offset(local_timezone);
let today = now.date();
let date = timestamp.date();
let mut hour = timestamp.hour();
let mut part = "am";
if hour > 12 {
hour -= 12;
part = "pm";
}
if date == today {
format!("{:02}:{:02}{}", hour, timestamp.minute(), part)
} else if date.next_day() == Some(today) {
format!("yesterday at {:02}:{:02}{}", hour, timestamp.minute(), part)
} else {
format!("{:02}/{}/{}", date.month() as u32, date.day(), date.year())
}
}

View file

@ -1,77 +1,71 @@
use alacritty_terminal::{ansi::Color as AnsiColor, term::color::Rgb as AlacRgb}; use alacritty_terminal::{ansi::Color as AnsiColor, term::color::Rgb as AlacRgb};
use gpui::color::Color; use gpui::color::Color;
use theme::TerminalColors; use theme::TerminalStyle;
///Converts a 2, 8, or 24 bit color ANSI color to the GPUI equivalent ///Converts a 2, 8, or 24 bit color ANSI color to the GPUI equivalent
pub fn convert_color(alac_color: &AnsiColor, colors: &TerminalColors, modal: bool) -> Color { pub fn convert_color(alac_color: &AnsiColor, style: &TerminalStyle) -> Color {
let background = if modal {
colors.modal_background
} else {
colors.background
};
match alac_color { match alac_color {
//Named and theme defined colors //Named and theme defined colors
alacritty_terminal::ansi::Color::Named(n) => match n { alacritty_terminal::ansi::Color::Named(n) => match n {
alacritty_terminal::ansi::NamedColor::Black => colors.black, alacritty_terminal::ansi::NamedColor::Black => style.black,
alacritty_terminal::ansi::NamedColor::Red => colors.red, alacritty_terminal::ansi::NamedColor::Red => style.red,
alacritty_terminal::ansi::NamedColor::Green => colors.green, alacritty_terminal::ansi::NamedColor::Green => style.green,
alacritty_terminal::ansi::NamedColor::Yellow => colors.yellow, alacritty_terminal::ansi::NamedColor::Yellow => style.yellow,
alacritty_terminal::ansi::NamedColor::Blue => colors.blue, alacritty_terminal::ansi::NamedColor::Blue => style.blue,
alacritty_terminal::ansi::NamedColor::Magenta => colors.magenta, alacritty_terminal::ansi::NamedColor::Magenta => style.magenta,
alacritty_terminal::ansi::NamedColor::Cyan => colors.cyan, alacritty_terminal::ansi::NamedColor::Cyan => style.cyan,
alacritty_terminal::ansi::NamedColor::White => colors.white, alacritty_terminal::ansi::NamedColor::White => style.white,
alacritty_terminal::ansi::NamedColor::BrightBlack => colors.bright_black, alacritty_terminal::ansi::NamedColor::BrightBlack => style.bright_black,
alacritty_terminal::ansi::NamedColor::BrightRed => colors.bright_red, alacritty_terminal::ansi::NamedColor::BrightRed => style.bright_red,
alacritty_terminal::ansi::NamedColor::BrightGreen => colors.bright_green, alacritty_terminal::ansi::NamedColor::BrightGreen => style.bright_green,
alacritty_terminal::ansi::NamedColor::BrightYellow => colors.bright_yellow, alacritty_terminal::ansi::NamedColor::BrightYellow => style.bright_yellow,
alacritty_terminal::ansi::NamedColor::BrightBlue => colors.bright_blue, alacritty_terminal::ansi::NamedColor::BrightBlue => style.bright_blue,
alacritty_terminal::ansi::NamedColor::BrightMagenta => colors.bright_magenta, alacritty_terminal::ansi::NamedColor::BrightMagenta => style.bright_magenta,
alacritty_terminal::ansi::NamedColor::BrightCyan => colors.bright_cyan, alacritty_terminal::ansi::NamedColor::BrightCyan => style.bright_cyan,
alacritty_terminal::ansi::NamedColor::BrightWhite => colors.bright_white, alacritty_terminal::ansi::NamedColor::BrightWhite => style.bright_white,
alacritty_terminal::ansi::NamedColor::Foreground => colors.foreground, alacritty_terminal::ansi::NamedColor::Foreground => style.foreground,
alacritty_terminal::ansi::NamedColor::Background => background, alacritty_terminal::ansi::NamedColor::Background => style.background,
alacritty_terminal::ansi::NamedColor::Cursor => colors.cursor, alacritty_terminal::ansi::NamedColor::Cursor => style.cursor,
alacritty_terminal::ansi::NamedColor::DimBlack => colors.dim_black, alacritty_terminal::ansi::NamedColor::DimBlack => style.dim_black,
alacritty_terminal::ansi::NamedColor::DimRed => colors.dim_red, alacritty_terminal::ansi::NamedColor::DimRed => style.dim_red,
alacritty_terminal::ansi::NamedColor::DimGreen => colors.dim_green, alacritty_terminal::ansi::NamedColor::DimGreen => style.dim_green,
alacritty_terminal::ansi::NamedColor::DimYellow => colors.dim_yellow, alacritty_terminal::ansi::NamedColor::DimYellow => style.dim_yellow,
alacritty_terminal::ansi::NamedColor::DimBlue => colors.dim_blue, alacritty_terminal::ansi::NamedColor::DimBlue => style.dim_blue,
alacritty_terminal::ansi::NamedColor::DimMagenta => colors.dim_magenta, alacritty_terminal::ansi::NamedColor::DimMagenta => style.dim_magenta,
alacritty_terminal::ansi::NamedColor::DimCyan => colors.dim_cyan, alacritty_terminal::ansi::NamedColor::DimCyan => style.dim_cyan,
alacritty_terminal::ansi::NamedColor::DimWhite => colors.dim_white, alacritty_terminal::ansi::NamedColor::DimWhite => style.dim_white,
alacritty_terminal::ansi::NamedColor::BrightForeground => colors.bright_foreground, alacritty_terminal::ansi::NamedColor::BrightForeground => style.bright_foreground,
alacritty_terminal::ansi::NamedColor::DimForeground => colors.dim_foreground, alacritty_terminal::ansi::NamedColor::DimForeground => style.dim_foreground,
}, },
//'True' colors //'True' colors
alacritty_terminal::ansi::Color::Spec(rgb) => Color::new(rgb.r, rgb.g, rgb.b, u8::MAX), alacritty_terminal::ansi::Color::Spec(rgb) => Color::new(rgb.r, rgb.g, rgb.b, u8::MAX),
//8 bit, indexed colors //8 bit, indexed colors
alacritty_terminal::ansi::Color::Indexed(i) => get_color_at_index(&(*i as usize), colors), alacritty_terminal::ansi::Color::Indexed(i) => get_color_at_index(&(*i as usize), style),
} }
} }
///Converts an 8 bit ANSI color to it's GPUI equivalent. ///Converts an 8 bit ANSI color to it's GPUI equivalent.
///Accepts usize for compatability with the alacritty::Colors interface, ///Accepts usize for compatability with the alacritty::Colors interface,
///Other than that use case, should only be called with values in the [0,255] range ///Other than that use case, should only be called with values in the [0,255] range
pub fn get_color_at_index(index: &usize, colors: &TerminalColors) -> Color { pub fn get_color_at_index(index: &usize, style: &TerminalStyle) -> Color {
match index { match index {
//0-15 are the same as the named colors above //0-15 are the same as the named colors above
0 => colors.black, 0 => style.black,
1 => colors.red, 1 => style.red,
2 => colors.green, 2 => style.green,
3 => colors.yellow, 3 => style.yellow,
4 => colors.blue, 4 => style.blue,
5 => colors.magenta, 5 => style.magenta,
6 => colors.cyan, 6 => style.cyan,
7 => colors.white, 7 => style.white,
8 => colors.bright_black, 8 => style.bright_black,
9 => colors.bright_red, 9 => style.bright_red,
10 => colors.bright_green, 10 => style.bright_green,
11 => colors.bright_yellow, 11 => style.bright_yellow,
12 => colors.bright_blue, 12 => style.bright_blue,
13 => colors.bright_magenta, 13 => style.bright_magenta,
14 => colors.bright_cyan, 14 => style.bright_cyan,
15 => colors.bright_white, 15 => style.bright_white,
//16-231 are mapped to their RGB colors on a 0-5 range per channel //16-231 are mapped to their RGB colors on a 0-5 range per channel
16..=231 => { 16..=231 => {
let (r, g, b) = rgb_for_index(&(*index as u8)); //Split the index into it's ANSI-RGB components let (r, g, b) = rgb_for_index(&(*index as u8)); //Split the index into it's ANSI-RGB components
@ -85,19 +79,19 @@ pub fn get_color_at_index(index: &usize, colors: &TerminalColors) -> Color {
Color::new(i * step, i * step, i * step, u8::MAX) //Map the ANSI-grayscale components to the RGB-grayscale Color::new(i * step, i * step, i * step, u8::MAX) //Map the ANSI-grayscale components to the RGB-grayscale
} }
//For compatability with the alacritty::Colors interface //For compatability with the alacritty::Colors interface
256 => colors.foreground, 256 => style.foreground,
257 => colors.background, 257 => style.background,
258 => colors.cursor, 258 => style.cursor,
259 => colors.dim_black, 259 => style.dim_black,
260 => colors.dim_red, 260 => style.dim_red,
261 => colors.dim_green, 261 => style.dim_green,
262 => colors.dim_yellow, 262 => style.dim_yellow,
263 => colors.dim_blue, 263 => style.dim_blue,
264 => colors.dim_magenta, 264 => style.dim_magenta,
265 => colors.dim_cyan, 265 => style.dim_cyan,
266 => colors.dim_white, 266 => style.dim_white,
267 => colors.bright_foreground, 267 => style.bright_foreground,
268 => colors.black, //'Dim Background', non-standard color 268 => style.black, //'Dim Background', non-standard color
_ => Color::new(0, 0, 0, 255), _ => Color::new(0, 0, 0, 255),
} }
} }

View file

@ -569,7 +569,7 @@ impl Terminal {
InternalEvent::ColorRequest(index, format) => { InternalEvent::ColorRequest(index, format) => {
let color = term.colors()[*index].unwrap_or_else(|| { let color = term.colors()[*index].unwrap_or_else(|| {
let term_style = &cx.global::<Settings>().theme.terminal; let term_style = &cx.global::<Settings>().theme.terminal;
to_alac_rgb(get_color_at_index(index, &term_style.colors)) to_alac_rgb(get_color_at_index(index, &term_style))
}); });
self.write_to_pty(format(color)) self.write_to_pty(format(color))
} }

View file

@ -165,18 +165,12 @@ impl View for TerminalContainer {
"Terminal" "Terminal"
} }
fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox { fn render(&mut self, _cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox {
let child_view = match &self.content { match &self.content {
TerminalContainerContent::Connected(connected) => ChildView::new(connected), TerminalContainerContent::Connected(connected) => ChildView::new(connected),
TerminalContainerContent::Error(error) => ChildView::new(error), TerminalContainerContent::Error(error) => ChildView::new(error),
};
if self.modal {
let settings = cx.global::<Settings>();
let container_style = settings.theme.terminal.modal_container;
child_view.contained().with_style(container_style).boxed()
} else {
child_view.boxed()
} }
.boxed()
} }
fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) { fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {

View file

@ -149,7 +149,6 @@ impl LayoutRect {
pub struct TerminalElement { pub struct TerminalElement {
terminal: WeakModelHandle<Terminal>, terminal: WeakModelHandle<Terminal>,
view: WeakViewHandle<TerminalView>, view: WeakViewHandle<TerminalView>,
modal: bool,
focused: bool, focused: bool,
cursor_visible: bool, cursor_visible: bool,
} }
@ -158,14 +157,12 @@ impl TerminalElement {
pub fn new( pub fn new(
view: WeakViewHandle<TerminalView>, view: WeakViewHandle<TerminalView>,
terminal: WeakModelHandle<Terminal>, terminal: WeakModelHandle<Terminal>,
modal: bool,
focused: bool, focused: bool,
cursor_visible: bool, cursor_visible: bool,
) -> TerminalElement { ) -> TerminalElement {
TerminalElement { TerminalElement {
view, view,
terminal, terminal,
modal,
focused, focused,
cursor_visible, cursor_visible,
} }
@ -179,7 +176,6 @@ impl TerminalElement {
terminal_theme: &TerminalStyle, terminal_theme: &TerminalStyle,
text_layout_cache: &TextLayoutCache, text_layout_cache: &TextLayoutCache,
font_cache: &FontCache, font_cache: &FontCache,
modal: bool,
) -> (Vec<LayoutCell>, Vec<LayoutRect>) { ) -> (Vec<LayoutCell>, Vec<LayoutRect>) {
let mut cells = vec![]; let mut cells = vec![];
let mut rects = vec![]; let mut rects = vec![];
@ -218,7 +214,7 @@ impl TerminalElement {
cur_rect = Some(LayoutRect::new( cur_rect = Some(LayoutRect::new(
Point::new(line_index as i32, cell.point.column.0 as i32), Point::new(line_index as i32, cell.point.column.0 as i32),
1, 1,
convert_color(&bg, &terminal_theme.colors, modal), convert_color(&bg, &terminal_theme),
)); ));
} }
} }
@ -227,7 +223,7 @@ impl TerminalElement {
cur_rect = Some(LayoutRect::new( cur_rect = Some(LayoutRect::new(
Point::new(line_index as i32, cell.point.column.0 as i32), Point::new(line_index as i32, cell.point.column.0 as i32),
1, 1,
convert_color(&bg, &terminal_theme.colors, modal), convert_color(&bg, &terminal_theme),
)); ));
} }
} }
@ -244,7 +240,6 @@ impl TerminalElement {
terminal_theme, terminal_theme,
text_style, text_style,
font_cache, font_cache,
modal,
); );
let layout_cell = text_layout_cache.layout_str( let layout_cell = text_layout_cache.layout_str(
@ -303,10 +298,9 @@ impl TerminalElement {
style: &TerminalStyle, style: &TerminalStyle,
text_style: &TextStyle, text_style: &TextStyle,
font_cache: &FontCache, font_cache: &FontCache,
modal: bool,
) -> RunStyle { ) -> RunStyle {
let flags = indexed.cell.flags; let flags = indexed.cell.flags;
let fg = convert_color(&fg, &style.colors, modal); let fg = convert_color(&fg, &style);
let underline = flags let underline = flags
.intersects(Flags::ALL_UNDERLINES) .intersects(Flags::ALL_UNDERLINES)
@ -562,11 +556,7 @@ impl Element for TerminalElement {
Default::default() Default::default()
}; };
let background_color = if self.modal { let background_color = terminal_theme.background;
terminal_theme.colors.modal_background
} else {
terminal_theme.colors.background
};
let terminal_handle = self.terminal.upgrade(cx).unwrap(); let terminal_handle = self.terminal.upgrade(cx).unwrap();
terminal_handle.update(cx.app, |terminal, cx| { terminal_handle.update(cx.app, |terminal, cx| {
@ -601,7 +591,6 @@ impl Element for TerminalElement {
&terminal_theme, &terminal_theme,
cx.text_layout_cache, cx.text_layout_cache,
cx.font_cache(), cx.font_cache(),
self.modal,
); );
//Layout cursor. Rectangle is used for IME, so we should lay it out even //Layout cursor. Rectangle is used for IME, so we should lay it out even
@ -614,9 +603,9 @@ impl Element for TerminalElement {
let str_trxt = cursor_char.to_string(); let str_trxt = cursor_char.to_string();
let color = if self.focused { let color = if self.focused {
terminal_theme.colors.background terminal_theme.background
} else { } else {
terminal_theme.colors.foreground terminal_theme.foreground
}; };
cx.text_layout_cache.layout_str( cx.text_layout_cache.layout_str(
@ -649,7 +638,7 @@ impl Element for TerminalElement {
cursor_position, cursor_position,
block_width, block_width,
dimensions.line_height, dimensions.line_height,
terminal_theme.colors.cursor, terminal_theme.cursor,
shape, shape,
Some(cursor_text), Some(cursor_text),
) )

View file

@ -343,7 +343,6 @@ impl View for TerminalView {
TerminalElement::new( TerminalElement::new(
cx.handle(), cx.handle(),
terminal_handle, terminal_handle,
self.modal,
focused, focused,
self.should_show_cursor(focused, cx), self.should_show_cursor(focused, cx),
) )

View file

@ -18,7 +18,6 @@ pub struct Theme {
pub meta: ThemeMeta, pub meta: ThemeMeta,
pub workspace: Workspace, pub workspace: Workspace,
pub context_menu: ContextMenu, pub context_menu: ContextMenu,
pub chat_panel: ChatPanel,
pub contacts_popover: ContactsPopover, pub contacts_popover: ContactsPopover,
pub contacts_panel: ContactsPanel, pub contacts_panel: ContactsPanel,
pub contact_finder: ContactFinder, pub contact_finder: ContactFinder,
@ -256,18 +255,6 @@ pub struct SidebarItem {
pub icon_size: f32, pub icon_size: f32,
} }
#[derive(Deserialize, Default)]
pub struct ChatPanel {
#[serde(flatten)]
pub container: ContainerStyle,
pub message: ChatMessage,
pub pending_message: ChatMessage,
pub channel_select: ChannelSelect,
pub input_editor: FieldEditor,
pub sign_in_prompt: TextStyle,
pub hovered_sign_in_prompt: TextStyle,
}
#[derive(Deserialize, Default)] #[derive(Deserialize, Default)]
pub struct ProjectPanel { pub struct ProjectPanel {
#[serde(flatten)] #[serde(flatten)]
@ -710,12 +697,6 @@ pub struct HoverPopover {
#[derive(Clone, Deserialize, Default)] #[derive(Clone, Deserialize, Default)]
pub struct TerminalStyle { pub struct TerminalStyle {
pub colors: TerminalColors,
pub modal_container: ContainerStyle,
}
#[derive(Clone, Deserialize, Default)]
pub struct TerminalColors {
pub black: Color, pub black: Color,
pub red: Color, pub red: Color,
pub green: Color, pub green: Color,

View file

@ -19,7 +19,6 @@ activity_indicator = { path = "../activity_indicator" }
assets = { path = "../assets" } assets = { path = "../assets" }
auto_update = { path = "../auto_update" } auto_update = { path = "../auto_update" }
breadcrumbs = { path = "../breadcrumbs" } breadcrumbs = { path = "../breadcrumbs" }
chat_panel = { path = "../chat_panel" }
cli = { path = "../cli" } cli = { path = "../cli" }
collections = { path = "../collections" } collections = { path = "../collections" }
command_palette = { path = "../command_palette" } command_palette = { path = "../command_palette" }

View file

@ -111,7 +111,6 @@ fn main() {
editor::init(cx); editor::init(cx);
go_to_line::init(cx); go_to_line::init(cx);
file_finder::init(cx); file_finder::init(cx);
chat_panel::init(cx);
contacts_panel::init(cx); contacts_panel::init(cx);
outline::init(cx); outline::init(cx);
project_symbols::init(cx); project_symbols::init(cx);

View file

@ -2,9 +2,9 @@ import * as fs from "fs";
import * as path from "path"; import * as path from "path";
import { tmpdir } from "os"; import { tmpdir } from "os";
import app from "./styleTree/app"; import app from "./styleTree/app";
import themes, { internalThemes, experimentalThemes } from "./themes"; import colorSchemes, { internalColorSchemes, experimentalColorSchemes } from "./colorSchemes";
import snakeCase from "./utils/snakeCase"; import snakeCase from "./utils/snakeCase";
import Theme from "./themes/common/theme"; import { ColorScheme } from "./themes/common/colorScheme";
const themeDirectory = `${__dirname}/../../assets/themes`; const themeDirectory = `${__dirname}/../../assets/themes`;
const internalDirectory = `${themeDirectory}/internal`; const internalDirectory = `${themeDirectory}/internal`;
@ -16,7 +16,7 @@ function clearThemes(themeDirectory: string) {
for (const file of fs.readdirSync(themeDirectory)) { for (const file of fs.readdirSync(themeDirectory)) {
if (file.endsWith(".json")) { if (file.endsWith(".json")) {
const name = file.replace(/\.json$/, ""); const name = file.replace(/\.json$/, "");
if (!themes.find((theme) => theme.name === name)) { if (!colorSchemes.find((colorScheme) => colorScheme.name === name)) {
fs.unlinkSync(path.join(themeDirectory, file)); fs.unlinkSync(path.join(themeDirectory, file));
} }
} }
@ -27,12 +27,12 @@ clearThemes(themeDirectory);
clearThemes(internalDirectory); clearThemes(internalDirectory);
clearThemes(experimentsDirectory); clearThemes(experimentsDirectory);
function writeThemes(themes: Theme[], outputDirectory: string) { function writeThemes(colorSchemes: ColorScheme[], outputDirectory: string) {
for (let theme of themes) { for (let colorScheme of colorSchemes) {
let styleTree = snakeCase(app(theme)); let styleTree = snakeCase(app(colorScheme));
let styleTreeJSON = JSON.stringify(styleTree, null, 2); let styleTreeJSON = JSON.stringify(styleTree, null, 2);
let tempPath = path.join(tempDirectory, `${theme.name}.json`); let tempPath = path.join(tempDirectory, `${colorScheme.name}.json`);
let outPath = path.join(outputDirectory, `${theme.name}.json`); let outPath = path.join(outputDirectory, `${colorScheme.name}.json`);
fs.writeFileSync(tempPath, styleTreeJSON); fs.writeFileSync(tempPath, styleTreeJSON);
fs.renameSync(tempPath, outPath); fs.renameSync(tempPath, outPath);
console.log(`- ${outPath} created`); console.log(`- ${outPath} created`);
@ -40,6 +40,6 @@ function writeThemes(themes: Theme[], outputDirectory: string) {
} }
// Write new themes to theme directory // Write new themes to theme directory
writeThemes(themes, themeDirectory); writeThemes(colorSchemes, themeDirectory);
writeThemes(internalThemes, internalDirectory); writeThemes(internalColorSchemes, internalDirectory);
writeThemes(experimentalThemes, experimentsDirectory); writeThemes(experimentalColorSchemes, experimentsDirectory);

View file

@ -0,0 +1,31 @@
import fs from "fs";
import path from "path";
import { ColorScheme } from "./themes/common/colorScheme";
const colorSchemes: ColorScheme[] = [];
export default colorSchemes;
const internalColorSchemes: ColorScheme[] = [];
export { internalColorSchemes }
const experimentalColorSchemes: ColorScheme[] = [];
export { experimentalColorSchemes }
function fillColorSchemes(themesPath: string, colorSchemes: ColorScheme[]) {
for (const fileName of fs.readdirSync(themesPath)) {
if (fileName == "template.ts") continue;
const filePath = path.join(themesPath, fileName);
if (fs.statSync(filePath).isFile()) {
const colorScheme = require(filePath);
if (colorScheme.dark) colorSchemes.push(colorScheme.dark);
if (colorScheme.light) colorSchemes.push(colorScheme.light);
}
}
}
fillColorSchemes(path.resolve(`${__dirname}/themes`), colorSchemes)
fillColorSchemes(path.resolve(`${__dirname}/themes/internal`), internalColorSchemes)
fillColorSchemes(path.resolve(`${__dirname}/themes/experiments`), experimentalColorSchemes)

View file

@ -1,5 +1,3 @@
import Theme from "../themes/common/theme";
import chatPanel from "./chatPanel";
import { text } from "./components"; import { text } from "./components";
import contactFinder from "./contactFinder"; import contactFinder from "./contactFinder";
import contactsPanel from "./contactsPanel"; import contactsPanel from "./contactsPanel";
@ -16,38 +14,38 @@ import contactNotification from "./contactNotification";
import updateNotification from "./updateNotification"; import updateNotification from "./updateNotification";
import tooltip from "./tooltip"; import tooltip from "./tooltip";
import terminal from "./terminal"; import terminal from "./terminal";
import { ColorScheme } from "../themes/common/colorScheme";
export const panel = { export const panel = {
padding: { top: 12, bottom: 12 }, padding: { top: 12, bottom: 12 },
}; };
export default function app(theme: Theme): Object { export default function app(colorScheme: ColorScheme): Object {
return { return {
meta: { meta: {
name: theme.name, name: colorScheme.name,
isLight: theme.isLight isLight: colorScheme.isLight
}, },
picker: picker(theme), picker: picker(colorScheme),
workspace: workspace(theme), workspace: workspace(colorScheme),
contextMenu: contextMenu(theme), contextMenu: contextMenu(colorScheme),
editor: editor(theme), editor: editor(colorScheme),
projectDiagnostics: projectDiagnostics(theme), projectDiagnostics: projectDiagnostics(colorScheme),
commandPalette: commandPalette(theme), commandPalette: commandPalette(colorScheme),
projectPanel: projectPanel(theme), projectPanel: projectPanel(colorScheme),
chatPanel: chatPanel(theme), contactsPopover: contactsPopover(colorScheme),
contactsPopover: contactsPopover(theme), contactsPanel: contactsPanel(colorScheme),
contactsPanel: contactsPanel(theme), contactFinder: contactFinder(colorScheme),
contactFinder: contactFinder(theme), search: search(colorScheme),
search: search(theme),
breadcrumbs: { breadcrumbs: {
...text(theme, "sans", "secondary"), ...text(colorScheme.lowest.top, "sans", "base", "variant"),
padding: { padding: {
left: 6, left: 6,
}, },
}, },
contactNotification: contactNotification(theme), contactNotification: contactNotification(colorScheme),
updateNotification: updateNotification(theme), updateNotification: updateNotification(colorScheme),
tooltip: tooltip(theme), tooltip: tooltip(colorScheme),
terminal: terminal(theme), terminal: terminal(colorScheme.lowest),
}; };
} }

View file

@ -1,108 +0,0 @@
import Theme from "../themes/common/theme";
import { panel } from "./app";
import {
backgroundColor,
border,
player,
text,
TextColor,
popoverShadow,
} from "./components";
export default function chatPanel(theme: Theme) {
function channelSelectItem(
theme: Theme,
textColor: TextColor,
hovered: boolean
) {
return {
name: text(theme, "sans", textColor),
padding: 4,
hash: {
...text(theme, "sans", "muted"),
margin: {
right: 8,
},
},
background: hovered ? backgroundColor(theme, 300, "hovered") : undefined,
cornerRadius: hovered ? 6 : 0,
};
}
const message = {
body: text(theme, "sans", "secondary"),
timestamp: text(theme, "sans", "muted", { size: "sm" }),
padding: {
bottom: 6,
},
sender: {
...text(theme, "sans", "primary", { weight: "bold" }),
margin: {
right: 8,
},
},
};
return {
...panel,
channelName: text(theme, "sans", "primary", { weight: "bold" }),
channelNameHash: {
...text(theme, "sans", "muted"),
padding: {
right: 8,
},
},
channelSelect: {
header: {
...channelSelectItem(theme, "primary", false),
padding: {
bottom: 4,
left: 0,
},
},
item: channelSelectItem(theme, "secondary", false),
hoveredItem: channelSelectItem(theme, "secondary", true),
activeItem: channelSelectItem(theme, "primary", false),
hoveredActiveItem: channelSelectItem(theme, "primary", true),
menu: {
background: backgroundColor(theme, 500),
cornerRadius: 6,
padding: 4,
border: border(theme, "primary"),
shadow: popoverShadow(theme),
},
},
signInPrompt: text(theme, "sans", "secondary", { underline: true }),
hoveredSignInPrompt: text(theme, "sans", "primary", { underline: true }),
message,
pendingMessage: {
...message,
body: {
...message.body,
color: theme.textColor.muted,
},
sender: {
...message.sender,
color: theme.textColor.muted,
},
timestamp: {
...message.timestamp,
color: theme.textColor.muted,
},
},
inputEditor: {
background: backgroundColor(theme, 500),
cornerRadius: 6,
text: text(theme, "mono", "primary"),
placeholderText: text(theme, "mono", "placeholder", { size: "sm" }),
selection: player(theme, 1).selection,
border: border(theme, "secondary"),
padding: {
bottom: 7,
left: 8,
right: 8,
top: 7,
},
},
};
}

View file

@ -1,14 +1,15 @@
import Theme from "../themes/common/theme"; import { ColorScheme } from "../themes/common/colorScheme";
import { text, backgroundColor, border } from "./components"; import { text, border, background } from "./components";
export default function commandPalette(theme: Theme) { export default function commandPalette(colorScheme: ColorScheme) {
let layer = colorScheme.highest.bottom;
return { return {
keystrokeSpacing: 8, keystrokeSpacing: 8,
key: { key: {
text: text(theme, "mono", "secondary", { size: "xs" }), text: text(layer, "mono", { size: "xs" }),
cornerRadius: 4, cornerRadius: 4,
background: backgroundColor(theme, "on300"), background: background(layer, "on"),
border: border(theme, "secondary"), border: border(layer),
padding: { padding: {
top: 2, top: 2,
bottom: 2, bottom: 2,
@ -19,7 +20,7 @@ export default function commandPalette(theme: Theme) {
left: 2, left: 2,
}, },
active: { active: {
text: text(theme, "mono", "active", { size: "xs" }), text: text(layer, "mono", "on", "active", { size: "xs" }),
}, },
}, },
}; };

View file

@ -1,30 +1,89 @@
import Theme, { BackgroundColorSet } from "../themes/common/theme";
import { fontFamilies, fontSizes, FontWeight } from "../common"; import { fontFamilies, fontSizes, FontWeight } from "../common";
import { Layer, Styles, StyleSets } from "../themes/common/colorScheme";
export function background(layer: Layer, styleSet?: StyleSets, style?: Styles): string {
return layer[styleSet ?? "base"][style ?? "default"].background;
}
export function borderColor(layer: Layer, styleSet?: StyleSets, style?: Styles): string {
return layer[styleSet ?? "base"][style ?? "default"].border;
}
export function foreground(layer: Layer, styleSet?: StyleSets, style?: Styles): string {
return layer[styleSet ?? "base"][style ?? "default"].foreground;
}
interface Text {
family: keyof typeof fontFamilies,
color: string,
size: number,
weight?: FontWeight,
underline?: boolean,
}
interface TextProperties {
size?: keyof typeof fontSizes;
weight?: FontWeight;
underline?: boolean;
}
export type TextColor = keyof Theme["textColor"];
export function text( export function text(
theme: Theme, layer: Layer,
fontFamily: keyof typeof fontFamilies, fontFamily: keyof typeof fontFamilies,
color: TextColor, styleSet: StyleSets,
properties?: { style: Styles,
size?: keyof typeof fontSizes; properties?: TextProperties
weight?: FontWeight; ): Text;
underline?: boolean; export function text(
} layer: Layer,
fontFamily: keyof typeof fontFamilies,
styleSet: StyleSets,
properties?: TextProperties): Text;
export function text(
layer: Layer,
fontFamily: keyof typeof fontFamilies,
properties?: TextProperties): Text;
export function text(
layer: Layer,
fontFamily: keyof typeof fontFamilies,
styleSetOrProperties?: StyleSets | TextProperties,
styleOrProperties?: Styles | TextProperties,
properties?: TextProperties
) { ) {
let styleSet: StyleSets = "base";
let style: Styles = "default";
if (typeof styleSetOrProperties === "string") {
styleSet = styleSetOrProperties
} else if (styleSetOrProperties !== undefined) {
properties = styleSetOrProperties;
}
if (typeof styleOrProperties === "string") {
style = styleOrProperties;
} else if (styleOrProperties !== undefined) {
properties = styleOrProperties;
}
let size = fontSizes[properties?.size || "sm"]; let size = fontSizes[properties?.size || "sm"];
return { return {
family: fontFamilies[fontFamily], family: fontFamilies[fontFamily],
color: theme.textColor[color], color: layer[styleSet][style].foreground,
...properties, ...properties,
size, size,
}; };
} }
export function textColor(theme: Theme, color: TextColor) {
return theme.textColor[color];
export interface Border {
color: string,
width: number,
top?: boolean;
bottom?: boolean;
left?: boolean;
right?: boolean;
overlay?: boolean;
} }
export type BorderColor = keyof Theme["borderColor"];
export interface BorderOptions { export interface BorderOptions {
width?: number; width?: number;
top?: boolean; top?: boolean;
@ -33,72 +92,46 @@ export interface BorderOptions {
right?: boolean; right?: boolean;
overlay?: boolean; overlay?: boolean;
} }
export function border( export function border(
theme: Theme, layer: Layer,
color: BorderColor, styleSet: StyleSets,
style: Styles,
options?: BorderOptions options?: BorderOptions
) { ): Border;
export function border(
layer: Layer,
styleSet: StyleSets,
options?: BorderOptions
): Border;
export function border(
layer: Layer,
options?: BorderOptions
): Border;
export function border(
layer: Layer,
styleSetOrOptions?: StyleSets | BorderOptions,
styleOrOptions?: Styles | BorderOptions,
options?: BorderOptions
): Border {
let styleSet: StyleSets = "base";
let style: Styles = "default";
if (typeof styleSetOrOptions === "string") {
styleSet = styleSetOrOptions
} else if (styleSetOrOptions !== undefined) {
options = styleSetOrOptions;
}
if (typeof styleOrOptions === "string") {
style = styleOrOptions;
} else if (styleOrOptions !== undefined) {
options = styleOrOptions;
}
return { return {
color: borderColor(theme, color), color: layer[styleSet][style].border,
width: 1, width: 1,
...options, ...options,
}; };
} }
export function borderColor(theme: Theme, color: BorderColor) {
return theme.borderColor[color];
}
export type IconColor = keyof Theme["iconColor"];
export function iconColor(theme: Theme, color: IconColor) {
return theme.iconColor[color];
}
export type PlayerIndex = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
export interface Player {
selection: {
cursor: string;
selection: string;
};
}
export function player(theme: Theme, playerNumber: PlayerIndex): Player {
return {
selection: {
cursor: theme.player[playerNumber].cursorColor,
selection: theme.player[playerNumber].selectionColor,
},
};
}
export type BackgroundColor = keyof Theme["backgroundColor"];
export type BackgroundState = keyof BackgroundColorSet;
export function backgroundColor(
theme: Theme,
name: BackgroundColor,
state?: BackgroundState
): string {
return theme.backgroundColor[name][state || "base"];
}
export function modalShadow(theme: Theme) {
return {
blur: 16,
color: theme.shadow,
offset: [0, 2],
};
}
export function popoverShadow(theme: Theme) {
return {
blur: 4,
color: theme.shadow,
offset: [1, 2],
};
}
export function draggedShadow(theme: Theme) {
return {
blur: 6,
color: theme.shadow,
offset: [1, 2],
};
}

View file

@ -1,18 +1,19 @@
import Theme from "../themes/common/theme";
import picker from "./picker"; import picker from "./picker";
import { backgroundColor, iconColor } from "./components"; import { ColorScheme } from "../themes/common/colorScheme";
import { background, foreground } from "./components";
export default function contactFinder(theme: Theme) { export default function contactFinder(colorScheme: ColorScheme) {
let layer = colorScheme.middle.bottom;
const contactButton = { const contactButton = {
background: backgroundColor(theme, 100), background: background(layer),
color: iconColor(theme, "primary"), color: foreground(layer),
iconWidth: 8, iconWidth: 8,
buttonWidth: 16, buttonWidth: 16,
cornerRadius: 8, cornerRadius: 8,
}; };
return { return {
...picker(theme), ...picker(colorScheme),
rowHeight: 28, rowHeight: 28,
contactAvatar: { contactAvatar: {
cornerRadius: 10, cornerRadius: 10,
@ -26,13 +27,13 @@ export default function contactFinder(theme: Theme) {
contactButton: { contactButton: {
...contactButton, ...contactButton,
hover: { hover: {
background: backgroundColor(theme, 100, "hovered"), background: background(layer, "base", "hovered"),
}, },
}, },
disabledContactButton: { disabledContactButton: {
...contactButton, ...contactButton,
background: backgroundColor(theme, 100), background: background(layer, "base", "disabled"),
color: iconColor(theme, "muted"), color: foreground(layer, "base", "disabled"),
}, },
}; };
} }

View file

@ -1,10 +1,11 @@
import Theme from "../themes/common/theme"; import { ColorScheme } from "../themes/common/colorScheme";
import { backgroundColor, iconColor, text } from "./components"; import { background, foreground, text } from "./components";
const avatarSize = 12; const avatarSize = 12;
const headerPadding = 8; const headerPadding = 8;
export default function contactNotification(theme: Theme): Object { export default function contactNotification(colorScheme: ColorScheme): Object {
let layer = colorScheme.middle.bottom;
return { return {
headerAvatar: { headerAvatar: {
height: avatarSize, height: avatarSize,
@ -12,32 +13,32 @@ export default function contactNotification(theme: Theme): Object {
cornerRadius: 6, cornerRadius: 6,
}, },
headerMessage: { headerMessage: {
...text(theme, "sans", "primary", { size: "xs" }), ...text(layer, "sans", { size: "xs" }),
margin: { left: headerPadding, right: headerPadding }, margin: { left: headerPadding, right: headerPadding },
}, },
headerHeight: 18, headerHeight: 18,
bodyMessage: { bodyMessage: {
...text(theme, "sans", "secondary", { size: "xs" }), ...text(layer, "sans", { size: "xs" }),
margin: { left: avatarSize + headerPadding, top: 6, bottom: 6 }, margin: { left: avatarSize + headerPadding, top: 6, bottom: 6 },
}, },
button: { button: {
...text(theme, "sans", "primary", { size: "xs" }), ...text(layer, "sans", "on", { size: "xs" }),
background: backgroundColor(theme, "on300"), background: background(layer, "on"),
padding: 4, padding: 4,
cornerRadius: 6, cornerRadius: 6,
margin: { left: 6 }, margin: { left: 6 },
hover: { hover: {
background: backgroundColor(theme, "on300", "hovered"), background: background(layer, "on", "hovered"),
}, },
}, },
dismissButton: { dismissButton: {
color: iconColor(theme, "secondary"), color: foreground(layer, "on"),
iconWidth: 8, iconWidth: 8,
iconHeight: 8, iconHeight: 8,
buttonWidth: 8, buttonWidth: 8,
buttonHeight: 8, buttonHeight: 8,
hover: { hover: {
color: iconColor(theme, "primary"), color: foreground(layer, "on", "hovered"),
}, },
}, },
}; };

View file

@ -1,18 +1,19 @@
import Theme from "../themes/common/theme"; import { ColorScheme } from "../themes/common/colorScheme";
import { panel } from "./app"; import { panel } from "./app";
import { import {
backgroundColor, background,
border, border,
borderColor, borderColor,
iconColor, foreground,
player,
text, text,
} from "./components"; } from "./components";
export default function contactsPanel(theme: Theme) { export default function contactsPanel(colorScheme: ColorScheme) {
const nameMargin = 8; const nameMargin = 8;
const sidePadding = 12; const sidePadding = 12;
let layer = colorScheme.lowest.middle;
const projectRow = { const projectRow = {
guestAvatarSpacing: 4, guestAvatarSpacing: 4,
height: 24, height: 24,
@ -21,7 +22,7 @@ export default function contactsPanel(theme: Theme) {
width: 14, width: 14,
}, },
name: { name: {
...text(theme, "mono", "placeholder", { size: "sm" }), ...text(layer, "mono", { size: "sm" }),
margin: { margin: {
left: nameMargin, left: nameMargin,
right: 6, right: 6,
@ -40,8 +41,8 @@ export default function contactsPanel(theme: Theme) {
}; };
const contactButton = { const contactButton = {
background: backgroundColor(theme, 100), background: background(layer, "on"),
color: iconColor(theme, "primary"), color: foreground(layer, "on"),
iconWidth: 8, iconWidth: 8,
buttonWidth: 16, buttonWidth: 16,
cornerRadius: 8, cornerRadius: 8,
@ -51,12 +52,12 @@ export default function contactsPanel(theme: Theme) {
...panel, ...panel,
padding: { top: panel.padding.top, bottom: 0 }, padding: { top: panel.padding.top, bottom: 0 },
userQueryEditor: { userQueryEditor: {
background: backgroundColor(theme, 500), background: background(layer, "on"),
cornerRadius: 6, cornerRadius: 6,
text: text(theme, "mono", "primary"), text: text(layer, "mono", "on"),
placeholderText: text(theme, "mono", "placeholder", { size: "sm" }), placeholderText: text(layer, "mono", "on", "disabled", { size: "sm" }),
selection: player(theme, 1).selection, selection: colorScheme.players[0],
border: border(theme, "secondary"), border: border(layer, "on"),
padding: { padding: {
bottom: 4, bottom: 4,
left: 8, left: 8,
@ -71,28 +72,28 @@ export default function contactsPanel(theme: Theme) {
userQueryEditorHeight: 32, userQueryEditorHeight: 32,
addContactButton: { addContactButton: {
margin: { left: 6, right: 12 }, margin: { left: 6, right: 12 },
color: iconColor(theme, "primary"), color: foreground(layer, "on"),
buttonWidth: 16, buttonWidth: 16,
iconWidth: 16, iconWidth: 16,
}, },
privateButton: { privateButton: {
iconWidth: 12, iconWidth: 12,
color: iconColor(theme, "primary"), color: foreground(layer, "on"),
cornerRadius: 5, cornerRadius: 5,
buttonWidth: 12, buttonWidth: 12,
}, },
rowHeight: 28, rowHeight: 28,
sectionIconSize: 8, sectionIconSize: 8,
headerRow: { headerRow: {
...text(theme, "mono", "secondary", { size: "sm" }), ...text(layer, "mono", { size: "sm" }),
margin: { top: 14 }, margin: { top: 14 },
padding: { padding: {
left: sidePadding, left: sidePadding,
right: sidePadding, right: sidePadding,
}, },
active: { active: {
...text(theme, "mono", "primary", { size: "sm" }), ...text(layer, "mono", "base", "active", { size: "sm" }),
background: backgroundColor(theme, 100, "active"), background: background(layer, "base", "active"),
}, },
}, },
contactRow: { contactRow: {
@ -101,17 +102,17 @@ export default function contactsPanel(theme: Theme) {
right: sidePadding, right: sidePadding,
}, },
active: { active: {
background: backgroundColor(theme, 100, "active"), background: background(layer, "base", "active"),
}, },
}, },
treeBranch: { treeBranch: {
color: borderColor(theme, "active"), color: borderColor(layer),
width: 1, width: 1,
hover: { hover: {
color: borderColor(theme, "active"), color: borderColor(layer, "base", "hovered"),
}, },
active: { active: {
color: borderColor(theme, "active"), color: borderColor(layer, "base", "active"),
}, },
}, },
contactAvatar: { contactAvatar: {
@ -119,7 +120,7 @@ export default function contactsPanel(theme: Theme) {
width: 18, width: 18,
}, },
contactUsername: { contactUsername: {
...text(theme, "mono", "primary", { size: "sm" }), ...text(layer, "mono", { size: "sm" }),
margin: { margin: {
left: nameMargin, left: nameMargin,
}, },
@ -128,26 +129,26 @@ export default function contactsPanel(theme: Theme) {
contactButton: { contactButton: {
...contactButton, ...contactButton,
hover: { hover: {
background: backgroundColor(theme, "on300", "hovered"), background: background(layer, "base", "hovered"),
}, },
}, },
disabledButton: { disabledButton: {
...contactButton, ...contactButton,
background: backgroundColor(theme, 100), background: background(layer, "on"),
color: iconColor(theme, "muted"), color: foreground(layer, "on"),
}, },
projectRow: { projectRow: {
...projectRow, ...projectRow,
background: backgroundColor(theme, 300), background: background(layer, "on"),
name: { name: {
...projectRow.name, ...projectRow.name,
...text(theme, "mono", "secondary", { size: "sm" }), ...text(layer, "mono", { size: "sm" }),
}, },
hover: { hover: {
background: backgroundColor(theme, 300, "hovered"), background: background(layer, "base", "hovered"),
}, },
active: { active: {
background: backgroundColor(theme, 300, "active"), background: background(layer, "base", "active"),
}, },
}, },
inviteRow: { inviteRow: {
@ -155,10 +156,10 @@ export default function contactsPanel(theme: Theme) {
left: sidePadding, left: sidePadding,
right: sidePadding, right: sidePadding,
}, },
border: { top: true, width: 1, color: borderColor(theme, "primary") }, border: border(layer, { top: true }),
text: text(theme, "sans", "secondary", { size: "sm" }), text: text(layer, "sans", { size: "sm" }),
hover: { hover: {
text: text(theme, "sans", "active", { size: "sm" }), text: text(layer, "sans", "base", "hovered", { size: "sm" }),
}, },
}, },
}; };

View file

@ -1,45 +1,46 @@
import Theme from "../themes/common/theme"; import { ColorScheme } from "../themes/common/colorScheme";
import { import {
backgroundColor, background,
border, border,
borderColor, borderColor,
popoverShadow,
text, text,
} from "./components"; } from "./components";
export default function contextMenu(theme: Theme) { export default function contextMenu(colorScheme: ColorScheme) {
let elevation = colorScheme.middle;
let layer = elevation.bottom;
return { return {
background: backgroundColor(theme, 300, "base"), background: background(layer),
cornerRadius: 6, cornerRadius: 6,
padding: 6, padding: 6,
shadow: popoverShadow(theme), shadow: elevation.shadow,
border: border(theme, "primary"), border: border(layer),
keystrokeMargin: 30, keystrokeMargin: 30,
item: { item: {
iconSpacing: 8, iconSpacing: 8,
iconWidth: 14, iconWidth: 14,
padding: { left: 4, right: 4, top: 2, bottom: 2 }, padding: { left: 4, right: 4, top: 2, bottom: 2 },
cornerRadius: 6, cornerRadius: 6,
label: text(theme, "sans", "primary", { size: "sm" }), label: text(layer, "sans", { size: "sm" }),
keystroke: { keystroke: {
...text(theme, "sans", "muted", { size: "sm", weight: "bold" }), ...text(layer, "sans", "base", "variant", { size: "sm", weight: "bold" }),
padding: { left: 3, right: 3 }, padding: { left: 3, right: 3 },
}, },
hover: { hover: {
background: backgroundColor(theme, 300, "hovered"), background: background(layer, "base", "hovered"),
text: text(theme, "sans", "primary", { size: "sm" }), text: text(layer, "sans", "base", "hovered", { size: "sm" }),
}, },
active: { active: {
background: backgroundColor(theme, 300, "active"), background: background(layer, "base", "active"),
text: text(theme, "sans", "active", { size: "sm" }), text: text(layer, "sans", "base", "active", { size: "sm" }),
}, },
activeHover: { activeHover: {
background: backgroundColor(theme, 300, "hovered"), background: background(layer, "base", "active"),
text: text(theme, "sans", "active", { size: "sm" }), text: text(layer, "sans", "base", "active", { size: "sm" }),
}, },
}, },
separator: { separator: {
background: borderColor(theme, "primary"), background: borderColor(layer),
margin: { top: 2, bottom: 2 }, margin: { top: 2, bottom: 2 },
}, },
}; };

View file

@ -1,17 +1,18 @@
import Theme from "../themes/common/theme"; import { fontWeights } from "../common";
import { ColorScheme, Elevation, Layer, StyleSets } from "../themes/common/colorScheme";
import { import {
backgroundColor, background,
border, border,
borderColor, borderColor,
iconColor, foreground,
player,
popoverShadow,
text, text,
TextColor,
} from "./components"; } from "./components";
import hoverPopover from "./hoverPopover"; import hoverPopover from "./hoverPopover";
export default function editor(theme: Theme) { export default function editor(colorScheme: ColorScheme) {
let elevation = colorScheme.lowest;
let layer = elevation.top;
const autocompleteItem = { const autocompleteItem = {
cornerRadius: 6, cornerRadius: 6,
padding: { padding: {
@ -22,17 +23,17 @@ export default function editor(theme: Theme) {
}, },
}; };
function diagnostic(theme: Theme, color: TextColor) { function diagnostic(layer: Layer, styleSet: StyleSets) {
return { return {
textScaleFactor: 0.857, textScaleFactor: 0.857,
header: { header: {
border: border(theme, "primary", { border: border(layer, {
top: true, top: true,
}), }),
}, },
message: { message: {
text: text(theme, "sans", color, { size: "sm" }), text: text(layer, "sans", styleSet, { size: "sm" }),
highlightText: text(theme, "sans", color, { highlightText: text(layer, "sans", styleSet, {
size: "sm", size: "sm",
weight: "bold", weight: "bold",
}), }),
@ -40,115 +41,193 @@ export default function editor(theme: Theme) {
}; };
} }
const syntax: any = {}; const syntax = {
for (const syntaxKey in theme.syntax) { primary: {
const style = theme.syntax[syntaxKey]; color: elevation.ramps.neutral(1).hex(),
syntax[syntaxKey] = { weight: fontWeights.normal,
color: style.color, },
weight: style.weight, comment: {
underline: style.underline, color: elevation.ramps.neutral(0.71).hex(),
italic: style.italic, weight: fontWeights.normal,
}; },
punctuation: {
color: elevation.ramps.neutral(0.86).hex(),
weight: fontWeights.normal,
},
constant: {
color: elevation.ramps.neutral(0.57).hex(),
weight: fontWeights.normal,
},
keyword: {
color: elevation.ramps.blue(0.5).hex(),
weight: fontWeights.normal,
},
function: {
color: elevation.ramps.yellow(0.5).hex(),
weight: fontWeights.normal,
},
type: {
color: elevation.ramps.cyan(0.5).hex(),
weight: fontWeights.normal,
},
constructor: {
color: elevation.ramps.blue(0.5).hex(),
weight: fontWeights.normal,
},
variant: {
color: elevation.ramps.blue(0.5).hex(),
weight: fontWeights.normal,
},
property: {
color: elevation.ramps.blue(0.5).hex(),
weight: fontWeights.normal,
},
enum: {
color: elevation.ramps.orange(0.5).hex(),
weight: fontWeights.normal,
},
operator: {
color: elevation.ramps.orange(0.5).hex(),
weight: fontWeights.normal,
},
string: {
color: elevation.ramps.orange(0.5).hex(),
weight: fontWeights.normal,
},
number: {
color: elevation.ramps.green(0.5).hex(),
weight: fontWeights.normal,
},
boolean: {
color: elevation.ramps.green(0.5).hex(),
weight: fontWeights.normal,
},
predictive: {
color: elevation.ramps.neutral(0.57).hex(),
weight: fontWeights.normal,
},
title: {
color: elevation.ramps.yellow(0.5).hex(),
weight: fontWeights.bold,
},
emphasis: {
color: elevation.ramps.blue(0.5).hex(),
weight: fontWeights.normal,
},
"emphasis.strong": {
color: elevation.ramps.blue(0.5).hex(),
weight: fontWeights.bold,
},
linkUri: {
color: elevation.ramps.green(0.5).hex(),
weight: fontWeights.normal,
underline: true,
},
linkText: {
color: elevation.ramps.orange(0.5).hex(),
weight: fontWeights.normal,
italic: true,
},
} }
return { return {
textColor: theme.syntax.primary.color, textColor: syntax.primary.color,
background: backgroundColor(theme, 500), background: background(layer),
activeLineBackground: theme.editor.line.active, activeLineBackground: elevation.ramps.neutral(0.29).hex(),
highlightedLineBackground: elevation.ramps.neutral(0.18).hex(),
codeActions: { codeActions: {
indicator: iconColor(theme, "secondary"), indicator: foreground(layer, "base", "variant"),
verticalScale: 0.618 verticalScale: 0.618
}, },
diffBackgroundDeleted: backgroundColor(theme, "error"), diffBackgroundDeleted: background(layer, "negative"),
diffBackgroundInserted: backgroundColor(theme, "ok"), diffBackgroundInserted: background(layer, "positive"),
documentHighlightReadBackground: theme.editor.highlight.occurrence, documentHighlightReadBackground: elevation.ramps.neutral(0.5).alpha(0.2).hex(), // TODO: This was blend
documentHighlightWriteBackground: theme.editor.highlight.activeOccurrence, documentHighlightWriteBackground: elevation.ramps.neutral(0.5).alpha(0.4).hex(), // TODO: This was blend * 2
errorColor: theme.textColor.error, errorColor: foreground(layer, "negative"),
gutterBackground: backgroundColor(theme, 500), gutterBackground: background(layer),
gutterPaddingFactor: 3.5, gutterPaddingFactor: 3.5,
highlightedLineBackground: theme.editor.line.highlighted, lineNumber: foreground(layer),
lineNumber: theme.editor.gutter.primary, lineNumberActive: foreground(layer, "base", "active"),
lineNumberActive: theme.editor.gutter.active,
renameFade: 0.6, renameFade: 0.6,
unnecessaryCodeFade: 0.5, unnecessaryCodeFade: 0.5,
selection: player(theme, 1).selection, selection: colorScheme.players[0],
guestSelections: [ guestSelections: [
player(theme, 2).selection, colorScheme.players[1],
player(theme, 3).selection, colorScheme.players[2],
player(theme, 4).selection, colorScheme.players[3],
player(theme, 5).selection, colorScheme.players[4],
player(theme, 6).selection, colorScheme.players[5],
player(theme, 7).selection, colorScheme.players[6],
player(theme, 8).selection, colorScheme.players[7],
], ],
autocomplete: { autocomplete: {
background: backgroundColor(theme, 500), background: background(elevation.above.top),
cornerRadius: 8, cornerRadius: 8,
padding: 4, padding: 4,
border: border(theme, "secondary"), border: border(elevation.above.top),
shadow: popoverShadow(theme), shadow: elevation.above.shadow,
item: autocompleteItem, item: autocompleteItem,
hoveredItem: { hoveredItem: {
...autocompleteItem, ...autocompleteItem,
background: backgroundColor(theme, 500, "hovered"), background: background(elevation.above.top, "base", "hovered"),
}, },
margin: { margin: {
left: -14, left: -14,
}, },
matchHighlight: text(theme, "mono", "feature"), matchHighlight: elevation.above.ramps.blue(0.5).hex(),
selectedItem: { selectedItem: {
...autocompleteItem, ...autocompleteItem,
background: backgroundColor(theme, 500, "active"), background: background(elevation.above.top, "base", "active"),
}, },
}, },
diagnosticHeader: { diagnosticHeader: {
background: backgroundColor(theme, 300), background: background(elevation.middle),
iconWidthFactor: 1.5, iconWidthFactor: 1.5,
textScaleFactor: 0.857, // NateQ: Will we need dynamic sizing for text? If so let's create tokens for these. textScaleFactor: 0.857, // NateQ: Will we need dynamic sizing for text? If so let's create tokens for these.
border: border(theme, "secondary", { border: border(elevation.middle, {
bottom: true, bottom: true,
top: true, top: true,
}), }),
code: { code: {
...text(theme, "mono", "secondary", { size: "sm" }), ...text(elevation.middle, "mono", { size: "sm" }),
margin: { margin: {
left: 10, left: 10,
}, },
}, },
message: { message: {
highlightText: text(theme, "sans", "primary", { highlightText: text(elevation.middle, "sans", {
size: "sm", size: "sm",
weight: "bold", weight: "bold",
}), }),
text: text(theme, "sans", "secondary", { size: "sm" }), text: text(elevation.middle, "sans", { size: "sm" }),
}, },
}, },
diagnosticPathHeader: { diagnosticPathHeader: {
background: theme.editor.line.active, background: background(elevation.middle),
textScaleFactor: 0.857, textScaleFactor: 0.857,
filename: text(theme, "mono", "primary", { size: "sm" }), filename: text(elevation.middle, "mono", { size: "sm" }),
path: { path: {
...text(theme, "mono", "muted", { size: "sm" }), ...text(elevation.middle, "mono", { size: "sm" }),
margin: { margin: {
left: 12, left: 12,
}, },
}, },
}, },
errorDiagnostic: diagnostic(theme, "error"), errorDiagnostic: diagnostic(elevation.middle, "negative"),
warningDiagnostic: diagnostic(theme, "warning"), warningDiagnostic: diagnostic(elevation.middle, "warning"),
informationDiagnostic: diagnostic(theme, "info"), informationDiagnostic: diagnostic(elevation.middle, "info"),
hintDiagnostic: diagnostic(theme, "info"), hintDiagnostic: diagnostic(elevation.middle, "positive"),
invalidErrorDiagnostic: diagnostic(theme, "secondary"), invalidErrorDiagnostic: diagnostic(elevation.middle, "base"),
invalidHintDiagnostic: diagnostic(theme, "secondary"), invalidHintDiagnostic: diagnostic(elevation.middle, "base"),
invalidInformationDiagnostic: diagnostic(theme, "secondary"), invalidInformationDiagnostic: diagnostic(elevation.middle, "base"),
invalidWarningDiagnostic: diagnostic(theme, "secondary"), invalidWarningDiagnostic: diagnostic(elevation.middle, "base"),
hoverPopover: hoverPopover(theme), hoverPopover: hoverPopover(elevation.above),
linkDefinition: { linkDefinition: {
color: theme.syntax.linkUri.color, color: syntax.linkUri.color,
underline: theme.syntax.linkUri.underline, underline: syntax.linkUri.underline,
}, },
jumpIcon: { jumpIcon: {
color: iconColor(theme, "secondary"), color: foreground(layer, "on"),
iconWidth: 20, iconWidth: 20,
buttonWidth: 20, buttonWidth: 20,
cornerRadius: 6, cornerRadius: 6,
@ -159,14 +238,14 @@ export default function editor(theme: Theme) {
right: 6, right: 6,
}, },
hover: { hover: {
color: iconColor(theme, "active"), color: foreground(layer, "on", "hovered"),
background: backgroundColor(theme, "on500"), background: background(layer, "on", "hovered"),
}, },
}, },
compositionMark: { compositionMark: {
underline: { underline: {
thickness: 1.0, thickness: 1.0,
color: borderColor(theme, "active") color: borderColor(layer),
}, },
}, },
syntax, syntax,

View file

@ -1,9 +1,10 @@
import Theme from "../themes/common/theme"; import { Elevation } from "../themes/common/colorScheme";
import { backgroundColor, border, popoverShadow, text } from "./components"; import { background, border, text } from "./components";
export default function HoverPopover(theme: Theme) { export default function HoverPopover(elevation: Elevation) {
let layer = elevation.middle;
let baseContainer = { let baseContainer = {
background: backgroundColor(theme, "on500"), background: background(layer),
cornerRadius: 8, cornerRadius: 8,
padding: { padding: {
left: 8, left: 8,
@ -11,8 +12,8 @@ export default function HoverPopover(theme: Theme) {
top: 4, top: 4,
bottom: 4 bottom: 4
}, },
shadow: popoverShadow(theme), shadow: elevation.shadow,
border: border(theme, "secondary"), border: border(layer),
margin: { margin: {
left: -8, left: -8,
}, },
@ -22,32 +23,23 @@ export default function HoverPopover(theme: Theme) {
container: baseContainer, container: baseContainer,
infoContainer: { infoContainer: {
...baseContainer, ...baseContainer,
background: backgroundColor(theme, "on500Info"), background: background(layer, "info"),
border: { border: border(layer, "info"),
color: theme.ramps.blue(0).hex(),
width: 1,
},
}, },
warningContainer: { warningContainer: {
...baseContainer, ...baseContainer,
background: backgroundColor(theme, "on500Warning"), background: background(layer, "warning"),
border: { border: border(layer, "warning"),
color: theme.ramps.yellow(0).hex(),
width: 1,
},
}, },
errorContainer: { errorContainer: {
...baseContainer, ...baseContainer,
background: backgroundColor(theme, "on500Error"), background: background(layer, "negative"),
border: { border: border(layer, "negative"),
color: theme.ramps.red(0).hex(),
width: 1,
}
}, },
block_style: { block_style: {
padding: { top: 4 }, padding: { top: 4 },
}, },
prose: text(theme, "sans", "primary", { size: "sm" }), prose: text(layer, "sans", { size: "sm" }),
highlight: theme.editor.highlight.occurrence, highlight: elevation.ramps.neutral(0.5).alpha(0.2).hex(), // TODO: blend was used here. Replace with something better
}; };
} }

View file

@ -1,15 +1,15 @@
import Theme from "../themes/common/theme"; import { ColorScheme } from "../themes/common/colorScheme";
import { import {
backgroundColor, background,
border, border,
player,
modalShadow,
text, text,
} from "./components"; } from "./components";
export default function picker(theme: Theme) { export default function picker(colorScheme: ColorScheme) {
let elevation = colorScheme.highest;
let layer = elevation.middle;
return { return {
background: backgroundColor(theme, 300), background: background(layer),
cornerRadius: 8, cornerRadius: 8,
padding: 8, padding: 8,
item: { item: {
@ -20,19 +20,19 @@ export default function picker(theme: Theme) {
top: 4, top: 4,
}, },
cornerRadius: 8, cornerRadius: 8,
text: text(theme, "sans", "secondary"), text: text(layer, "sans"),
highlightText: text(theme, "sans", "feature", { weight: "bold" }), highlightText: text(layer, "sans", { weight: "bold" }),
active: { active: {
background: backgroundColor(theme, 300, "active"), background: background(layer, "base", "active"),
text: text(theme, "sans", "active"), text: text(layer, "sans", "base", "active"),
}, },
hover: { hover: {
background: backgroundColor(theme, 300, "hovered"), background: background(layer, "base", "hovered"),
}, },
}, },
border: border(theme, "primary"), border: border(layer),
empty: { empty: {
text: text(theme, "sans", "muted"), text: text(layer, "sans"),
padding: { padding: {
bottom: 4, bottom: 4,
left: 12, left: 12,
@ -41,12 +41,12 @@ export default function picker(theme: Theme) {
}, },
}, },
inputEditor: { inputEditor: {
background: backgroundColor(theme, 500), background: background(layer, "on"),
cornerRadius: 8, cornerRadius: 8,
placeholderText: text(theme, "sans", "placeholder"), placeholderText: text(layer, "sans", "on", "disabled"),
selection: player(theme, 1).selection, selection: colorScheme.players[0],
text: text(theme, "mono", "primary"), text: text(layer, "mono", "on"),
border: border(theme, "secondary"), border: border(layer, "on"),
padding: { padding: {
bottom: 7, bottom: 7,
left: 16, left: 16,
@ -54,6 +54,6 @@ export default function picker(theme: Theme) {
top: 7, top: 7,
}, },
}, },
shadow: modalShadow(theme), shadow: elevation.shadow,
}; };
} }

View file

@ -1,12 +1,13 @@
import Theme from "../themes/common/theme"; import { ColorScheme } from "../themes/common/colorScheme";
import { backgroundColor, text } from "./components"; import { background, text } from "./components";
export default function projectDiagnostics(theme: Theme) { export default function projectDiagnostics(colorScheme: ColorScheme) {
let layer = colorScheme.lowest.top;
return { return {
background: backgroundColor(theme, 500), background: background(layer),
tabIconSpacing: 4, tabIconSpacing: 4,
tabIconWidth: 13, tabIconWidth: 13,
tabSummarySpacing: 10, tabSummarySpacing: 10,
emptyMessage: text(theme, "sans", "secondary", { size: "md" }), emptyMessage: text(layer, "sans", "base", "variant", { size: "md" }),
}; };
} }

View file

@ -1,36 +1,37 @@
import Theme from "../themes/common/theme"; import { ColorScheme } from "../themes/common/colorScheme";
import { panel } from "./app"; import { panel } from "./app";
import { backgroundColor, iconColor, player, text } from "./components"; import { background, foreground, text } from "./components";
export default function projectPanel(theme: Theme) { export default function projectPanel(colorScheme: ColorScheme) {
let layer = colorScheme.lowest.middle;
return { return {
...panel, ...panel,
padding: { left: 12, right: 12, top: 6, bottom: 6 }, padding: { left: 12, right: 12, top: 6, bottom: 6 },
indentWidth: 8, indentWidth: 8,
entry: { entry: {
height: 24, height: 24,
iconColor: iconColor(theme, "muted"), iconColor: foreground(layer, "on"),
iconSize: 8, iconSize: 8,
iconSpacing: 8, iconSpacing: 8,
text: text(theme, "mono", "secondary", { size: "sm" }), text: text(layer, "mono", "on", { size: "sm" }),
hover: { hover: {
background: backgroundColor(theme, 300, "hovered"), background: background(layer, "on", "hovered"),
}, },
active: { active: {
background: backgroundColor(theme, 300, "active"), background: background(layer, "base", "active"),
text: text(theme, "mono", "active", { size: "sm" }), text: text(layer, "mono", "base", "active", { size: "sm" }),
}, },
activeHover: { activeHover: {
background: backgroundColor(theme, 300, "active"), background: background(layer, "base", "hovered"),
text: text(theme, "mono", "active", { size: "sm" }), text: text(layer, "mono", "base", "active", { size: "sm" }),
}, },
}, },
cutEntryFade: 0.4, cutEntryFade: 0.4,
ignoredEntryFade: 0.6, ignoredEntryFade: 0.6,
filenameEditor: { filenameEditor: {
background: backgroundColor(theme, "on300"), background: background(layer, "on"),
text: text(theme, "mono", "active", { size: "sm" }), text: text(layer, "mono", "on", "active", { size: "sm" }),
selection: player(theme, 1).selection, selection: colorScheme.players[0],
}, },
}; };
} }

View file

@ -1,17 +1,19 @@
import Theme from "../themes/common/theme"; import { ColorScheme } from "../themes/common/colorScheme";
import { backgroundColor, border, player, text } from "./components"; import { background, border, text } from "./components";
export default function search(colorScheme: ColorScheme) {
let layer = colorScheme.lowest.top;
export default function search(theme: Theme) {
// Search input // Search input
const editor = { const editor = {
background: backgroundColor(theme, 500), background: background(layer),
cornerRadius: 8, cornerRadius: 8,
minWidth: 200, minWidth: 200,
maxWidth: 500, maxWidth: 500,
placeholderText: text(theme, "mono", "placeholder"), placeholderText: text(layer, "mono", "base", "disabled"),
selection: player(theme, 1).selection, selection: colorScheme.players[0],
text: text(theme, "mono", "active"), text: text(layer, "mono", "base", "active"),
border: border(theme, "secondary"), border: border(layer),
margin: { margin: {
right: 12, right: 12,
}, },
@ -24,14 +26,14 @@ export default function search(theme: Theme) {
}; };
return { return {
matchBackground: theme.editor.highlight.match, matchBackground: background(layer), // theme.editor.highlight.match,
tabIconSpacing: 8, tabIconSpacing: 8,
tabIconWidth: 14, tabIconWidth: 14,
optionButton: { optionButton: {
...text(theme, "mono", "secondary"), ...text(layer, "mono", "on"),
background: backgroundColor(theme, "on500"), background: background(layer, "on"),
cornerRadius: 6, cornerRadius: 6,
border: border(theme, "secondary"), border: border(layer, "on"),
margin: { margin: {
right: 4, right: 4,
}, },
@ -42,28 +44,28 @@ export default function search(theme: Theme) {
top: 2, top: 2,
}, },
active: { active: {
...text(theme, "mono", "active"), ...text(layer, "mono", "on", "active"),
background: backgroundColor(theme, "on500", "active"), background: background(layer, "on", "active"),
border: border(theme, "muted"), border: border(layer, "on", "active"),
}, },
clicked: { clicked: {
...text(theme, "mono", "active"), ...text(layer, "mono", "on", "pressed"),
background: backgroundColor(theme, "on300", "active"), background: background(layer, "on", "pressed"),
border: border(theme, "secondary"), border: border(layer, "on", "pressed"),
}, },
hover: { hover: {
...text(theme, "mono", "active"), ...text(layer, "mono", "on", "hovered"),
background: backgroundColor(theme, "on500", "hovered"), background: background(layer, "on", "hovered"),
border: border(theme, "muted"), border: border(layer, "on", "hovered"),
}, },
}, },
editor, editor,
invalidEditor: { invalidEditor: {
...editor, ...editor,
border: border(theme, "error"), border: border(layer, "negative"),
}, },
matchIndex: { matchIndex: {
...text(theme, "mono", "muted"), ...text(layer, "mono", "on", "variant"),
padding: 6, padding: 6,
}, },
optionButtonGroup: { optionButtonGroup: {
@ -73,7 +75,7 @@ export default function search(theme: Theme) {
}, },
}, },
resultsStatus: { resultsStatus: {
...text(theme, "mono", "primary"), ...text(layer, "mono", "on"),
size: 18, size: 18,
}, },
}; };

View file

@ -1,8 +1,9 @@
import Theme from "../themes/common/theme"; import { ColorScheme } from "../themes/common/colorScheme";
import { backgroundColor, border, iconColor, text } from "./components"; import { background, border, foreground, text } from "./components";
import { workspaceBackground } from "./workspace";
export default function statusBar(colorScheme: ColorScheme) {
let layer = colorScheme.lowest.bottom;
export default function statusBar(theme: Theme) {
const statusContainer = { const statusContainer = {
cornerRadius: 6, cornerRadius: 6,
padding: { top: 3, bottom: 3, left: 6, right: 6 }, padding: { top: 3, bottom: 3, left: 6, right: 6 },
@ -22,70 +23,70 @@ export default function statusBar(theme: Theme) {
left: 6, left: 6,
right: 6, right: 6,
}, },
border: border(theme, "primary", { top: true, overlay: true }), border: border(layer, { top: true, overlay: true }),
cursorPosition: text(theme, "sans", "secondary"), cursorPosition: text(layer, "sans"),
autoUpdateProgressMessage: text(theme, "sans", "secondary"), autoUpdateProgressMessage: text(layer, "sans"),
autoUpdateDoneMessage: text(theme, "sans", "secondary"), autoUpdateDoneMessage: text(layer, "sans"),
lspStatus: { lspStatus: {
...diagnosticStatusContainer, ...diagnosticStatusContainer,
iconSpacing: 4, iconSpacing: 4,
iconWidth: 14, iconWidth: 14,
height: 18, height: 18,
message: text(theme, "sans", "secondary"), message: text(layer, "sans"),
iconColor: iconColor(theme, "muted"), iconColor: foreground(layer),
hover: { hover: {
message: text(theme, "sans", "primary"), message: text(layer, "sans"),
iconColor: iconColor(theme, "primary"), iconColor: foreground(layer),
background: backgroundColor(theme, 300, "hovered"), background: background(layer),
}, },
}, },
diagnosticMessage: { diagnosticMessage: {
...text(theme, "sans", "secondary"), ...text(layer, "sans"),
hover: text(theme, "sans", "active"), hover: text(layer, "sans", "base", "hovered"),
}, },
feedback: { feedback: {
...text(theme, "sans", "secondary"), ...text(layer, "sans"),
hover: text(theme, "sans", "active"), hover: text(layer, "sans"),
}, },
diagnosticSummary: { diagnosticSummary: {
height: 16, height: 16,
iconWidth: 16, iconWidth: 16,
iconSpacing: 2, iconSpacing: 2,
summarySpacing: 6, summarySpacing: 6,
text: text(theme, "sans", "primary", { size: "sm" }), text: text(layer, "sans", { size: "sm" }),
iconColorOk: iconColor(theme, "muted"), iconColorOk: foreground(layer, "positive"),
iconColorWarning: iconColor(theme, "warning"), iconColorWarning: foreground(layer, "warning"),
iconColorError: iconColor(theme, "error"), iconColorError: foreground(layer, "negative"),
containerOk: { containerOk: {
cornerRadius: 6, cornerRadius: 6,
padding: { top: 3, bottom: 3, left: 7, right: 7 }, padding: { top: 3, bottom: 3, left: 7, right: 7 },
}, },
containerWarning: { containerWarning: {
...diagnosticStatusContainer, ...diagnosticStatusContainer,
background: backgroundColor(theme, "warning"), background: background(layer, "warning"),
border: border(theme, "warning"), border: border(layer, "warning"),
}, },
containerError: { containerError: {
...diagnosticStatusContainer, ...diagnosticStatusContainer,
background: backgroundColor(theme, "error"), background: background(layer, "negative"),
border: border(theme, "error"), border: border(layer, "negative"),
}, },
hover: { hover: {
iconColorOk: iconColor(theme, "active"), iconColorOk: foreground(layer, "on"),
containerOk: { containerOk: {
cornerRadius: 6, cornerRadius: 6,
padding: { top: 3, bottom: 3, left: 7, right: 7 }, padding: { top: 3, bottom: 3, left: 7, right: 7 },
background: backgroundColor(theme, 300, "hovered"), background: background(layer, "on", "hovered"),
}, },
containerWarning: { containerWarning: {
...diagnosticStatusContainer, ...diagnosticStatusContainer,
background: backgroundColor(theme, "warning", "hovered"), background: background(layer, "warning", "hovered"),
border: border(theme, "warning"), border: border(layer, "warning", "hovered"),
}, },
containerError: { containerError: {
...diagnosticStatusContainer, ...diagnosticStatusContainer,
background: backgroundColor(theme, "error", "hovered"), background: background(layer, "negative", "hovered"),
border: border(theme, "error"), border: border(layer, "negative", "hovered"),
}, },
}, },
}, },
@ -95,22 +96,22 @@ export default function statusBar(theme: Theme) {
item: { item: {
...statusContainer, ...statusContainer,
iconSize: 16, iconSize: 16,
iconColor: iconColor(theme, "muted"), iconColor: foreground(layer),
hover: { hover: {
iconColor: iconColor(theme, "active"), iconColor: foreground(layer, "base", "hovered"),
background: backgroundColor(theme, 300, "hovered"), background: background(layer, "base", "hovered"),
}, },
active: { active: {
iconColor: iconColor(theme, "active"), iconColor: foreground(layer, "base", "active"),
background: backgroundColor(theme, 300, "active"), background: background(layer, "base", "active"),
}, },
}, },
badge: { badge: {
cornerRadius: 3, cornerRadius: 3,
padding: 2, padding: 2,
margin: { bottom: -1, right: -1 }, margin: { bottom: -1, right: -1 },
border: { width: 1, color: workspaceBackground(theme) }, border: border(layer),
background: iconColor(theme, "feature"), background: background(layer),
}, },
}, },
}; };

View file

@ -1,39 +1,42 @@
import Theme from "../themes/common/theme"; import { ColorScheme } from "../themes/common/colorScheme";
import { withOpacity } from "../utils/color"; import { withOpacity } from "../utils/color";
import { iconColor, text, border, backgroundColor, draggedShadow } from "./components"; import { text, border, background, foreground } from "./components";
export default function tabBar(theme: Theme) { export default function tabBar(colorScheme: ColorScheme) {
const height = 32; const height = 32;
let elevation = colorScheme.lowest;
let layer = elevation.middle;
const tab = { const tab = {
height, height,
background: backgroundColor(theme, 300), background: background(layer),
border: border(theme, "primary", { border: border(layer, {
left: true, left: true,
bottom: true, bottom: true,
overlay: true, overlay: true,
}), }),
iconClose: iconColor(theme, "muted"), iconClose: foreground(layer),
iconCloseActive: iconColor(theme, "active"), iconCloseActive: foreground(layer, "base", "active"),
iconConflict: iconColor(theme, "warning"), iconConflict: foreground(layer, "warning"),
iconDirty: iconColor(theme, "info"), iconDirty: foreground(layer, "info"),
iconWidth: 8, iconWidth: 8,
spacing: 8, spacing: 8,
text: text(theme, "sans", "secondary", { size: "sm" }), text: text(layer, "sans", { size: "sm" }),
padding: { padding: {
left: 8, left: 8,
right: 8, right: 8,
}, },
description: { description: {
margin: { left: 6, top: 1 }, margin: { left: 6, top: 1 },
...text(theme, "sans", "muted", { size: "2xs" }) ...text(layer, "sans", "base", "variant", { size: "2xs" })
} }
}; };
const activePaneActiveTab = { const activePaneActiveTab = {
...tab, ...tab,
background: backgroundColor(theme, 500), background: background(elevation.top),
text: text(theme, "sans", "active", { size: "sm" }), text: text(elevation.top, "sans", "base", "active", { size: "sm" }),
border: { border: {
...tab.border, ...tab.border,
bottom: false bottom: false
@ -42,14 +45,14 @@ export default function tabBar(theme: Theme) {
const inactivePaneInactiveTab = { const inactivePaneInactiveTab = {
...tab, ...tab,
background: backgroundColor(theme, 300), background: background(layer),
text: text(theme, "sans", "muted", { size: "sm" }), text: text(layer, "sans", { size: "sm" }),
}; };
const inactivePaneActiveTab = { const inactivePaneActiveTab = {
...tab, ...tab,
background: backgroundColor(theme, 500), background: background(layer),
text: text(theme, "sans", "secondary", { size: "sm" }), text: text(layer, "sans", "base", "active", { size: "sm" }),
border: { border: {
...tab.border, ...tab.border,
bottom: false bottom: false
@ -59,15 +62,16 @@ export default function tabBar(theme: Theme) {
const draggedTab = { const draggedTab = {
...activePaneActiveTab, ...activePaneActiveTab,
background: withOpacity(tab.background, 0.8), background: withOpacity(tab.background, 0.8),
border: undefined as any, // Remove border border: undefined as any,
shadow: draggedShadow(theme), shadow: elevation.above.shadow,
} }
return { return {
height, height,
background: backgroundColor(theme, 300), background: background(layer),
dropTargetOverlayColor: withOpacity(theme.textColor.muted, 0.6), dropTargetOverlayColor: withOpacity(foreground(layer), 0.6),
border: border(theme, "primary", { border: border(layer, {
left: true,
bottom: true, bottom: true,
overlay: true, overlay: true,
}), }),
@ -81,11 +85,11 @@ export default function tabBar(theme: Theme) {
}, },
draggedTab, draggedTab,
paneButton: { paneButton: {
color: iconColor(theme, "secondary"), color: foreground(layer),
iconWidth: 12, iconWidth: 12,
buttonWidth: activePaneActiveTab.height, buttonWidth: activePaneActiveTab.height,
hover: { hover: {
color: iconColor(theme, "active"), color: foreground(layer, "base", "hovered"),
}, },
}, },
paneButtonContainer: { paneButtonContainer: {

View file

@ -1,7 +1,6 @@
import Theme from "../themes/common/theme"; import { Elevation } from "../themes/common/colorScheme";
import { border, modalShadow, player } from "./components";
export default function terminal(theme: Theme) { export default function terminal(elevation: Elevation) {
/** /**
* Colors are controlled per-cell in the terminal grid. * Colors are controlled per-cell in the terminal grid.
* Cells can be set to any of these more 'theme-capable' colors * Cells can be set to any of these more 'theme-capable' colors
@ -9,57 +8,45 @@ export default function terminal(theme: Theme) {
* Here are the common interpretations of these names: * Here are the common interpretations of these names:
* https://en.wikipedia.org/wiki/ANSI_escape_code#Colors * https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
*/ */
let colors = { return {
black: theme.ramps.neutral(0).hex(), black: elevation.ramps.neutral(0).hex(),
red: theme.ramps.red(0.5).hex(), red: elevation.ramps.red(0.5).hex(),
green: theme.ramps.green(0.5).hex(), green: elevation.ramps.green(0.5).hex(),
yellow: theme.ramps.yellow(0.5).hex(), yellow: elevation.ramps.yellow(0.5).hex(),
blue: theme.ramps.blue(0.5).hex(), blue: elevation.ramps.blue(0.5).hex(),
magenta: theme.ramps.magenta(0.5).hex(), magenta: elevation.ramps.magenta(0.5).hex(),
cyan: theme.ramps.cyan(0.5).hex(), cyan: elevation.ramps.cyan(0.5).hex(),
white: theme.ramps.neutral(7).hex(), white: elevation.ramps.neutral(1).hex(),
brightBlack: theme.ramps.neutral(4).hex(), brightBlack: elevation.ramps.neutral(0.4).hex(),
brightRed: theme.ramps.red(0.25).hex(), brightRed: elevation.ramps.red(0.25).hex(),
brightGreen: theme.ramps.green(0.25).hex(), brightGreen: elevation.ramps.green(0.25).hex(),
brightYellow: theme.ramps.yellow(0.25).hex(), brightYellow: elevation.ramps.yellow(0.25).hex(),
brightBlue: theme.ramps.blue(0.25).hex(), brightBlue: elevation.ramps.blue(0.25).hex(),
brightMagenta: theme.ramps.magenta(0.25).hex(), brightMagenta: elevation.ramps.magenta(0.25).hex(),
brightCyan: theme.ramps.cyan(0.25).hex(), brightCyan: elevation.ramps.cyan(0.25).hex(),
brightWhite: theme.ramps.neutral(7).hex(), brightWhite: elevation.ramps.neutral(1).hex(),
/** /**
* Default color for characters * Default color for characters
*/ */
foreground: theme.ramps.neutral(7).hex(), foreground: elevation.ramps.neutral(1).hex(),
/** /**
* Default color for the rectangle background of a cell * Default color for the rectangle background of a cell
*/ */
background: theme.ramps.neutral(0).hex(), background: elevation.ramps.neutral(0).hex(),
modalBackground: theme.ramps.neutral(1).hex(), modalBackground: elevation.ramps.neutral(0.1).hex(),
/** /**
* Default color for the cursor * Default color for the cursor
*/ */
cursor: player(theme, 1).selection.cursor, cursor: elevation.ramps.blue(0).hex(),
dimBlack: theme.ramps.neutral(7).hex(), dimBlack: elevation.ramps.neutral(1).hex(),
dimRed: theme.ramps.red(0.75).hex(), dimRed: elevation.ramps.red(0.75).hex(),
dimGreen: theme.ramps.green(0.75).hex(), dimGreen: elevation.ramps.green(0.75).hex(),
dimYellow: theme.ramps.yellow(0.75).hex(), dimYellow: elevation.ramps.yellow(0.75).hex(),
dimBlue: theme.ramps.blue(0.75).hex(), dimBlue: elevation.ramps.blue(0.75).hex(),
dimMagenta: theme.ramps.magenta(0.75).hex(), dimMagenta: elevation.ramps.magenta(0.75).hex(),
dimCyan: theme.ramps.cyan(0.75).hex(), dimCyan: elevation.ramps.cyan(0.75).hex(),
dimWhite: theme.ramps.neutral(5).hex(), dimWhite: elevation.ramps.neutral(0.6).hex(),
brightForeground: theme.ramps.neutral(7).hex(), brightForeground: elevation.ramps.neutral(1).hex(),
dimForeground: theme.ramps.neutral(0).hex(), dimForeground: elevation.ramps.neutral(0).hex(),
};
return {
colors,
modalContainer: {
background: colors.modalBackground,
cornerRadius: 8,
padding: 8,
margin: 25,
border: border(theme, "primary"),
shadow: modalShadow(theme),
},
}; };
} }

View file

@ -1,21 +1,23 @@
import Theme from "../themes/common/theme"; import { ColorScheme } from "../themes/common/colorScheme";
import { backgroundColor, border, popoverShadow, text } from "./components"; import { background, border, text } from "./components";
export default function tooltip(theme: Theme) { export default function tooltip(colorScheme: ColorScheme) {
let elevation = colorScheme.middle;
let layer = colorScheme.middle.middle;
return { return {
background: backgroundColor(theme, 500), background: background(layer),
border: border(theme, "secondary"), border: border(layer),
padding: { top: 4, bottom: 4, left: 8, right: 8 }, padding: { top: 4, bottom: 4, left: 8, right: 8 },
margin: { top: 6, left: 6 }, margin: { top: 6, left: 6 },
shadow: popoverShadow(theme), shadow: elevation.shadow,
cornerRadius: 6, cornerRadius: 6,
text: text(theme, "sans", "primary", { size: "xs" }), text: text(layer, "sans", { size: "xs" }),
keystroke: { keystroke: {
background: backgroundColor(theme, "on500"), background: background(layer, "on"),
cornerRadius: 4, cornerRadius: 4,
margin: { left: 6 }, margin: { left: 6 },
padding: { left: 4, right: 4 }, padding: { left: 4, right: 4 },
...text(theme, "mono", "secondary", { size: "xs", weight: "bold" }), ...text(layer, "mono", "on", { size: "xs", weight: "bold" }),
}, },
maxTextWidth: 200, maxTextWidth: 200,
}; };

View file

@ -1,29 +1,30 @@
import Theme from "../themes/common/theme"; import { ColorScheme } from "../themes/common/colorScheme";
import { iconColor, text } from "./components"; import { foreground, text } from "./components";
const headerPadding = 8; const headerPadding = 8;
export default function updateNotification(theme: Theme): Object { export default function updateNotification(colorScheme: ColorScheme): Object {
let layer = colorScheme.middle.middle;
return { return {
message: { message: {
...text(theme, "sans", "primary", { size: "xs" }), ...text(layer, "sans", { size: "xs" }),
margin: { left: headerPadding, right: headerPadding }, margin: { left: headerPadding, right: headerPadding },
}, },
actionMessage: { actionMessage: {
...text(theme, "sans", "secondary", { size: "xs" }), ...text(layer, "sans", { size: "xs" }),
margin: { left: headerPadding, top: 6, bottom: 6 }, margin: { left: headerPadding, top: 6, bottom: 6 },
hover: { hover: {
color: theme.textColor["active"], color: foreground(layer, "base", "hovered"),
}, },
}, },
dismissButton: { dismissButton: {
color: iconColor(theme, "secondary"), color: foreground(layer),
iconWidth: 8, iconWidth: 8,
iconHeight: 8, iconHeight: 8,
buttonWidth: 8, buttonWidth: 8,
buttonHeight: 8, buttonHeight: 8,
hover: { hover: {
color: iconColor(theme, "primary"), color: foreground(layer, "base", "hovered"),
}, },
}, },
}; };

View file

@ -1,35 +1,33 @@
import Theme from "../themes/common/theme"; import { ColorScheme } from "../themes/common/colorScheme";
import { withOpacity } from "../utils/color"; import { withOpacity } from "../utils/color";
import { import {
backgroundColor, background,
border, border,
iconColor, borderColor,
modalShadow, foreground,
text, text
} from "./components"; } from "./components";
import statusBar from "./statusBar"; import statusBar from "./statusBar";
import tabBar from "./tabBar"; import tabBar from "./tabBar";
export function workspaceBackground(theme: Theme) { export default function workspace(colorScheme: ColorScheme) {
return backgroundColor(theme, 300); const elevation = colorScheme.lowest;
} const layer = elevation.middle;
export default function workspace(theme: Theme) {
const titlebarPadding = 6; const titlebarPadding = 6;
return { return {
background: backgroundColor(theme, 300), background: background(layer),
joiningProjectAvatar: { joiningProjectAvatar: {
cornerRadius: 40, cornerRadius: 40,
width: 80, width: 80,
}, },
joiningProjectMessage: { joiningProjectMessage: {
padding: 12, padding: 12,
...text(theme, "sans", "primary", { size: "lg" }), ...text(layer, "sans", { size: "lg" }),
}, },
leaderBorderOpacity: 0.7, leaderBorderOpacity: 0.7,
leaderBorderWidth: 2.0, leaderBorderWidth: 2.0,
tabBar: tabBar(theme), tabBar: tabBar(colorScheme),
modal: { modal: {
margin: { margin: {
bottom: 52, bottom: 52,
@ -39,28 +37,26 @@ export default function workspace(theme: Theme) {
}, },
sidebar: { sidebar: {
initialSize: 240, initialSize: 240,
border: { border: border(
color: border(theme, "primary").color, layer,
width: 1, { left: true, right: true }
left: true, ),
right: true,
}
}, },
paneDivider: { paneDivider: {
color: border(theme, "secondary").color, color: borderColor(layer),
width: 1, width: 1,
}, },
statusBar: statusBar(theme), statusBar: statusBar(colorScheme),
titlebar: { titlebar: {
avatarWidth: 18, avatarWidth: 18,
avatarMargin: 8, avatarMargin: 8,
height: 33, height: 33,
background: backgroundColor(theme, 100), background: background(layer),
padding: { padding: {
left: 80, left: 80,
right: titlebarPadding, right: titlebarPadding,
}, },
title: text(theme, "sans", "primary"), title: text(layer, "sans"),
avatar: { avatar: {
cornerRadius: 10, cornerRadius: 10,
border: { border: {
@ -74,10 +70,10 @@ export default function workspace(theme: Theme) {
// TODO: The background for this ideally should be // TODO: The background for this ideally should be
// set with a token, not hardcoded in rust // set with a token, not hardcoded in rust
}, },
border: border(theme, "primary", { bottom: true, overlay: true }), border: border(layer, { bottom: true, overlay: true }),
signInPrompt: { signInPrompt: {
background: backgroundColor(theme, 100), background: background(layer),
border: border(theme, "secondary"), border: border(layer),
cornerRadius: 6, cornerRadius: 6,
margin: { margin: {
top: 1, top: 1,
@ -88,15 +84,15 @@ export default function workspace(theme: Theme) {
left: 7, left: 7,
right: 7, right: 7,
}, },
...text(theme, "sans", "secondary", { size: "xs" }), ...text(layer, "sans", { size: "xs" }),
hover: { hover: {
...text(theme, "sans", "active", { size: "xs" }), ...text(layer, "sans", "on", "hovered", { size: "xs" }),
background: backgroundColor(theme, "on300", "hovered"), background: background(layer, "on", "hovered"),
border: border(theme, "primary"), border: border(layer, "on", "hovered"),
}, },
}, },
offlineIcon: { offlineIcon: {
color: iconColor(theme, "secondary"), color: foreground(layer, "on"),
width: 16, width: 16,
margin: { margin: {
left: titlebarPadding, left: titlebarPadding,
@ -106,9 +102,9 @@ export default function workspace(theme: Theme) {
}, },
}, },
outdatedWarning: { outdatedWarning: {
...text(theme, "sans", "warning", { size: "xs" }), ...text(layer, "sans", "warning", { size: "xs" }),
background: backgroundColor(theme, "warning"), background: background(layer, "warning"),
border: border(theme, "warning"), border: border(layer, "warning"),
margin: { margin: {
left: titlebarPadding, left: titlebarPadding,
}, },
@ -121,39 +117,39 @@ export default function workspace(theme: Theme) {
}, },
toolbar: { toolbar: {
height: 34, height: 34,
background: backgroundColor(theme, 500), background: background(layer),
border: border(theme, "secondary", { bottom: true }), border: border(layer, "base", "variant", { bottom: true }),
itemSpacing: 8, itemSpacing: 8,
navButton: { navButton: {
color: iconColor(theme, "primary"), color: foreground(layer, "on"),
iconWidth: 12, iconWidth: 12,
buttonWidth: 24, buttonWidth: 24,
cornerRadius: 6, cornerRadius: 6,
hover: { hover: {
color: iconColor(theme, "active"), color: foreground(layer, "on", "hovered"),
background: backgroundColor(theme, "on500", "hovered"), background: background(layer, "on", "hovered"),
}, },
disabled: { disabled: {
color: withOpacity(iconColor(theme, "muted"), 0.6), color: foreground(layer, "on", "disabled"),
}, },
}, },
padding: { left: 8, right: 8, top: 4, bottom: 4 }, padding: { left: 8, right: 8, top: 4, bottom: 4 },
}, },
breadcrumbs: { breadcrumbs: {
...text(theme, "mono", "secondary"), ...text(layer, "mono", "on", "variant"),
padding: { left: 6 }, padding: { left: 6 },
}, },
disconnectedOverlay: { disconnectedOverlay: {
...text(theme, "sans", "active"), ...text(layer, "sans"),
background: withOpacity(theme.backgroundColor[500].base, 0.8), background: withOpacity(background(layer), 0.8),
}, },
notification: { notification: {
margin: { top: 10 }, margin: { top: 10 },
background: backgroundColor(theme, 300), background: background(elevation.above.middle),
cornerRadius: 6, cornerRadius: 6,
padding: 12, padding: 12,
border: border(theme, "primary"), border: border(elevation.above.middle),
shadow: modalShadow(theme), shadow: elevation.above.shadow,
}, },
notifications: { notifications: {
width: 400, width: 400,
@ -162,17 +158,14 @@ export default function workspace(theme: Theme) {
dock: { dock: {
initialSizeRight: 640, initialSizeRight: 640,
initialSizeBottom: 480, initialSizeBottom: 480,
wash_color: withOpacity(theme.backgroundColor[500].base, 0.5), wash_color: withOpacity(background(elevation.top), 0.5),
panel: { panel: {
border: { border: border(elevation.top),
...border(theme, "secondary"),
width: 1
},
}, },
maximized: { maximized: {
margin: 24, margin: 32,
border: border(theme, "secondary", { "overlay": true }), border: border(elevation.above.top, { "overlay": true }),
shadow: modalShadow(theme), shadow: elevation.above.shadow,
} }
} }
}; };

View file

@ -1,31 +0,0 @@
import fs from "fs";
import path from "path";
import Theme from "./themes/common/theme";
const themes: Theme[] = [];
export default themes;
const internalThemes: Theme[] = [];
export { internalThemes }
const experimentalThemes: Theme[] = [];
export { experimentalThemes }
function fillThemes(themesPath: string, themes: Theme[]) {
for (const fileName of fs.readdirSync(themesPath)) {
if (fileName == "template.ts") continue;
const filePath = path.join(themesPath, fileName);
if (fs.statSync(filePath).isFile()) {
const theme = require(filePath);
if (theme.dark) themes.push(theme.dark);
if (theme.light) themes.push(theme.light);
}
}
}
fillThemes(path.resolve(`${__dirname}/themes`), themes)
fillThemes(path.resolve(`${__dirname}/themes/internal`), internalThemes)
fillThemes(path.resolve(`${__dirname}/themes/experiments`), experimentalThemes)

View file

@ -1,5 +1,5 @@
import chroma from "chroma-js"; import chroma from "chroma-js";
import { colorRamp, createTheme } from "./common/base16"; import { colorRamp, createColorScheme } from "./common/ramps";
const name = "abruzzo"; const name = "abruzzo";
@ -24,5 +24,5 @@ const ramps = {
magenta: colorRamp(chroma("#c1a3ef")), magenta: colorRamp(chroma("#c1a3ef")),
}; };
export const dark = createTheme(`${name}`, false, ramps); export const dark = createColorScheme(`${name}`, false, ramps);
// export const light = createTheme(`${name}-light`, true, ramps); // export const light = createTheme(`${name}-light`, true, ramps);

View file

@ -1,5 +1,5 @@
import chroma from "chroma-js"; import chroma from "chroma-js";
import { colorRamp, createTheme } from "./common/base16"; import { colorRamp, createColorScheme } from "./common/ramps";
const name = "andromeda"; const name = "andromeda";
@ -24,4 +24,4 @@ const ramps = {
magenta: colorRamp(chroma("#C74DED")), magenta: colorRamp(chroma("#C74DED")),
}; };
export const dark = createTheme(`${name}`, false, ramps); export const dark = createColorScheme(`${name}`, false, ramps);

View file

@ -1,5 +1,5 @@
import chroma from "chroma-js"; import chroma from "chroma-js";
import { colorRamp, createTheme } from "./common/base16"; import { colorRamp, createColorScheme } from "./common/ramps";
const name = "brush-tree"; const name = "brush-tree";
@ -24,5 +24,5 @@ const ramps = {
magenta: colorRamp(chroma("#b39f9f")), magenta: colorRamp(chroma("#b39f9f")),
}; };
export const dark = createTheme(`${name}-dark`, false, ramps); export const dark = createColorScheme(`${name}-dark`, false, ramps);
export const light = createTheme(`${name}-light`, true, ramps); export const light = createColorScheme(`${name}-light`, true, ramps);

View file

@ -1,5 +1,5 @@
import chroma from "chroma-js"; import chroma from "chroma-js";
import { colorRamp, createTheme } from "./common/base16"; import { colorRamp, createColorScheme } from "./common/ramps";
const name = "cave"; const name = "cave";
@ -24,5 +24,5 @@ const ramps = {
magenta: colorRamp(chroma("#bf40bf")), magenta: colorRamp(chroma("#bf40bf")),
}; };
export const dark = createTheme(`${name}-dark`, false, ramps); export const dark = createColorScheme(`${name}-dark`, false, ramps);
export const light = createTheme(`${name}-light`, true, ramps); export const light = createColorScheme(`${name}-light`, true, ramps);

View file

@ -1,288 +0,0 @@
import chroma, { Color, Scale } from "chroma-js";
import { fontWeights } from "../../common";
import { withOpacity } from "../../utils/color";
import Theme, { buildPlayer, Syntax } from "./theme";
export function colorRamp(color: Color): Scale {
let hue = color.hsl()[0];
let endColor = chroma.hsl(hue, 0.88, 0.96);
let startColor = chroma.hsl(hue, 0.68, 0.12);
return chroma.scale([startColor, color, endColor]).mode("hsl");
}
export function createTheme(
name: string,
isLight: boolean,
color_ramps: { [rampName: string]: Scale }
): Theme {
let ramps: typeof color_ramps = {};
// Chromajs mutates the underlying ramp when you call domain. This causes problems because
// we now store the ramps object in the theme so that we can pull colors out of them.
// So instead of calling domain and storing the result, we have to construct new ramps for each
// theme so that we don't modify the passed in ramps.
// This combined with an error in the type definitions for chroma js means we have to cast the colors
// function to any in order to get the colors back out from the original ramps.
if (isLight) {
for (var rampName in color_ramps) {
ramps[rampName] = chroma
.scale((color_ramps[rampName].colors as any)())
.domain([1, 0]);
}
ramps.neutral = chroma
.scale((color_ramps.neutral.colors as any)())
.domain([7, 0]);
} else {
for (var rampName in color_ramps) {
ramps[rampName] = chroma
.scale((color_ramps[rampName].colors as any)())
.domain([0, 1]);
}
ramps.neutral = chroma
.scale((color_ramps.neutral.colors as any)())
.domain([0, 7]);
}
let blend = isLight ? 0.12 : 0.24;
function sample(ramp: Scale, index: number): string {
return ramp(index).hex();
}
const darkest = ramps.neutral(isLight ? 7 : 0).hex();
const backgroundColor = {
// Title bar
100: {
base: sample(ramps.neutral, 1.25),
hovered: sample(ramps.neutral, 1.5),
active: sample(ramps.neutral, 1.75),
},
// Midground (panels, etc)
300: {
base: sample(ramps.neutral, 1),
hovered: sample(ramps.neutral, 1.25),
active: sample(ramps.neutral, 1.5),
},
// Editor
500: {
base: sample(ramps.neutral, 0),
hovered: sample(ramps.neutral, 0.25),
active: sample(ramps.neutral, 0.5),
},
on300: {
base: sample(ramps.neutral, 0),
hovered: sample(ramps.neutral, 0.5),
active: sample(ramps.neutral, 1),
},
on500: {
base: sample(ramps.neutral, 1),
hovered: sample(ramps.neutral, 1.5),
active: sample(ramps.neutral, 2),
},
ok: {
base: withOpacity(sample(ramps.green, 0.5), 0.15),
hovered: withOpacity(sample(ramps.green, 0.5), 0.2),
active: withOpacity(sample(ramps.green, 0.5), 0.25),
},
error: {
base: withOpacity(sample(ramps.red, 0.5), 0.15),
hovered: withOpacity(sample(ramps.red, 0.5), 0.2),
active: withOpacity(sample(ramps.red, 0.5), 0.25),
},
on500Error: {
base: sample(ramps.red, 0.05),
hovered: sample(ramps.red, 0.1),
active: sample(ramps.red, 0.15),
},
warning: {
base: withOpacity(sample(ramps.yellow, 0.5), 0.15),
hovered: withOpacity(sample(ramps.yellow, 0.5), 0.2),
active: withOpacity(sample(ramps.yellow, 0.5), 0.25),
},
on500Warning: {
base: sample(ramps.yellow, 0.05),
hovered: sample(ramps.yellow, 0.1),
active: sample(ramps.yellow, 0.15),
},
info: {
base: withOpacity(sample(ramps.blue, 0.5), 0.15),
hovered: withOpacity(sample(ramps.blue, 0.5), 0.2),
active: withOpacity(sample(ramps.blue, 0.5), 0.25),
},
on500Info: {
base: sample(ramps.blue, 0.05),
hovered: sample(ramps.blue, 0.1),
active: sample(ramps.blue, 0.15),
},
};
const borderColor = {
primary: sample(ramps.neutral, isLight ? 1.5 : 0),
secondary: sample(ramps.neutral, isLight ? 1.25 : 1),
muted: sample(ramps.neutral, isLight ? 1 : 3),
active: sample(ramps.neutral, isLight ? 4 : 3),
onMedia: withOpacity(darkest, 0.1),
ok: sample(ramps.green, 0.3),
error: sample(ramps.red, 0.3),
warning: sample(ramps.yellow, 0.3),
info: sample(ramps.blue, 0.3),
};
const textColor = {
primary: sample(ramps.neutral, 6),
secondary: sample(ramps.neutral, 5),
muted: sample(ramps.neutral, 4),
placeholder: sample(ramps.neutral, 3),
active: sample(ramps.neutral, 7),
feature: sample(ramps.blue, 0.5),
ok: sample(ramps.green, 0.5),
error: sample(ramps.red, 0.5),
warning: sample(ramps.yellow, 0.5),
info: sample(ramps.blue, 0.5),
onMedia: darkest,
};
const player = {
1: buildPlayer(sample(ramps.blue, 0.5)),
2: buildPlayer(sample(ramps.green, 0.5)),
3: buildPlayer(sample(ramps.magenta, 0.5)),
4: buildPlayer(sample(ramps.orange, 0.5)),
5: buildPlayer(sample(ramps.violet, 0.5)),
6: buildPlayer(sample(ramps.cyan, 0.5)),
7: buildPlayer(sample(ramps.red, 0.5)),
8: buildPlayer(sample(ramps.yellow, 0.5)),
};
const editor = {
background: backgroundColor[500].base,
indent_guide: borderColor.muted,
indent_guide_active: borderColor.secondary,
line: {
active: sample(ramps.neutral, 1),
highlighted: sample(ramps.neutral, 1.25), // TODO: Where is this used?
},
highlight: {
selection: player[1].selectionColor,
occurrence: withOpacity(sample(ramps.neutral, 3.5), blend),
activeOccurrence: withOpacity(sample(ramps.neutral, 3.5), blend * 2), // TODO: Not hooked up - https://github.com/zed-industries/zed/issues/751
matchingBracket: backgroundColor[500].active, // TODO: Not hooked up
match: sample(ramps.violet, 0.15),
activeMatch: withOpacity(sample(ramps.violet, 0.4), blend * 2), // TODO: Not hooked up - https://github.com/zed-industries/zed/issues/751
related: backgroundColor[500].hovered,
},
gutter: {
primary: textColor.placeholder,
active: textColor.active,
},
};
const syntax: Syntax = {
primary: {
color: sample(ramps.neutral, 7),
weight: fontWeights.normal,
},
comment: {
color: sample(ramps.neutral, 5),
weight: fontWeights.normal,
},
punctuation: {
color: sample(ramps.neutral, 6),
weight: fontWeights.normal,
},
constant: {
color: sample(ramps.neutral, 4),
weight: fontWeights.normal,
},
keyword: {
color: sample(ramps.blue, 0.5),
weight: fontWeights.normal,
},
function: {
color: sample(ramps.yellow, 0.5),
weight: fontWeights.normal,
},
type: {
color: sample(ramps.cyan, 0.5),
weight: fontWeights.normal,
},
constructor: {
color: sample(ramps.blue, 0.5),
weight: fontWeights.normal,
},
variant: {
color: sample(ramps.blue, 0.5),
weight: fontWeights.normal,
},
property: {
color: sample(ramps.blue, 0.5),
weight: fontWeights.normal,
},
enum: {
color: sample(ramps.orange, 0.5),
weight: fontWeights.normal,
},
operator: {
color: sample(ramps.orange, 0.5),
weight: fontWeights.normal,
},
string: {
color: sample(ramps.orange, 0.5),
weight: fontWeights.normal,
},
number: {
color: sample(ramps.green, 0.5),
weight: fontWeights.normal,
},
boolean: {
color: sample(ramps.green, 0.5),
weight: fontWeights.normal,
},
predictive: {
color: textColor.muted,
weight: fontWeights.normal,
},
title: {
color: sample(ramps.yellow, 0.5),
weight: fontWeights.bold,
},
emphasis: {
color: textColor.feature,
weight: fontWeights.normal,
},
"emphasis.strong": {
color: textColor.feature,
weight: fontWeights.bold,
},
linkUri: {
color: sample(ramps.green, 0.5),
weight: fontWeights.normal,
underline: true,
},
linkText: {
color: sample(ramps.orange, 0.5),
weight: fontWeights.normal,
italic: true,
},
};
const shadow = withOpacity(
ramps
.neutral(isLight ? 7 : 0)
.darken()
.hex(),
blend
);
return {
name,
isLight,
backgroundColor,
borderColor,
textColor,
iconColor: textColor,
editor,
syntax,
player,
shadow,
ramps,
};
}

View file

@ -0,0 +1,83 @@
import { Scale } from "chroma-js";
export interface ColorScheme {
name: string,
isLight: boolean,
lowest: Elevation,
middle: Elevation,
highest: Elevation,
players: Players,
}
export interface Player {
cursor: string,
selection: string,
}
export interface Players {
"0": Player,
"1": Player,
"2": Player,
"3": Player,
"4": Player,
"5": Player,
"6": Player,
"7": Player,
}
export interface Elevation {
ramps: RampSet,
bottom: Layer,
middle: Layer,
top: Layer,
above?: Elevation,
shadow?: Shadow
}
export interface Shadow {
blur: number,
color: string,
offset: number[],
}
export type StyleSets = keyof Layer;
export interface Layer {
base: StyleSet,
on: StyleSet,
info: StyleSet,
positive: StyleSet,
warning: StyleSet,
negative: StyleSet,
}
export interface RampSet {
neutral: Scale,
red: Scale,
orange: Scale,
yellow: Scale,
green: Scale,
cyan: Scale,
blue: Scale,
violet: Scale,
magenta: Scale,
}
export type Styles = keyof StyleSet;
export interface StyleSet {
default: Style,
variant: Style,
active: Style,
disabled: Style,
hovered: Style,
pressed: Style,
}
export interface Style {
background: string,
border: string,
foreground: string,
}

View file

@ -0,0 +1,176 @@
import chroma, { Color, Scale } from "chroma-js";
import { ColorScheme, Elevation, Layer, Player, RampSet, Shadow, Style, StyleSet } from "./colorScheme";
export function colorRamp(color: Color): Scale {
let hue = color.hsl()[0];
let endColor = chroma.hsl(hue, 0.88, 0.96);
let startColor = chroma.hsl(hue, 0.68, 0.12);
return chroma.scale([startColor, color, endColor]).mode("hsl");
}
export function createColorScheme(name: string, isLight: boolean, colorRamps: { [rampName: string]: Scale }): ColorScheme {
// Chromajs scales from 0 to 1 flipped if isLight is true
let baseRamps: typeof colorRamps = {};
// Chromajs mutates the underlying ramp when you call domain. This causes problems because
// we now store the ramps object in the theme so that we can pull colors out of them.
// So instead of calling domain and storing the result, we have to construct new ramps for each
// theme so that we don't modify the passed in ramps.
// This combined with an error in the type definitions for chroma js means we have to cast the colors
// function to any in order to get the colors back out from the original ramps.
if (isLight) {
for (var rampName in colorRamps) {
baseRamps[rampName] = chroma
.scale((colorRamps[rampName].colors as any)())
.domain([1, 0]);
}
baseRamps.neutral = chroma
.scale((colorRamps.neutral.colors as any)())
.domain([1, 0]);
} else {
for (var rampName in colorRamps) {
baseRamps[rampName] = chroma
.scale((colorRamps[rampName].colors as any)())
.domain([0, 1]);
}
baseRamps.neutral = chroma
.scale((colorRamps.neutral.colors as any)())
.domain([0, 1]);
}
let baseSet = {
neutral: baseRamps.neutral,
red: baseRamps.red,
orange: baseRamps.orange,
yellow: baseRamps.yellow,
green: baseRamps.green,
cyan: baseRamps.cyan,
blue: baseRamps.blue,
violet: baseRamps.violet,
magenta: baseRamps.magenta,
};
let lowest = elevation(
resampleSet(
baseSet,
evenSamples(0, 1)
),
isLight,
);
let middle = elevation(
resampleSet(
baseSet,
evenSamples(0.125, 1)
),
isLight,
{
blur: 4,
color: baseSet.neutral(isLight ? 7 : 0).darken().alpha(0.2).hex(), // TODO used blend previously. Replace with something else
offset: [1, 2],
}
);
lowest.above = middle;
let highest = elevation(
resampleSet(
baseSet,
evenSamples(0.25, 1)
),
isLight,
{
blur: 16,
color: baseSet.neutral(isLight ? 7 : 0).darken().alpha(0.2).hex(), // TODO used blend previously. Replace with something else
offset: [0, 2],
}
);
middle.above = highest;
let players = {
"0": player(baseSet.blue),
"1": player(baseSet.green),
"2": player(baseSet.magenta),
"3": player(baseSet.orange),
"4": player(baseSet.violet),
"5": player(baseSet.cyan),
"6": player(baseSet.red),
"7": player(baseSet.yellow),
}
return {
name,
isLight,
lowest,
middle,
highest,
players,
};
}
function player(ramp: Scale): Player {
return {
selection: ramp(0.5).alpha(0.24).hex(),
cursor: ramp(0.5).hex(),
}
}
function evenSamples(min: number, max: number): number[] {
return Array.from(Array(101).keys()).map((i) => (i / 100) * (max - min) + min);
}
function resampleSet(ramps: RampSet, samples: number[]): RampSet {
return {
neutral: resample(ramps.neutral, samples),
red: resample(ramps.neutral, samples),
orange: resample(ramps.neutral, samples),
yellow: resample(ramps.neutral, samples),
green: resample(ramps.neutral, samples),
cyan: resample(ramps.neutral, samples),
blue: resample(ramps.neutral, samples),
violet: resample(ramps.neutral, samples),
magenta: resample(ramps.neutral, samples),
}
}
function resample(scale: Scale, samples: number[]): Scale {
let newColors = samples.map((sample) => scale(sample));
return chroma.scale(newColors);
}
function elevation(ramps: RampSet, isLight: boolean, shadow?: Shadow): Elevation {
let style: Style = {
background: ramps.neutral(0.25).hex(),
border: ramps.neutral(0.9).hex(),
foreground: ramps.neutral(1).hex(),
};
let styleSet: StyleSet = {
default: style,
variant: style,
active: style,
disabled: style,
hovered: style,
pressed: style,
};
let layer: Layer = {
base: styleSet,
on: styleSet,
info: styleSet,
positive: styleSet,
warning: styleSet,
negative: styleSet
};
return {
ramps,
bottom: layer,
middle: layer,
top: layer,
shadow,
};
}

View file

@ -1,164 +0,0 @@
import { Scale } from "chroma-js";
import { FontWeight } from "../../common";
import { withOpacity } from "../../utils/color";
export interface SyntaxHighlightStyle {
color: string;
weight?: FontWeight;
underline?: boolean;
italic?: boolean;
}
export interface Player {
baseColor: string;
cursorColor: string;
selectionColor: string;
borderColor: string;
}
export function buildPlayer(
color: string,
cursorOpacity?: number,
selectionOpacity?: number,
borderOpacity?: number
) {
return {
baseColor: color,
cursorColor: withOpacity(color, cursorOpacity || 1.0),
selectionColor: withOpacity(color, selectionOpacity || 0.24),
borderColor: withOpacity(color, borderOpacity || 0.8),
};
}
export interface BackgroundColorSet {
base: string;
hovered: string;
active: string;
}
export interface Syntax {
primary: SyntaxHighlightStyle;
comment: SyntaxHighlightStyle;
punctuation: SyntaxHighlightStyle;
constant: SyntaxHighlightStyle;
keyword: SyntaxHighlightStyle;
function: SyntaxHighlightStyle;
type: SyntaxHighlightStyle;
variant: SyntaxHighlightStyle;
property: SyntaxHighlightStyle;
enum: SyntaxHighlightStyle;
operator: SyntaxHighlightStyle;
string: SyntaxHighlightStyle;
number: SyntaxHighlightStyle;
boolean: SyntaxHighlightStyle;
predictive: SyntaxHighlightStyle;
title: SyntaxHighlightStyle;
emphasis: SyntaxHighlightStyle;
linkUri: SyntaxHighlightStyle;
linkText: SyntaxHighlightStyle;
[key: string]: SyntaxHighlightStyle;
}
export default interface Theme {
name: string;
isLight: boolean;
backgroundColor: {
// Basically just Title Bar
// Lowest background level
100: BackgroundColorSet;
// Tab bars, panels, popovers
// Mid-ground
300: BackgroundColorSet;
// The editor
// Foreground
500: BackgroundColorSet;
// Hacks for elements on top of the midground
// Buttons in a panel, tab bar, or panel
on300: BackgroundColorSet;
// Hacks for elements on top of the editor
on500: BackgroundColorSet;
ok: BackgroundColorSet;
error: BackgroundColorSet;
on500Error: BackgroundColorSet;
warning: BackgroundColorSet;
on500Warning: BackgroundColorSet;
info: BackgroundColorSet;
on500Info: BackgroundColorSet;
};
borderColor: {
primary: string;
secondary: string;
muted: string;
active: string;
/**
* Used for rendering borders on top of media like avatars, images, video, etc.
*/
onMedia: string;
ok: string;
error: string;
warning: string;
info: string;
};
textColor: {
primary: string;
secondary: string;
muted: string;
placeholder: string;
active: string;
feature: string;
ok: string;
error: string;
warning: string;
info: string;
onMedia: string;
};
iconColor: {
primary: string;
secondary: string;
muted: string;
placeholder: string;
active: string;
feature: string;
ok: string;
error: string;
warning: string;
info: string;
};
editor: {
background: string;
indent_guide: string;
indent_guide_active: string;
line: {
active: string;
highlighted: string;
};
highlight: {
selection: string;
occurrence: string;
activeOccurrence: string;
matchingBracket: string;
match: string;
activeMatch: string;
related: string;
};
gutter: {
primary: string;
active: string;
};
};
syntax: Syntax;
player: {
1: Player;
2: Player;
3: Player;
4: Player;
5: Player;
6: Player;
7: Player;
8: Player;
};
shadow: string;
ramps: { [rampName: string]: Scale };
}

View file

@ -1,5 +1,5 @@
import chroma from "chroma-js"; import chroma from "chroma-js";
import { colorRamp, createTheme } from "./common/base16"; import { colorRamp, createColorScheme } from "./common/ramps";
const name = "one"; const name = "one";
const author = "Chris Kempson (http://chriskempson.com)"; const author = "Chris Kempson (http://chriskempson.com)";
@ -44,4 +44,4 @@ const ramps = {
magenta: colorRamp(chroma(base0F)), magenta: colorRamp(chroma(base0F)),
}; };
export const dark = createTheme(`${name}-dark`, false, ramps); export const dark = createColorScheme(`${name}-dark`, false, ramps);

View file

@ -1,5 +1,5 @@
import chroma from "chroma-js"; import chroma from "chroma-js";
import { colorRamp, createTheme } from "./common/base16"; import { colorRamp, createColorScheme } from "./common/ramps";
const name = "one"; const name = "one";
const author = "Daniel Pfeifer (http://github.com/purpleKarrot)"; const author = "Daniel Pfeifer (http://github.com/purpleKarrot)";
@ -44,4 +44,4 @@ const ramps = {
magenta: colorRamp(chroma(base0F)), magenta: colorRamp(chroma(base0F)),
}; };
export const light = createTheme(`${name}-light`, true, ramps); export const light = createColorScheme(`${name}-light`, true, ramps);

View file

@ -1,5 +1,5 @@
import chroma from "chroma-js"; import chroma from "chroma-js";
import { colorRamp, createTheme } from "./common/base16"; import { colorRamp, createColorScheme } from "./common/ramps";
const name = "rosé-pine-dawn"; const name = "rosé-pine-dawn";
@ -24,4 +24,4 @@ const ramps = {
magenta: colorRamp(chroma("#79549F")), magenta: colorRamp(chroma("#79549F")),
}; };
export const light = createTheme(`${name}`, true, ramps); export const light = createColorScheme(`${name}`, true, ramps);

View file

@ -1,5 +1,5 @@
import chroma from "chroma-js"; import chroma from "chroma-js";
import { colorRamp, createTheme } from "./common/base16"; import { colorRamp, createColorScheme } from "./common/ramps";
const name = "rosé-pine-moon"; const name = "rosé-pine-moon";
@ -24,4 +24,4 @@ const ramps = {
magenta: colorRamp(chroma("#AB6FE9")), magenta: colorRamp(chroma("#AB6FE9")),
}; };
export const dark = createTheme(`${name}`, false, ramps); export const dark = createColorScheme(`${name}`, false, ramps);

View file

@ -1,5 +1,5 @@
import chroma from "chroma-js"; import chroma from "chroma-js";
import { colorRamp, createTheme } from "./common/base16"; import { colorRamp, createColorScheme } from "./common/ramps";
const name = "rosé-pine"; const name = "rosé-pine";
@ -24,4 +24,4 @@ const ramps = {
magenta: colorRamp(chroma("#AB6FE9")), magenta: colorRamp(chroma("#AB6FE9")),
}; };
export const dark = createTheme(`${name}`, false, ramps); export const dark = createColorScheme(`${name}`, false, ramps);

View file

@ -1,5 +1,5 @@
import chroma from "chroma-js"; import chroma from "chroma-js";
import { colorRamp, createTheme } from "./common/base16"; import { colorRamp, createColorScheme } from "./common/ramps";
const name = "sandcastle"; const name = "sandcastle";
@ -24,4 +24,4 @@ const ramps = {
magenta: colorRamp(chroma("#a87322")), magenta: colorRamp(chroma("#a87322")),
}; };
export const dark = createTheme(`${name}`, false, ramps); export const dark = createColorScheme(`${name}`, false, ramps);

View file

@ -1,5 +1,5 @@
import chroma from "chroma-js"; import chroma from "chroma-js";
import { colorRamp, createTheme } from "./common/base16"; import { colorRamp, createColorScheme } from "./common/ramps";
const name = "solarized"; const name = "solarized";
@ -24,5 +24,5 @@ const ramps = {
magenta: colorRamp(chroma("#d33682")), magenta: colorRamp(chroma("#d33682")),
}; };
export const dark = createTheme(`${name}-dark`, false, ramps); export const dark = createColorScheme(`${name}-dark`, false, ramps);
export const light = createTheme(`${name}-light`, true, ramps); export const light = createColorScheme(`${name}-light`, true, ramps);

View file

@ -1,5 +1,5 @@
import chroma from "chroma-js"; import chroma from "chroma-js";
import { colorRamp, createTheme } from "./common/base16"; import { colorRamp, createColorScheme } from "./common/ramps";
const name = "sulphurpool"; const name = "sulphurpool";
@ -24,5 +24,5 @@ const ramps = {
magenta: colorRamp(chroma("#9c637a")), magenta: colorRamp(chroma("#9c637a")),
}; };
export const dark = createTheme(`${name}-dark`, false, ramps); export const dark = createColorScheme(`${name}-dark`, false, ramps);
export const light = createTheme(`${name}-light`, true, ramps); export const light = createColorScheme(`${name}-light`, true, ramps);

View file

@ -1,5 +1,5 @@
import chroma from "chroma-js"; import chroma from "chroma-js";
import { colorRamp, createTheme } from "./common/base16"; import { colorRamp, createColorScheme } from "./common/ramps";
const name = "summercamp"; const name = "summercamp";
@ -24,4 +24,4 @@ const ramps = {
magenta: colorRamp(chroma("#F69BE7")), magenta: colorRamp(chroma("#F69BE7")),
}; };
export const dark = createTheme(`${name}`, false, ramps); export const dark = createColorScheme(`${name}`, false, ramps);

View file

@ -1,5 +1,5 @@
import chroma from "chroma-js"; import chroma from "chroma-js";
import { colorRamp, createTheme } from "./common/base16"; import { colorRamp, createColorScheme } from "./common/ramps";
const name = "summerfruit"; const name = "summerfruit";
@ -24,5 +24,5 @@ const ramps = {
magenta: colorRamp(chroma("#CC6633")), magenta: colorRamp(chroma("#CC6633")),
}; };
export const dark = createTheme(`${name}-dark`, false, ramps); export const dark = createColorScheme(`${name}-dark`, false, ramps);
export const light = createTheme(`${name}-light`, true, ramps); export const light = createColorScheme(`${name}-light`, true, ramps);

View file

@ -3,7 +3,7 @@
**/ **/
import chroma from "chroma-js"; import chroma from "chroma-js";
import { colorRamp, createTheme } from "./common/base16"; import { colorRamp, createColorScheme } from "./common/ramps";
/** /**
* Theme Name * Theme Name
@ -56,14 +56,14 @@ const ramps = {
}; };
/** /**
* Theme Variants * Color Scheme Variants
* *
* Currently we only support (and require) dark and light themes * Currently we only support (and require) dark and light themes
* Eventually you will be able to have only a light or dark theme, * Eventually you will be able to have only a light or dark theme,
* and define other variants here. * and define other variants here.
* *
* createTheme([name], [isLight], [arrayOfRamps]) * createColorScheme([name], [isLight], [arrayOfRamps])
**/ **/
export const dark = createTheme(`${name}-dark`, false, ramps); export const dark = createColorScheme(`${name}-dark`, false, ramps);
export const light = createTheme(`${name}-light`, true, ramps); export const light = createColorScheme(`${name}-light`, true, ramps);