1
0
mirror of https://github.com/alexandrev/xslt-lab.git synced 2026-09-16 18:23:16 +00:00
Commit Graph

207 Commits

Author SHA1 Message Date
alexandrev-tibco 1921079c8a Fix Clarity script: missing 'script' argument in IIFE call
The snippet was called with 4 args instead of 5, causing r=clarityId
(createElement with wrong tag) and i=undefined (tag src broken).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 00:10:54 +02:00
alexandrev-tibco b56564f6f4 Add /xslt-2-0/ and /xslt-3-0/ internal links in footer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 17:49:22 +02:00
alexandrev-tibco 5581258bd0 Handle ?v= URL param to pre-select XSLT version from landing pages
Reading /?v=2.0 or /?v=3.0 now sets the version on the active workspace
and updates the stylesheet version declaration. URL param is cleaned after
reading. Enables CTAs from /xslt-2-0/ and /xslt-3-0/ landing pages.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 13:17:24 +02:00
alexandrev-tibco 77a2d2c123 Restore dual-placement: fixedheader explicit load + stickybox via MutationObserver
Revert to pre-5d81b58 pattern that had both working:
- xsltplayground-main: fixedheader, always in DOM, loaded with load(element)
- xsltplayground-params: stickybox, inside params panel, only rendered when
  ethicalAdsReady=true so EthicalAds MutationObserver auto-discovers it
