Skip to content

docs(editor): interactive playground and tutorial system#139

Open
johnleider wants to merge 42 commits intomasterfrom
docs/editor
Open

docs(editor): interactive playground and tutorial system#139
johnleider wants to merge 42 commits intomasterfrom
docs/editor

Conversation

@johnleider
Copy link
Member

Summary

  • Adds a full interactive v0 REPL editor (/playground) with file tree, tab management, resizable panels, and live preview
  • Introduces a tutorial system (/skillz/tutorial/[id]) with markdown instruction panels, step preloading, URL routing, and resume support
  • Ships four tutorial tracks: Vue Basics, Vue Intermediate, Vue Advanced, and v0 Basics (each with 7–8 steps)
  • Redesigns the Skillz resume popup with snooze, level badge, progress bar, and dot grid
  • Separates local UI preferences from synced progress data in the skillz store
  • Adds horizontal drag-scroll skill card carousel, keyboard navigation, and accessibility improvements

Test plan

  • Visit /playground — editor loads with file tree, tabs, and live preview
  • Edit a file in the playground — preview updates without iframe recreation
  • Visit /skillz/tutorial/vue-basics — tutorial loads at the correct step
  • Step through a tutorial — progress persists and resume popup appears on revisit
  • Snooze the resume popup — it dismisses and doesn't reappear until snooze expires
  • Toggle doc site theme — preview iframe theme syncs
  • Test on mobile — file panel opens as overlay, layout toggle works

Vue REPL with Monaco editor, @vuetify/v0 import map,
and fullscreen layout. Initial working layout with
h-screen + absolute positioning for proper sizing.
Set up multi-file REPL matching Vuetify Play's v0 template: main.ts
with createThemePlugin, uno.config.ts with presetWind4 runtime and
v0 color token mapping. Updated default example to use UnoCSS utility
classes. Added scrollbar-gutter override for fullscreen layout.
Move pt-[72px] padding from App.vue to default/home layouts so
fullscreen layout stays flush. Reset preview iframe body margin
and widen default stepper example.
Lazy-load example files in EditorExamples to reduce editor chunk size.
Prefetch @vue/repl and Monaco from docs layout during idle time so the
editor page loads from HTTP cache. Fix flash of unstyled content by
hiding #app until after mount and setting theme-aware body background.
Add tab close buttons, sync nested file edits to flat aliases, fix
kebab-case component names, and replace header with Vuetify Play logo.
- Add draggable resize handle for file panel using v0 useToggleScope/useEventListener
- Persist sidebar width to localStorage via useStorage
- Add Ctrl+B hotkey to toggle file panel (useHotkey)
- Allow closing all tabs, show "Open file" button when empty
- Hide breadcrumbs and REPL when no tabs open
- Use vuetify-play icon for "Open in Editor" buttons
- Skip hidden alias files from project folder in file tree
- Add lang="ts" to new .vue file boilerplate
- Double-click resize handle resets to default width
- Stabilize previewOptions as computed to prevent re-renders during resize
- Preserve URL hash for shareable editor links
- Fix editor-container height to fill available space
Extract useEditorFiles and useFileTreeCrud composables to reduce
component complexity. Lazy-load fflate to remove ~13KB from the shared
docs bundle. Replace backdrop overlay with useClickOutside + Escape
key support. Consolidate infrastructure file constants, deduplicate
generateAppWrapper, alphabetize file tree, and guard activeFile access.
Replace Vuetify Play references with v0 Editor, add editor/examples
icons, pass fileName prop to code panes, and delete unused playground.ts.
Add Scrim to fullscreen layout for stack coordination. On mobile,
file tree opens as a fixed overlay with proper z-index from useStack.
Syncs sidebar state with breakpoint changes.
…n hydration

Replace CSS Grid with nested flexbox and add three draggable resize handles
(markdown width, editor/preview split, file tree width) with persistent storage.
Optimize step transitions by preloading all tutorial steps in background and
using RAF-throttled pointer events. Hydrate v-html code fences and callouts
into DocsMarkup/DocsCallout components matching the docs site styling.
- Consolidate tutorial route into skillz.tutorial.[id].vue
- Remove deprecated getting-started tutorial
- Add vue-basics, vue-intermediate, vue-advanced, and v0-basics tutorial content
- Improve editor file tree, tabs, and markdown panel
- Add SkillzBadge and SkillzComplete components
- Update typed-router and component declarations
Add carousel view mode for skill card decks with drag-to-scroll,
CSS fade masks on edges, and right-edge viewport bleed. Persisted
via carousel setting in useSettings.
…rovements

Add hover arrows for click-to-scroll, left/right keyboard navigation
between cards, reactive fade masks based on scroll position, and
focus-visible styles. Replace querySelector usage with useTemplateRef,
add immediate option to useResizeObserver.
Replace store.setFiles() with incremental in-place file mutations.
store.setFiles() writes to import-map.json, which triggers @vue/repl's
getImportMap() watch → createSandbox() → iframe recreation → volar
language worker restart on every Next/Prev click.

The incremental approach mutates files reactively:
- existing files: update .code in-place, compile only if changed
- new files: store.files[filename] = new ReplFile then pass the Proxy
  (not the raw instance) to compileFile — compileFile destructures
  { compiled } and writes compiled.js; going through the Proxy makes
  the write reactive so updatePreview re-runs correctly
