Skip to content

Commit d6e5a7c

Browse files
committed
display repo information on the package page, and link to the tags view
1 parent 4f1368b commit d6e5a7c

File tree

8 files changed

+328
-25
lines changed

8 files changed

+328
-25
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<div align="center">
22

3-
<strong><em><code>unidoc</code></em></strong><br><small><code>0.2.6</code></small>
3+
<strong><em><code>unidoc</code></em></strong><br><small><code>0.2.7</code></small>
44

55
[![ci build status](https://github.com/kelvin13/swift-unidoc/actions/workflows/build.yml/badge.svg)](https://github.com/kelvin13/swift-unidoc/actions/workflows/build.yml)
66

Sources/GitHubAPI/GitHubRateLimitError.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ public
44
protocol GitHubRateLimitError:Error, Equatable, Sendable
55
{
66
/// The UTC epoch second when the rate limit will reset.
7-
var until:UnixTime { get }
7+
var until:UnixInstant { get }
88
}

Sources/GitHubClient/GitHubClient.RateLimitError.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ extension GitHubClient
77
struct RateLimitError:GitHubRateLimitError, Equatable, Sendable
88
{
99
public
10-
let until:UnixTime
10+
let until:UnixInstant
1111

1212
@inlinable internal
13-
init(until:UnixTime)
13+
init(until:UnixInstant)
1414
{
1515
self.until = until
1616
}

Sources/UnidocDB/BSON.Millisecond (ext).swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import UnixTime
44
extension BSON.Millisecond
55
{
66
@inlinable public
7-
init(_ unix:UnixTime)
7+
init(_ unix:UnixInstant)
88
{
99
self.init(1000 * unix.second + unix.nanoseconds / 1_000_000)
1010
}

Sources/UnidocPages/Templates/Site.Docs.Meta.swift

Lines changed: 114 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import GitHubAPI
12
import HTML
23
import MarkdownRendering
34
import ModuleGraphs
45
import SHA1
56
import Unidoc
67
import UnidocDB
78
import UnidocRecords
9+
import UnixTime
810
import URI
911

1012
extension Site.Docs
@@ -93,32 +95,116 @@ extension Site.Docs.Meta:ApplicationPage
9395

9496
$0[.h1] = self.title
9597

96-
if case .github(let path)? = self.repo?.origin,
97-
let refname:String = self.names.refname
98+
switch self.repo
9899
{
99-
$0 += HTML.SourceLink.init(file: path.dropFirst(),
100-
target: "https://github.com\(path)/tree/\(refname)")
100+
case .github(let repo)?:
101+
$0[.p] = repo.about
102+
103+
case nil:
104+
break
105+
}
106+
if let refname:String = self.names.refname
107+
{
108+
switch self.repo?.origin
109+
{
110+
case .github(let path)?:
111+
$0 += HTML.SourceLink.init(file: path.dropFirst(),
112+
target: "https://github.com\(path)/tree/\(refname)")
113+
114+
case nil:
115+
break
116+
}
101117
}
102118
}
103119

104120
main[.section] { $0.class = "notice canonical" } = self.canonical
105121

106-
main[.section]
107-
{
108-
$0.class = "details"
109-
}
110-
content:
122+
main[.section, { $0.class = "details" }]
111123
{
112-
if !self.master.platforms.isEmpty
124+
if let repo:PackageRepo = self.repo
113125
{
114-
$0[.h2] = "Platform Requirements"
126+
$0[.h2] = "Package Repository"
115127

116128
$0[.dl]
117129
{
118-
for platform:PlatformRequirement in self.master.platforms
130+
switch repo
119131
{
120-
$0[.dt] = "\(platform.id)"
121-
$0[.dd] = "\(platform.min)"
132+
case .github(let repo):
133+
let now:UnixInstant = .now()
134+
135+
$0[.dt] = "Provider"
136+
$0[.dd]
137+
{
138+
$0[.a]
139+
{
140+
$0.href = "https://github.com/\(repo.owner.login)/\(repo.name)"
141+
$0.target = "_blank"
142+
} = "GitHub"
143+
}
144+
145+
if let license:GitHub.Repo.License = repo.license
146+
{
147+
$0[.dt] = "License"
148+
$0[.dd] = license.name
149+
}
150+
if !repo.topics.isEmpty
151+
{
152+
$0[.dt] = "Keywords"
153+
$0[.dd] = repo.topics.joined(separator: ", ")
154+
}
155+
156+
$0[.dt] = "Watchers"
157+
$0[.dd] = "\(repo.watchers)"
158+
159+
$0[.dt] = "Forks"
160+
$0[.dd] = "\(repo.forks)"
161+
162+
$0[.dt] = "Stars"
163+
$0[.dd] = "\(repo.stars)"
164+
165+
$0[.dt] = "Archived?"
166+
$0[.dd] = repo.archived ? "yes" : "no"
167+
168+
if let created:Timestamp = .init(iso8601: repo.created)
169+
{
170+
$0[.dt] = "Created"
171+
$0[.dd] = "\(created.month(.en)) \(created.day), \(created.year)"
172+
}
173+
if let updated:Timestamp = .init(iso8601: repo.updated),
174+
let updated:UnixInstant = .init(timestamp: updated)
175+
{
176+
let age:Duration = now - updated
177+
178+
$0[.dt] = "Last Pushed"
179+
$0[.dd]
180+
{
181+
if age.components.seconds < 2 * 60
182+
{
183+
$0 += "just now"
184+
}
185+
else if age.components.seconds < 2 * 60 * 60
186+
{
187+
$0 += "\(age.components.seconds / 60) minutes ago"
188+
}
189+
else if age.components.seconds < 2 * 24 * 3600
190+
{
191+
$0 += "\(age.components.seconds / 3600) hours ago"
192+
}
193+
else
194+
{
195+
$0 += "\(age.components.seconds / 86400) days ago"
196+
}
197+
198+
$0 += " ("
199+
200+
$0[.a]
201+
{
202+
$0.href = "\(Site.Tags[self.names.package])"
203+
} = "view tags"
204+
205+
$0 += ")"
206+
}
207+
}
122208
}
123209
}
124210
}
@@ -176,6 +262,20 @@ extension Site.Docs.Meta:ApplicationPage
176262
}
177263
}
178264

265+
if !self.master.platforms.isEmpty
266+
{
267+
$0[.h2] = "Platform Requirements"
268+
269+
$0[.dl]
270+
{
271+
for platform:PlatformRequirement in self.master.platforms
272+
{
273+
$0[.dt] = "\(platform.id)"
274+
$0[.dd] = "\(platform.min)"
275+
}
276+
}
277+
}
278+
179279
$0[.h2] = "Interface Breakdown"
180280

181281
$0 += Unidoc.StatsBreakdown.init(
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
extension Timestamp
2+
{
3+
@frozen public
4+
enum Locale
5+
{
6+
case en
7+
}
8+
}

Sources/UnixTime/Timestamp.swift

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
@frozen public
2+
struct Timestamp:Equatable, Hashable, Sendable
3+
{
4+
public
5+
var year:Int32
6+
public
7+
var month:Int32
8+
public
9+
var day:Int32
10+
public
11+
var hour:Int32
12+
public
13+
var minute:Int32
14+
public
15+
var second:Int32
16+
17+
@inlinable public
18+
init(year:Int32, month:Int32, day:Int32, hour:Int32, minute:Int32, second:Int32)
19+
{
20+
self.year = year
21+
self.month = month
22+
self.day = day
23+
self.hour = hour
24+
self.minute = minute
25+
self.second = second
26+
}
27+
}
28+
extension Timestamp
29+
{
30+
public
31+
init?(iso8601 string:String)
32+
{
33+
self.init(iso8601: string[...])
34+
}
35+
36+
public
37+
init?(iso8601 string:Substring)
38+
{
39+
guard
40+
let hyphen:String.Index = string.firstIndex(of: "-"),
41+
let year:Int32 = .init(string[..<hyphen])
42+
else
43+
{
44+
return nil
45+
}
46+
47+
let month:String.Index = string.index(after: hyphen)
48+
49+
guard
50+
let hyphen:String.Index = string[month...].firstIndex(of: "-"),
51+
let month:Int32 = .init(string[month ..< hyphen])
52+
else
53+
{
54+
return nil
55+
}
56+
57+
let day:String.Index = string.index(after: hyphen)
58+
59+
guard
60+
let t:String.Index = string[day...].firstIndex(of: "T"),
61+
let day:Int32 = .init(string[day ..< t])
62+
else
63+
{
64+
return nil
65+
}
66+
67+
let hour:String.Index = string.index(after: t)
68+
69+
guard
70+
let colon:String.Index = string[hour...].firstIndex(of: ":"),
71+
let hour:Int32 = .init(string[hour ..< colon])
72+
else
73+
{
74+
return nil
75+
}
76+
77+
let minute:String.Index = string.index(after: colon)
78+
79+
guard
80+
let colon:String.Index = string[minute...].firstIndex(of: ":"),
81+
let minute:Int32 = .init(string[minute ..< colon])
82+
else
83+
{
84+
return nil
85+
}
86+
87+
let second:String.Index = string.index(after: colon)
88+
89+
guard
90+
let z:String.Index = string.indices.last, case "Z" = string[z],
91+
let second:Int32 = .init(string[second ..< z])
92+
else
93+
{
94+
return nil
95+
}
96+
97+
if 1 ... 12 ~= month,
98+
1 ... 31 ~= day,
99+
0 ..< 24 ~= hour,
100+
0 ..< 60 ~= minute,
101+
0 ... 60 ~= second
102+
{
103+
self.init(
104+
year: year,
105+
month: month,
106+
day: day,
107+
hour: hour,
108+
minute: minute,
109+
second: second)
110+
}
111+
else
112+
{
113+
return nil
114+
}
115+
}
116+
}
117+
extension Timestamp
118+
{
119+
@inlinable public
120+
func m(_ locale:Locale) -> String
121+
{
122+
switch locale
123+
{
124+
case .en:
125+
switch self.month
126+
{
127+
case 1: return "Jan"
128+
case 2: return "Feb"
129+
case 3: return "Mar"
130+
case 4: return "Apr"
131+
case 5: return "May"
132+
case 6: return "Jun"
133+
case 7: return "Jul"
134+
case 8: return "Aug"
135+
case 9: return "Sep"
136+
case 10: return "Oct"
137+
case 11: return "Nov"
138+
case 12: return "Dec"
139+
case _: return "???"
140+
}
141+
}
142+
}
143+
144+
@inlinable public
145+
func month(_ locale:Locale) -> String
146+
{
147+
switch locale
148+
{
149+
case .en:
150+
switch self.month
151+
{
152+
case 1: return "January"
153+
case 2: return "February"
154+
case 3: return "March"
155+
case 4: return "April"
156+
case 5: return "May"
157+
case 6: return "June"
158+
case 7: return "July"
159+
case 8: return "August"
160+
case 9: return "September"
161+
case 10: return "October"
162+
case 11: return "November"
163+
case 12: return "December"
164+
case _: return "?"
165+
}
166+
}
167+
}
168+
}

0 commit comments

Comments
 (0)