1import { icon_button, toggleable_icon_button } from "../component/icon_button"
2import { toggleable_text_button } from "../component/text_button"
3import { interactive, toggleable } from "../element"
4import { useTheme } from "../theme"
5import { with_opacity } from "../theme/color"
6import { background, border, foreground, text } from "./components"
7
8const ITEM_SPACING = 8
9const TITLEBAR_HEIGHT = 32
10
11function build_spacing(
12 container_height: number,
13 element_height: number,
14 spacing: number
15) {
16 return {
17 group: spacing,
18 item: spacing / 2,
19 half_item: spacing / 4,
20 margin_y: (container_height - element_height) / 2,
21 margin_x: (container_height - element_height) / 2,
22 }
23}
24
25function call_controls() {
26 const theme = useTheme()
27
28 const button_height = 18
29
30 const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING)
31 const margin_y = {
32 top: space.margin_y,
33 bottom: space.margin_y,
34 }
35
36 return {
37 toggle_microphone_button: toggleable_icon_button(theme, {
38 margin: {
39 ...margin_y,
40 left: space.group,
41 right: space.half_item,
42 },
43 active_color: "negative",
44 }),
45
46 toggle_speakers_button: toggleable_icon_button(theme, {
47 margin: {
48 ...margin_y,
49 left: space.half_item,
50 right: space.half_item,
51 },
52 }),
53
54 screen_share_button: toggleable_icon_button(theme, {
55 margin: {
56 ...margin_y,
57 left: space.half_item,
58 right: space.group,
59 },
60 active_color: "accent",
61 }),
62
63 muted: foreground(theme.lowest, "negative"),
64 speaking: foreground(theme.lowest, "accent"),
65 }
66}
67
68/**
69 * Opens the User Menu when toggled
70 *
71 * When logged in shows the user's avatar and a chevron,
72 * When logged out only shows a chevron.
73 */
74function user_menu() {
75 const theme = useTheme()
76
77 const button_height = 18
78
79 const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING)
80
81 const build_button = ({ online }: { online: boolean }) => {
82 const button = toggleable({
83 base: interactive({
84 base: {
85 corner_radius: 6,
86 height: button_height,
87 width: online ? 37 : 24,
88 padding: {
89 top: 2,
90 bottom: 2,
91 left: 6,
92 right: 6,
93 },
94 margin: {
95 left: space.item,
96 right: space.item,
97 },
98 ...text(theme.lowest, "sans", { size: "xs" }),
99 background: background(theme.lowest),
100 },
101 state: {
102 hovered: {
103 ...text(theme.lowest, "sans", "hovered", {
104 size: "xs",
105 }),
106 background: background(theme.lowest, "hovered"),
107 },
108 clicked: {
109 ...text(theme.lowest, "sans", "pressed", {
110 size: "xs",
111 }),
112 background: background(theme.lowest, "pressed"),
113 },
114 },
115 }),
116 state: {
117 active: {
118 default: {
119 ...text(theme.lowest, "sans", "active", { size: "xs" }),
120 background: background(theme.middle),
121 },
122 hovered: {
123 ...text(theme.lowest, "sans", "active", { size: "xs" }),
124 background: background(theme.middle, "hovered"),
125 },
126 clicked: {
127 ...text(theme.lowest, "sans", "active", { size: "xs" }),
128 background: background(theme.middle, "pressed"),
129 },
130 },
131 },
132 })
133
134 return {
135 user_menu: button,
136 avatar: {
137 icon_width: 16,
138 icon_height: 16,
139 corner_radius: 4,
140 outer_width: 16,
141 outer_corner_radius: 16,
142 },
143 icon: {
144 margin: {
145 top: 2,
146 left: online ? space.item : 0,
147 right: space.group,
148 bottom: 2,
149 },
150 width: 11,
151 height: 11,
152 color: foreground(theme.lowest),
153 },
154 }
155 }
156 return {
157 user_menu_button_online: build_button({ online: true }),
158 user_menu_button_offline: build_button({ online: false }),
159 }
160}
161
162export function titlebar(): any {
163 const theme = useTheme()
164
165 const avatar_width = 15
166 const avatar_outer_width = avatar_width + 4
167 const follower_avatar_width = 14
168 const follower_avatar_outer_width = follower_avatar_width + 4
169
170 return {
171 item_spacing: ITEM_SPACING,
172 face_pile_spacing: 2,
173 height: TITLEBAR_HEIGHT,
174 background: background(theme.lowest),
175 border: border(theme.lowest, { bottom: true }),
176 padding: {
177 left: 80,
178 right: 0,
179 },
180
181 // Project
182 project_name_divider: text(theme.lowest, "sans", "variant"),
183
184 project_menu_button: toggleable_text_button(theme, {
185 color: 'base',
186 }),
187 git_menu_button: toggleable_text_button(theme, {
188 color: 'variant',
189 }),
190
191 // Collaborators
192 leader_avatar: {
193 width: avatar_width,
194 outer_width: avatar_outer_width,
195 corner_radius: avatar_width / 2,
196 outer_corner_radius: avatar_outer_width / 2,
197 },
198 follower_avatar: {
199 width: follower_avatar_width,
200 outer_width: follower_avatar_outer_width,
201 corner_radius: follower_avatar_width / 2,
202 outer_corner_radius: follower_avatar_outer_width / 2,
203 },
204 inactive_avatar_grayscale: true,
205 follower_avatar_overlap: 8,
206 leader_selection: {
207 margin: {
208 top: 4,
209 bottom: 4,
210 },
211 padding: {
212 left: 2,
213 right: 2,
214 top: 2,
215 bottom: 2,
216 },
217 corner_radius: 6,
218 },
219 avatar_ribbon: {
220 height: 3,
221 width: 14,
222 // TODO: Chore: Make avatarRibbon colors driven by the theme rather than being hard coded.
223 },
224
225 sign_in_button: toggleable_text_button(theme, {}),
226 offline_icon: {
227 color: foreground(theme.lowest, "variant"),
228 width: 16,
229 margin: {
230 left: ITEM_SPACING,
231 },
232 padding: {
233 right: 4,
234 },
235 },
236
237 // When the collaboration server is out of date, show a warning
238 outdated_warning: {
239 ...text(theme.lowest, "sans", "warning", { size: "xs" }),
240 background: with_opacity(background(theme.lowest, "warning"), 0.3),
241 border: border(theme.lowest, "warning"),
242 margin: {
243 left: ITEM_SPACING,
244 },
245 padding: {
246 left: 8,
247 right: 8,
248 },
249 corner_radius: 6,
250 },
251
252 leave_call_button: icon_button({
253 margin: {
254 left: ITEM_SPACING / 2,
255 right: ITEM_SPACING,
256 },
257 }),
258
259 ...call_controls(),
260
261 toggle_contacts_button: toggleable_icon_button(theme, {
262 margin: {
263 left: ITEM_SPACING,
264 },
265 }),
266
267 // Jewel that notifies you that there are new contact requests
268 toggle_contacts_badge: {
269 corner_radius: 3,
270 padding: 2,
271 margin: { top: 3, left: 3 },
272 border: border(theme.lowest),
273 background: foreground(theme.lowest, "accent"),
274 },
275 share_button: toggleable_text_button(theme, {}),
276 user_menu: user_menu(),
277 }
278}