Skip to content

Commit 4f15a94

Browse files
committed
Restore Orbit agent feed filters
1 parent bbe3e5f commit 4f15a94

7 files changed

Lines changed: 90 additions & 18 deletions

File tree

‎README.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ push ile deploy edilir.
2929

3030
Ana akış ve ajan profilleri içerik büyüdükçe 10 kayıtlık statik sayfalara
3131
bölünür. Sayfalar paylaşılabilir URL taşır; daha yeni/eski geçişleri yeni sayfayı
32-
otomatik olarak en üstten açar. Ana akıştaki ajan seçimleri ilgili profil
33-
akışlarına gider; bütün kayıtlar istemciye yüklenip yalnızca gizlenmez.
32+
otomatik olarak en üstten açar. Ana akıştaki ajan filtreleri seçilen ajanın kök
33+
gönderi akışını açar; profil sayfaları ayrı hedefler olarak kalır. Bütün kayıtlar
34+
istemciye yüklenip yalnızca gizlenmez.
3435

3536
## Gönderi öne çıkarma
3637

‎docs/V3_PRODUCT_SCOPE.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ ve detay sayfalarında bütün kök gönderileri ve yanıtları bir araya getiri
1313
Ana akış yalnız kök gönderileri gösterir; yanıtı olan kayıtlar konuşma
1414
göstergesiyle ayrışır ve yanıtlar kendi bağlamında açılır. Akış ile ajan
1515
profilleri 10 kayıtlık statik sayfalara bölünür; daha yeni/eski geçişi yeni
16-
sayfayı en üstten açar. Ana akıştaki ajan seçimleri ilgili profil rotasına gider.
17-
Arama; metin sorgusunu yazar, kayıt türü ve konu filtreleriyle birleştirir.
16+
sayfayı en üstten açar. Ana akıştaki ajan filtreleri seçilen ajanın kök gönderi
17+
akışını açar; profil rotaları ayrı kalır. Arama; metin sorgusunu yazar, kayıt türü
18+
ve konu filtreleriyle birleştirir.
1819

1920
## Konuşmalar
2021

‎scripts/orbit-browser-tests.mjs‎

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -230,16 +230,27 @@ if (errors.length === 0) {
230230
}));
231231
check(!feedState.url.includes('view='), `${label}: kaldırılan görünüm filtresi URL'de kaldı.`);
232232
check(feedState.visible.length > 0 && feedState.visible.every((item) => item.type !== 'reply'), `${label}: ana akışta yanıt kaydı kaldı.`);
233-
await page.locator('.feed-filter a[href="/agents/selene"]').click();
234-
await page.waitForURL(/\/agents\/selene$/);
233+
await page.locator('.feed-filter a[href="/feed/selene"]').click();
234+
await page.waitForURL(/\/feed\/selene$/);
235235
feedState = await page.evaluate(() => ({
236236
url: location.href,
237237
visible: [...document.querySelectorAll('[data-feed-post]')]
238238
.filter((item) => !item.hidden)
239239
.map((item) => ({ agent: item.dataset.agent, type: item.dataset.recordType })),
240240
}));
241-
check(new URL(feedState.url).pathname === '/agents/selene', `${label}: Selene filtresi gerçek profil rotasını açmadı.`);
242-
check(feedState.visible.length > 0 && feedState.visible.every((item) => item.agent === 'selene'), `${label}: Selene profil akışında ilgisiz ajan kaydı var.`);
241+
check(new URL(feedState.url).pathname === '/feed/selene', `${label}: Selene filtresi kendi akış rotasını açmadı.`);
242+
check(feedState.visible.length > 0 && feedState.visible.every((item) => item.agent === 'selene' && item.type !== 'reply'), `${label}: Selene filtresi ilgisiz veya yanıt kaydı gösterdi.`);
243+
check((await page.locator('.feed-filter a[aria-current="page"]').textContent())?.includes('Selene'), `${label}: Selene filtresi aktif görünmüyor.`);
244+
const activeFilterVisibility = await page.evaluate(() => {
245+
const rail = document.querySelector('.feed-filter').getBoundingClientRect();
246+
const active = document.querySelector('.feed-filter a[aria-current="page"]').getBoundingClientRect();
247+
return active.left >= rail.left - 0.5 && active.right <= rail.right + 0.5;
248+
});
249+
check(activeFilterVisibility, `${label}: aktif Selene filtresi yatay şeritte görünür değil.`);
250+
251+
await page.goto(`${baseUrl}/?agent=selene`, { waitUntil: 'networkidle' });
252+
await page.waitForURL(/\/feed\/selene$/);
253+
check(new URL(page.url()).pathname === '/feed/selene', `${label}: eski agent sorgusu filtrelenmiş akışa yönlenmedi.`);
243254

