- Add @codemirror/autocomplete with a custom completion source
- New xsltCompletions.js: ~80 xsl:* elements + ~120 XPath functions,
each tagged with minVersion (1.0/2.0/3.0) and optional blogSlug
- Completions filter to the active XSLT version of each workspace
- Tooltip info() renders argument signature + "Full docs →" link
pointing to blog.xsltplayground.com/xslt/functions/<slug>
(placeholders until Phase 2 blog pages are written)
- Auto-close tags, XML linting and Format button also wired up
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds VITE_FEEDBACK_WEBHOOK_URL env var passed to frontend container,
wired to frontend.feedbackWebhookUrl in values.yaml.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Simple form with type selector (idea/bug/other) + textarea
- POSTs to VITE_FEEDBACK_WEBHOOK_URL (runtime env, set in Helm/entrypoint)
- States: idle → sending → success/error
- Removes email/GitHub links — no context switch for user
- Adds VITE_FEEDBACK_WEBHOOK_URL to entrypoint.sh env
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Main XSLT editor uses eager=true to skip requestIdleCallback delay
(it's the LCP element — must render ASAP)
- Secondary editors (XML inputs, result) keep deferred loading
- Preload Monaco CDN loader.js and editor.main.js in <head> so
they start downloading before JS requests them
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The v0.2.0 label was meaningless. Now shows the short commit SHA
that links directly to the commit on GitHub. Injected at build time
via Vite (execSync git rev-parse --short HEAD).
Also removes CHANGELOG.md (unmaintained) and the changelogAnchor helper.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All editors were mounting simultaneously on initial render, causing
Monaco to block the main thread (TBT 1520ms). Now uses requestIdleCallback
(timeout 1.5s) to defer Monaco initialization until after first paint.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- gzip level 6 for JS, CSS, JSON, SVG, fonts
- immutable cache (1yr) for hashed JS/CSS assets
- 7-day cache for static assets (SVG, fonts, images)
- no-store for env.js (runtime config must be fresh)
- no-cache for HTML (SPA index)
Reduces JS transfer from ~460KB to ~115KB gzip.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The file-input CSS class (position:absolute 1px clip) was preventing the
label click from triggering the file picker in some browsers.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Users were rage-clicking the "Drop your input XML files here" area
expecting a file picker. Converted to a label with hidden file input
supporting multiple XML files, same logic as drag-and-drop.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Refreshing every 30s regardless of visibility was causing low view rate
(23-38%) because the ad was often scrolled out of view. Now uses
IntersectionObserver (threshold 0.5) to gate both the interval refresh
and the post-transform refresh.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ad div was first in DOM causing it to be the LCP element (10.2s).
Moved to end of app-container and repositioned visually with order:-1
so the ad still appears at the top without blocking LCP measurement.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously only the arrow button toggled the panel. Now the full header
acts as the toggle, with a guard to ignore clicks that were actually drags.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add id="xsltplayground-main" to EthicalAds div for Placements report
- Refresh ad every 30s via setInterval
- Also refresh on each successful transform (throttled to 30s minimum)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Auto-report link on 5xx/network errors: pre-fills GitHub issue with version, error, and stylesheet snippet
- Microsoft Clarity: conditional on VITE_CLARITY_ID env var, loaded after page load
- Usage survey: appears after 3 successful transforms, fires GA4 event, one-shot (stored in localStorage)
- 27 tests passing (10 new tests covering buildBugReportUrl, server error detection, survey lifecycle)
Frontend:
- Add XSLT 3.0 option to version selector
- Add tests: version selector renders 1.0/2.0/3.0, version change updates stylesheet
Backend:
- Validate version field: reject anything other than 1.0, 2.0, 3.0 or empty
- Add tests: pickSourceXML (preferred keys, fallback, no XML, HTML entity unescaping)
- Add tests: version validation rejects invalid, accepts all valid values
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Update index.html title, description, keywords to include xslt 3.0, validator, saxon
- Update JSON-LD schema with full feature list and XSLT 3.0
- Change footer link from "News" to "Blog & Tutorials", update URL to blog.xsltplayground.com
- New articles: online editor guide, validator guide, string functions, xsl:for-each-group
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Move site/ Hugo source from gh-pages to main so the workflow can trigger correctly
- Fix publish-hugo.yml: now in main, builds and deploys to gh-pages:docs/ via peaceiris/actions-gh-pages
- Add 3 new SEO articles: XSLT 3.0 features, beginners guide, template matching
- Add llms.txt to blog and frontend so ChatGPT/Gemini can recommend the tool better
- Remove stale /site mkdocs ignore rule, add site/public to gitignore instead
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add visually hidden H1 for search engines and screen readers
- Add JSON-LD structured data (WebApplication schema)
- Add subtle footer tagline with keywords
- Use semantic H1 in loading shell
- Add CLAUDE.md for Claude Code guidance
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>