this repo has no description
13
fork

Configure Feed

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

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