No createPortal, no conflict between explicit and auto-discovery loads.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 18:05:00 +02:00
alexandrev-tibco b9a9ba2a93 Re-add fixedheader: load stickybox explicitly, header with delay
Load stickybox via load(element) first (proven to work), then load
fixedheader separately 300ms later to avoid conflict between the two calls.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 16:48:00 +02:00
alexandrev-tibco 406f55865c Restore stickybox to exact b5736c5 implementation
Remove fixedheader slot, restore single xsltplayground-params stickybox
via createPortal with load(element) + innerHTML clear, exactly as at b5736c5.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 10:35:41 +02:00
alexandrev-tibco ace77fee33 SEO: rewrite homepage, add XSLT 2.0/3.0 landing pages, update sitemap
- Rewrite index.html title, meta description, H1 targeting "xslt online"
- Add static 600-word SEO section (crawlable by Googlebot, outside #root)
- Add FAQPage + BreadcrumbList + SoftwareApplication schema.org markup
- New /xslt-2-0/ landing page (~800 words, feature grid, FAQ)
- New /xslt-3-0/ landing page (~900 words, "only free tool" badge, FAQ)
- Update sitemap.xml to include all three URLs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 16:42:08 +02:00
alexandrev-tibco 986a1e05ee Add robots.txt — was returning SPA index.html (404 for crawlers)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 15:58:17 +02:00
alexandrev-tibco 23a7f75e56 Restore stickybox: createPortal to body + original placement ID
Original working implementation used createPortal to document.body and
id=xsltplayground-params. Restore both to match the known-working state.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 15:39:27 +02:00
alexandrev-tibco c4f78816bf Use ethicalads.load() no-arg to discover both slots simultaneously
Calling load(element) twice in sequence was silently failing on the second.
No-arg load() auto-discovers all EA elements in the DOM at once.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 15:25:12 +02:00
alexandrev-tibco 72306d2215 Fix stickybox: always in DOM, loaded alongside fixedheader on EA ready
Both slots rendered unconditionally at app root — EA's stickybox is
position:fixed so it doesn't need to live inside the result pane.
Single effect loads both refs when ethicalAdsReady.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 15:14:19 +02:00
alexandrev-tibco 5e7b1c0764 Reserve 50px for fixedheader slot to prevent layout shift on load
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 14:31:45 +02:00
alexandrev-tibco a480a05e03 Fix stickybox not loading: separate effect triggered by showResultPane
The stickybox slot only mounts after the first transform (showResultPane=true).
Split into two effects: header loads on ethicalAdsReady, sticky loads when
showResultPane changes and its ref is available.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 14:28:08 +02:00
alexandrev-tibco 9a1b9e7108 Restore fixedheader + add stickybox in result pane
- fixedheader: native EthicalAds placement at top of app (above tabs),
  full-width sticky bar as designed
- stickybox: new slot in result pane right column (160px), shown whenever
  result pane is visible
- Two slots loaded via separate refs; both initialized on ethicalAdsReady

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 14:21:52 +02:00
alexandrev-tibco 2f525dacee Add AdSense verification meta tag to frontend and blog
Adds google-adsense-account meta for publisher ca-pub-1549720748100858
to both xsltplayground.com and blog.xsltplayground.com.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 13:32:18 +02:00
alexandrev-tibco 2ee596888a Use fixedheader style natively, neutralize position:fixed only
Let EthicalAds render its own horizontal bar layout via data-ea-style=fixedheader.
CSS only overrides position/z-index to keep it inline instead of viewport-fixed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-04 13:12:23 +02:00
alexandrev-tibco 70da86d7d6 Force ea-callout inline: flex-row on both ethical-ad and ea-content
Apply flex-direction:row + inline-flex on callout regardless of which
nesting level EthicalAds places it at.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-04 13:01:14 +02:00
alexandrev-tibco ff73d15807 Fix EthicalAds bar: callout inline, bigger text, no bottom padding
- Move flex-row to .ethical-ad (not .ea-content) so callout aligns inline
- Font size 11.5px → 13px for readability
- Image 18px → 22px
- ea-callout no longer needs margin-left:auto (natural flex end)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-04 12:51:37 +02:00
alexandrev-tibco d068b6838f Move ad above Success bar, fixedheader-style thin strip
- Relocate EthicalAds slot to top of result pane (before success/running box)
- CSS override on EthicalAds text card: force flex-row, 18px icon,
  single line of text, ~26px total height — matches fixedheader look
  without the fixed positioning

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-04 12:36:37 +02:00
alexandrev-tibco 2a826ca6d1 Use text ad type for compact horizontal bar in result pane
Replace image (300x250 card) with text type always — renders as a slim
horizontal unit with small image + copy, matching the original header bar
look. Adjusted .result-ad CSS: thin bg, border-bottom separator.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-04 12:29:52 +02:00
alexandrev-tibco 9563518fb0 Fix SaxonDaemon classpath: quote glob to prevent shell expansion
The shell was expanding /opt/saxon/* into space-separated filenames,
causing Java to treat each jar as a separate argument and fail with
ClassNotFoundException. Single-quoting lets the JVM handle the glob.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 17:39:59 +02:00
alexandrev-tibco d6dffa530c Replace per-request JVM with persistent Saxon daemon
Start a long-lived Java HTTP server (SaxonDaemon) on 127.0.0.1:8081 at
container startup. The Go backend now proxies /transform calls to it instead
of spawning a new JVM per request, eliminating ~500ms cold-start overhead.

- SaxonDaemon.java: HttpServer on :8081, two Processor instances (normal +
  trace), warm-up at startup, per-request compile/transform
- Runner.java: make enableCompileWithTracing, DeduplicatingErrorReporter and
  attachTraceListener package-private for daemon access
- main.go: remove exec.Command path; POST to daemon, parse JSON response
- Dockerfile: compile SaxonDaemon, download Gson, ship start.sh
- start.sh: wait for daemon /health, then exec Go server

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 17:26:46 +02:00
alexandrev-tibco c48acd1a8c Add sticky sidebar ad to blog articles, fix EA script loading
- Article pages (single.html): two-column grid layout — article + 160px
  sidebar with sticky EA ad (id="xsltplayground-blog")
- Non-article pages (home, list): keep existing sticky header bar
  (id="xsltplayground-blog-header")
- Move EA script to <head> in baseof.html so it loads on all pages
  regardless of placement; remove script tag from ethicalads partial
- has-ethicalads body class now only applied on non-article pages
  (no 64px header-offset shift on article pages)
- Sidebar hidden on viewports <= 860px (mobile/tablet)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:22:52 +02:00
alexandrev-tibco a07f9df934 Move EthicalAds to inline result pane, drop A/B test, optimize SEO title
- Replace fixedheader/stickybox A/B with a single inline placement inside
  the result pane (before the editor, no data-ea-style) to improve view rate
- Remove adPlacement random split and derived variables (isCompactEthicalAd,
  ethicalAdStyle, ethicalAdHeight, ethicalAdVariant)
- Drop createPortal import (no longer needed)
- SEO: swap title order to "Online XSLT Editor, Tester & Validator — XSLT Playground"
  and rewrite meta description leading with "Test XSLT online" for higher CTR
  on queries: xslt online, xslt tester, xslt validator
- Bump chart to 0.1.4

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 14:37:53 +02:00
alexandrev-tibco 28f5ea981a Add undo button for format action in editor and result pane
After formatting XSLT or result XML, an undo button appears next to
the sparkles icon. Clicking it restores the pre-format content.
Undo state resets on new transform or tab switch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 12:49:14 +02:00
alexandrev-tibco fd7bf2c799 Increase transform debounce from 500ms to 2000ms
Prevents overwhelming the backend with requests on every keystroke.
Users reported slowdown when typing — 2s gap feels natural and still
gives near-instant feedback after finishing edits.
Update test timeouts accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 12:40:45 +02:00
alexandrev-tibco b0569736d4 Restore A/B test header vs sidebar, move BuyMeACoffee to left
- 50/50 random per session: header (xsltplayground-main fixedheader)
  vs sidebar (xsltplayground-params stickybox via portal)
- BuyMeACoffee moved to Left position to avoid collision with stickybox

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 16:31:40 +02:00
alexandrev-tibco b5736c51af Add frontend test step to CI before Docker build
Runs npm test (vitest) as a required job before build-and-push.
Catches runtime import errors like the createPortal/react-dom mistake.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 13:12:18 +02:00
alexandrev-tibco b61669308a Fix createPortal import: use react-dom instead of react
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 13:10:21 +02:00
alexandrev-tibco 09a0978cff Switch to xsltplayground-params stickybox as sole ad placement
Remove A/B test and xsltplayground-main fixedheader. Use only
xsltplayground-params (stickybox) rendered via createPortal to document.body,
always active. Higher eCPM ($1.66 vs $0.82) observed vs fixedheader.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 12:27:55 +02:00
alexandrev-tibco 33d8c0ec84 Fix sidebar ad variant using createPortal to escape overflow:hidden container
The stickybox div was being crushed to 0 height inside app-container
(height:100% flex column). Use createPortal to mount it at document.body
so EthicalAds can position it freely as a floating widget.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 16:59:28 +02:00
alexandrev-tibco 610a3f8741 Fix A/B ad placement: move sidebar ad outside collapsed params panel
The sidebar ad was inside the paramsCollapsed conditional block, so
when params were collapsed ethicalSlotRef was null and the ad never loaded.
Move both ad variants to the root level of the component so they're
always in the DOM regardless of panel state.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 11:17:25 +02:00
alexandrev-tibco 43ecf16340 A/B test ad placement: header vs sidebar (50/50 random per session)
Each page load randomly assigns adPlacement='header' or 'sidebar'.
- header: xsltplayground-main fixedheader (current behavior)
- sidebar: xsltplayground-params stickybox in the params panel
Never shows both simultaneously, complying with EthicalAds single-ad policy.
GA4 event 'ad_placement_variant' tracks which variant each user sees.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 13:17:22 +02:00
alexandrev-tibco 5d81b58e2f Remove duplicate EthicalAds placement to comply with publisher policy
Single ad per page policy violation: remove xsltplayground-params placement
from the params panel, keeping only xsltplayground-main.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 12:54:10 +02:00
alexandrev-tibco 12ba1c7de9 Fix param block hiding on editor focus
Always show injectParamBlock() in the editor — no more switching value
on focus/blur. onChange already calls stripParamBlock() before saving,
so editing is safe. Removes editorFocused state entirely.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 12:07:35 +02:00
alexandrev-tibco 9ddf5b5c6b Copy link button: place right next to Success text 2026-04-21 12:02:29 +02:00
alexandrev-tibco 45e0895a76 Share button: integrated styling + error panel + clearer text
- Button blends into green/red bar (no separate border/background)
- Text changed to "🔗 Copy link" — unambiguous, not "uploading"
- Also shown in error panel header (red context styling)
- Ad retry only fires if slot is still empty after 1.5s

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 11:57:29 +02:00
alexandrev-tibco 782973e8f3 Share button polish + ad retry fix
- Share button only appears after user's own transform (not auto-run)
- Clipboard text includes motivating message: "Check out my XSLT transformation! "
- Success bar still spans full width; share button floats right aligned
- EthicalAds main slot retries load() after 1s to fix intermittent race condition

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 11:40:24 +02:00
alexandrev-tibco b200e81746 Add share button, OG image, and share_transform GA4 tracking
- OG image (1200x630) generated from brand assets for Slack/Teams unfurls
- Twitter card + og:image:width/height meta tags in index.html
- "Share transform" pill button appears next to "Success" after each run:
  copies shareable ?xslt=...&xml=... URL to clipboard
- Fires gtag share_transform event with xslt_version dimension
- CSS: gradient pill, hover lift, green "copied" state, dark mode support

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 11:32:07 +02:00
alexandrev-tibco 0dd55ba75d EthicalAds: refresh every 30s when visible (both placements)
Remove transform-count gate — ad now refreshes every 30s if visible,
regardless of user activity. Improves view count for users who do few
transforms (e.g. blog tryUrl arrivals).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 19:26:24 +02:00
alexandrev-tibco 688ea2f0a3 Fix xpath-document tryUrl: replace document('colors.xml') with inline xsl:key lookup
Colors data embedded in the XML input document, avoiding the local
file reference that fails in the sandbox.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 13:45:20 +02:00
alexandrev-tibco 7690ab0cac Fix tryUrl auto-run + add doc() sandbox warning
- autoRunReady initializes to true when page loads from ?xslt= URL,
  so the transform fires immediately without requiring a click
- Add doc(uri) to completions list (XSLT 2.0+) with note that only
  HTTP/HTTPS URLs are supported in the playground
- Show a yellow hint in the error panel when FODC0002/I-O error
  detected, explaining that local file paths are not supported

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 13:42:55 +02:00
alexandrev-tibco 19bfe481e9 Fix merge article tryUrls: replace doc() with inline xsl:variable data
The 6 xsl:merge-related articles had tryUrls that failed at runtime because
doc() tried to load external XML files that don't exist in the backend sandbox.
Replaced with self-contained XSLTs using inline variable data.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 13:25:07 +02:00
alexandrev-tibco bf645b5378 Revert foldGutter; move feedback widget top-right; add email field
- Revert foldGutter: false — was causing comments to appear hidden
  when editor was focused (fold markers + codeFolding() interference)
- FeedbackWidget: default position now top-right at editor height
  (STORAGE_KEY bumped to feedbackPos2 to reset saved position)
- FeedbackWidget: add optional email input mapped to 'mail' in webhook

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 12:57:18 +02:00
alexandrev-tibco 3c9b82d56b Fix Full docs link: use pointerdown + window.open
Replace passive anchor click with explicit pointerdown handler that
opens the URL via window.open. This fires before any tooltip-close
logic can intercept the interaction, and stopPropagation prevents
CodeMirror from treating it as an editor event.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 12:09:37 +02:00
alexandrev-tibco 13a85804b2 Add placement id to params panel EthicalAds unit
Adds id="xsltplayground-params" so this unit is tracked separately
from the main "xsltplayground-main" placement in EthicalAds analytics.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 11:45:16 +02:00
alexandrev-tibco 6316bc2a1d Fix Full docs link in hover tooltip; enable fold gutter
- Add mousedown stopPropagation on tooltip wrapper so CodeMirror doesn't
  intercept clicks and block "Full docs →" link navigation
- Enable foldGutter in editor basicSetup so expand/collapse controls
  appear in the line number gutter area

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 11:40:02 +02:00
alexandrev-tibco 798ab314a0 Fix params-ad overflow, update copyright year and author link
- Fix EthicalAds second unit: switch text→image type, add overflow:hidden
  and flex centering to prevent ad from bleeding outside params column
- Copyright: 2025 → 2026
- Author name now links to alexandre-vazquez.com

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 11:30:00 +02:00
alexandrev-tibco 7ebf9d26ec Add push_and_deploy.sh script for CI-gated deploys
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 11:24:40 +02:00
alexandrev-tibco 107592067d Add second EthicalAds text unit in params panel footer
Adds a text-type ad at the bottom of the data pipeline (params)
column, visible when the panel is open. Only renders when EthicalAds
is enabled and loaded, so no impact on localhost or ad-blocked users.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 11:21:49 +02:00