Compare commits
3
Commits
882296b1c0
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
600949e475 | ||
|
|
26d2d3e379 | ||
|
|
61c2b62141 |
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "instaarchive-viewer",
|
||||
"version": "1.8.0",
|
||||
"version": "1.8.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "instaarchive-viewer",
|
||||
"version": "1.8.0",
|
||||
"version": "1.8.1",
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.1.14",
|
||||
"@vitejs/plugin-react": "^5.0.4",
|
||||
|
||||
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "instaarchive-viewer",
|
||||
"private": true,
|
||||
"version": "1.8.0",
|
||||
"version": "1.8.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --port=3000 --host=0.0.0.0",
|
||||
"build": "vite build && npm run build:server",
|
||||
"build:server": "tsc server.ts --esModuleInterop --module ESNext --target ES2022 --moduleResolution bundler --outDir dist-server",
|
||||
"build:server": "tsc server.ts --esModuleInterop --module ESNext --target ES2022 --moduleResolution bundler --removeComments --outDir dist-server",
|
||||
"preview": "vite preview",
|
||||
"server": "tsx server.ts",
|
||||
"clean": "rm -rf dist",
|
||||
|
||||
+55
-1
@@ -73,6 +73,17 @@ export default function App() {
|
||||
*/
|
||||
const initialRouteRef = useRef(parseRoute(window.location.pathname, window.location.search));
|
||||
|
||||
/**
|
||||
* Back-button support for the post view. Every other URL change
|
||||
* (`replaceState`s the tab/archive) is intentionally NOT pushed — only
|
||||
* opening a post gets its own history entry, matching Instagram's own
|
||||
* back-button behaviour: Back closes the post instead of leaving the app.
|
||||
*/
|
||||
const pushedPostRef = useRef(false);
|
||||
/** Set while reacting to a popstate, so the URL-sync effect below does not
|
||||
* try to push/replace/back() again for a change the browser already made. */
|
||||
const suppressNextSyncRef = useRef(false);
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const profilePicInputRef = useRef<HTMLInputElement>(null);
|
||||
@@ -367,6 +378,13 @@ export default function App() {
|
||||
// loader below is waiting to read.
|
||||
if (!hasInitialLoaded) return;
|
||||
|
||||
// Consumed exactly once per popstate, regardless of what happens below:
|
||||
// a popstate-driven change often already matches the URL (the browser
|
||||
// already moved the pointer), which used to leave this flag stuck true
|
||||
// and silently no-op the NEXT real close/open until something reset it.
|
||||
const wasPopState = suppressNextSyncRef.current;
|
||||
suppressNextSyncRef.current = false;
|
||||
|
||||
const archive = currentArchive?.name ?? (allPosts.length > 0 ? username : null) ?? null;
|
||||
const nextPath = buildPath({
|
||||
archive,
|
||||
@@ -374,12 +392,48 @@ export default function App() {
|
||||
post: selectedPost ? postSlug(selectedPost) : null,
|
||||
});
|
||||
|
||||
if (nextPath !== window.location.pathname + window.location.search) {
|
||||
if (nextPath === window.location.pathname + window.location.search) return;
|
||||
if (wasPopState) return; // the browser already navigated; nothing to add
|
||||
|
||||
console.log(`[Permalink] Updating URL to: ${nextPath}`);
|
||||
|
||||
if (selectedPost && !pushedPostRef.current) {
|
||||
// Opening a post: push, so Back closes it instead of leaving the app.
|
||||
window.history.pushState(null, '', nextPath);
|
||||
pushedPostRef.current = true;
|
||||
} else if (!selectedPost && pushedPostRef.current) {
|
||||
// Closing a post that was pushed for: consume that entry rather than
|
||||
// piling a new one on top of it, so Back still means "one step".
|
||||
pushedPostRef.current = false;
|
||||
window.history.back();
|
||||
} else {
|
||||
window.history.replaceState(null, '', nextPath);
|
||||
}
|
||||
}, [hasInitialLoaded, currentArchive?.name, username, allPosts.length, activeTab, selectedPost?.id]);
|
||||
|
||||
/**
|
||||
* Back/forward support for the post view. Only a post push (above) ever
|
||||
* creates an entry, so this only ever needs to open or close a post —
|
||||
* never re-derive the tab or archive, which stayed on replaceState.
|
||||
*/
|
||||
useEffect(() => {
|
||||
const onPopState = () => {
|
||||
suppressNextSyncRef.current = true;
|
||||
const route = parseRoute(window.location.pathname, window.location.search);
|
||||
const post = route.post ? findPostBySlug(allPosts, route.post) : null;
|
||||
if (post) {
|
||||
setActiveTab(tabForSource(post.source));
|
||||
setSelectedPost(post);
|
||||
pushedPostRef.current = true; // forward navigation can land back here
|
||||
} else {
|
||||
setSelectedPost(null);
|
||||
pushedPostRef.current = false;
|
||||
}
|
||||
};
|
||||
window.addEventListener('popstate', onPopState);
|
||||
return () => window.removeEventListener('popstate', onPopState);
|
||||
}, [allPosts]);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasInitialLoaded) return;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user