Skip to content

Instantly share code, notes, and snippets.

@benigumocom
Last active April 2, 2024 03:15
Show Gist options
  • Save benigumocom/9b475b176185135d3c1725a1cdec6c23 to your computer and use it in GitHub Desktop.
Save benigumocom/9b475b176185135d3c1725a1cdec6c23 to your computer and use it in GitHub Desktop.
【SwiftUI】 スクレイピングで GitHub Contribution Graph をつくる 👉 https://android.benigumo.com/20240402/github-contributions/
import SwiftUI
struct Graph: View {
@State var cells: [Cell] = []
private let colors: [Color] = [.clear, .level0, .level1, .level2, .level3, .level4]
var body: some View {
Grid(horizontalSpacing: 2, verticalSpacing: 2) {
ForEach(0 ..< 7, id: \.self) { row in
GridRow {
ForEach(0 ..< cells.count / 7, id: \.self) { col in
colors[cells[col * 7 + row].level + 1]
.cornerRadius(2)
.frame(width: 8, height: 8)
}
}
}
}
.frame(width: 550, height: 100)
.background()
.task {
cells = await Cell.generate(account: "benigumocom")
}
}
}
struct Cell: Hashable {
var date: String
var level: Int
init(date: String = "", level: Int = -1) {
self.date = date
self.level = level
}
}
private extension Cell {
static func generate(account: String) async -> [Cell] {
var data: [Cell] = []
do {
let url = URL(string: String(format: "https://github.com/users/%@/contributions", account))!
for try await line in url.lines {
if let cell = parse(line) {
data.append(cell)
}
}
} catch {
fatalError("Could not generate data.")
}
return data.sorted(by: { $0.date < $1.date }) + Array(repeating: Cell(), count: 53 * 7 - data.count)
}
private static func parse(_ line: String) -> Cell? {
guard let date = line.firstMatch(of: /data-date="(.+?)"/),
let level = line.firstMatch(of: /data-level="(.+?)"/) else { return nil }
return Cell(date: String(date.1), level: Int(level.1)!)
}
}
private extension Color {
static let none = Color.clear
static let level0 = Color(red: 232 / 256, green: 234 / 256, blue: 237 / 256)
static let level1 = Color(red: 138 / 256, green: 230 / 256, blue: 162 / 256)
static let level2 = Color(red: 36 / 256, green: 189 / 256, blue: 95 / 256)
static let level3 = Color(red: 25 / 256, green: 151 / 256, blue: 74 / 256)
static let level4 = Color(red: 20 / 256, green: 99 / 256, blue: 53 / 256)
}
#Preview {
Graph()
}
@benigumocom
Copy link
Author

sc 2024-04-02 at 11 52 50

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment