Mirror of https://github.com/improsocial/impro An extensible Bluesky client for web impro.social
5

Configure Feed

Select the types of activity you want to include in your feed.

Improve logged out feed configuration

Grace Kind (Jul 11, 2026, 6:12 PM -0500) b503c90f 4d2a3bf7

+38 -11
+1 -1
package.json
··· 1 1 { 2 2 "name": "impro", 3 - "version": "0.17.137", 3 + "version": "0.17.138", 4 4 "type": "module", 5 5 "scripts": { 6 6 "start": "rm -rf \"${BUILD_DIR:-build}\" && NODE_ENV=development eleventy --serve",
+1 -1
src/js/config.js
··· 5 5 export const HASHTAG_FEED_PAGE_SIZE = 40; 6 6 export const BOOKMARKS_PAGE_SIZE = 40; 7 7 export const AUTHOR_FEED_PAGE_SIZE = 40; 8 - export const DISCOVER_FEED_URI = 8 + export const LOGGED_OUT_FEED_URI = 9 9 "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot"; 10 10 export const CHAT_MESSAGES_PAGE_SIZE = 100; 11 11
+4
src/js/dataHelpers.js
··· 38 38 return `at://${repo}/${collection}/${rkey}`; 39 39 } 40 40 41 + export function isListFeed(feedURI) { 42 + return feedURI.includes("/app.bsky.graph.list/"); 43 + } 44 + 41 45 export function getRKey(record) { 42 46 return record.uri.split("/").pop(); 43 47 }
+2 -2
src/js/dataLayer/requests.js
··· 9 9 getPostUrisFromNotifications, 10 10 buildUri, 11 11 parseUri, 12 + isListFeed, 12 13 isGroupConvo, 13 14 getGroupConvoDetails, 14 15 getJoinLinkCodesFromPosts, ··· 473 474 const cursor = reload 474 475 ? "" 475 476 : readCollectionCursor(this.dataStore.$feeds, { key: feedURI }); 476 - const isListFeed = feedURI.includes("/app.bsky.graph.list/"); 477 477 const feed = 478 478 feedURI === "following" 479 479 ? await this.api.getFollowingFeed({ limit, cursor, labelers }) 480 - : isListFeed 480 + : isListFeed(feedURI) 481 481 ? await this.api.getListFeed(feedURI, { limit, cursor, labelers }) 482 482 : await this.api.getFeed(feedURI, { limit, cursor, labelers }); 483 483 // Save posts
+4 -3
src/js/preferences.js
··· 10 10 } from "/js/dataHelpers.js"; 11 11 import { deepClone } from "/js/utils.js"; 12 12 import { generateTid } from "/js/atproto.js"; 13 - import { DISCOVER_FEED_URI, BSKY_LABELER_DID } from "/js/config.js"; 13 + import { LOGGED_OUT_FEED_URI, BSKY_LABELER_DID } from "/js/config.js"; 14 14 import { getTagsFromFacets } from "/js/facetHelpers.js"; 15 + import { isListFeed } from "/js/dataHelpers.js"; 15 16 16 17 function getContentTextFromEmbed(embed) { 17 18 const texts = []; ··· 611 612 items: [ 612 613 { 613 614 id: "3l6ovcmm2vd2j", 614 - type: "feed", 615 - value: DISCOVER_FEED_URI, 615 + type: isListFeed(LOGGED_OUT_FEED_URI) ? "list" : "feed", 616 + value: LOGGED_OUT_FEED_URI, 616 617 pinned: true, 617 618 }, 618 619 ],
+5 -4
src/js/views/home.view.js
··· 5 5 import { headerTemplate } from "/js/templates/header.template.js"; 6 6 import "/js/components/tab-bar.js"; 7 7 import { PostSeenObserver } from "/js/postSeenObserver.js"; 8 - import { FEED_PAGE_SIZE, DISCOVER_FEED_URI } from "/js/config.js"; 8 + import { FEED_PAGE_SIZE, LOGGED_OUT_FEED_URI } from "/js/config.js"; 9 9 import { bindToPage, pageEffect } from "/js/router.js"; 10 10 import { showToast } from "/js/toasts.js"; 11 11 import { Signal, ReactiveStore } from "/js/signals.js"; ··· 38 38 39 39 function resetToDefaultFeed() { 40 40 state.$currentFeedUri.set( 41 - isAuthenticated ? "following" : DISCOVER_FEED_URI, 41 + isAuthenticated ? "following" : LOGGED_OUT_FEED_URI, 42 42 ); 43 43 } 44 44 ··· 81 81 return; 82 82 } 83 83 const interactableItems = pinnedItems.filter( 84 - (item) => item.acceptsInteractions || item.uri === DISCOVER_FEED_URI, 84 + (item) => item.acceptsInteractions || item.uri === LOGGED_OUT_FEED_URI, 85 85 ); 86 86 for (const observer of postSeenObservers.values()) { 87 87 observer.disconnect(); ··· 220 220 <main> 221 221 ${pinnedItems.map((item) => { 222 222 const acceptsInteractions = 223 - item.acceptsInteractions || item.uri === DISCOVER_FEED_URI; 223 + item.acceptsInteractions || 224 + item.uri === LOGGED_OUT_FEED_URI; 224 225 const feed = dataLayer.derived.$hydratedFeeds.get(item.uri); 225 226 const feedRequestStatus = 226 227 dataLayer.requests.statusStore.$statuses.get(
+21
tests/unit/specs/dataHelpers.test.js
··· 4 4 avatarThumbnailUrl, 5 5 getRKey, 6 6 getIsLiked, 7 + isListFeed, 7 8 getQuotedPost, 8 9 getBlockedQuote, 9 10 createEmbedFromPost, ··· 79 80 it("should handle URI with single path segment", () => { 80 81 const post = { uri: "single-segment" }; 81 82 assert.deepEqual(getRKey(post), "single-segment"); 83 + }); 84 + }); 85 + 86 + describe("isListFeed", () => { 87 + it("should return true for a list URI", () => { 88 + assert.deepEqual( 89 + isListFeed("at://did:plc:123/app.bsky.graph.list/3ltcvl4ver723"), 90 + true, 91 + ); 92 + }); 93 + 94 + it("should return false for a feed generator URI", () => { 95 + assert.deepEqual( 96 + isListFeed("at://did:plc:123/app.bsky.feed.generator/whats-hot"), 97 + false, 98 + ); 99 + }); 100 + 101 + it("should return false for the following feed", () => { 102 + assert.deepEqual(isListFeed("following"), false); 82 103 }); 83 104 }); 84 105