feat: merge AI / Cloud / HomeLab into Tech pill with sub-sections
- Removed AI, Cloud, HomeLab as top-level pills - Tech pill now matches all their slugs (ai, ml, cloud, homelab, security, dev) - Tech view shows a sectioned front page: AI · Cloud · HomeLab · Security · Dev · Technology - Sub-sections defined via NewsSection.techSubSections + StoryPill.subSections - digest() extracted to makeDigest(sections:) so any pill can have sections - Tech auto-loads 100 stories to fill its sub-sections (same as All) - "All" Tech section in the main feed now links to Tech pill Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -60,15 +60,15 @@ struct SignalFeedView: View {
|
||||
private var isDigest: Bool { true }
|
||||
|
||||
/// Front-page digest: Top Stories + up to 3 per category section, deduped.
|
||||
private var digest: (top: [StorySummary], sections: [(NewsSection, [StorySummary])]) {
|
||||
private func makeDigest(sections: [NewsSection]) -> (top: [StorySummary], sections: [(NewsSection, [StorySummary])]) {
|
||||
let unread = filteredStories.filter { !readStoryIds.contains($0.id) }
|
||||
let top = Array(unread.prefix(5))
|
||||
var pool = Array(unread.dropFirst(5))
|
||||
var out: [(NewsSection, [StorySummary])] = []
|
||||
for section in NewsSection.sections {
|
||||
for section in sections {
|
||||
var picked: [StorySummary] = [], rest: [StorySummary] = []
|
||||
for s in pool {
|
||||
if picked.count < 3 && s.inSection(section) { picked.append(s) }
|
||||
if picked.count < 4 && s.inSection(section) { picked.append(s) }
|
||||
else { rest.append(s) }
|
||||
}
|
||||
pool = rest
|
||||
@@ -136,8 +136,8 @@ struct SignalFeedView: View {
|
||||
.task(id: selectedPill) {
|
||||
await store.setPill(selectedPill)
|
||||
var pages = 0
|
||||
if selectedPill == .all {
|
||||
// Front page: pull enough stories to fill the sections.
|
||||
// All and Tech both use multi-section layouts that need enough stories.
|
||||
if selectedPill == .all || selectedPill == .tech {
|
||||
while store.stories.count < 100 && store.hasMore && pages < 5 {
|
||||
await store.loadMore(); pages += 1
|
||||
}
|
||||
@@ -262,10 +262,12 @@ struct SignalFeedView: View {
|
||||
/// Card layout for every pill. "All" gets full multi-section front page;
|
||||
/// topic pills get a hero card + flat list within that topic.
|
||||
@ViewBuilder private var digestContent: some View {
|
||||
let d = digest
|
||||
let headerLabel = selectedPill == .all
|
||||
? "TOP STORIES"
|
||||
: selectedPill.label.uppercased()
|
||||
let activeSections = selectedPill == .all
|
||||
? NewsSection.sections
|
||||
: (selectedPill.subSections ?? [])
|
||||
let d = makeDigest(sections: activeSections)
|
||||
let headerLabel = selectedPill == .all ? "TOP STORIES" : selectedPill.label.uppercased()
|
||||
|
||||
sectionHeader(headerLabel, pill: nil)
|
||||
if let lead = d.top.first {
|
||||
mainRow(lead, hero: true)
|
||||
@@ -273,11 +275,10 @@ struct SignalFeedView: View {
|
||||
} else {
|
||||
emptyState.plainBlackRow()
|
||||
}
|
||||
if selectedPill == .all {
|
||||
ForEach(d.sections, id: \.0.id) { section, stories in
|
||||
sectionHeader(section.label.uppercased(), pill: section.pill)
|
||||
ForEach(stories) { mainRow($0) }
|
||||
}
|
||||
// "All" and pills with sub-sections (Tech) get a sectioned breakdown.
|
||||
ForEach(d.sections, id: \.0.id) { section, stories in
|
||||
sectionHeader(section.label.uppercased(), pill: section.pill)
|
||||
ForEach(stories) { mainRow($0) }
|
||||
}
|
||||
readShelf
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user