Skip to content

ux: implement premium symmetrical skeletons and async render performance improvements#131

Merged
ThisIs-Developer merged 3 commits into
mainfrom
ux/skeleton-loading-remediation
May 30, 2026
Merged

ux: implement premium symmetrical skeletons and async render performance improvements#131
ThisIs-Developer merged 3 commits into
mainfrom
ux/skeleton-loading-remediation

Conversation

@ThisIs-Developer

Copy link
Copy Markdown
Owner

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

  • Introduced theme-aware CSS variables (--skeleton-bg and --skeleton-glow) mapped to Slate-Gray (light mode) and Charcoal-Slate (dark mode) in styles.css.
  • Configured .editor-skeleton to serve as a complete absolute viewport overlay rather than individual inline lines.
  • Set editor textarea opacity to 0 while loading to guarantee zero text bleed under pulsing skeletons.
  • Standardized heights, margins, and border-radii for .skeleton-title, .skeleton-subtitle, and .skeleton-line.
  • Standardized widths via dynamic utility classes (.skeleton-w90, .skeleton-w92, .skeleton-w88, .skeleton-w85, .skeleton-w60, .skeleton-w45) inside both panes.

2. Dual-Motion Animations

  • Blended horizontal @keyframes skeleton-shimmer sweep (1.6s cubic-bezier loop) and an alternate @keyframes skeleton-pulse opacity transition (2.2s loop) to create highly fluid visual loading states.

3. Large Paste & Document Async Rendering

  • Configured debouncedRender in script.js to immediately trigger showPreviewSkeleton() on inputs exceeding 15,000 characters.
  • Shifted parsing, marked compilation, sanitization, and typesetting for large files into an asynchronous timer thread (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

  • Bumped PWA service worker CACHE_NAME to markdown-viewer-cache-v3.6.9 in sw.js to clear client cache allocations.
  • Re-ran offline assets preparation script (node prepare.js) to fully compile and package script, style, and index updates for the Neutralino desktop-app.

Verification & Manual Testing

  • Checked that pulsing skeletons appear symmetrically in both Editor and Preview panes on refresh.
  • Verified visual contrast and visibility in both Light and Dark themes.
  • Verified zero layout shift (CLS) during progressive loading cycles.
  • Verified that pasting a large markdown file (>100KB) renders a skeleton immediately in the preview tab while parsing runs in the background, keeping the editor typing interface completely responsive.

Copilot AI review requested due to automatic review settings May 30, 2026 19:43
@vercel

vercel Bot commented May 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
markdown-viwer Ready Ready Preview, Comment May 30, 2026 8:11pm

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-live announcer + 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 thread script.js
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 thread script.js
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 thread styles.css
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 thread script.js
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 thread styles.css
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
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented May 30, 2026

Copy link
Copy Markdown

Deploying markdownviewer with  Cloudflare Pages  Cloudflare Pages

Latest commit: 9970f2e
Status: ✅  Deploy successful!
Preview URL: https://24a2d73a.markdownviewer.pages.dev
Branch Preview URL: https://ux-skeleton-loading-remediat.markdownviewer.pages.dev

View logs

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented May 30, 2026

Copy link
Copy Markdown

Deploying markdown-viewer with  Cloudflare Pages  Cloudflare Pages

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

View logs

@ThisIs-Developer ThisIs-Developer merged commit d4c36dc into main May 30, 2026
6 checks passed
@ThisIs-Developer ThisIs-Developer deleted the ux/skeleton-loading-remediation branch May 30, 2026 20:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants