- merge.py: keep private activities in _merged/index.json instead of
stripping them; privacy filtering is now done client-side
- ActivityFeed: detect logged-in user via bincio:me event; show private
activities only when viewing your own profile; private cards get a lock
badge
This commit is contained in:
@@ -152,7 +152,6 @@ def merge_one(data_dir: Path, activity_id: str) -> None:
|
||||
s = _apply_sidecar_summary(s, fm)
|
||||
activities.append(s)
|
||||
|
||||
activities = [a for a in activities if a.get("privacy") != "private"]
|
||||
activities.sort(key=lambda a: a.get("started_at", ""), reverse=True)
|
||||
activities.sort(key=lambda a: 0 if a.get("custom", {}).get("highlight") else 1)
|
||||
|
||||
@@ -262,9 +261,9 @@ def merge_all(data_dir: Path) -> int:
|
||||
activities.append(s)
|
||||
|
||||
# Drop private activities from the published feed
|
||||
activities = [a for a in activities if a.get("privacy") != "private"]
|
||||
|
||||
# Sort: newest first, then bring highlighted activities to the top
|
||||
# Private activities are kept in the index so the owner can see them;
|
||||
# the feed UI filters them out for non-owners client-side.
|
||||
activities.sort(key=lambda a: a.get("started_at", ""), reverse=True)
|
||||
activities.sort(key=lambda a: 0 if a.get("custom", {}).get("highlight") else 1)
|
||||
|
||||
|
||||
@@ -43,8 +43,20 @@
|
||||
let loading = true;
|
||||
let error = '';
|
||||
let mounted = false;
|
||||
/** Logged-in handle — resolved async via bincio:me event. */
|
||||
let me: string = '';
|
||||
|
||||
$: filtered = sport === 'all' ? all : all.filter(a => a.sport === sport);
|
||||
// Show private activities only to their owner.
|
||||
// On a profile page (filterHandle set): show private if me === filterHandle.
|
||||
// On the global feed: show private only for the logged-in user's own activities.
|
||||
$: isOwner = filterHandle !== '' && me === filterHandle;
|
||||
$: withPrivacy = all.filter(a => {
|
||||
if (a.privacy === 'private') {
|
||||
return filterHandle ? isOwner : (me !== '' && (a as any).handle === me);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
$: filtered = sport === 'all' ? withPrivacy : withPrivacy.filter(a => a.sport === sport);
|
||||
$: visible = filtered.slice(0, shown);
|
||||
$: hasMore = shown < filtered.length;
|
||||
|
||||
@@ -60,18 +72,26 @@
|
||||
onMount(async () => {
|
||||
sport = (new URLSearchParams(window.location.search).get('sport') as Sport | 'all') ?? 'all';
|
||||
mounted = true;
|
||||
|
||||
// Resolve the logged-in handle so we can show the owner their private activities.
|
||||
if ((window as any).__bincioMe !== undefined) {
|
||||
me = (window as any).__bincioMe;
|
||||
} else {
|
||||
window.addEventListener('bincio:me', (e: Event) => { me = (e as CustomEvent).detail; }, { once: true });
|
||||
}
|
||||
|
||||
try {
|
||||
const indexUrl = profileIndexUrl
|
||||
? `${base}data/${profileIndexUrl}`
|
||||
: `${base}data/index.json`;
|
||||
const index = await loadIndex(base, indexUrl);
|
||||
let activities = index.activities.filter(a => a.privacy !== 'private');
|
||||
let activities = index.activities;
|
||||
// filterHandle only applies when loading the root manifest (multi-user feed).
|
||||
// When profileIndexUrl is set we already loaded the right user's shard directly —
|
||||
// activities from a direct shard fetch have no handle tag, so the filter would
|
||||
// remove everything.
|
||||
if (filterHandle && !profileIndexUrl) {
|
||||
activities = activities.filter(a => a.handle === filterHandle);
|
||||
activities = activities.filter(a => (a as any).handle === filterHandle);
|
||||
}
|
||||
all = activities;
|
||||
} catch (e: any) {
|
||||
@@ -140,10 +160,13 @@
|
||||
>@{a.handle}</a>{/if}
|
||||
</p>
|
||||
<!-- stretched link covers the whole card; sits below the handle link -->
|
||||
<h3 class="font-semibold text-white truncate group-hover:text-[--accent] transition-colors">
|
||||
<h3 class="font-semibold text-white truncate group-hover:text-[--accent] transition-colors flex items-center gap-1.5">
|
||||
{#if a.privacy === 'private'}
|
||||
<span class="text-zinc-500 shrink-0" title="Private">🔒</span>
|
||||
{/if}
|
||||
<a
|
||||
href={a.detail_url ? `${import.meta.env.BASE_URL}activity/${a.id}/` : `${import.meta.env.BASE_URL}activity/local/?id=${a.id}`}
|
||||
class="before:absolute before:inset-0 before:content-['']"
|
||||
class="before:absolute before:inset-0 before:content-[''] truncate"
|
||||
>{a.title}</a>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user