╭ changed ───────────────╮ │src/ui/Repo/Markdown.zig│ ╰────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │277 } │ │278 │ │279 // the focus kind a link follows, or "" when it isn't clickable: web links│ │280 - // are raw links, and a repo path is a files route relative to this file │ │280 + // are raw links, a repo path is a files route relative to this file, and │ │281 + // outside a repo a leading `/` is a page on this site │ │282 fn resolveLink(b: Builder, dest: []const u8) ![]const u8 { │ │283 const aa = b.page_arena.allocator(); │ │284 for ([_][]const u8{ "http:", "https:", "mailto:" }) |scheme| { │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │285 if (std.ascii.startsWithIgnoreCase(dest, scheme)) return aa.print("{s}{s}", .{ ui.raw_link_prefix, dest });│ │286 } │ │287 if (hasScheme(dest) or std.mem.startsWith(u8, dest, "//")) return ""; │ │287 - const data = b.data orelse return ""; │ │288 const end = std.mem.indexOfAny(u8, dest, "?#") orelse dest.len; │ │289 if (end == 0) return ""; │ │290 + const data = b.data orelse { │ │291 + if (dest[0] != '/') return ""; │ │292 + const route = ui.RoutablePage.fromUrl(dest[0..end]) orelse return ""; │ │293 + return aa.print("a:{s}", .{try route.toUrl(b.page_arena)}); │ │294 + }; │ │295 const decoded = std.Uri.percentDecodeInPlace(try aa.dupe(u8, dest[0..end])); │ │296 │ │297 var segments: std.ArrayList([]const u8) = .empty; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