Last active
April 2, 2024 03:15
-
-
Save benigumocom/9b475b176185135d3c1725a1cdec6c23 to your computer and use it in GitHub Desktop.
【SwiftUI】 スクレイピングで GitHub Contribution Graph をつくる 👉 https://android.benigumo.com/20240402/github-contributions/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | |
} |
Author
benigumocom
commented
Apr 2, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment