Commit d58e5ef7d8
d58e5ef7d8a719fdf2a0117721a6a5dd7d44131a
parent: 0a519cfa8f
Verified · cmc
cmc <hello@cleberg.net> · 2026-09-22 18:04 UTC
profile: render the about text under about_path
Layout: unified · split
gitbay/Discovery/ProfileViewModel.swift
+4 −7
| @@ -16,7 +16,9 @@ final class ProfileViewModel { |
| 16 | 16 | /// Long-form profile text, rendered between the header and the |
| 17 | 17 | /// activity graph the way the web renders it. |
| 18 | 18 | let about: String? |
| 19 | | let aboutFormat: String? |
| 19 | /// The file in `<name>/.gitbay` the text was read from, e.g. |
| 20 | /// `profile/README.org`. Its extension picks the renderer. |
| 21 | let aboutPath: String? |
| 20 | 22 | let links: [Link]? |
| 21 | 23 | let orgs: [Member]? |
| 22 | 24 | let members: [Member]? |
| @@ -26,7 +28,7 @@ final class ProfileViewModel { |
| 26 | 28 | |
| 27 | 29 | enum CodingKeys: String, CodingKey { |
| 28 | 30 | case name, kind, description, website, about, links, orgs, members, repos, activity |
| 29 | | case aboutFormat = "about_format" |
| 31 | case aboutPath = "about_path" |
| 30 | 32 | case activityTotal = "activity_total" |
| 31 | 33 | } |
| 32 | 34 | |
| @@ -42,11 +44,6 @@ final class ProfileViewModel { |
| 42 | 44 | return name == username |
| 43 | 45 | } |
| 44 | 46 | |
| 45 | | /// The filename the about text is rendered under. The server has |
| 46 | | /// none to dispatch on either, so the stored format picks the |
| 47 | | /// extension and anything but org is markdown. |
| 48 | | var aboutFile: String { aboutFormat == "org" ? "about.org" : "about.md" } |
| 49 | | |
| 50 | 47 | /// One of the free-form links a profile carries beside its |
| 51 | 48 | /// website. The server caps the list at five. |
| 52 | 49 | nonisolated struct Link: Decodable, Sendable, Hashable { |
gitbay/Views/Discovery/ProfileView.swift
+1 −1
| @@ -142,7 +142,7 @@ struct ProfileView: View { |
| 142 | 142 | private func aboutSection(_ profile: ProfileViewModel.Profile) -> some View { |
| 143 | 143 | if let about = profile.about, !about.isEmpty { |
| 144 | 144 | Section("About") { |
| 145 | | ReadmeView(name: profile.aboutFile, content: about) |
| 145 | ReadmeView(name: profile.aboutPath ?? "", content: about) |
| 146 | 146 | .padding(.vertical, 4) |
| 147 | 147 | } |
| 148 | 148 | } |
gitbayTests/ProfileCommitTests.swift
+5 −5
| @@ -15,7 +15,7 @@ private func makeClient() throws -> (GitbayClient, StubProtocol.Box) { |
| 15 | 15 | private let userProfileJSON = """ |
| 16 | 16 | {"protocol_version":1,"data":{"name":"cmc","kind":"user",\ |
| 17 | 17 | "description":"Org-Mode · Self-Hosting · Privacy","website":"https://cleberg.net",\ |
| 18 | | "about":"* Christian\\n\\nOrg-Mode.","about_format":"org",\ |
| 18 | "about":"* Christian\\n\\nOrg-Mode.","about_format":"org","about_path":"profile/README.org",\ |
| 19 | 19 | "links":[{"label":"Tor","url":"http://example.onion/"},{"url":"https://krz.sh"}],\ |
| 20 | 20 | "orgs":[{"name":"krz","role":"admin"},{"name":"audit-labs","role":"admin"}],\ |
| 21 | 21 | "repos":[{"path":"cmc/notes","visibility":"private","description":"notes",\ |
| @@ -53,8 +53,8 @@ struct ProfileAggregateTests { |
| 53 | 53 | #expect(profile.repos[1].topics == nil) |
| 54 | 54 | #expect(profile.repos[1].meta.isEmpty) |
| 55 | 55 | #expect(profile.about == "* Christian\n\nOrg-Mode.") |
| 56 | | // The format picks the filename the about text renders under. |
| 57 | | #expect(profile.aboutFile == "about.org") |
| 56 | // The file's own path picks the renderer, as it does on the web. |
| 57 | #expect(profile.aboutPath == "profile/README.org") |
| 58 | 58 | #expect(profile.links?.map(\.title) == ["Tor", "https://krz.sh"]) |
| 59 | 59 | #expect(profile.activityTotal == 15) |
| 60 | 60 | // One read builds the whole page. |
| @@ -78,8 +78,8 @@ struct ProfileAggregateTests { |
| 78 | 78 | // A profile with no about text and no links renders neither. |
| 79 | 79 | #expect(profile.about == nil) |
| 80 | 80 | #expect(profile.links == nil) |
| 81 | | // Markdown is the default for anything but org. |
| 82 | | #expect(profile.aboutFile == "about.md") |
| 81 | // No about file, no path. |
| 82 | #expect(profile.aboutPath == nil) |
| 83 | 83 | } |
| 84 | 84 | |
| 85 | 85 | @Test func anUnknownNameIsAnEmptyState() async throws { |