Files
bitvid/js/hashChangeHandler.js
thePR0M3TH3ANandClaude Opus 4.8 04621efc52 feed: stop the grid re-sorting ranked feeds chronologically; Trending defaults
The real reason every tab looked identical: VideoListView.render re-sorts
displayVideos by date UNLESS metadata.preserveOrder is set, and only Explore set
it. So For You's tiering, Trending's view-count ranking, and Kids' scoring were
all discarded at render and shown in plain chronological order — i.e. the #21
feed-identity work was invisible. Set preserveOrder for For You, Trending, and
Kids so their feed-engine order survives to the grid.

Also per request:
- Sidebar: Trending now sits above Recently Added.
- Default homepage: logged-out users land on Trending (gated by
  FEATURE_TRENDING_FEED, falls back to Recent); logged-in stays For You. The
  logout-from-For-You redirect follows the same rule.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-24 13:13:45 -04:00

143 lines
3.8 KiB
JavaScript

import { devLogger as defaultDevLogger, userLogger as defaultUserLogger } from "./utils/logger.js";
import { FEED_TYPES, FEATURE_TRENDING_FEED } from "./constants.js";
const LEGACY_DOCS_VIEWS = {
about: "about",
"community-guidelines": "community-guidelines",
"getting-started": "getting-started",
"upload-content": "upload-content",
roadmap: "roadmap",
links: "links"
};
const createLoggerFacade = (logger, fallback) => {
if (logger && typeof logger === "object") {
return {
log: typeof logger.log === "function" ? logger.log.bind(logger) : fallback.log,
warn:
typeof logger.warn === "function" ? logger.warn.bind(logger) : fallback.warn,
error:
typeof logger.error === "function"
? logger.error.bind(logger)
: fallback.error,
};
}
return fallback;
};
const noopLogger = {
log() {},
warn() {},
error() {},
};
export function createHashChangeHandler({
getApplication,
getApplicationReady,
loadView,
viewInitRegistry,
devLogger = defaultDevLogger,
userLogger = defaultUserLogger,
} = {}) {
const devLog = createLoggerFacade(devLogger, noopLogger);
const userLog = createLoggerFacade(userLogger, noopLogger);
let currentViewName = null;
const getReadyPromise = () => {
if (typeof getApplicationReady === "function") {
return getApplicationReady();
}
return Promise.resolve();
};
const resolveIsLoggedIn = () => {
if (typeof getApplication !== "function") {
return false;
}
const app = getApplication();
if (!app || typeof app.isUserLoggedIn !== "function") {
return false;
}
return Boolean(app.isUserLoggedIn());
};
return async function handleHashChange() {
const currentHash =
typeof window !== "undefined" && window.location
? window.location.hash
: undefined;
devLog.log("handleHashChange called, current hash =", currentHash);
try {
await getReadyPromise();
} catch (error) {
userLog.warn(
"Proceeding with hash handling despite application initialization failure:",
error,
);
}
const hash =
typeof window !== "undefined" && window.location && window.location.hash
? window.location.hash
: "";
if (hash === `#${FEED_TYPES.KIDS}`) {
window.location.hash = `#view=${FEED_TYPES.KIDS}`;
return;
}
const match = hash.match(/^#view=([^&]+)/);
try {
if (!match || !match[1]) {
// Logged in → personalized For You; logged out → Trending (the best
// not-personalized landing), falling back to Recent if Trending is off.
const defaultViewName = resolveIsLoggedIn()
? FEED_TYPES.FOR_YOU
: FEATURE_TRENDING_FEED
? FEED_TYPES.TRENDING
: FEED_TYPES.RECENT;
if (defaultViewName === currentViewName) {
return;
}
await loadView(`views/${defaultViewName}.html`);
currentViewName = defaultViewName;
const initFn = viewInitRegistry?.[defaultViewName];
if (typeof initFn === "function") {
await initFn();
}
return;
}
const viewName = match[1];
if (Object.prototype.hasOwnProperty.call(LEGACY_DOCS_VIEWS, viewName)) {
const docSlug = LEGACY_DOCS_VIEWS[viewName];
window.location.hash = `#view=docs&doc=${docSlug}`;
return;
}
if (viewName === currentViewName) {
return;
}
if (typeof viewName === "string" && viewName.toLowerCase() === FEED_TYPES.HISTORY) {
}
const viewUrl = `views/${viewName}.html`;
await loadView(viewUrl);
currentViewName = viewName;
const initFn = viewInitRegistry?.[viewName];
if (typeof initFn === "function") {
await initFn();
}
} catch (error) {
userLog.error("Failed to handle hash change:", error);
}
};
}