Compare commits

...

6 Commits

Author SHA1 Message Date
b5241a2a42 Style update banner correctly 2025-12-27 18:29:23 +00:00
8bf33e2d45 style: Consolidate update banner styles and add theme support
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2025-12-27 18:15:22 +00:00
987c401dc4 chore: Update client version mismatch message 2025-12-27 18:15:18 +00:00
6facbd3397 chore: Log service worker update check 2025-12-27 18:13:07 +00:00
a680b4b446 feat: Check for service worker updates on feed load
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2025-12-27 18:01:45 +00:00
2757f701d0 feat: Implement in-app service worker update notification
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2025-12-27 17:52:45 +00:00
7 changed files with 86 additions and 1 deletions

View File

@@ -19,6 +19,7 @@ function App() {
const [theme, setTheme] = useState(localStorage.getItem('theme') || '');
const cache = useRef({});
const [isFullScreen, setIsFullScreen] = useState(!!document.fullscreenElement);
const [waitingWorker, setWaitingWorker] = useState(null);
const updateCache = useCallback((key, value) => {
cache.current[key] = value;
@@ -44,6 +45,14 @@ function App() {
localStorage.setItem('theme', 'red');
};
useEffect(() => {
const onSWUpdate = e => {
setWaitingWorker(e.detail.waiting);
};
window.addEventListener('swUpdate', onSWUpdate);
return () => window.removeEventListener('swUpdate', onSWUpdate);
}, []);
useEffect(() => {
if (Object.keys(cache.current).length === 0) {
localForage.iterate((value, key) => {
@@ -90,6 +99,19 @@ function App() {
return (
<div className={theme}>
{waitingWorker &&
<div className='update-banner'>
Client version mismatch, please refresh:{' '}
<button onClick={() => {
waitingWorker.postMessage({ type: 'SKIP_WAITING' });
navigator.serviceWorker.addEventListener('controllerchange', () => {
window.location.reload();
});
}}>
Refresh
</button>
</div>
}
<Router>
<div className='container menu'>
<p>

View File

@@ -20,6 +20,15 @@ function Feed({ updateCache }) {
useEffect(() => {
const controller = new AbortController();
if ('serviceWorker' in navigator) {
navigator.serviceWorker.getRegistration().then(reg => {
if (reg) {
console.log('Checking for client update...');
reg.update();
}
});
}
fetch(filterSmallweb ? '/api?smallweb=true' : '/api', { signal: controller.signal })
.then(res => {
if (!res.ok) {

View File

@@ -75,3 +75,14 @@
.black .copy-button {
color: #828282;
}
.black .update-banner {
background-color: #333;
color: #ddd;
}
.black .update-banner button {
background-color: #444444;
border-color: #bbb;
color: #ddd;
}

View File

@@ -71,3 +71,14 @@
.dark .copy-button {
color: #828282;
}
.dark .update-banner {
background-color: #333;
color: #ddd;
}
.dark .update-banner button {
background-color: #444444;
border-color: #bbb;
color: #ddd;
}

View File

@@ -43,6 +43,21 @@ input {
border-radius: 4px;
}
.update-banner {
background-color: #ddd;
padding: 0.75rem;
text-align: center;
}
.update-banner button {
margin-left: 1rem;
padding: 0.25rem 0.75rem;
border: 1px solid #828282;
border-radius: 4px;
background-color: transparent;
cursor: pointer;
}
.fullscreen {
margin: 0.25rem;
padding: 0.25rem;

View File

@@ -93,3 +93,14 @@
.red .copy-button {
color: #690000;
}
.red .update-banner {
background-color: #300;
color: #d00;
}
.red .update-banner button {
background-color: #440000;
border-color: #b00;
color: #d00;
}

View File

@@ -3,9 +3,15 @@ import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
// version 3
ReactDOM.render(<App />, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// // unregister() to register() below. Note this comes with some pitfalls.
// // Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
serviceWorker.register({
onUpdate: registration => {
window.dispatchEvent(new CustomEvent('swUpdate', { detail: registration }));
}
});