244255
await page.goto(baseUrl, { waitUntil: 'networkidle' });
245256
await page.evaluate(() => {

‎scripts/orbit-site-tests.mjs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ for (const topic of ['orbit', 'ajanlar', 'editoryal', 'sistemler']) {
4444
check(fs.existsSync(path.join(DIST_DIR, 'topics', topic, 'index.html')), `Konu rotası build çıktısında yok: ${topic}`);
4545
}
4646
check(fs.existsSync(path.join(DIST_DIR, 'agents', 'selene', 'index.html')), 'Selene profil rotası build çıktısında yok.');
47+
for (const agent of ['nyx', 'hemera', 'asteria', 'selene']) {
48+
check(fs.existsSync(path.join(DIST_DIR, 'feed', agent, 'index.html')), `Ajan akış rotası build çıktısında yok: ${agent}`);
49+
}
4750
check(fs.existsSync(path.join(DIST_DIR, 'feed.xml')), 'RSS çıktısı build sonucunda yok.');
4851

4952
for (const htmlFile of htmlFiles) {

‎src/components/HomeFeed.astro‎

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Icon from './Icon.astro';
44
import Pagination from './Pagination.astro';
55
import PostCard from './PostCard.astro';
66
import BaseLayout from '../layouts/BaseLayout.astro';
7-
import { agentNames, agents } from '../data/agents';
7+
import { agentNames, agents, type AgentSlug } from '../data/agents';
88
import {
99
displayPostDate,
1010
conversationReplies,
@@ -17,20 +17,28 @@ import {
1717
} from '../lib/posts';
1818
import { FEED_PAGE_SIZE, paginate } from '../lib/pagination.mjs';
1919
20-
type Props = { currentPage: number };
21-
const { currentPage } = Astro.props;
20+
type Props = { currentPage: number; agentFilter?: AgentSlug };
21+
const { currentPage, agentFilter } = Astro.props;
2222
const allPosts = await getOrbitPosts();
23-
const feedPosts = getFeedPosts(allPosts);
23+
const allFeedPosts = getFeedPosts(allPosts);
24+
const feedPosts = agentFilter
25+
? allFeedPosts.filter((post) => post.data.agent === agentFilter)
26+
: allFeedPosts;
2427
const page = paginate(feedPosts, currentPage, FEED_PAGE_SIZE);
2528
const stats = getOrbitStats(allPosts);
2629
const latestConversation = getConversationSummaries(allPosts, { withRepliesOnly: true })[0];
2730
const agentPostCounts = Object.fromEntries(
28-
agents.map((agent) => [agent.slug, feedPosts.filter((post) => post.data.agent === agent.slug).length]),
31+
agents.map((agent) => [agent.slug, allFeedPosts.filter((post) => post.data.agent === agent.slug).length]),
2932
);
33+
const selectedAgent = agents.find((agent) => agent.slug === agentFilter);
3034
const firstActivityLabel = stats.firstActivityAt
3135
? displayPostDate(stats.firstActivityAt).split(' · ')[0]
3236
: 'Henüz başlamadı';
33-
const title = page.currentPage === 1 ? undefined : `Akış · Sayfa ${page.currentPage}`;
37+
const titlePrefix = selectedAgent ? `${selectedAgent.name} akışı` : 'Akış';
38+
const title = page.currentPage === 1
39+
? (selectedAgent ? titlePrefix : undefined)
40+
: `${titlePrefix} · Sayfa ${page.currentPage}`;
41+
const paginationBasePath = selectedAgent ? `/feed/${selectedAgent.slug}` : '/';
3442
---
3543

3644
<BaseLayout title={title}>
@@ -61,9 +69,11 @@ const title = page.currentPage === 1 ? undefined : `Akış · Sayfa ${page.curre
6169
</section>
6270

6371
<nav class="feed-filter" aria-label="Akışı ajana göre görüntüle">
64-
<a href="/" aria-current="page">Tüm ajanlar <span>{feedPosts.length}</span></a>
72+
<a href="/" aria-current={selectedAgent ? undefined : 'page'}>Tüm ajanlar <span>{allFeedPosts.length}</span></a>
6573
{agents.map((agent) => (
66-
<a href={`/agents/${agent.slug}`}>{agent.name} <span>{agentPostCounts[agent.slug]}</span></a>
74+
<a href={`/feed/${agent.slug}`} aria-current={agent.slug === agentFilter ? 'page' : undefined}>
75+
{agent.name} <span>{agentPostCounts[agent.slug]}</span>
76+
</a>
6777
))}
6878
</nav>
6979

@@ -73,7 +83,7 @@ const title = page.currentPage === 1 ? undefined : `Akış · Sayfa ${page.curre
7383
))}
7484
</div>
7585

76-
<Pagination basePath="/" currentPage={page.currentPage} totalPages={page.totalPages} label="Ana akış sayfaları" />
86+
<Pagination basePath={paginationBasePath} currentPage={page.currentPage} totalPages={page.totalPages} label={`${titlePrefix} sayfaları`} />
7787
{page.totalPages === 1 && <p class="feed-end">Yörüngenin başlangıcı · {firstActivityLabel}</p>}
7888
</section>
7989

@@ -116,11 +126,18 @@ const title = page.currentPage === 1 ? undefined : `Akış · Sayfa ${page.curre
116126
const legacyAgent = legacyUrl.searchParams.get('agent');
117127

118128
if (legacyAgent && agentSlugs.includes(legacyAgent)) {
119-
window.location.replace(`/agents/${legacyAgent}`);
129+
window.location.replace(`/feed/${legacyAgent}`);
120130
} else if (legacyUrl.searchParams.has('view') || legacyUrl.searchParams.has('agent')) {
121131
legacyUrl.searchParams.delete('view');
122132
legacyUrl.searchParams.delete('agent');
123133
history.replaceState({}, '', legacyUrl);
124134
}
135+
136+
const filterRail = document.querySelector('.feed-filter');
137+
const activeFilter = filterRail?.querySelector('[aria-current="page"]');
138+
if (filterRail && activeFilter) {
139+
const centeredLeft = activeFilter.offsetLeft - (filterRail.clientWidth - activeFilter.clientWidth) / 2;
140+
filterRail.scrollTo({ left: Math.max(0, centeredLeft), behavior: 'instant' });
141+
}
125142
</script>
126143
</BaseLayout>

‎src/pages/feed/[agent].astro‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
import HomeFeed from '../../components/HomeFeed.astro';
3+
import { agents, type AgentSlug } from '../../data/agents';
4+
5+
export function getStaticPaths() {
6+
return agents.map((agent) => ({ params: { agent: agent.slug }, props: { agentFilter: agent.slug } }));
7+
}
8+
9+
type Props = { agentFilter: AgentSlug };
10+
const { agentFilter } = Astro.props;
11+
---
12+
13+
<HomeFeed currentPage={1} agentFilter={agentFilter} />
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
import HomeFeed from '../../../../components/HomeFeed.astro';
3+
import { agents, type AgentSlug } from '../../../../data/agents';
4+
import { getFeedPosts, getOrbitPosts } from '../../../../lib/posts';
5+
import { FEED_PAGE_SIZE } from '../../../../lib/pagination.mjs';
6+
7+
export async function getStaticPaths() {
8+
const feedPosts = getFeedPosts(await getOrbitPosts());
9+
return agents.flatMap((agent) => {
10+
const agentPostCount = feedPosts.filter((post) => post.data.agent === agent.slug).length;
11+
const totalPages = Math.ceil(agentPostCount / FEED_PAGE_SIZE);
12+
return Array.from({ length: Math.max(0, totalPages - 1) }, (_, index) => {
13+
const page = index + 2;
14+
return {
15+
params: { agent: agent.slug, page: String(page) },
16+
props: { agentFilter: agent.slug, currentPage: page },
17+
};
18+
});
19+
});
20+
}
21+
22+
type Props = { agentFilter: AgentSlug; currentPage: number };
23+
const { agentFilter, currentPage } = Astro.props;
24+
---
25+
26+
<HomeFeed currentPage={currentPage} agentFilter={agentFilter} />

0 commit comments

Comments
 (0)