- deleted files: removed from store.files without touching the protected
  import-map.json or tsconfig.json
- Save step progress to skillz store as user navigates (begin, record, setLastStep)
- Add ?step=N query param support for bookmark, share, and resume
- Resume notification (SkillzResume) now handles tutorial mode with step param
- Back button navigates to /skillz/:id instead of /skillz
- Hide sidebar toggle when stepOptions.hideFiles is true
- Export begin, record, setLastStep from skillz store; extend pendingTour to match tutorials
- Fix SVG width/height lint errors in 5 tutorial step files
- Rename editor → playground (/playground route, nav item at order 1.15)
- Add EditorIntroPanel with markdown content, DocsCallout/DocsMarkup
  mounting, close button, and useStorage persistence
- Extract useMarkdownMount composable shared by intro and tutorial panels
- Fix useMarkdown table/callout renderers to parse inline markdown
  (backticks, links, bold) via a separate sync Marked instance
- Add TOUR callout support to useMarkdown + useMarkdownMount
- Encode editor state (files + active file) to URL hash on change;
  restore active file on load; backwards-compat with legacy hash format
- Patch @vue/repl to suppress Symbol(props) injection warn and skip
  internal Sandbox when store.showOutput is false (removes duplicate
  iframe and allow-scripts+allow-same-origin browser warning)
- Back button navigates to previous in-app route via history.state.back
- Replace large DEFAULT_CODE stepper example with simpler tabs demo
- Move snoozedUntil/dismissed out of TourProgress into a separate
  skillz-prefs localStorage key (LocalSkillzPrefs) — keeps TourProgress
  a clean, server-syncable DTO
- dismiss() now hides the resume popup without wiping progress; reset()
  remains the only way to delete tour data
- Extract SkillzAdapter interface with createLocalAdapter() as the seam
  for future Vuetify One API integration
- Fix: use spread-reassignment (clearPrefs) instead of delete to ensure
  Vue's deep watch persists prefs removals to localStorage
@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 19, 2026

Open in StackBlitz

commit: 9a51837

Mirrors the tours directory structure by adding beginner/intermediate/advanced
level folders under skillz/tutorials/. Updates glob patterns and path parsing
in index.ts to handle the extra folder depth.
Renames all files, components, composables, storage keys, and CSS classes
from the "editor" naming to "playground" to match the final feature name.
Also renames editorLink composable to usePlaygroundLink per conventions.
- New stores/playground.ts — Pinia store managing panel/sidebar/examples
  UI state with namespaced control objects (playground.panel.open(), etc.)
- Rename usePlaygroundStore composable → usePlaygroundRepl to avoid
  collision; add PlaygroundContext interface; default showOutput to false
- PlaygroundWorkspace absorbs mobile file-browser overlay (useStack)
  and emits update:sidebarOpen
- playground.vue always renders PlaygroundWorkspace (no more dual
  Repl/WorkSpace mode); all UI state delegated to Pinia store
- skillz.[id].vue passes playground store in tour context
- using-the-playground tour handlers implemented
- PlaygroundWorkspace: dual layout branches — panel mode (file tree +
  editor top, preview full-width below) vs standard mode (file tree
  full-height sidebar, togglable vertical/horizontal split)
- Add vertical/horizontal layout toggle button to tab bar in standard mode
- defaultLayout prop pins layout without touching user's stored preference
- Add layout-horizontal/layout-vertical icons (mdiViewSplitVertical/Horizontal)
- PlaygroundFileTree: fix template ref name collision (tree → tree-el)
- PlaygroundBreadcrumbs: move divider style to class prop
- playground.vue: intro panel open/close watcher, panel resize handle
- router.ts: guard querySelector against invalid hash selectors (base64)
- skillz tutorial: misc fixes
- Add mobile editor/preview toggle (Code/Preview buttons) with mobileView state
- Mobile intro panel via Teleport + useStack overlay with proper z-index
- File panel starts closed on mobile (immediate watcher on isDesktop)
- Fix tour step order: sidebar-toggle → file-tree → editor → preview → panel/examples
- Add welcome preamble steps to all four beginner tours
- Force center placement for first and last tour steps (DiscoveryContent)
- Delay resume popup 3s to avoid immediate flash
- Remove discovery watches that prevented panel closing on welcome step
- Reset button hidden unless devmode is active (skillz/[id])
- Hide Duration/Reset on mobile; Next button truncates gracefully
- Add padding to skill title when completed medal is shown
- Global grabbing cursor during resize (useResizeHandle)
- Clean up abandoned UnoCSS runtime style elements on recompile
- Track latest pointermove position in RAF instead of dropping events;
  reset latestPos on each drag start to prevent stale carryover
- Remove contain-strict toggling during drag (expensive containment
  context churn on every frame)
- Disable Monaco auto-resize during drag to prevent ResizeObserver
  layout thrashing
- Lock overflow-y: scroll on intro panel during panel resize to skip
  browser scrollbar double-pass layout
Split 420-line PlaygroundWorkspace.vue into four new components:
- PlaygroundEditor — Repl pane with scoped REPL CSS
- PlaygroundPreview — Sandbox pane with scoped preview CSS
- PlaygroundMobileSidebar — mobile file browser overlay
- PlaygroundTabBar — tabs row with Code/Preview and layout toggle

WorkSpace is now structural scaffolding only.
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.

1 participant