 
     // MARK: Layout
 
+    private func configure(cell: PageHistoryCollectionViewCell, for item: WMFPageHistoryRevision, at indexPath: IndexPath) {
+        if let date = item.revisionDate {
+            // TODO: Local to UTC
+            cell.time = DateFormatter.wmf_shortTime()?.string(from: date)
+        }
+        // TODO: Use logged-in icon when available
+        cell.authorImage = item.isAnon ? UIImage(named: "bot") : UIImage(named: "anon")
+        cell.author = item.user
+        cell.sizeDiff = item.revisionSize
+        cell.comment = item.parsedComment?.removingHTML
+        cell.apply(theme: theme)
+    }
+
+    override func collectionView(_ collectionView: UICollectionView, estimatedHeightForItemAt indexPath: IndexPath, forColumnWidth columnWidth: CGFloat) -> ColumnarCollectionViewLayoutHeightEstimate {
+        // The layout estimate can be re-used in this case becuause both labels are one line, meaning the cell
+        // size only varies with font size. The layout estimate is nil'd when the font size changes on trait collection change
+        if let estimate = cellLayoutEstimate {
+            return estimate
+        }
+        var estimate = ColumnarCollectionViewLayoutHeightEstimate(precalculated: false, height: 70)
+        guard let placeholderCell = layoutManager.placeholder(forCellWithReuseIdentifier: PageHistoryCollectionViewCell.identifier) as? PageHistoryCollectionViewCell else {
+            return estimate
+        }
+        let item = pageHistorySections[indexPath.section].items[indexPath.item]
+        configure(cell: placeholderCell, for: item, at: indexPath)
+        estimate.height = placeholderCell.sizeThatFits(CGSize(width: columnWidth, height: UIView.noIntrinsicMetric), apply: false).height
+        estimate.precalculated = true
+        cellLayoutEstimate = estimate
+        return estimate
+    }
+
     override func metrics(with boundsSize: CGSize, readableWidth: CGFloat, layoutMargins: UIEdgeInsets) -> ColumnarCollectionViewLayoutMetrics {
         return ColumnarCollectionViewLayoutMetrics.tableViewMetrics(with: boundsSize, readableWidth: readableWidth, layoutMargins: layoutMargins, interSectionSpacing: 0, interItemSpacing: 20)
     }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        delegate?.pageHistoryViewControllerDidDisappear(self)
    }

    private func getPageHistory() {


    private var batchComplete = false
    private var isLoadingData = false

    private var cellLayoutEstimate: ColumnarCollectionViewLayoutHeightEstimate?

    var shouldLoadNewData: Bool {
        if batchComplete || isLoadingData {
