Skip to content

feat: глобальное переключение Fenom/MODX в code-group - #683

Open
GulomovCreative wants to merge 1 commit into
masterfrom
vitepress-syntax-switcher
Open

feat: глобальное переключение Fenom/MODX в code-group#683
GulomovCreative wants to merge 1 commit into
masterfrom
vitepress-syntax-switcher

Conversation

@GulomovCreative

@GulomovCreative GulomovCreative commented Apr 26, 2023

Copy link
Copy Markdown
Member

Summary

Что изменено

  • useSyntaxSwitcher в .vitepress/theme/composables/syntax-switcher.ts
  • Подключение в DocsLayout.vue
  • Переключение через input.checked + класс .active без .click() — VitePress больше не вызывает scrollIntoView на каждой синхронизированной группе
  • Определение синтаксиса по language-fenom / language-modx на блоке (работает и при кастомных заголовках табов вроде [myForm.tpl])
  • Cleanup click listener в onUnmounted
  • useRouter() на верхнем уровне composable
  • Восстановление после смены роута: watch + nextTick, плюс onContentUpdated (dev/HMR)

Test plan

  • Открыть страницу с несколькими Fenom/MODX code-group (например /components/msviewcounter/frontend/catalog)
  • Переключить таб на Fenom — остальные группы на странице тоже переключаются
  • Скролл страницы не прыгает при sync соседних групп
  • Перейти на другую страницу с code-group — выбранный синтаксис восстанавливается
  • Группы без fenom/modx (другие языки / только кастомные пары) не затрагиваются
  • HMR / повторный заход на страницу в pnpm dev — preference сохраняется

@biz87

biz87 commented Jan 25, 2026

Copy link
Copy Markdown
Member

Привет @GulomovCreative!

Функционал очень полезный — в документации 78 code-groups, и глобальное переключение синтаксисов сильно улучшит UX.

Нашёл несколько проблем в текущей реализации:

  1. Утечка event listener

window.addEventListener('click', ...)
Добавляется в onMounted, но не удаляется в onUnmounted. При hot reload будут накапливаться обработчики.

  1. useRouter() внутри onMounted
onMounted(() => {
   const { route } = useRouter()
 })

Лучше вызывать на верхнем уровне composable.

  1. Хрупкое сравнение через innerText

.find(el => el.innerText === syntax)
Если в табе будет лишний пробел или другой регистр — не сработает. Лучше textContent?.trim().toLowerCase().

  1. Возможные проблемы с таймингом

После смены роута DOM может быть не готов. Стоит добавить nextTick.

Предложение по рефакторингу


  export function useSyntaxSwitcher(key: string, labels: string[]) {
    if (!inBrowser) return

    const { route } = useRouter()
    const normalizedLabels = labels.map(l => l.toLowerCase())

    const handleClick = (e: Event) => {
      const target = e.target as HTMLElement
      if (!e.isTrusted || !target.matches('.vp-code-group .tabs label')) return

      const syntax = target.textContent?.trim().toLowerCase()
      if (!syntax || !normalizedLabels.includes(syntax)) return

      localStorage.setItem(key, syntax)
      setSyntax(syntax, target.closest('.vp-code-group'))
    }

    onMounted(() => {
      window.addEventListener('click', handleClick)

      watch(() => route.path, () => {
        nextTick(() => {
          const saved = localStorage.getItem(key)
          if (saved) setSyntax(saved)
        })
      }, { immediate: true })
    })

    onUnmounted(() => {
      window.removeEventListener('click', handleClick)
    })
  }

Готов помочь с доработкой или могу сам оформить PR с исправлениями, если нет времени.

Доработка #683: sync через radio+.active без click (без scroll jump),
cleanup listener, useRouter на верхнем уровне, nextTick/onContentUpdated.
Определение синтаксиса по language-* классу блока, а не по тексту таба.
@Ibochkarev
Ibochkarev force-pushed the vitepress-syntax-switcher branch from 61f2cd7 to 2a4cd5b Compare September 9, 2026 03:19
@Ibochkarev
Ibochkarev marked this pull request as ready for review September 9, 2026 03:19
@Ibochkarev

Copy link
Copy Markdown
Member

Ветка vitepress-syntax-switcher пересобрана от актуального master с учётом ревью.

Кратко по фиксам:

  1. Listener снимается в onUnmounted
  2. useRouter() на верхнем уровне
  3. Нормализация через trim().toLowerCase() + match по language-* классу блока (не по хрупкому innerText таба)
  4. nextTick после смены роута + onContentUpdated
  5. Скролл: sync без .click(), чтобы VitePress не дергал scrollIntoView на каждой группе

Готово к ревью. @GulomovCreative

@Ibochkarev Ibochkarev changed the title feat: Функционал глобального переключения синтаксисов feat: глобальное переключение Fenom/MODX в code-group Sep 9, 2026
@Ibochkarev
Ibochkarev requested a review from biz87 September 9, 2026 03:21
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.

3 participants