ux: implement premium symmetrical skeletons and async render performance improvements#131
Merged
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR improves perceived performance and UX by introducing symmetrical skeleton loaders for the editor/preview (including Mermaid placeholders), adding async deferral for large-document renders to avoid UI freezes, and enhancing accessibility with live-region announcements. The same updates are mirrored into the Neutralino desktop app’s bundled resources and the service worker cache is bumped to invalidate older clients.
Changes:
- Add theme-aware skeleton shimmer/pulse system and initial skeleton DOM for both panes (web + desktop resources).
- Defer large markdown renders (15k+ chars) to allow the skeleton to paint immediately; add Mermaid “loading” state styling and cleanup.
- Add an
aria-liveannouncer + localized loading strings; add visual skeletons for emoji modal and GitHub import tree while loading.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| sw.js | Cache version bump to force client refresh of updated assets. |
| styles.css | Adds theme variables and the skeleton shimmer/pulse styling (editor overlay, preview skeleton, Mermaid loading state, visually-hidden utility). |
| script.js | Implements preview skeleton injection for large renders, Mermaid loading class cleanup, emoji/GitHub import skeletons, and screen reader announcements. |
| index.html | Adds initial editor/preview skeleton markup and the live-region announcer element. |
| desktop-app/resources/styles.css | Mirrors skeleton styling and utilities for the desktop bundle. |
| desktop-app/resources/js/script.js | Mirrors async render/skeleton/accessibility behavior for the desktop bundle. |
| desktop-app/resources/index.html | Mirrors initial skeleton markup and live-region announcer for the desktop bundle. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+7196
to
+7204
| function announceToScreenReader(message) { | ||
| const announcer = document.getElementById('app-accessibility-announcer'); | ||
| if (announcer) { | ||
| announcer.textContent = ''; | ||
| setTimeout(() => { | ||
| announcer.textContent = message; | ||
| }, 50); | ||
| } | ||
| } |
Comment on lines
+7196
to
+7204
| function announceToScreenReader(message) { | ||
| const announcer = document.getElementById('app-accessibility-announcer'); | ||
| if (announcer) { | ||
| announcer.textContent = ''; | ||
| setTimeout(() => { | ||
| announcer.textContent = message; | ||
| }, 50); | ||
| } | ||
| } |
Comment on lines
3065
to
3068
| function insertEmojis() { | ||
| if (!emojiSelection.size) return; | ||
| const ordered = emojiItems | ||
| .filter((item) => emojiSelection.has(item.shortcode)) | ||
| .map((item) => item.shortcode); | ||
| const ordered = Array.from(emojiSelection); | ||
| const insertion = ordered.join(' '); |
Comment on lines
3065
to
3068
| function insertEmojis() { | ||
| if (!emojiSelection.size) return; | ||
| const ordered = emojiItems | ||
| .filter((item) => emojiSelection.has(item.shortcode)) | ||
| .map((item) => item.shortcode); | ||
| const ordered = Array.from(emojiSelection); | ||
| const insertion = ordered.join(' '); |
Comment on lines
+3488
to
+3490
| overflow: hidden !important; | ||
| clip: rect(0, 0, 0, 0) !important; | ||
| white-space: nowrap !important; |
Comment on lines
+7196
to
+7204
| function announceToScreenReader(message) { | ||
| const announcer = document.getElementById('app-accessibility-announcer'); | ||
| if (announcer) { | ||
| announcer.textContent = ''; | ||
| setTimeout(() => { | ||
| announcer.textContent = message; | ||
| }, 50); | ||
| } | ||
| } |
Comment on lines
3065
to
3068
| function insertEmojis() { | ||
| if (!emojiSelection.size) return; | ||
| const ordered = emojiItems | ||
| .filter((item) => emojiSelection.has(item.shortcode)) | ||
| .map((item) => item.shortcode); | ||
| const ordered = Array.from(emojiSelection); | ||
| const insertion = ordered.join(' '); |
Comment on lines
3065
to
3068
| function insertEmojis() { | ||
| if (!emojiSelection.size) return; | ||
| const ordered = emojiItems | ||
| .filter((item) => emojiSelection.has(item.shortcode)) | ||
| .map((item) => item.shortcode); | ||
| const ordered = Array.from(emojiSelection); | ||
| const insertion = ordered.join(' '); |
Comment on lines
+3488
to
+3490
| overflow: hidden !important; | ||
| clip: rect(0, 0, 0, 0) !important; | ||
| white-space: nowrap !important; |
Comment on lines
+3488
to
+3490
| overflow: hidden !important; | ||
| clip: rect(0, 0, 0, 0) !important; | ||
| white-space: nowrap !important; |
…rs, visual emoji ordering, and visually-hidden clip-path
Deploying markdownviewer with
|
| Latest commit: |
9970f2e
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://24a2d73a.markdownviewer.pages.dev |
| Branch Preview URL: | https://ux-skeleton-loading-remediat.markdownviewer.pages.dev |
Deploying markdown-viewer with
|
| Latest commit: |
9970f2e
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://803582ac.markdown-viewer.pages.dev |
| Branch Preview URL: | https://ux-skeleton-loading-remediat.markdown-viewer.pages.dev |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
This Pull Request remediates the skeleton loading experience, synchronizes visual layout hierarchies across panes, resolves contrast issues on light/dark themes, and introduces asynchronous parsing optimizations to prevent browser thread freezes during large document pastes.
Key Changes
1. Unified Symmetrical CSS Skeletons
--skeleton-bgand--skeleton-glow) mapped to Slate-Gray (light mode) and Charcoal-Slate (dark mode) instyles.css..editor-skeletonto serve as a complete absolute viewport overlay rather than individual inline lines.0while loading to guarantee zero text bleed under pulsing skeletons..skeleton-title,.skeleton-subtitle, and.skeleton-line..skeleton-w90,.skeleton-w92,.skeleton-w88,.skeleton-w85,.skeleton-w60,.skeleton-w45) inside both panes.2. Dual-Motion Animations
@keyframes skeleton-shimmersweep (1.6s cubic-bezier loop) and an alternate@keyframes skeleton-pulseopacity transition (2.2s loop) to create highly fluid visual loading states.3. Large Paste & Document Async Rendering
debouncedRenderinscript.jsto immediately triggershowPreviewSkeleton()on inputs exceeding 15,000 characters.setTimeout(..., 30)). This allows the browser to paint and animate the preview skeleton instantly on the first frame of a paste operation.4. Client Cache & Offline Synchronization
CACHE_NAMEtomarkdown-viewer-cache-v3.6.9insw.jsto clear client cache allocations.node prepare.js) to fully compile and package script, style, and index updates for the Neutralino desktop-app.Verification & Manual Testing