Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync code group selection #2954

Open
4 tasks done
re-ovo opened this issue Sep 13, 2023 · 7 comments
Open
4 tasks done

Sync code group selection #2954

re-ovo opened this issue Sep 13, 2023 · 7 comments
Labels
stale theme Related to the theme

Comments

@re-ovo
Copy link

re-ovo commented Sep 13, 2023

Is your feature request related to a problem? Please describe.

In many cases, developers will provide code groups for multiple programming languages at the same time. I hope that after the user switches one, other code groups can automatically follow, and it is best to be persistent.

#2773, a solution is proposed here, but I don't think it's good enough

  1. Only supports tab, but code group needs it more
  2. This is a very commonly used feature, I think it should be officially supported, not by a plugin

Describe the solution you'd like

::: code-group

```js [config.js] :js <-- key
const config = {
// ...
}

export default config
```

```ts [config.ts] :ts
import type { UserConfig } from 'vitepress'

const config: UserConfig = {
// ...
}

export default config
```

:::

Describe alternatives you've considered

No response

Additional context

No response

Validations

@brc-dd brc-dd added enhancement theme Related to the theme labels Sep 13, 2023
@brc-dd
Copy link
Member

brc-dd commented Sep 25, 2023

Only supports tab, but code group needs it more.

Can you elaborate more on this point.

@re-ovo
Copy link
Author

re-ovo commented Sep 26, 2023

Only supports tab, but code group needs it more.

Can you elaborate more on this point.

Will using tabs give me the same appearance as code groups? I noticed that the code block on your site has a white background

截屏2023-09-26 09 14 03

@github-actions github-actions bot added the stale label Nov 6, 2023
@svanimpe
Copy link

svanimpe commented Jan 13, 2024

+1 from me. I was excited to use code groups, but find them useless without synchronisation.

@re-ovo FYI: I added the following styles to make tabs look more like code groups:

.plugin-tabs--content {
    padding: 0px !important;
}

.plugin-tabs--content div[class*='language-'] {
    background-color: var(--vp-code-block-bg) !important;
    border-radius: 0 !important;
}

@github-actions github-actions bot removed the stale label Jan 18, 2024
@Lehoczky
Copy link
Contributor

+1, It would be great to have code group syncing as a core feature, like it is in docusaurus.

@github-actions github-actions bot added the stale label Apr 12, 2024
@maxnorth
Copy link

maxnorth commented Jul 2, 2024

Came here looking for this, would love to see it added!

@github-actions github-actions bot removed the stale label Jul 17, 2024
@everdrone
Copy link

+1 for this feature, much needed for documentation pages!

@github-actions github-actions bot added the stale label Sep 29, 2024
@pascalbaljet
Copy link

Here's how I did it (.vitepress/theme/index.js). It syncs the code group tab and reselects the tab on navigation and full-page refresh. It also keeps the scroll position of the selected tab in case the code groups above the tab are getting bigger or smaller. Demo: https://inertiaui.com/inertia-modal/docs/basic-usage

import { onMounted, nextTick, watch } from 'vue'
import { inBrowser, useRoute } from 'vitepress'
import DefaultTheme from 'vitepress/theme'

export default {
    extends: DefaultTheme,

    setup() {
        if (inBrowser) {
            const route = useRoute()

            // Click on the tab with the given label text
            function showCodeWithLabel(labelText) {
                document.querySelectorAll(`.vp-code-group .tabs label`).forEach((label) => {
                    if (label.innerText === labelText) {
                        const input = document.getElementById(label.getAttribute('for'))

                        if (!input.checked) {
                            label.click()
                        }
                    }
                })
            }

            let preventScroll = false

            function bindClickEvents() {
                // Find all the labels
                const labels = document.querySelectorAll('.vp-code-group .tabs label')

                labels.forEach((label) => {
                    label.addEventListener('click', ($event) => {
                        const labelFor = label.getAttribute('for')
                        const initialRect = label.getBoundingClientRect()
                        const initialScrollY = window.scrollY

                        // Save the selected tab
                        localStorage.setItem('codeGroupTab', label.innerText)

                        // Show the selected tab on each code group
                        showCodeWithLabel(label.innerText)

                        // Use nextTick to ensure DOM is updated and scroll to the position
                        // so that the clicked label is at the same position as before
                        nextTick(() => {
                            if (preventScroll || !$event.isTrusted) {
                                return
                            }

                            // Find the new position of the label
                            const labelNew = document.querySelector(`label[for="${labelFor}"]`)
                            const newRect = labelNew.getBoundingClientRect()

                            // Calculate the difference in position relative to the document
                            const yDiff = newRect.top + window.scrollY - (initialRect.top + initialScrollY)

                            // Scroll to maintain the label's position
                            scrollToY(initialScrollY + yDiff)
                        })
                    })
                })
            }

            // Scroll to the given Y position without animation
            function scrollToY(y) {
                window.scrollTo({
                    top: y,
                    behavior: 'instant',
                })
            }

            // Select the given tab and scroll to the top of the page
            function selectTabAndScrollToTop(tab) {
                if (!tab) {
                    return
                }

                // Restore the last selected tab and scroll back to to top
                // Enable 'preventScroll' to avoid scrolling to all the tabs
                preventScroll = true
                showCodeWithLabel(tab)
                nextTick(() => {
                    preventScroll = false
                    scrollToY(0)
                })
            }

            // Bind click event on initial page and restore the last selected tab
            onMounted(() =>
                nextTick(() => {
                    bindClickEvents()
                    selectTabAndScrollToTop(localStorage.getItem('codeGroupTab'))
                }),
            )

            watch(
                () => route.path,
                () => {
                    nextTick(() => {
                        // Bind click event on new page
                        bindClickEvents()
                        selectTabAndScrollToTop(localStorage.getItem('codeGroupTab'))
                    })
                },
            )
        }
    },
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale theme Related to the theme
Projects
None yet
Development

No branches or pull requests

7 participants