279 lines
8.2 KiB
TypeScript
279 lines
8.2 KiB
TypeScript
import { icon_button, toggleable_icon_button } from "../component/icon_button"
|
|
import { toggleable_text_button } from "../component/text_button"
|
|
import { interactive, toggleable } from "../element"
|
|
import { useTheme } from "../theme"
|
|
import { with_opacity } from "../theme/color"
|
|
import { background, border, foreground, text } from "./components"
|
|
|
|
const ITEM_SPACING = 8
|
|
const TITLEBAR_HEIGHT = 32
|
|
|
|
function build_spacing(
|
|
container_height: number,
|
|
element_height: number,
|
|
spacing: number
|
|
) {
|
|
return {
|
|
group: spacing,
|
|
item: spacing / 2,
|
|
half_item: spacing / 4,
|
|
margin_y: (container_height - element_height) / 2,
|
|
margin_x: (container_height - element_height) / 2,
|
|
}
|
|
}
|
|
|
|
function call_controls() {
|
|
const theme = useTheme()
|
|
|
|
const button_height = 18
|
|
|
|
const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING)
|
|
const margin_y = {
|
|
top: space.margin_y,
|
|
bottom: space.margin_y,
|
|
}
|
|
|
|
return {
|
|
toggle_microphone_button: toggleable_icon_button(theme, {
|
|
margin: {
|
|
...margin_y,
|
|
left: space.group,
|
|
right: space.half_item,
|
|
},
|
|
active_color: "negative",
|
|
}),
|
|
|
|
toggle_speakers_button: toggleable_icon_button(theme, {
|
|
margin: {
|
|
...margin_y,
|
|
left: space.half_item,
|
|
right: space.half_item,
|
|
},
|
|
}),
|
|
|
|
screen_share_button: toggleable_icon_button(theme, {
|
|
margin: {
|
|
...margin_y,
|
|
left: space.half_item,
|
|
right: space.group,
|
|
},
|
|
active_color: "accent",
|
|
}),
|
|
|
|
muted: foreground(theme.lowest, "negative"),
|
|
speaking: foreground(theme.lowest, "accent"),
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Opens the User Menu when toggled
|
|
*
|
|
* When logged in shows the user's avatar and a chevron,
|
|
* When logged out only shows a chevron.
|
|
*/
|
|
function user_menu() {
|
|
const theme = useTheme()
|
|
|
|
const button_height = 18
|
|
|
|
const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING)
|
|
|
|
const build_button = ({ online }: { online: boolean }) => {
|
|
const button = toggleable({
|
|
base: interactive({
|
|
base: {
|
|
corner_radius: 6,
|
|
height: button_height,
|
|
width: 20,
|
|
padding: {
|
|
top: 2,
|
|
bottom: 2,
|
|
left: 6,
|
|
right: 6,
|
|
},
|
|
margin: {
|
|
left: space.item,
|
|
right: space.item,
|
|
},
|
|
...text(theme.lowest, "sans", { size: "xs" }),
|
|
background: background(theme.lowest),
|
|
},
|
|
state: {
|
|
hovered: {
|
|
...text(theme.lowest, "sans", "hovered", {
|
|
size: "xs",
|
|
}),
|
|
background: background(theme.lowest, "hovered"),
|
|
},
|
|
clicked: {
|
|
...text(theme.lowest, "sans", "pressed", {
|
|
size: "xs",
|
|
}),
|
|
background: background(theme.lowest, "pressed"),
|
|
},
|
|
},
|
|
}),
|
|
state: {
|
|
active: {
|
|
default: {
|
|
...text(theme.lowest, "sans", "active", { size: "xs" }),
|
|
background: background(theme.middle),
|
|
},
|
|
hovered: {
|
|
...text(theme.lowest, "sans", "active", { size: "xs" }),
|
|
background: background(theme.middle, "hovered"),
|
|
},
|
|
clicked: {
|
|
...text(theme.lowest, "sans", "active", { size: "xs" }),
|
|
background: background(theme.middle, "pressed"),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
return {
|
|
user_menu: button,
|
|
avatar: {
|
|
icon_width: 16,
|
|
icon_height: 16,
|
|
corner_radius: 4,
|
|
outer_width: 16,
|
|
outer_corner_radius: 16,
|
|
},
|
|
icon: {
|
|
margin: {
|
|
top: 2,
|
|
left: online ? space.item : 0,
|
|
right: space.group,
|
|
bottom: 2,
|
|
},
|
|
width: 11,
|
|
height: 11,
|
|
color: foreground(theme.lowest),
|
|
},
|
|
}
|
|
}
|
|
|
|
return {
|
|
user_menu_button_online: build_button({ online: true }),
|
|
user_menu_button_offline: build_button({ online: false }),
|
|
}
|
|
}
|
|
|
|
export function titlebar(): any {
|
|
const theme = useTheme()
|
|
|
|
const avatar_width = 15
|
|
const avatar_outer_width = avatar_width + 4
|
|
const follower_avatar_width = 14
|
|
const follower_avatar_outer_width = follower_avatar_width + 4
|
|
|
|
return {
|
|
item_spacing: ITEM_SPACING,
|
|
face_pile_spacing: 2,
|
|
height: TITLEBAR_HEIGHT,
|
|
background: background(theme.lowest),
|
|
border: border(theme.lowest, { bottom: true }),
|
|
padding: {
|
|
left: 80,
|
|
right: 0,
|
|
},
|
|
|
|
// Project
|
|
project_name_divider: text(theme.lowest, "sans", "variant"),
|
|
|
|
project_menu_button: toggleable_text_button(theme, {
|
|
color: 'base',
|
|
}),
|
|
git_menu_button: toggleable_text_button(theme, {
|
|
color: 'variant',
|
|
}),
|
|
|
|
// Collaborators
|
|
leader_avatar: {
|
|
width: avatar_width,
|
|
outer_width: avatar_outer_width,
|
|
corner_radius: avatar_width / 2,
|
|
outer_corner_radius: avatar_outer_width / 2,
|
|
},
|
|
follower_avatar: {
|
|
width: follower_avatar_width,
|
|
outer_width: follower_avatar_outer_width,
|
|
corner_radius: follower_avatar_width / 2,
|
|
outer_corner_radius: follower_avatar_outer_width / 2,
|
|
},
|
|
inactive_avatar_grayscale: true,
|
|
follower_avatar_overlap: 8,
|
|
leader_selection: {
|
|
margin: {
|
|
top: 4,
|
|
bottom: 4,
|
|
},
|
|
padding: {
|
|
left: 2,
|
|
right: 2,
|
|
top: 2,
|
|
bottom: 2,
|
|
},
|
|
corner_radius: 6,
|
|
},
|
|
avatar_ribbon: {
|
|
height: 3,
|
|
width: 14,
|
|
// TODO: Chore: Make avatarRibbon colors driven by the theme rather than being hard coded.
|
|
},
|
|
|
|
sign_in_button: toggleable_text_button(theme, {}),
|
|
offline_icon: {
|
|
color: foreground(theme.lowest, "variant"),
|
|
width: 16,
|
|
margin: {
|
|
left: ITEM_SPACING,
|
|
},
|
|
padding: {
|
|
right: 4,
|
|
},
|
|
},
|
|
|
|
// When the collaboration server is out of date, show a warning
|
|
outdated_warning: {
|
|
...text(theme.lowest, "sans", "warning", { size: "xs" }),
|
|
background: with_opacity(background(theme.lowest, "warning"), 0.3),
|
|
border: border(theme.lowest, "warning"),
|
|
margin: {
|
|
left: ITEM_SPACING,
|
|
},
|
|
padding: {
|
|
left: 8,
|
|
right: 8,
|
|
},
|
|
corner_radius: 6,
|
|
},
|
|
|
|
leave_call_button: icon_button({
|
|
margin: {
|
|
left: ITEM_SPACING / 2,
|
|
right: ITEM_SPACING,
|
|
},
|
|
}),
|
|
|
|
...call_controls(),
|
|
|
|
toggle_contacts_button: toggleable_icon_button(theme, {
|
|
margin: {
|
|
left: ITEM_SPACING,
|
|
},
|
|
}),
|
|
|
|
// Jewel that notifies you that there are new contact requests
|
|
toggle_contacts_badge: {
|
|
corner_radius: 3,
|
|
padding: 2,
|
|
margin: { top: 3, left: 3 },
|
|
border: border(theme.lowest),
|
|
background: foreground(theme.lowest, "accent"),
|
|
},
|
|
share_button: toggleable_text_button(theme, {}),
|
|
user_menu: user_menu(),
|
|
}
|
|
}
|