Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions pages/_app.public.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { RevalidateProvider } from 'next-swr';
import { useEffect } from 'react';
import { SWRConfig } from 'swr';
import '@tabnews/ui/css';

Expand All @@ -20,6 +21,101 @@ async function SWRFetcher(resource, init) {
const fallbackData = { body: null, headers: {} };

function MyApp({ Component, pageProps }) {
useEffect(() => {
const handleBeforeUnload = () => {
sessionStorage.setItem('scrollPos', window.scrollY);
console.warn('Posição do Scroll SALVA:', window.scrollY);
};

window.addEventListener('beforeunload', handleBeforeUnload);

// Restaura posição do scroll apenas se a navegação atual for um reload.
// Usa Navigation Timing API com fallback para performance.navigation.
try {
let isReload = false;
if (performance && typeof performance.getEntriesByType === 'function') {
const nav = performance.getEntriesByType('navigation')[0];
if (nav && nav.type === 'reload') isReload = true;
}

if (!isReload && performance && performance.navigation) {
if (performance.navigation.type === performance.navigation.TYPE_RELOAD) {
isReload = true;
}
}

if (isReload) {
const savedPos = sessionStorage.getItem('scrollPos');
if (savedPos) {
// usei requestAnimationFrame para tentar aplicar o scroll repetidamente até que a altura da página permita rolar para a posição desejada ou até um timeout.
const target = parseInt(savedPos, 10) || 0;
const maxMs = 2000; // tempo máximo de tentativas
const start = performance && performance.now ? performance.now() : Date.now();

const tryOnce = () => {
// tenta rolar uma vez
window.scrollTo(0, target);
// Se já estamos na posição desejada, fim.
if (window.scrollY === target) return true;

// Segunda tentativa novamente no próximo frame
const height = document.documentElement.scrollHeight || document.body.scrollHeight;
const canReach = height >= target + (window.innerHeight || 0);
return canReach;
};

const step = () => {
try {
const now = performance && performance.now ? performance.now() : Date.now();
// Se tryOnce indica que já rolou ou que a página tem altura para rolar, executa o scroll uma vez mais e finaliza.
if (tryOnce()) {
// Garante remoção do valor
try {
sessionStorage.removeItem('scrollPos');
} catch (e) {
void 0;
}
return;
}

if (now - start < maxMs) {
requestAnimationFrame(step);
} else {
// timeout: faz uma última tentativa e remove o valor salvo
try {
window.scrollTo(0, target);
} catch (e) {
void 0;
}
try {
sessionStorage.removeItem('scrollPos');
} catch (e) {
void 0;
}
}
} catch (e) {
// Remove savedPos para não tentar sempre
try {
sessionStorage.removeItem('scrollPos');
} catch (err) {
void 0;
}
}
};

// Inicia tentativas no próximo frame
requestAnimationFrame(step);
}
}
} catch (e) {
// Se não estiver disponível, seguir sem restauração
void 0;
}

return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
};
}, []);
return (
<ThemeProvider>
<Turnstile />
Expand Down
2 changes: 2 additions & 0 deletions pages/interface/components/Markdown/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { MarkdownEditor, MarkdownViewer } from '@tabnews/ui/markdown';
const shouldAddNofollow = (url) => !isTrustedDomain(url);

export default function Viewer(props) {
// Viewer é um wrapper puro agora; o scroll é tratado em `pages/_app.public.js`
// para não duplicar e evitar efeitos colaterais em navegações SPA.
return MarkdownViewer({
shouldAddNofollow,
...props,
Expand Down