this repo has no description
13
fork

Configure Feed

Select the types of activity you want to include in your feed.

at f8b45b39501a9edfa4ebeb302d4213934e70ccb1 354 lines 17 kB view raw
1const std = @import("std"); 2const fmt = std.fmt; 3const heap = std.heap; 4const mem = std.mem; 5const meta = std.meta; 6 7const vaxis = @import("vaxis"); 8 9const log = std.log.scoped(.main); 10 11const ActiveSection = enum { 12 top, 13 mid, 14 btm, 15}; 16 17pub fn main() !void { 18 var gpa = heap.GeneralPurposeAllocator(.{}){}; 19 defer if (gpa.detectLeaks()) log.err("Memory leak detected!", .{}); 20 const alloc = gpa.allocator(); 21 22 // Users set up below the main function 23 const users_buf = try alloc.dupe(User, users[0..]); 24 var user_list = std.ArrayList(User).fromOwnedSlice(users_buf); 25 defer user_list.deinit(alloc); 26 var user_mal = std.MultiArrayList(User){}; 27 for (users_buf[0..]) |user| try user_mal.append(alloc, user); 28 defer user_mal.deinit(alloc); 29 30 var buffer: [1024]u8 = undefined; 31 var tty = try vaxis.Tty.init(&buffer); 32 defer tty.deinit(); 33 const tty_writer = tty.writer(); 34 var vx = try vaxis.init(alloc, .{ 35 .kitty_keyboard_flags = .{ .report_events = true }, 36 }); 37 defer vx.deinit(alloc, tty.writer()); 38 39 var loop: vaxis.Loop(union(enum) { 40 key_press: vaxis.Key, 41 winsize: vaxis.Winsize, 42 table_upd, 43 }) = .{ .tty = &tty, .vaxis = &vx }; 44 try loop.init(); 45 try loop.start(); 46 defer loop.stop(); 47 try vx.enterAltScreen(tty.writer()); 48 try vx.queryTerminal(tty.writer(), 250 * std.time.ns_per_ms); 49 50 const logo = 51 \\░█░█░█▀█░█░█░▀█▀░█▀▀░░░▀█▀░█▀█░█▀▄░█░░░█▀▀░ 52 \\░▀▄▀░█▀█░▄▀▄░░█░░▀▀█░░░░█░░█▀█░█▀▄░█░░░█▀▀░ 53 \\░░▀░░▀░▀░▀░▀░▀▀▀░▀▀▀░░░░▀░░▀░▀░▀▀░░▀▀▀░▀▀▀░ 54 ; 55 const title_logo = vaxis.Cell.Segment{ 56 .text = logo, 57 .style = .{}, 58 }; 59 const title_info = vaxis.Cell.Segment{ 60 .text = "===A Demo of the the Vaxis Table Widget!===", 61 .style = .{}, 62 }; 63 const title_disclaimer = vaxis.Cell.Segment{ 64 .text = "(All data is non-sensical & LLM generated.)", 65 .style = .{}, 66 }; 67 var title_segs = [_]vaxis.Cell.Segment{ title_logo, title_info, title_disclaimer }; 68 69 var cmd_input = vaxis.widgets.TextInput.init(alloc, &vx.unicode); 70 defer cmd_input.deinit(); 71 72 // Colors 73 const active_bg: vaxis.Cell.Color = .{ .rgb = .{ 64, 128, 255 } }; 74 const selected_bg: vaxis.Cell.Color = .{ .rgb = .{ 32, 64, 255 } }; 75 const other_bg: vaxis.Cell.Color = .{ .rgb = .{ 32, 32, 48 } }; 76 77 // Table Context 78 var demo_tbl: vaxis.widgets.Table.TableContext = .{ 79 .active_bg = active_bg, 80 .active_fg = .{ .rgb = .{ 0, 0, 0 } }, 81 .row_bg_1 = .{ .rgb = .{ 8, 8, 8 } }, 82 .selected_bg = selected_bg, 83 .header_names = .{ .custom = &.{ "First", "Last", "Username", "Phone#", "Email" } }, 84 //.header_align = .left, 85 .col_indexes = .{ .by_idx = &.{ 0, 1, 2, 4, 3 } }, 86 //.col_align = .{ .by_idx = &.{ .left, .left, .center, .center, .left } }, 87 //.col_align = .{ .all = .center }, 88 //.header_borders = true, 89 //.col_borders = true, 90 //.col_width = .{ .static_all = 15 }, 91 //.col_width = .{ .dynamic_header_len = 3 }, 92 //.col_width = .{ .static_individual = &.{ 10, 20, 15, 25, 15 } }, 93 //.col_width = .dynamic_fill, 94 //.y_off = 10, 95 }; 96 defer if (demo_tbl.sel_rows) |rows| alloc.free(rows); 97 98 // TUI State 99 var active: ActiveSection = .mid; 100 var moving = false; 101 var see_content = false; 102 103 // Create an Arena Allocator for easy allocations on each Event. 104 var event_arena = heap.ArenaAllocator.init(alloc); 105 defer event_arena.deinit(); 106 while (true) { 107 defer _ = event_arena.reset(.retain_capacity); 108 defer tty_writer.flush() catch {}; 109 const event_alloc = event_arena.allocator(); 110 const event = loop.nextEvent(); 111 112 switch (event) { 113 .key_press => |key| keyEvt: { 114 // Close the Program 115 if (key.matches('c', .{ .ctrl = true })) { 116 break; 117 } 118 // Refresh the Screen 119 if (key.matches('l', .{ .ctrl = true })) { 120 vx.queueRefresh(); 121 break :keyEvt; 122 } 123 // Enter Moving State 124 if (key.matches('w', .{ .ctrl = true })) { 125 moving = !moving; 126 break :keyEvt; 127 } 128 // Command State 129 if (active != .btm and 130 key.matchesAny(&.{ ':', '/', 'g', 'G' }, .{})) 131 { 132 active = .btm; 133 cmd_input.clearAndFree(); 134 try cmd_input.update(.{ .key_press = key }); 135 break :keyEvt; 136 } 137 138 switch (active) { 139 .top => { 140 if (key.matchesAny(&.{ vaxis.Key.down, 'j' }, .{}) and moving) active = .mid; 141 }, 142 .mid => midEvt: { 143 if (moving) { 144 if (key.matchesAny(&.{ vaxis.Key.up, 'k' }, .{})) active = .top; 145 if (key.matchesAny(&.{ vaxis.Key.down, 'j' }, .{})) active = .btm; 146 break :midEvt; 147 } 148 // Change Row 149 if (key.matchesAny(&.{ vaxis.Key.up, 'k' }, .{})) demo_tbl.row -|= 1; 150 if (key.matchesAny(&.{ vaxis.Key.down, 'j' }, .{})) demo_tbl.row +|= 1; 151 // Change Column 152 if (key.matchesAny(&.{ vaxis.Key.left, 'h' }, .{})) demo_tbl.col -|= 1; 153 if (key.matchesAny(&.{ vaxis.Key.right, 'l' }, .{})) demo_tbl.col +|= 1; 154 // Select/Unselect Row 155 if (key.matches(vaxis.Key.space, .{})) { 156 const rows = demo_tbl.sel_rows orelse createRows: { 157 demo_tbl.sel_rows = try alloc.alloc(u16, 1); 158 break :createRows demo_tbl.sel_rows.?; 159 }; 160 var rows_list = std.ArrayList(u16).fromOwnedSlice(rows); 161 for (rows_list.items, 0..) |row, idx| { 162 if (row != demo_tbl.row) continue; 163 _ = rows_list.orderedRemove(idx); 164 break; 165 } else try rows_list.append(alloc, demo_tbl.row); 166 demo_tbl.sel_rows = try rows_list.toOwnedSlice(alloc); 167 } 168 // See Row Content 169 if (key.matches(vaxis.Key.enter, .{}) or key.matches('j', .{ .ctrl = true })) see_content = !see_content; 170 }, 171 .btm => { 172 if (key.matchesAny(&.{ vaxis.Key.up, 'k' }, .{}) and moving) active = .mid 173 // Run Command and Clear Command Bar 174 else if (key.matchExact(vaxis.Key.enter, .{}) or key.matchExact('j', .{ .ctrl = true })) { 175 const cmd = try cmd_input.toOwnedSlice(); 176 defer alloc.free(cmd); 177 if (mem.eql(u8, ":q", cmd) or 178 mem.eql(u8, ":quit", cmd) or 179 mem.eql(u8, ":exit", cmd)) return; 180 if (mem.eql(u8, "G", cmd)) { 181 demo_tbl.row = @intCast(user_list.items.len - 1); 182 active = .mid; 183 } 184 if (cmd.len >= 2 and mem.eql(u8, "gg", cmd[0..2])) { 185 const goto_row = fmt.parseInt(u16, cmd[2..], 0) catch 0; 186 demo_tbl.row = goto_row; 187 active = .mid; 188 } 189 } else try cmd_input.update(.{ .key_press = key }); 190 }, 191 } 192 moving = false; 193 }, 194 .winsize => |ws| try vx.resize(alloc, tty.writer(), ws), 195 else => {}, 196 } 197 198 // Content 199 seeRow: { 200 if (!see_content) { 201 demo_tbl.active_content_fn = null; 202 demo_tbl.active_ctx = &{}; 203 break :seeRow; 204 } 205 const RowContext = struct { 206 row: []const u8, 207 bg: vaxis.Color, 208 }; 209 const row_ctx = RowContext{ 210 .row = try fmt.allocPrint(event_alloc, "Row #: {d}", .{demo_tbl.row}), 211 .bg = demo_tbl.active_bg, 212 }; 213 demo_tbl.active_ctx = &row_ctx; 214 demo_tbl.active_content_fn = struct { 215 fn see(win: *vaxis.Window, ctx_raw: *const anyopaque) !u16 { 216 const ctx: *const RowContext = @ptrCast(@alignCast(ctx_raw)); 217 win.height = 5; 218 const see_win = win.child(.{ 219 .x_off = 0, 220 .y_off = 1, 221 .width = win.width, 222 .height = 4, 223 }); 224 see_win.fill(.{ .style = .{ .bg = ctx.bg } }); 225 const content_logo = 226 \\ 227 \\░█▀▄░█▀█░█░█░░░█▀▀░█▀█░█▀█░▀█▀░█▀▀░█▀█░▀█▀ 228 \\░█▀▄░█░█░█▄█░░░█░░░█░█░█░█░░█░░█▀▀░█░█░░█░ 229 \\░▀░▀░▀▀▀░▀░▀░░░▀▀▀░▀▀▀░▀░▀░░▀░░▀▀▀░▀░▀░░▀░ 230 ; 231 const content_segs: []const vaxis.Cell.Segment = &.{ 232 .{ 233 .text = ctx.row, 234 .style = .{ .bg = ctx.bg }, 235 }, 236 .{ 237 .text = content_logo, 238 .style = .{ .bg = ctx.bg }, 239 }, 240 }; 241 _ = see_win.print(content_segs, .{}); 242 return see_win.height; 243 } 244 }.see; 245 loop.postEvent(.table_upd); 246 } 247 248 // Sections 249 // - Window 250 const win = vx.window(); 251 win.clear(); 252 253 // - Top 254 const top_div = 6; 255 const top_bar = win.child(.{ 256 .x_off = 0, 257 .y_off = 0, 258 .width = win.width, 259 .height = win.height / top_div, 260 }); 261 for (title_segs[0..]) |*title_seg| 262 title_seg.style.bg = if (active == .top) selected_bg else other_bg; 263 top_bar.fill(.{ .style = .{ 264 .bg = if (active == .top) selected_bg else other_bg, 265 } }); 266 const logo_bar = vaxis.widgets.alignment.center( 267 top_bar, 268 44, 269 top_bar.height - (top_bar.height / 3), 270 ); 271 _ = logo_bar.print(title_segs[0..], .{ .wrap = .word }); 272 273 // - Middle 274 const middle_bar = win.child(.{ 275 .x_off = 0, 276 .y_off = win.height / top_div, 277 .width = win.width, 278 .height = win.height - (top_bar.height + 1), 279 }); 280 if (user_list.items.len > 0) { 281 demo_tbl.active = active == .mid; 282 try vaxis.widgets.Table.drawTable( 283 event_alloc, 284 middle_bar, 285 //users_buf[0..], 286 //user_list, 287 user_mal, 288 &demo_tbl, 289 ); 290 } 291 292 // - Bottom 293 const bottom_bar = win.child(.{ 294 .x_off = 0, 295 .y_off = win.height - 1, 296 .width = win.width, 297 .height = 1, 298 }); 299 if (active == .btm) bottom_bar.fill(.{ .style = .{ .bg = active_bg } }); 300 cmd_input.draw(bottom_bar); 301 302 // Render the screen 303 try vx.render(tty_writer); 304 } 305} 306 307/// User Struct 308pub const User = struct { 309 first: []const u8, 310 last: []const u8, 311 user: []const u8, 312 email: ?[]const u8 = null, 313 phone: ?[]const u8 = null, 314}; 315 316// Users Array 317const users = [_]User{ 318 .{ .first = "Nancy", .last = "Dudley", .user = "angela73", .email = "brian47@rodriguez.biz", .phone = null }, 319 .{ .first = "Emily", .last = "Thornton", .user = "mrogers", .email = null, .phone = "(558)888-8604x094" }, 320 .{ .first = "Kyle", .last = "Huff", .user = "xsmith", .email = null, .phone = "301.127.0801x12398" }, 321 .{ .first = "Christine", .last = "Dodson", .user = "amandabradley", .email = "cheryl21@sullivan.com", .phone = null }, 322 .{ .first = "Nathaniel", .last = "Kennedy", .user = "nrobinson", .email = null, .phone = null }, 323 .{ .first = "Laura", .last = "Leon", .user = "dawnjones", .email = "fjenkins@patel.com", .phone = "1833013180" }, 324 .{ .first = "Patrick", .last = "Landry", .user = "michaelhutchinson", .email = "daniel17@medina-wallace.net", .phone = "+1-634-486-6444x964" }, 325 .{ .first = "Tammy", .last = "Hall", .user = "jamessmith", .email = null, .phone = "(926)810-3385x22059" }, 326 .{ .first = "Stephanie", .last = "Anderson", .user = "wgillespie", .email = "campbelljaime@yahoo.com", .phone = null }, 327 .{ .first = "Jennifer", .last = "Williams", .user = "shawn60", .email = null, .phone = "611-385-4771x97523" }, 328 .{ .first = "Elizabeth", .last = "Ortiz", .user = "jennifer76", .email = "johnbradley@delgado.info", .phone = null }, 329 .{ .first = "Stacy", .last = "Mays", .user = "scottgonzalez", .email = "kramermatthew@gmail.com", .phone = null }, 330 .{ .first = "Jennifer", .last = "Smith", .user = "joseph75", .email = "masseyalexander@hill-moore.net", .phone = null }, 331 .{ .first = "Gary", .last = "Hammond", .user = "brittany26", .email = null, .phone = null }, 332 .{ .first = "Lisa", .last = "Johnson", .user = "tina28", .email = null, .phone = "850-606-2978x1081" }, 333 .{ .first = "Zachary", .last = "Hopkins", .user = "vargasmichael", .email = null, .phone = null }, 334 .{ .first = "Joshua", .last = "Kidd", .user = "ghanna", .email = "jbrown@yahoo.com", .phone = null }, 335 .{ .first = "Dawn", .last = "Jones", .user = "alisonlindsey", .email = null, .phone = null }, 336 .{ .first = "Monica", .last = "Berry", .user = "barbara40", .email = "michael00@hotmail.com", .phone = "(295)346-6453x343" }, 337 .{ .first = "Shannon", .last = "Roberts", .user = "krystal37", .email = null, .phone = "980-920-9386x454" }, 338 .{ .first = "Thomas", .last = "Mitchell", .user = "williamscorey", .email = "richardduncan@roberts.com", .phone = null }, 339 .{ .first = "Nicole", .last = "Shaffer", .user = "rogerstroy", .email = null, .phone = "(570)128-5662" }, 340 .{ .first = "Edward", .last = "Bennett", .user = "andersonchristina", .email = null, .phone = null }, 341 .{ .first = "Duane", .last = "Howard", .user = "pcarpenter", .email = "griffithwayne@parker.net", .phone = null }, 342 .{ .first = "Mary", .last = "Brown", .user = "kimberlyfrost", .email = "perezsara@anderson-andrews.net", .phone = null }, 343 .{ .first = "Pamela", .last = "Sloan", .user = "kvelez", .email = "huynhlacey@moore-bell.biz", .phone = "001-359-125-1393x8716" }, 344 .{ .first = "Timothy", .last = "Charles", .user = "anthony04", .email = "morrissara@hawkins.info", .phone = "+1-619-369-9572" }, 345 .{ .first = "Sydney", .last = "Torres", .user = "scott42", .email = "asnyder@mitchell.net", .phone = null }, 346 .{ .first = "John", .last = "Jones", .user = "anthonymoore", .email = null, .phone = "701.236.0571x99622" }, 347 .{ .first = "Erik", .last = "Johnson", .user = "allisonsanders", .email = null, .phone = null }, 348 .{ .first = "Donna", .last = "Kirk", .user = "laurie81", .email = null, .phone = null }, 349 .{ .first = "Karina", .last = "White", .user = "uperez", .email = null, .phone = null }, 350 .{ .first = "Jesse", .last = "Schwartz", .user = "ryan60", .email = "latoyawilliams@gmail.com", .phone = null }, 351 .{ .first = "Cindy", .last = "Romero", .user = "christopher78", .email = "faulknerchristina@gmail.com", .phone = "780.288.2319x583" }, 352 .{ .first = "Tyler", .last = "Sanders", .user = "bennettjessica", .email = null, .phone = "1966269423" }, 353 .{ .first = "Pamela", .last = "Carter", .user = "zsnyder", .email = null, .phone = "125-062-9130x58413" }, 354};