diff --git a/src/app/update/file.rs b/src/app/update/file.rs index c18815d09..d762a2303 100644 --- a/src/app/update/file.rs +++ b/src/app/update/file.rs @@ -2019,6 +2019,15 @@ impl OpenCADStudio { self.apply_display_defaults(idx); idx }; + // A Restore-all batch's LAST restore inserts its tab here — one + // async round AFTER its settle message. The focus flag therefore + // also fires here: the message-boundary hook alone could run + // before this insertion and be overwritten by it. + #[cfg(target_arch = "wasm32")] + if self.web_session_focus_pending && self.web_autosave_restore_all_remaining == 0 { + self.web_session_focus_pending = false; + self.select_remembered_session_tab(); + } // Missing-on-open: neutral command-line notice plus a flag // the Reference Manager reads. Never an auto-open modal. @@ -4176,19 +4185,19 @@ impl OpenCADStudio { /// from the after-message hook (`web_session_focus_pending`), so the /// whole settle batch — including the last tab insertion — is done. #[cfg(target_arch = "wasm32")] - pub(super) fn select_remembered_session_tab(&mut self) { + pub(super) fn select_remembered_session_tab(&mut self) -> Task { let Some(session) = self.web_session.as_ref() else { - return; + return Task::none(); }; let Some(remembered) = session.tabs.get(session.active) else { - return; + return Task::none(); }; let recovered = crate::io::web_autosave::recovered_name(remembered); let Some(index) = self.tabs.iter().position(|tab| { let name = tab.tab_display_name(); name == remembered.as_str() || name == recovered }) else { - return; + return Task::none(); }; self.active_tab = index; // The active tab changed under the ribbon; re-sync its chips like @@ -4196,6 +4205,8 @@ impl OpenCADStudio { self.sync_ribbon_layers(); self.sync_ribbon_styles(); self.sync_ribbon_from_selection(); + + Task::none() } /// Remember the open-tab list (names + active index) in localStorage — diff --git a/src/app/update/mod.rs b/src/app/update/mod.rs index 7ccce051f..9cb0e0006 100644 --- a/src/app/update/mod.rs +++ b/src/app/update/mod.rs @@ -487,7 +487,7 @@ impl OpenCADStudio { #[cfg(target_arch = "wasm32")] if self.web_session_focus_pending { self.web_session_focus_pending = false; - self.select_remembered_session_tab(); + return self.select_remembered_session_tab(); } self.sync_open_command_history(); // Close the document-level first-touch transaction started by diff --git a/web-app.html b/web-app.html index b66bb39f0..3c380d6df 100644 --- a/web-app.html +++ b/web-app.html @@ -1,6 +1,7 @@ + @@ -46,6 +47,8 @@ + +
diff --git a/web/app.webmanifest b/web/app.webmanifest new file mode 100644 index 000000000..0e79b2c53 --- /dev/null +++ b/web/app.webmanifest @@ -0,0 +1,18 @@ +{ + "name": "Open CAD Studio", + "short_name": "OCS", + "description": "A free CAD editor for DWG and DXF drawings.", + "start_url": "./", + "scope": "./", + "display": "standalone", + "background_color": "#1e1e1e", + "theme_color": "#1e1e1e", + "icons": [ + { + "src": "logo.svg", + "sizes": "any", + "type": "image/svg+xml", + "purpose": "any" + } + ] +} diff --git a/web/sw.js b/web/sw.js index d1e76c95f..597a62c39 100644 --- a/web/sw.js +++ b/web/sw.js @@ -89,9 +89,13 @@ self.addEventListener("fetch", (event) => { event.respondWith( (async () => { const cache = await caches.open(CACHE_NAME); + // Only the scope root is the app shell: caching any other in-scope + // navigation here would store e.g. a font or JSON body under the + // shell key and serve it for every offline navigation. + const isShell = new URL(request.url).pathname === SHELL_URL.pathname; try { const fresh = await fetch(request); - await put(cache, SHELL_URL, fresh); + if (isShell) await put(cache, SHELL_URL, fresh); return fresh; } catch { const cached = await cache.match(SHELL_URL);