diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts index 0e7ba37f..cdb9edbc 100644 --- a/docs/.vitepress/theme/index.ts +++ b/docs/.vitepress/theme/index.ts @@ -1,4 +1,4 @@ -import Theme from 'vitepress/theme' +import Theme from 'vitepress/theme/v2' import 'virtual:group-icons.css' import './styles.css' diff --git a/docs/.vitepress/theme/styles.css b/docs/.vitepress/theme/styles.css index 2635e80d..9f8b4c78 100644 --- a/docs/.vitepress/theme/styles.css +++ b/docs/.vitepress/theme/styles.css @@ -1,3 +1,5 @@ +/* TODO: Check this file and update if needed. */ + :root:where(:lang(fa)) { --vp-font-family-base: 'Vazirmatn', 'Inter', ui-sans-serif, system-ui, sans-serif, diff --git a/package.json b/package.json index 507c94fa..d39e174d 100644 --- a/package.json +++ b/package.json @@ -30,9 +30,17 @@ "types": "./theme.d.ts", "default": "./dist/client/theme-default/index.js" }, + "./theme/v2": { + "types": "./theme/v2.d.ts", + "default": "./dist/client/theme-default-v2/index.js" + }, "./theme-without-fonts": { "types": "./theme-without-fonts.d.ts", "default": "./dist/client/theme-default/without-fonts.js" + }, + "./theme-without-fonts/v2": { + "types": "./theme/v2.d.ts", + "default": "./dist/client/theme-default-v2/without-fonts.js" } }, "main": "dist/node/index.js", diff --git a/src/client/theme-default-v2/Layout.vue b/src/client/theme-default-v2/Layout.vue new file mode 100644 index 00000000..2af45c66 --- /dev/null +++ b/src/client/theme-default-v2/Layout.vue @@ -0,0 +1,96 @@ + + + + + diff --git a/src/client/theme-default-v2/NotFound.vue b/src/client/theme-default-v2/NotFound.vue new file mode 100644 index 00000000..f65d3a6d --- /dev/null +++ b/src/client/theme-default-v2/NotFound.vue @@ -0,0 +1,96 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPAlgoliaSearchBox.vue b/src/client/theme-default-v2/components/VPAlgoliaSearchBox.vue new file mode 100644 index 00000000..02baf5b7 --- /dev/null +++ b/src/client/theme-default-v2/components/VPAlgoliaSearchBox.vue @@ -0,0 +1,92 @@ + + + diff --git a/src/client/theme-default-v2/components/VPBackdrop.vue b/src/client/theme-default-v2/components/VPBackdrop.vue new file mode 100644 index 00000000..8b0757d4 --- /dev/null +++ b/src/client/theme-default-v2/components/VPBackdrop.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPBadge.vue b/src/client/theme-default-v2/components/VPBadge.vue new file mode 100644 index 00000000..1d5c1678 --- /dev/null +++ b/src/client/theme-default-v2/components/VPBadge.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPButton.vue b/src/client/theme-default-v2/components/VPButton.vue new file mode 100644 index 00000000..d0a5de70 --- /dev/null +++ b/src/client/theme-default-v2/components/VPButton.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPCarbonAds.vue b/src/client/theme-default-v2/components/VPCarbonAds.vue new file mode 100644 index 00000000..a233d1ef --- /dev/null +++ b/src/client/theme-default-v2/components/VPCarbonAds.vue @@ -0,0 +1,109 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPContent.vue b/src/client/theme-default-v2/components/VPContent.vue new file mode 100644 index 00000000..8b033785 --- /dev/null +++ b/src/client/theme-default-v2/components/VPContent.vue @@ -0,0 +1,95 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPDoc.vue b/src/client/theme-default-v2/components/VPDoc.vue new file mode 100644 index 00000000..4ac18bd9 --- /dev/null +++ b/src/client/theme-default-v2/components/VPDoc.vue @@ -0,0 +1,194 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPDocAside.vue b/src/client/theme-default-v2/components/VPDocAside.vue new file mode 100644 index 00000000..314e8a4b --- /dev/null +++ b/src/client/theme-default-v2/components/VPDocAside.vue @@ -0,0 +1,46 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPDocAsideCarbonAds.vue b/src/client/theme-default-v2/components/VPDocAsideCarbonAds.vue new file mode 100644 index 00000000..d10598dd --- /dev/null +++ b/src/client/theme-default-v2/components/VPDocAsideCarbonAds.vue @@ -0,0 +1,18 @@ + + + diff --git a/src/client/theme-default-v2/components/VPDocAsideOutline.vue b/src/client/theme-default-v2/components/VPDocAsideOutline.vue new file mode 100644 index 00000000..efaadc09 --- /dev/null +++ b/src/client/theme-default-v2/components/VPDocAsideOutline.vue @@ -0,0 +1,80 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPDocAsideSponsors.vue b/src/client/theme-default-v2/components/VPDocAsideSponsors.vue new file mode 100644 index 00000000..9e023dbc --- /dev/null +++ b/src/client/theme-default-v2/components/VPDocAsideSponsors.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/client/theme-default-v2/components/VPDocFooter.vue b/src/client/theme-default-v2/components/VPDocFooter.vue new file mode 100644 index 00000000..0b6ff2a8 --- /dev/null +++ b/src/client/theme-default-v2/components/VPDocFooter.vue @@ -0,0 +1,167 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPDocFooterLastUpdated.vue b/src/client/theme-default-v2/components/VPDocFooterLastUpdated.vue new file mode 100644 index 00000000..5ec3cfeb --- /dev/null +++ b/src/client/theme-default-v2/components/VPDocFooterLastUpdated.vue @@ -0,0 +1,50 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPDocOutlineItem.vue b/src/client/theme-default-v2/components/VPDocOutlineItem.vue new file mode 100644 index 00000000..c945fc21 --- /dev/null +++ b/src/client/theme-default-v2/components/VPDocOutlineItem.vue @@ -0,0 +1,61 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPFeature.vue b/src/client/theme-default-v2/components/VPFeature.vue new file mode 100644 index 00000000..ff36fe97 --- /dev/null +++ b/src/client/theme-default-v2/components/VPFeature.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPFeatures.vue b/src/client/theme-default-v2/components/VPFeatures.vue new file mode 100644 index 00000000..1868aac4 --- /dev/null +++ b/src/client/theme-default-v2/components/VPFeatures.vue @@ -0,0 +1,121 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPFlyout.vue b/src/client/theme-default-v2/components/VPFlyout.vue new file mode 100644 index 00000000..c05c579c --- /dev/null +++ b/src/client/theme-default-v2/components/VPFlyout.vue @@ -0,0 +1,137 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPFooter.vue b/src/client/theme-default-v2/components/VPFooter.vue new file mode 100644 index 00000000..63638044 --- /dev/null +++ b/src/client/theme-default-v2/components/VPFooter.vue @@ -0,0 +1,60 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPHero.vue b/src/client/theme-default-v2/components/VPHero.vue new file mode 100644 index 00000000..4e1e2e9b --- /dev/null +++ b/src/client/theme-default-v2/components/VPHero.vue @@ -0,0 +1,346 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPHome.vue b/src/client/theme-default-v2/components/VPHome.vue new file mode 100644 index 00000000..0467e5f7 --- /dev/null +++ b/src/client/theme-default-v2/components/VPHome.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPHomeContent.vue b/src/client/theme-default-v2/components/VPHomeContent.vue new file mode 100644 index 00000000..3e026235 --- /dev/null +++ b/src/client/theme-default-v2/components/VPHomeContent.vue @@ -0,0 +1,55 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPHomeFeatures.vue b/src/client/theme-default-v2/components/VPHomeFeatures.vue new file mode 100644 index 00000000..ed4565cf --- /dev/null +++ b/src/client/theme-default-v2/components/VPHomeFeatures.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/client/theme-default-v2/components/VPHomeHero.vue b/src/client/theme-default-v2/components/VPHomeHero.vue new file mode 100644 index 00000000..972a1f61 --- /dev/null +++ b/src/client/theme-default-v2/components/VPHomeHero.vue @@ -0,0 +1,24 @@ + + + diff --git a/src/client/theme-default-v2/components/VPHomeSponsors.vue b/src/client/theme-default-v2/components/VPHomeSponsors.vue new file mode 100644 index 00000000..d4eaacd2 --- /dev/null +++ b/src/client/theme-default-v2/components/VPHomeSponsors.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPImage.vue b/src/client/theme-default-v2/components/VPImage.vue new file mode 100644 index 00000000..79e2c6ae --- /dev/null +++ b/src/client/theme-default-v2/components/VPImage.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPLink.vue b/src/client/theme-default-v2/components/VPLink.vue new file mode 100644 index 00000000..f57e3328 --- /dev/null +++ b/src/client/theme-default-v2/components/VPLink.vue @@ -0,0 +1,37 @@ + + + diff --git a/src/client/theme-default-v2/components/VPLocalNav.vue b/src/client/theme-default-v2/components/VPLocalNav.vue new file mode 100644 index 00000000..b950205a --- /dev/null +++ b/src/client/theme-default-v2/components/VPLocalNav.vue @@ -0,0 +1,150 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPLocalNavOutlineDropdown.vue b/src/client/theme-default-v2/components/VPLocalNavOutlineDropdown.vue new file mode 100644 index 00000000..cf842baa --- /dev/null +++ b/src/client/theme-default-v2/components/VPLocalNavOutlineDropdown.vue @@ -0,0 +1,192 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPLocalSearchBox.vue b/src/client/theme-default-v2/components/VPLocalSearchBox.vue new file mode 100644 index 00000000..825a22b5 --- /dev/null +++ b/src/client/theme-default-v2/components/VPLocalSearchBox.vue @@ -0,0 +1,877 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPMenu.vue b/src/client/theme-default-v2/components/VPMenu.vue new file mode 100644 index 00000000..91ebb404 --- /dev/null +++ b/src/client/theme-default-v2/components/VPMenu.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPMenuGroup.vue b/src/client/theme-default-v2/components/VPMenuGroup.vue new file mode 100644 index 00000000..7d12eb75 --- /dev/null +++ b/src/client/theme-default-v2/components/VPMenuGroup.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPMenuLink.vue b/src/client/theme-default-v2/components/VPMenuLink.vue new file mode 100644 index 00000000..0a708186 --- /dev/null +++ b/src/client/theme-default-v2/components/VPMenuLink.vue @@ -0,0 +1,63 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNav.vue b/src/client/theme-default-v2/components/VPNav.vue new file mode 100644 index 00000000..ccbe62f6 --- /dev/null +++ b/src/client/theme-default-v2/components/VPNav.vue @@ -0,0 +1,55 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavBar.vue b/src/client/theme-default-v2/components/VPNavBar.vue new file mode 100644 index 00000000..026d45e6 --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavBar.vue @@ -0,0 +1,166 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavBarAppearance.vue b/src/client/theme-default-v2/components/VPNavBarAppearance.vue new file mode 100644 index 00000000..523e5b6b --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavBarAppearance.vue @@ -0,0 +1,32 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavBarExtra.vue b/src/client/theme-default-v2/components/VPNavBarExtra.vue new file mode 100644 index 00000000..988a814a --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavBarExtra.vue @@ -0,0 +1,108 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavBarHamburger.vue b/src/client/theme-default-v2/components/VPNavBarHamburger.vue new file mode 100644 index 00000000..dabc1bd5 --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavBarHamburger.vue @@ -0,0 +1,82 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavBarMenu.vue b/src/client/theme-default-v2/components/VPNavBarMenu.vue new file mode 100644 index 00000000..c4d741b9 --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavBarMenu.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavBarMenuGroup.vue b/src/client/theme-default-v2/components/VPNavBarMenuGroup.vue new file mode 100644 index 00000000..12e8cf6f --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavBarMenuGroup.vue @@ -0,0 +1,42 @@ + + + diff --git a/src/client/theme-default-v2/components/VPNavBarMenuLink.vue b/src/client/theme-default-v2/components/VPNavBarMenuLink.vue new file mode 100644 index 00000000..6f504791 --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavBarMenuLink.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavBarSearch.vue b/src/client/theme-default-v2/components/VPNavBarSearch.vue new file mode 100644 index 00000000..e04afe39 --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavBarSearch.vue @@ -0,0 +1,160 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavBarSearchButton.vue b/src/client/theme-default-v2/components/VPNavBarSearchButton.vue new file mode 100644 index 00000000..5830f487 --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavBarSearchButton.vue @@ -0,0 +1,172 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavBarSocialLinks.vue b/src/client/theme-default-v2/components/VPNavBarSocialLinks.vue new file mode 100644 index 00000000..1adc8037 --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavBarSocialLinks.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavBarTitle.vue b/src/client/theme-default-v2/components/VPNavBarTitle.vue new file mode 100644 index 00000000..3f0c1d37 --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavBarTitle.vue @@ -0,0 +1,74 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavBarTranslations.vue b/src/client/theme-default-v2/components/VPNavBarTranslations.vue new file mode 100644 index 00000000..a92aad8c --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavBarTranslations.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavScreen.vue b/src/client/theme-default-v2/components/VPNavScreen.vue new file mode 100644 index 00000000..d9d3b776 --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavScreen.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavScreenActions.vue b/src/client/theme-default-v2/components/VPNavScreenActions.vue new file mode 100644 index 00000000..abb8811b --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavScreenActions.vue @@ -0,0 +1,125 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavScreenAppearance.vue b/src/client/theme-default-v2/components/VPNavScreenAppearance.vue new file mode 100644 index 00000000..4f7d2640 --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavScreenAppearance.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavScreenMenu.vue b/src/client/theme-default-v2/components/VPNavScreenMenu.vue new file mode 100644 index 00000000..9c248ebd --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavScreenMenu.vue @@ -0,0 +1,26 @@ + + + diff --git a/src/client/theme-default-v2/components/VPNavScreenMenuGroup.vue b/src/client/theme-default-v2/components/VPNavScreenMenuGroup.vue new file mode 100644 index 00000000..d2b6e50d --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavScreenMenuGroup.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavScreenMenuGroupLink.vue b/src/client/theme-default-v2/components/VPNavScreenMenuGroupLink.vue new file mode 100644 index 00000000..6481c391 --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavScreenMenuGroupLink.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavScreenMenuGroupSection.vue b/src/client/theme-default-v2/components/VPNavScreenMenuGroupSection.vue new file mode 100644 index 00000000..f401bd3b --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavScreenMenuGroupSection.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavScreenMenuLink.vue b/src/client/theme-default-v2/components/VPNavScreenMenuLink.vue new file mode 100644 index 00000000..38beb9c2 --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavScreenMenuLink.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPNavScreenSocialLinks.vue b/src/client/theme-default-v2/components/VPNavScreenSocialLinks.vue new file mode 100644 index 00000000..f5311024 --- /dev/null +++ b/src/client/theme-default-v2/components/VPNavScreenSocialLinks.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/client/theme-default-v2/components/VPPage.vue b/src/client/theme-default-v2/components/VPPage.vue new file mode 100644 index 00000000..8e735fd0 --- /dev/null +++ b/src/client/theme-default-v2/components/VPPage.vue @@ -0,0 +1,7 @@ + diff --git a/src/client/theme-default-v2/components/VPSidebar.vue b/src/client/theme-default-v2/components/VPSidebar.vue new file mode 100644 index 00000000..b27d8028 --- /dev/null +++ b/src/client/theme-default-v2/components/VPSidebar.vue @@ -0,0 +1,136 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPSidebarGroup.vue b/src/client/theme-default-v2/components/VPSidebarGroup.vue new file mode 100644 index 00000000..0c200174 --- /dev/null +++ b/src/client/theme-default-v2/components/VPSidebarGroup.vue @@ -0,0 +1,56 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPSidebarItem.vue b/src/client/theme-default-v2/components/VPSidebarItem.vue new file mode 100644 index 00000000..d71d1062 --- /dev/null +++ b/src/client/theme-default-v2/components/VPSidebarItem.vue @@ -0,0 +1,251 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPSkipLink.vue b/src/client/theme-default-v2/components/VPSkipLink.vue new file mode 100644 index 00000000..ad56622d --- /dev/null +++ b/src/client/theme-default-v2/components/VPSkipLink.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPSocialLink.vue b/src/client/theme-default-v2/components/VPSocialLink.vue new file mode 100644 index 00000000..a9059a28 --- /dev/null +++ b/src/client/theme-default-v2/components/VPSocialLink.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPSocialLinks.vue b/src/client/theme-default-v2/components/VPSocialLinks.vue new file mode 100644 index 00000000..d10b34da --- /dev/null +++ b/src/client/theme-default-v2/components/VPSocialLinks.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPSponsors.vue b/src/client/theme-default-v2/components/VPSponsors.vue new file mode 100644 index 00000000..e7e739dc --- /dev/null +++ b/src/client/theme-default-v2/components/VPSponsors.vue @@ -0,0 +1,48 @@ + + + diff --git a/src/client/theme-default-v2/components/VPSponsorsGrid.vue b/src/client/theme-default-v2/components/VPSponsorsGrid.vue new file mode 100644 index 00000000..29312c55 --- /dev/null +++ b/src/client/theme-default-v2/components/VPSponsorsGrid.vue @@ -0,0 +1,47 @@ + + + diff --git a/src/client/theme-default-v2/components/VPSwitch.vue b/src/client/theme-default-v2/components/VPSwitch.vue new file mode 100644 index 00000000..36af1cba --- /dev/null +++ b/src/client/theme-default-v2/components/VPSwitch.vue @@ -0,0 +1,63 @@ + + + diff --git a/src/client/theme-default-v2/components/VPSwitchAppearance.vue b/src/client/theme-default-v2/components/VPSwitchAppearance.vue new file mode 100644 index 00000000..f42e249f --- /dev/null +++ b/src/client/theme-default-v2/components/VPSwitchAppearance.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPTeamMembers.vue b/src/client/theme-default-v2/components/VPTeamMembers.vue new file mode 100644 index 00000000..0337eb5a --- /dev/null +++ b/src/client/theme-default-v2/components/VPTeamMembers.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPTeamMembersItem.vue b/src/client/theme-default-v2/components/VPTeamMembersItem.vue new file mode 100644 index 00000000..a4dc411b --- /dev/null +++ b/src/client/theme-default-v2/components/VPTeamMembersItem.vue @@ -0,0 +1,225 @@ + + + + + diff --git a/src/client/theme-default-v2/components/VPTeamPage.vue b/src/client/theme-default-v2/components/VPTeamPage.vue new file mode 100644 index 00000000..71d9bdb5 --- /dev/null +++ b/src/client/theme-default-v2/components/VPTeamPage.vue @@ -0,0 +1,58 @@ + + + diff --git a/src/client/theme-default-v2/components/VPTeamPageSection.vue b/src/client/theme-default-v2/components/VPTeamPageSection.vue new file mode 100644 index 00000000..2bb52ab9 --- /dev/null +++ b/src/client/theme-default-v2/components/VPTeamPageSection.vue @@ -0,0 +1,77 @@ + + + diff --git a/src/client/theme-default-v2/components/VPTeamPageTitle.vue b/src/client/theme-default-v2/components/VPTeamPageTitle.vue new file mode 100644 index 00000000..9751a188 --- /dev/null +++ b/src/client/theme-default-v2/components/VPTeamPageTitle.vue @@ -0,0 +1,63 @@ + + + diff --git a/src/client/theme-default-v2/components/icons/VPIconAlignJustify.vue b/src/client/theme-default-v2/components/icons/VPIconAlignJustify.vue new file mode 100644 index 00000000..653dab13 --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconAlignJustify.vue @@ -0,0 +1,8 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconAlignLeft.vue b/src/client/theme-default-v2/components/icons/VPIconAlignLeft.vue new file mode 100644 index 00000000..8dc84eae --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconAlignLeft.vue @@ -0,0 +1,8 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconAlignRight.vue b/src/client/theme-default-v2/components/icons/VPIconAlignRight.vue new file mode 100644 index 00000000..16cbb3c7 --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconAlignRight.vue @@ -0,0 +1,8 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconArrowLeft.vue b/src/client/theme-default-v2/components/icons/VPIconArrowLeft.vue new file mode 100644 index 00000000..3f65b866 --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconArrowLeft.vue @@ -0,0 +1,7 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconArrowRight.vue b/src/client/theme-default-v2/components/icons/VPIconArrowRight.vue new file mode 100644 index 00000000..ed89263f --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconArrowRight.vue @@ -0,0 +1,7 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconChevronDown.vue b/src/client/theme-default-v2/components/icons/VPIconChevronDown.vue new file mode 100644 index 00000000..d72f4ee8 --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconChevronDown.vue @@ -0,0 +1,5 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconChevronLeft.vue b/src/client/theme-default-v2/components/icons/VPIconChevronLeft.vue new file mode 100644 index 00000000..013eb7fd --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconChevronLeft.vue @@ -0,0 +1,5 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconChevronRight.vue b/src/client/theme-default-v2/components/icons/VPIconChevronRight.vue new file mode 100644 index 00000000..cf72418f --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconChevronRight.vue @@ -0,0 +1,5 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconChevronUp.vue b/src/client/theme-default-v2/components/icons/VPIconChevronUp.vue new file mode 100644 index 00000000..0b6a873e --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconChevronUp.vue @@ -0,0 +1,5 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconEdit.vue b/src/client/theme-default-v2/components/icons/VPIconEdit.vue new file mode 100644 index 00000000..f30a62dd --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconEdit.vue @@ -0,0 +1,6 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconHeart.vue b/src/client/theme-default-v2/components/icons/VPIconHeart.vue new file mode 100644 index 00000000..d408828f --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconHeart.vue @@ -0,0 +1,5 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconLanguages.vue b/src/client/theme-default-v2/components/icons/VPIconLanguages.vue new file mode 100644 index 00000000..71a728fc --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconLanguages.vue @@ -0,0 +1,9 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconMinus.vue b/src/client/theme-default-v2/components/icons/VPIconMinus.vue new file mode 100644 index 00000000..e0229195 --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconMinus.vue @@ -0,0 +1,5 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconMinusSquare.vue b/src/client/theme-default-v2/components/icons/VPIconMinusSquare.vue new file mode 100644 index 00000000..266ae3da --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconMinusSquare.vue @@ -0,0 +1,6 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconMoon.vue b/src/client/theme-default-v2/components/icons/VPIconMoon.vue new file mode 100644 index 00000000..a9b205c6 --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconMoon.vue @@ -0,0 +1,5 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconMoreHorizontal.vue b/src/client/theme-default-v2/components/icons/VPIconMoreHorizontal.vue new file mode 100644 index 00000000..6fa7fca2 --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconMoreHorizontal.vue @@ -0,0 +1,7 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconPlus.vue b/src/client/theme-default-v2/components/icons/VPIconPlus.vue new file mode 100644 index 00000000..74d9f695 --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconPlus.vue @@ -0,0 +1,5 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconPlusSquare.vue b/src/client/theme-default-v2/components/icons/VPIconPlusSquare.vue new file mode 100644 index 00000000..88e5b5cf --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconPlusSquare.vue @@ -0,0 +1,6 @@ + diff --git a/src/client/theme-default-v2/components/icons/VPIconSun.vue b/src/client/theme-default-v2/components/icons/VPIconSun.vue new file mode 100644 index 00000000..8ecb25ba --- /dev/null +++ b/src/client/theme-default-v2/components/icons/VPIconSun.vue @@ -0,0 +1,13 @@ + diff --git a/src/client/theme-default-v2/composables/aside.ts b/src/client/theme-default-v2/composables/aside.ts new file mode 100644 index 00000000..50f20626 --- /dev/null +++ b/src/client/theme-default-v2/composables/aside.ts @@ -0,0 +1,21 @@ +import { useMediaQuery } from '@vueuse/core' +import { computed } from 'vue' +import { useLayout } from './layout' + +export function useAside() { + const { hasSidebar } = useLayout() + const is960 = useMediaQuery('(min-width: 960px)') + const is1280 = useMediaQuery('(min-width: 1280px)') + + const isAsideEnabled = computed(() => { + if (!is1280.value && !is960.value) { + return false + } + + return hasSidebar.value ? is1280.value : is960.value + }) + + return { + isAsideEnabled + } +} diff --git a/src/client/theme-default-v2/composables/data.ts b/src/client/theme-default-v2/composables/data.ts new file mode 100644 index 00000000..513b2c53 --- /dev/null +++ b/src/client/theme-default-v2/composables/data.ts @@ -0,0 +1,4 @@ +import { useData as useData$ } from 'vitepress' +import type { DefaultTheme } from 'vitepress/theme' + +export const useData: typeof useData$ = useData$ diff --git a/src/client/theme-default-v2/composables/edit-link.ts b/src/client/theme-default-v2/composables/edit-link.ts new file mode 100644 index 00000000..75fecc03 --- /dev/null +++ b/src/client/theme-default-v2/composables/edit-link.ts @@ -0,0 +1,18 @@ +import { computed } from 'vue' +import { useData } from './data' + +export function useEditLink() { + const { theme, page } = useData() + + return computed(() => { + const { text = 'Edit this page', pattern = '' } = theme.value.editLink || {} + let url: string + if (typeof pattern === 'function') { + url = pattern(page.value) + } else { + url = pattern.replace(/:path/g, page.value.filePath) + } + + return { url, text } + }) +} diff --git a/src/client/theme-default-v2/composables/flyout.ts b/src/client/theme-default-v2/composables/flyout.ts new file mode 100644 index 00000000..9b10a704 --- /dev/null +++ b/src/client/theme-default-v2/composables/flyout.ts @@ -0,0 +1,59 @@ +import { onUnmounted, readonly, type Ref, ref, watch } from 'vue' +import { inBrowser } from '../../shared' + +interface UseFlyoutOptions { + el: Ref + onFocus?(): void + onBlur?(): void +} + +export const focusedElement = ref() + +let active = false +let listeners = 0 + +export function useFlyout(options: UseFlyoutOptions) { + const focus = ref(false) + + if (inBrowser) { + !active && activateFocusTracking() + + listeners++ + + const unwatch = watch(focusedElement, (el) => { + if (el === options.el.value || options.el.value?.contains(el!)) { + focus.value = true + options.onFocus?.() + } else { + focus.value = false + options.onBlur?.() + } + }) + + onUnmounted(() => { + unwatch() + + listeners-- + + if (!listeners) { + deactivateFocusTracking() + } + }) + } + + return readonly(focus) +} + +function activateFocusTracking() { + document.addEventListener('focusin', handleFocusIn) + active = true + focusedElement.value = document.activeElement as HTMLElement +} + +function deactivateFocusTracking() { + document.removeEventListener('focusin', handleFocusIn) +} + +function handleFocusIn() { + focusedElement.value = document.activeElement as HTMLElement +} diff --git a/src/client/theme-default-v2/composables/langs.ts b/src/client/theme-default-v2/composables/langs.ts new file mode 100644 index 00000000..7d5a2e4c --- /dev/null +++ b/src/client/theme-default-v2/composables/langs.ts @@ -0,0 +1,50 @@ +import { computed } from 'vue' +import { ensureStartingSlash } from '../support/utils' +import { useData } from './data' + +export function useLangs({ correspondingLink = false } = {}) { + const { site, localeIndex, page, theme, hash } = useData() + const currentLang = computed(() => ({ + label: site.value.locales[localeIndex.value]?.label, + link: + site.value.locales[localeIndex.value]?.link || + (localeIndex.value === 'root' ? '/' : `/${localeIndex.value}/`) + })) + + const localeLinks = computed(() => + Object.entries(site.value.locales).flatMap(([key, value]) => + currentLang.value.label === value.label + ? [] + : { + text: value.label, + link: + normalizeLink( + value.link || (key === 'root' ? '/' : `/${key}/`), + theme.value.i18nRouting !== false && correspondingLink, + page.value.relativePath.slice( + currentLang.value.link.length - 1 + ), + !site.value.cleanUrls + ) + hash.value + } + ) + ) + + return { localeLinks, currentLang } +} + +function normalizeLink( + link: string, + addPath: boolean, + path: string, + addExt: boolean +) { + return addPath + ? link.replace(/\/$/, '') + + ensureStartingSlash( + path + .replace(/(^|\/)index\.md$/, '$1') + .replace(/\.md$/, addExt ? '.html' : '') + ) + : link +} diff --git a/src/client/theme-default-v2/composables/layout.ts b/src/client/theme-default-v2/composables/layout.ts new file mode 100644 index 00000000..e0484cf2 --- /dev/null +++ b/src/client/theme-default-v2/composables/layout.ts @@ -0,0 +1,118 @@ +import { inBrowser, onContentUpdated, useRoute } from 'vitepress' +import type { DefaultTheme, useLayout as expected } from 'vitepress/theme' +import { + computed, + shallowReadonly, + shallowRef, + watch, + type ComputedRef, + type InjectionKey +} from 'vue' +import { getSidebar, getSidebarGroups } from '../support/sidebar' +import { useData } from './data' +import { getHeaders } from './outline' +import { useCloseSidebarOnEscape } from './sidebar' + +const headers = shallowRef([]) +const sidebar = shallowRef([]) + +const is960 = shallowRef(false) + +export function useLayout(): ReturnType { + const { frontmatter, theme } = useData() + + const isHome = computed(() => { + return !!(frontmatter.value.isHome ?? frontmatter.value.layout === 'home') + }) + + const hasSidebar = computed(() => { + return ( + frontmatter.value.sidebar !== false && + sidebar.value.length > 0 && + !isHome.value + ) + }) + + const isSidebarEnabled = computed(() => hasSidebar.value && is960.value) + + const sidebarGroups = computed(() => { + return hasSidebar.value ? getSidebarGroups(sidebar.value) : [] + }) + + const hasAside = computed(() => { + if (isHome.value) return false + if (frontmatter.value.aside != null) return !!frontmatter.value.aside + return theme.value.aside !== false + }) + + const leftAside = computed(() => { + if (!hasAside.value) return false + return frontmatter.value.aside == null + ? theme.value.aside === 'left' + : frontmatter.value.aside === 'left' + }) + + const hasLocalNav = computed(() => { + return headers.value.length > 0 + }) + + return { + isHome, + sidebar: shallowReadonly(sidebar), + sidebarGroups, + hasSidebar, + isSidebarEnabled, + hasAside, + leftAside, + headers: shallowReadonly(headers), + hasLocalNav + } +} + +interface RegisterWatchersOptions { + closeSidebar: () => void +} + +export function registerWatchers({ closeSidebar }: RegisterWatchersOptions) { + const { frontmatter, page, theme } = useData() + + watch( + () => [page.value.relativePath, theme.value.sidebar] as const, + ([relativePath, sidebarConfig]) => { + const newSidebar = sidebarConfig + ? getSidebar(sidebarConfig, relativePath) + : [] + if (JSON.stringify(newSidebar) !== JSON.stringify(sidebar.value)) { + sidebar.value = newSidebar + } + }, + { immediate: true, deep: true, flush: 'sync' } + ) + + onContentUpdated(() => { + headers.value = getHeaders(frontmatter.value.outline ?? theme.value.outline) + }) + + if (inBrowser) { + is960.value = window.innerWidth >= 960 + window.addEventListener( + 'resize', + () => { + is960.value = window.innerWidth >= 960 + }, + { passive: true } + ) + } + + const route = useRoute() + watch(() => route.path, closeSidebar) + + useCloseSidebarOnEscape(closeSidebar) +} + +export interface LayoutInfo { + heroImageSlotExists: ComputedRef +} + +export const layoutInfoInjectionKey: InjectionKey = + Symbol('layout-info') diff --git a/src/client/theme-default-v2/composables/nav.ts b/src/client/theme-default-v2/composables/nav.ts new file mode 100644 index 00000000..370c9e08 --- /dev/null +++ b/src/client/theme-default-v2/composables/nav.ts @@ -0,0 +1,43 @@ +import { useRoute } from 'vitepress' +import { ref, watch, type InjectionKey } from 'vue' + +export function useNav() { + const isScreenOpen = ref(false) + + function openScreen() { + isScreenOpen.value = true + window.addEventListener('resize', closeScreenOnTabletWindow) + } + + function closeScreen() { + isScreenOpen.value = false + window.removeEventListener('resize', closeScreenOnTabletWindow) + } + + function toggleScreen() { + isScreenOpen.value ? closeScreen() : openScreen() + } + + /** + * Close screen when the user resizes the window wider than tablet size. + */ + function closeScreenOnTabletWindow() { + window.outerWidth >= 768 && closeScreen() + } + + const route = useRoute() + watch(() => route.path, closeScreen) + + return { + isScreenOpen, + openScreen, + closeScreen, + toggleScreen + } +} + +export interface NavExposedMethods { + closeScreen: () => void +} + +export const navInjectionKey: InjectionKey = Symbol('nav') diff --git a/src/client/theme-default-v2/composables/outline.ts b/src/client/theme-default-v2/composables/outline.ts new file mode 100644 index 00000000..d9eda9c1 --- /dev/null +++ b/src/client/theme-default-v2/composables/outline.ts @@ -0,0 +1,232 @@ +import { getScrollOffset } from 'vitepress' +import type { DefaultTheme } from 'vitepress/theme' +import { onMounted, onUnmounted, onUpdated, type Ref } from 'vue' +import { throttleAndDebounce } from '../support/utils' +import { useAside } from './aside' + +const ignoreRE = /\b(?:VPBadge|header-anchor|footnote-ref|ignore-header)\b/ + +// cached list of anchor elements from resolveHeaders +const resolvedHeaders: { element: HTMLHeadElement; link: string }[] = [] + +export function resolveTitle(theme: DefaultTheme.Config): string { + return ( + (typeof theme.outline === 'object' && + !Array.isArray(theme.outline) && + theme.outline.label) || + theme.outlineTitle || + 'On this page' + ) +} + +export function getHeaders( + range: DefaultTheme.Config['outline'] +): DefaultTheme.OutlineItem[] { + const headers = [ + ...document.querySelectorAll('.VPDoc :where(h1,h2,h3,h4,h5,h6)') + ] + .filter((el) => el.id && el.hasChildNodes()) + .map((el) => { + const level = Number(el.tagName[1]) + return { + element: el as HTMLHeadElement, + title: serializeHeader(el), + link: '#' + el.id, + level + } + }) + + return resolveHeaders(headers, range) +} + +function serializeHeader(h: Element): string { + let ret = '' + for (const node of h.childNodes) { + if (node.nodeType === 1) { + if (ignoreRE.test((node as Element).className)) continue + ret += node.textContent + } else if (node.nodeType === 3) { + ret += node.textContent + } + } + return ret.trim() +} + +export function resolveHeaders( + headers: DefaultTheme.OutlineItem[], + range?: DefaultTheme.Config['outline'] +): DefaultTheme.OutlineItem[] { + if (range === false) { + return [] + } + + const levelsRange = + (typeof range === 'object' && !Array.isArray(range) + ? range.level + : range) || 2 + + const [high, low]: [number, number] = + typeof levelsRange === 'number' + ? [levelsRange, levelsRange] + : levelsRange === 'deep' + ? [2, 6] + : levelsRange + + return buildTree(headers, high, low) +} + +export function useActiveAnchor( + container: Ref, + marker: Ref +): void { + const { isAsideEnabled } = useAside() + + const onScroll = throttleAndDebounce(setActiveLink, 100) + + let prevActiveLink: HTMLAnchorElement | null = null + + onMounted(() => { + requestAnimationFrame(setActiveLink) + window.addEventListener('scroll', onScroll) + }) + + onUpdated(() => { + // sidebar update means a route change + activateLink(location.hash) + }) + + onUnmounted(() => { + window.removeEventListener('scroll', onScroll) + }) + + function setActiveLink() { + if (!isAsideEnabled.value) { + return + } + + const scrollY = window.scrollY + const innerHeight = window.innerHeight + const offsetHeight = document.body.offsetHeight + const isBottom = Math.abs(scrollY + innerHeight - offsetHeight) < 1 + + // resolvedHeaders may be repositioned, hidden or fix positioned + const headers = resolvedHeaders + .map(({ element, link }) => ({ + link, + top: getAbsoluteTop(element) + })) + .filter(({ top }) => !Number.isNaN(top)) + .sort((a, b) => a.top - b.top) + + // no headers available for active link + if (!headers.length) { + activateLink(null) + return + } + + // page top + if (scrollY < 1) { + activateLink(null) + return + } + + // page bottom - highlight last link + if (isBottom) { + activateLink(headers[headers.length - 1].link) + return + } + + // find the last header above the top of viewport + let activeLink: string | null = null + for (const { link, top } of headers) { + if (top > scrollY + getScrollOffset() + 4) { + break + } + activeLink = link + } + activateLink(activeLink) + } + + function activateLink(hash: string | null) { + if (prevActiveLink) { + prevActiveLink.classList.remove('active') + } + + if (hash == null) { + prevActiveLink = null + } else { + prevActiveLink = container.value.querySelector( + `a[href="${decodeURIComponent(hash)}"]` + ) + } + + const activeLink = prevActiveLink + + if (activeLink) { + activeLink.classList.add('active') + marker.value.style.top = activeLink.offsetTop + 39 + 'px' + marker.value.style.opacity = '1' + } else { + marker.value.style.top = '33px' + marker.value.style.opacity = '0' + } + } +} + +function getAbsoluteTop(element: HTMLElement): number { + let offsetTop = 0 + while (element !== document.body) { + if (element === null) { + // child element is: + // - not attached to the DOM (display: none) + // - set to fixed position (not scrollable) + // - body or html element (null offsetParent) + return NaN + } + offsetTop += element.offsetTop + element = element.offsetParent as HTMLElement + } + return offsetTop +} + +function buildTree( + data: DefaultTheme.OutlineItem[], + min: number, + max: number +): DefaultTheme.OutlineItem[] { + resolvedHeaders.length = 0 + + const result: DefaultTheme.OutlineItem[] = [] + const stack: ( + | DefaultTheme.OutlineItem + | { level: number; shouldIgnore: true } + )[] = [] + + data.forEach((item) => { + const node = { ...item, children: [] } + let parent = stack[stack.length - 1] + + while (parent && parent.level >= node.level) { + stack.pop() + parent = stack[stack.length - 1] + } + + if ( + node.element.classList.contains('ignore-header') || + (parent && 'shouldIgnore' in parent) + ) { + stack.push({ level: node.level, shouldIgnore: true }) + return + } + + if (node.level > max || node.level < min) return + resolvedHeaders.push({ element: node.element, link: node.link }) + + if (parent) parent.children!.push(node) + else result.push(node) + + stack.push(node) + }) + + return result +} diff --git a/src/client/theme-default-v2/composables/prev-next.ts b/src/client/theme-default-v2/composables/prev-next.ts new file mode 100644 index 00000000..494242a6 --- /dev/null +++ b/src/client/theme-default-v2/composables/prev-next.ts @@ -0,0 +1,74 @@ +import { computed } from 'vue' +import { isActive } from '../../shared' +import { getFlatSideBarLinks, getSidebar } from '../support/sidebar' +import { useData } from './data' + +export function usePrevNext() { + const { page, theme, frontmatter } = useData() + + return computed(() => { + const sidebar = getSidebar(theme.value.sidebar, page.value.relativePath) + const links = getFlatSideBarLinks(sidebar) + + // ignore inner-page links with hashes + const candidates = uniqBy(links, (link) => link.link.replace(/[?#].*$/, '')) + + const index = candidates.findIndex((link) => { + return isActive(page.value.relativePath, link.link) + }) + + const hidePrev = + (theme.value.docFooter?.prev === false && !frontmatter.value.prev) || + frontmatter.value.prev === false + + const hideNext = + (theme.value.docFooter?.next === false && !frontmatter.value.next) || + frontmatter.value.next === false + + return { + prev: hidePrev + ? undefined + : { + text: + (typeof frontmatter.value.prev === 'string' + ? frontmatter.value.prev + : typeof frontmatter.value.prev === 'object' + ? frontmatter.value.prev.text + : undefined) ?? + candidates[index - 1]?.docFooterText ?? + candidates[index - 1]?.text, + link: + (typeof frontmatter.value.prev === 'object' + ? frontmatter.value.prev.link + : undefined) ?? candidates[index - 1]?.link + }, + next: hideNext + ? undefined + : { + text: + (typeof frontmatter.value.next === 'string' + ? frontmatter.value.next + : typeof frontmatter.value.next === 'object' + ? frontmatter.value.next.text + : undefined) ?? + candidates[index + 1]?.docFooterText ?? + candidates[index + 1]?.text, + link: + (typeof frontmatter.value.next === 'object' + ? frontmatter.value.next.link + : undefined) ?? candidates[index + 1]?.link + } + } as { + prev?: { text?: string; link?: string } + next?: { text?: string; link?: string } + } + }) +} + +function uniqBy(array: T[], keyFn: (item: T) => any): T[] { + const seen = new Set() + return array.filter((item) => { + const k = keyFn(item) + return seen.has(k) ? false : seen.add(k) + }) +} diff --git a/src/client/theme-default-v2/composables/sidebar.ts b/src/client/theme-default-v2/composables/sidebar.ts new file mode 100644 index 00000000..b693cc89 --- /dev/null +++ b/src/client/theme-default-v2/composables/sidebar.ts @@ -0,0 +1,128 @@ +import type { DefaultTheme } from 'vitepress/theme' +import { + computed, + onMounted, + onUnmounted, + ref, + watch, + watchEffect, + watchPostEffect, + type ComputedRef +} from 'vue' +import { isActive } from '../../shared' +import { hasActiveLink as containsActiveLink } from '../support/sidebar' +import { useData } from './data' + +const isOpen = ref(false) + +/** + * a11y: cache the element that opened the Sidebar (the menu button) then + * focus that button again when Menu is closed with Escape key. + */ +export function useCloseSidebarOnEscape(close: () => void) { + let triggerElement: HTMLButtonElement | undefined + + watchEffect(() => { + triggerElement = isOpen.value + ? (document.activeElement as HTMLButtonElement) + : undefined + }) + + onMounted(() => { + window.addEventListener('keyup', onEscape) + }) + + onUnmounted(() => { + window.removeEventListener('keyup', onEscape) + }) + + function onEscape(e: KeyboardEvent) { + if (e.key === 'Escape' && isOpen.value) { + close() + triggerElement?.focus() + } + } +} + +export function useSidebarControl() { + function open() { + isOpen.value = true + } + + function close() { + isOpen.value = false + } + + function toggle() { + isOpen.value ? close() : open() + } + + return { + isOpen, + open, + close, + toggle + } +} + +export function useSidebarItemControl( + item: ComputedRef +) { + const { page, hash } = useData() + + const collapsed = ref(false) + + const collapsible = computed(() => { + return item.value.collapsed != null + }) + + const isLink = computed(() => { + return !!item.value.link + }) + + const isActiveLink = ref(false) + const updateIsActiveLink = () => { + isActiveLink.value = isActive(page.value.relativePath, item.value.link) + } + + watch([page, item, hash], updateIsActiveLink) + onMounted(updateIsActiveLink) + + const hasActiveLink = computed(() => { + if (isActiveLink.value) { + return true + } + + return item.value.items + ? containsActiveLink(page.value.relativePath, item.value.items) + : false + }) + + const hasChildren = computed(() => { + return !!(item.value.items && item.value.items.length) + }) + + watchEffect(() => { + collapsed.value = !!(collapsible.value && item.value.collapsed) + }) + + watchPostEffect(() => { + ;(isActiveLink.value || hasActiveLink.value) && (collapsed.value = false) + }) + + function toggle() { + if (collapsible.value) { + collapsed.value = !collapsed.value + } + } + + return { + collapsed, + collapsible, + isLink, + isActiveLink, + hasActiveLink, + hasChildren, + toggle + } +} diff --git a/src/client/theme-default-v2/composables/sponsor-grid.ts b/src/client/theme-default-v2/composables/sponsor-grid.ts new file mode 100644 index 00000000..3a6f7e3b --- /dev/null +++ b/src/client/theme-default-v2/composables/sponsor-grid.ts @@ -0,0 +1,135 @@ +import { type Ref, onMounted, onUnmounted } from 'vue' +import { throttleAndDebounce } from '../support/utils' + +export interface GridSetting { + [size: string]: [number, number][] +} + +export type GridSize = 'xmini' | 'mini' | 'small' | 'medium' | 'big' + +export interface UseSponsorsGridOptions { + el: Ref + size?: GridSize +} + +/** + * Defines grid configuration for each sponsor size in tuple. + * + * [Screen width, Column size] + * + * It sets grid size on matching screen size. For example, `[768, 5]` will + * set 5 columns when screen size is bigger or equal to 768px. + * + * Column will set only when item size is bigger than the column size. For + * example, even we define 5 columns, if we only have 1 sponsor yet, we would + * like to show it in 1 column to make it stand out. + */ +const GridSettings: GridSetting = { + xmini: [[0, 2]], + mini: [], + small: [ + [920, 6], + [768, 5], + [640, 4], + [480, 3], + [0, 2] + ], + medium: [ + [960, 5], + [832, 4], + [640, 3], + [480, 2] + ], + big: [ + [832, 3], + [640, 2] + ] +} + +export function useSponsorsGrid({ + el, + size = 'medium' +}: UseSponsorsGridOptions) { + const onResize = throttleAndDebounce(manage, 100) + + onMounted(() => { + manage() + window.addEventListener('resize', onResize) + }) + + onUnmounted(() => { + window.removeEventListener('resize', onResize) + }) + + function manage() { + adjustSlots(el.value!, size) + } +} + +function adjustSlots(el: HTMLElement, size: GridSize) { + const tsize = el.children.length + const asize = el.querySelectorAll('.vp-sponsor-grid-item:not(.empty)').length + + const grid = setGrid(el, size, asize) + + manageSlots(el, grid, tsize, asize) +} + +function setGrid(el: HTMLElement, size: GridSize, items: number) { + const settings = GridSettings[size] + const screen = window.innerWidth + + let grid = 1 + + settings.some(([breakpoint, value]) => { + if (screen >= breakpoint) { + grid = items < value ? items : value + return true + } + }) + + setGridData(el, grid) + + return grid +} + +function setGridData(el: HTMLElement, value: number) { + el.dataset.vpGrid = String(value) +} + +function manageSlots( + el: HTMLElement, + grid: number, + tsize: number, + asize: number +) { + const diff = tsize - asize + const rem = asize % grid + const drem = rem === 0 ? rem : grid - rem + + neutralizeSlots(el, drem - diff) +} + +function neutralizeSlots(el: HTMLElement, count: number) { + if (count === 0) { + return + } + + count > 0 ? addSlots(el, count) : removeSlots(el, count * -1) +} + +function addSlots(el: HTMLElement, count: number) { + for (let i = 0; i < count; i++) { + const slot = document.createElement('div') + + slot.classList.add('vp-sponsor-grid-item', 'empty') + + el.append(slot) + } +} + +function removeSlots(el: HTMLElement, count: number) { + for (let i = 0; i < count; i++) { + el.removeChild(el.lastElementChild!) + } +} diff --git a/src/client/theme-default-v2/fonts/inter-italic-cyrillic-ext.woff2 b/src/client/theme-default-v2/fonts/inter-italic-cyrillic-ext.woff2 new file mode 100644 index 00000000..b6b603d5 Binary files /dev/null and b/src/client/theme-default-v2/fonts/inter-italic-cyrillic-ext.woff2 differ diff --git a/src/client/theme-default-v2/fonts/inter-italic-cyrillic.woff2 b/src/client/theme-default-v2/fonts/inter-italic-cyrillic.woff2 new file mode 100644 index 00000000..def40a4f Binary files /dev/null and b/src/client/theme-default-v2/fonts/inter-italic-cyrillic.woff2 differ diff --git a/src/client/theme-default-v2/fonts/inter-italic-greek-ext.woff2 b/src/client/theme-default-v2/fonts/inter-italic-greek-ext.woff2 new file mode 100644 index 00000000..e070c3d3 Binary files /dev/null and b/src/client/theme-default-v2/fonts/inter-italic-greek-ext.woff2 differ diff --git a/src/client/theme-default-v2/fonts/inter-italic-greek.woff2 b/src/client/theme-default-v2/fonts/inter-italic-greek.woff2 new file mode 100644 index 00000000..a3c16ca4 Binary files /dev/null and b/src/client/theme-default-v2/fonts/inter-italic-greek.woff2 differ diff --git a/src/client/theme-default-v2/fonts/inter-italic-latin-ext.woff2 b/src/client/theme-default-v2/fonts/inter-italic-latin-ext.woff2 new file mode 100644 index 00000000..2210a899 Binary files /dev/null and b/src/client/theme-default-v2/fonts/inter-italic-latin-ext.woff2 differ diff --git a/src/client/theme-default-v2/fonts/inter-italic-latin.woff2 b/src/client/theme-default-v2/fonts/inter-italic-latin.woff2 new file mode 100644 index 00000000..790d62dc Binary files /dev/null and b/src/client/theme-default-v2/fonts/inter-italic-latin.woff2 differ diff --git a/src/client/theme-default-v2/fonts/inter-italic-vietnamese.woff2 b/src/client/theme-default-v2/fonts/inter-italic-vietnamese.woff2 new file mode 100644 index 00000000..1eec0775 Binary files /dev/null and b/src/client/theme-default-v2/fonts/inter-italic-vietnamese.woff2 differ diff --git a/src/client/theme-default-v2/fonts/inter-roman-cyrillic-ext.woff2 b/src/client/theme-default-v2/fonts/inter-roman-cyrillic-ext.woff2 new file mode 100644 index 00000000..2cfe6153 Binary files /dev/null and b/src/client/theme-default-v2/fonts/inter-roman-cyrillic-ext.woff2 differ diff --git a/src/client/theme-default-v2/fonts/inter-roman-cyrillic.woff2 b/src/client/theme-default-v2/fonts/inter-roman-cyrillic.woff2 new file mode 100644 index 00000000..e3886dd1 Binary files /dev/null and b/src/client/theme-default-v2/fonts/inter-roman-cyrillic.woff2 differ diff --git a/src/client/theme-default-v2/fonts/inter-roman-greek-ext.woff2 b/src/client/theme-default-v2/fonts/inter-roman-greek-ext.woff2 new file mode 100644 index 00000000..36d67487 Binary files /dev/null and b/src/client/theme-default-v2/fonts/inter-roman-greek-ext.woff2 differ diff --git a/src/client/theme-default-v2/fonts/inter-roman-greek.woff2 b/src/client/theme-default-v2/fonts/inter-roman-greek.woff2 new file mode 100644 index 00000000..2bed1e85 Binary files /dev/null and b/src/client/theme-default-v2/fonts/inter-roman-greek.woff2 differ diff --git a/src/client/theme-default-v2/fonts/inter-roman-latin-ext.woff2 b/src/client/theme-default-v2/fonts/inter-roman-latin-ext.woff2 new file mode 100644 index 00000000..9a8d1e2b Binary files /dev/null and b/src/client/theme-default-v2/fonts/inter-roman-latin-ext.woff2 differ diff --git a/src/client/theme-default-v2/fonts/inter-roman-latin.woff2 b/src/client/theme-default-v2/fonts/inter-roman-latin.woff2 new file mode 100644 index 00000000..07d3c53a Binary files /dev/null and b/src/client/theme-default-v2/fonts/inter-roman-latin.woff2 differ diff --git a/src/client/theme-default-v2/fonts/inter-roman-vietnamese.woff2 b/src/client/theme-default-v2/fonts/inter-roman-vietnamese.woff2 new file mode 100644 index 00000000..57bdc22a Binary files /dev/null and b/src/client/theme-default-v2/fonts/inter-roman-vietnamese.woff2 differ diff --git a/src/client/theme-default-v2/index.ts b/src/client/theme-default-v2/index.ts new file mode 100644 index 00000000..fe52cd65 --- /dev/null +++ b/src/client/theme-default-v2/index.ts @@ -0,0 +1,4 @@ +import './styles/fonts.css' + +export * from './without-fonts' +export { default as default } from './without-fonts' diff --git a/src/client/theme-default-v2/styles/base.css b/src/client/theme-default-v2/styles/base.css new file mode 100644 index 00000000..f5bcad1d --- /dev/null +++ b/src/client/theme-default-v2/styles/base.css @@ -0,0 +1,251 @@ +@media (prefers-reduced-motion: reduce) { + *, + ::before, + ::after { + animation-delay: -1ms !important; + animation-duration: 1ms !important; + animation-iteration-count: 1 !important; + background-attachment: initial !important; + scroll-behavior: auto !important; + transition-duration: 0s !important; + transition-delay: 0s !important; + } +} + +*, +::before, +::after { + box-sizing: border-box; +} + +html { + line-height: 1.4; + font-size: 16px; + -webkit-text-size-adjust: 100%; +} + +html.dark { + color-scheme: dark; +} + +body { + margin: 0; + width: 100%; + min-width: 320px; + min-height: 100vh; + line-height: var(--vp-leading-base); + font-family: var(--vp-font-family-base); + font-size: var(--vp-font-size-base); + font-weight: 400; + color: var(--vp-c-text-1); + background-color: var(--vp-c-bg-1); + font-synthesis: style; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +main { + display: block; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + line-height: var(--vp-leading-base); + font-size: var(--vp-font-size-base); + font-weight: 400; +} + +p { + margin: 0; +} + +strong, +b { + font-weight: 600; +} + +/** + * Avoid 300ms click delay on touch devices that support the `touch-action` + * CSS property. + * + * In particular, unlike most other browsers, IE11+Edge on Windows 10 on + * touch devices and IE Mobile 10-11 DON'T remove the click delay when + * `` is present. + * However, they DO support removing the click delay via + * `touch-action: manipulation`. + * + * See: + * - http://v4-alpha.getbootstrap.com/content/reboot/#click-delay-optimization-for-touch + * - http://caniuse.com/#feat=css-touch-action + * - http://patrickhlauke.github.io/touch/tests/results/#suppressing-300ms-delay + */ +a, +area, +button, +[role='button'], +input, +label, +select, +summary, +textarea { + touch-action: manipulation; +} + +a { + color: inherit; + text-decoration: inherit; +} + +ol, +ul { + list-style: none; + margin: 0; + padding: 0; +} + +blockquote { + margin: 0; +} + +pre, +code, +kbd, +samp { + font-family: var(--vp-font-family-mono); +} + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; +} + +figure { + margin: 0; +} + +img, +video { + max-width: 100%; + height: auto; +} + +button, +input, +optgroup, +select, +textarea { + border: 0; + padding: 0; + line-height: inherit; + color: inherit; +} + +button { + padding: 0; + font-family: inherit; + background-color: transparent; + background-image: none; +} + +button:enabled, +[role='button']:enabled { + cursor: pointer; +} + +button:focus, +button:focus-visible { + outline: 1px dotted; + outline: 4px auto -webkit-focus-ring-color; +} + +button:focus:not(:focus-visible) { + outline: none !important; +} + +input:focus, +textarea:focus, +select:focus { + outline: none; +} + +table { + border-collapse: collapse; +} + +input { + background-color: transparent; +} + +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + color: var(--vp-c-text-3); +} + +input::-ms-input-placeholder, +textarea::-ms-input-placeholder { + color: var(--vp-c-text-3); +} + +input::placeholder, +textarea::placeholder { + color: var(--vp-c-text-3); +} + +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +input[type='number'] { + -moz-appearance: textfield; +} + +textarea { + resize: vertical; +} + +select { + -webkit-appearance: none; +} + +fieldset { + margin: 0; + padding: 0; +} + +h1, +h2, +h3, +h4, +h5, +h6, +li, +p { + overflow-wrap: break-word; +} + +vite-error-overlay { + z-index: 9999; +} + +mjx-container { + overflow-x: auto; +} + +mjx-container > svg { + display: inline-block; + margin: auto; +} diff --git a/src/client/theme-default-v2/styles/components/custom-block.css b/src/client/theme-default-v2/styles/components/custom-block.css new file mode 100644 index 00000000..a960381c --- /dev/null +++ b/src/client/theme-default-v2/styles/components/custom-block.css @@ -0,0 +1,208 @@ +.custom-block { + border: 1px solid transparent; + border-radius: 8px; + padding: 16px 16px 8px; + line-height: 24px; + font-size: var(--vp-custom-block-font-size); + color: var(--vp-c-text-2); +} + +.custom-block.info { + border-color: var(--vp-custom-block-info-border); + color: var(--vp-custom-block-info-text); + background-color: var(--vp-custom-block-info-bg); +} + +.custom-block.info a, +.custom-block.info code { + color: var(--vp-c-brand-1); +} + +.custom-block.info a:hover, +.custom-block.info a:hover > code { + color: var(--vp-c-brand-2); +} + +.custom-block.info code { + background-color: var(--vp-custom-block-info-code-bg); +} + +.custom-block.note { + border-color: var(--vp-custom-block-note-border); + color: var(--vp-custom-block-note-text); + background-color: var(--vp-custom-block-note-bg); +} + +.custom-block.note a, +.custom-block.note code { + color: var(--vp-c-brand-1); +} + +.custom-block.note a:hover, +.custom-block.note a:hover > code { + color: var(--vp-c-brand-2); +} + +.custom-block.note code { + background-color: var(--vp-custom-block-note-code-bg); +} + +.custom-block.tip { + border-color: var(--vp-custom-block-tip-border); + color: var(--vp-custom-block-tip-text); + background-color: var(--vp-custom-block-tip-bg); +} + +.custom-block.tip a, +.custom-block.tip code { + color: var(--vp-c-tip-1); +} + +.custom-block.tip a:hover, +.custom-block.tip a:hover > code { + color: var(--vp-c-tip-2); +} + +.custom-block.tip code { + background-color: var(--vp-custom-block-tip-code-bg); +} + +.custom-block.important { + border-color: var(--vp-custom-block-important-border); + color: var(--vp-custom-block-important-text); + background-color: var(--vp-custom-block-important-bg); +} + +.custom-block.important a, +.custom-block.important code { + color: var(--vp-c-important-1); +} + +.custom-block.important a:hover, +.custom-block.important a:hover > code { + color: var(--vp-c-important-2); +} + +.custom-block.important code { + background-color: var(--vp-custom-block-important-code-bg); +} + +.custom-block.warning { + border-color: var(--vp-custom-block-warning-border); + color: var(--vp-custom-block-warning-text); + background-color: var(--vp-custom-block-warning-bg); +} + +.custom-block.warning a, +.custom-block.warning code { + color: var(--vp-c-warning-1); +} + +.custom-block.warning a:hover, +.custom-block.warning a:hover > code { + color: var(--vp-c-warning-2); +} + +.custom-block.warning code { + background-color: var(--vp-custom-block-warning-code-bg); +} + +.custom-block.danger { + border-color: var(--vp-custom-block-danger-border); + color: var(--vp-custom-block-danger-text); + background-color: var(--vp-custom-block-danger-bg); +} + +.custom-block.danger a, +.custom-block.danger code { + color: var(--vp-c-danger-1); +} + +.custom-block.danger a:hover, +.custom-block.danger a:hover > code { + color: var(--vp-c-danger-2); +} + +.custom-block.danger code { + background-color: var(--vp-custom-block-danger-code-bg); +} + +.custom-block.caution { + border-color: var(--vp-custom-block-caution-border); + color: var(--vp-custom-block-caution-text); + background-color: var(--vp-custom-block-caution-bg); +} + +.custom-block.caution a, +.custom-block.caution code { + color: var(--vp-c-caution-1); +} + +.custom-block.caution a:hover, +.custom-block.caution a:hover > code { + color: var(--vp-c-caution-2); +} + +.custom-block.caution code { + background-color: var(--vp-custom-block-caution-code-bg); +} + +.custom-block.details { + border-color: var(--vp-custom-block-details-border); + color: var(--vp-custom-block-details-text); + background-color: var(--vp-custom-block-details-bg); +} + +.custom-block.details a { + color: var(--vp-c-brand-1); +} + +.custom-block.details a:hover, +.custom-block.details a:hover > code { + color: var(--vp-c-brand-2); +} + +.custom-block.details code { + background-color: var(--vp-custom-block-details-code-bg); +} + +.custom-block-title { + font-weight: 600; +} + +.custom-block p + p { + margin: 8px 0; +} + +.custom-block.details summary { + margin: 0 0 8px; + font-weight: 700; + cursor: pointer; + user-select: none; +} + +.custom-block.details summary + p { + margin: 8px 0; +} + +.custom-block a { + color: inherit; + font-weight: 600; + text-decoration: underline; + text-underline-offset: 2px; + transition: opacity 0.25s; +} + +.custom-block a:hover { + opacity: 0.75; +} + +.custom-block code { + font-size: var(--vp-custom-block-code-font-size); +} + +.custom-block.custom-block th, +.custom-block.custom-block blockquote > p { + font-size: var(--vp-custom-block-font-size); + color: inherit; +} diff --git a/src/client/theme-default-v2/styles/components/vp-code-group.css b/src/client/theme-default-v2/styles/components/vp-code-group.css new file mode 100644 index 00000000..4f23a416 --- /dev/null +++ b/src/client/theme-default-v2/styles/components/vp-code-group.css @@ -0,0 +1,85 @@ +.vp-code-group { + margin-top: 16px; +} + +.vp-code-group .tabs { + position: relative; + display: flex; + margin-right: -24px; + margin-left: -24px; + padding: 0 12px; + background-color: var(--vp-code-tab-bg); + overflow-x: auto; + overflow-y: hidden; + box-shadow: inset 0 -1px var(--vp-code-tab-divider); +} + +@media (min-width: 640px) { + .vp-code-group .tabs { + margin-right: 0; + margin-left: 0; + border-radius: 8px 8px 0 0; + } +} + +.vp-code-group .tabs input { + position: fixed; + opacity: 0; + pointer-events: none; +} + +.vp-code-group .tabs label { + position: relative; + display: inline-block; + border-bottom: 1px solid transparent; + padding: 0 12px; + line-height: 48px; + font-size: 14px; + font-weight: 500; + color: var(--vp-code-tab-text-color); + white-space: nowrap; + cursor: pointer; + transition: color 0.25s; +} + +.vp-code-group .tabs label::after { + position: absolute; + right: 8px; + bottom: -1px; + left: 8px; + z-index: 1; + height: 2px; + border-radius: 2px; + content: ''; + background-color: transparent; + transition: background-color 0.25s; +} + +.vp-code-group label:hover { + color: var(--vp-code-tab-hover-text-color); +} + +.vp-code-group input:checked + label { + color: var(--vp-code-tab-active-text-color); +} + +.vp-code-group input:checked + label::after { + background-color: var(--vp-code-tab-active-bar-color); +} + +.vp-code-group div[class*='language-'], +.vp-block { + display: none; + margin-top: 0 !important; + border-top-left-radius: 0 !important; + border-top-right-radius: 0 !important; +} + +.vp-code-group div[class*='language-'].active, +.vp-block.active { + display: block; +} + +.vp-block { + padding: 20px 24px; +} diff --git a/src/client/theme-default-v2/styles/components/vp-code.css b/src/client/theme-default-v2/styles/components/vp-code.css new file mode 100644 index 00000000..5c42b9ca --- /dev/null +++ b/src/client/theme-default-v2/styles/components/vp-code.css @@ -0,0 +1,7 @@ +.dark .shiki span { + color: var(--shiki-dark, inherit); +} + +html:not(.dark) .shiki span { + color: var(--shiki-light, inherit); +} diff --git a/src/client/theme-default-v2/styles/components/vp-doc.css b/src/client/theme-default-v2/styles/components/vp-doc.css new file mode 100644 index 00000000..caf8c3b6 --- /dev/null +++ b/src/client/theme-default-v2/styles/components/vp-doc.css @@ -0,0 +1,571 @@ +/** + * Headings + * -------------------------------------------------------------------------- */ + +.vp-doc h1, +.vp-doc h2, +.vp-doc h3, +.vp-doc h4, +.vp-doc h5, +.vp-doc h6 { + position: relative; + font-weight: 600; + outline: none; +} + +.vp-doc h1 { + letter-spacing: -0.02em; + line-height: 40px; + font-size: 28px; +} + +.vp-doc h2 { + margin: 48px 0 16px; + border-top: 1px solid var(--vp-c-divider); + padding-top: 24px; + letter-spacing: -0.02em; + line-height: 32px; + font-size: 24px; +} + +.vp-doc h3 { + margin: 32px 0 0; + letter-spacing: -0.01em; + line-height: 28px; + font-size: 20px; +} + +.vp-doc h4 { + margin: 24px 0 0; + letter-spacing: -0.01em; + line-height: 24px; + font-size: 18px; +} + +.vp-doc .header-anchor { + position: absolute; + top: 0; + left: 0; + margin-left: -0.87em; + font-weight: 500; + user-select: none; + opacity: 0; + text-decoration: none; + transition: + color 0.25s, + opacity 0.25s; +} + +.vp-doc .header-anchor:before { + content: var(--vp-header-anchor-symbol); +} + +.vp-doc h1:hover .header-anchor, +.vp-doc h1 .header-anchor:focus, +.vp-doc h2:hover .header-anchor, +.vp-doc h2 .header-anchor:focus, +.vp-doc h3:hover .header-anchor, +.vp-doc h3 .header-anchor:focus, +.vp-doc h4:hover .header-anchor, +.vp-doc h4 .header-anchor:focus, +.vp-doc h5:hover .header-anchor, +.vp-doc h5 .header-anchor:focus, +.vp-doc h6:hover .header-anchor, +.vp-doc h6 .header-anchor:focus { + opacity: 1; +} + +@media (min-width: 768px) { + .vp-doc h1 { + letter-spacing: -0.02em; + line-height: 40px; + font-size: 32px; + } +} + +.vp-doc h2 .header-anchor { + top: 24px; +} + +/** + * Paragraph and inline elements + * -------------------------------------------------------------------------- */ + +.vp-doc p, +.vp-doc summary { + margin: 16px 0; +} + +.vp-doc p { + line-height: 28px; +} + +.vp-doc blockquote { + margin: 16px 0; + border-left: 2px solid var(--vp-c-divider); + padding-left: 16px; + transition: border-color 0.5s; + color: var(--vp-c-text-2); +} + +.vp-doc blockquote > p { + margin: 0; + font-size: 16px; + transition: color 0.5s; +} + +.vp-doc a { + font-weight: 500; + color: var(--vp-c-brand-1); + text-decoration: underline; + text-underline-offset: 2px; + transition: + color 0.25s, + opacity 0.25s; +} + +.vp-doc a:hover { + color: var(--vp-c-brand-2); +} + +.vp-doc strong { + font-weight: 600; +} + +/** + * Lists + * -------------------------------------------------------------------------- */ + +.vp-doc ul, +.vp-doc ol { + padding-left: 1.25rem; + margin: 16px 0; +} + +.vp-doc ul { + list-style: disc; +} + +.vp-doc ol { + list-style: decimal; +} + +.vp-doc li + li { + margin-top: 8px; +} + +.vp-doc li > ol, +.vp-doc li > ul { + margin: 8px 0 0; +} + +/** + * Table + * -------------------------------------------------------------------------- */ + +.vp-doc table { + display: block; + border-collapse: collapse; + margin: 20px 0; + overflow-x: auto; +} + +.vp-doc tr { + background-color: var(--vp-c-bg); + border-top: 1px solid var(--vp-c-divider); + transition: background-color 0.5s; +} + +.vp-doc tr:nth-child(2n) { + background-color: var(--vp-c-bg-soft); +} + +.vp-doc th, +.vp-doc td { + border: 1px solid var(--vp-c-divider); + padding: 8px 16px; +} + +.vp-doc th { + text-align: left; + font-size: 14px; + font-weight: 600; + color: var(--vp-c-text-2); + background-color: var(--vp-c-bg-soft); +} + +.vp-doc td { + font-size: 14px; +} + +/** + * Decorational elements + * -------------------------------------------------------------------------- */ + +.vp-doc hr { + margin: 16px 0; + border: none; + border-top: 1px solid var(--vp-c-divider); +} + +/** + * Custom Block + * -------------------------------------------------------------------------- */ + +.vp-doc .custom-block { + margin: 16px 0; +} + +.vp-doc .custom-block p { + margin: 8px 0; + line-height: 24px; +} + +.vp-doc .custom-block p:first-child { + margin: 0; +} + +.vp-doc .custom-block div[class*='language-'] { + margin: 8px 0; + border-radius: 8px; +} + +.vp-doc .custom-block div[class*='language-'] code { + font-weight: 400; + background-color: transparent; +} + +.vp-doc .custom-block .vp-code-group .tabs { + margin: 0; + border-radius: 8px 8px 0 0; +} + +/** + * Code + * -------------------------------------------------------------------------- */ + +/* inline code */ +.vp-doc :not(pre, h1, h2, h3, h4, h5, h6) > code { + font-size: var(--vp-code-font-size); + color: var(--vp-code-color); +} + +.vp-doc :not(pre) > code { + border-radius: 4px; + padding: 3px 6px; + background-color: var(--vp-code-bg); + transition: + color 0.25s, + background-color 0.5s; +} + +.vp-doc a > code { + color: var(--vp-code-link-color); +} + +.vp-doc a:hover > code { + color: var(--vp-code-link-hover-color); +} + +.vp-doc h1 > code, +.vp-doc h2 > code, +.vp-doc h3 > code, +.vp-doc h4 > code { + font-size: 0.9em; +} + +.vp-doc div[class*='language-'], +.vp-block { + position: relative; + margin: 16px -24px; + background-color: var(--vp-code-block-bg); + overflow-x: auto; + transition: background-color 0.5s; +} + +@media (min-width: 640px) { + .vp-doc div[class*='language-'], + .vp-block { + border-radius: 8px; + margin: 16px 0; + } +} + +@media (max-width: 639px) { + .vp-doc li div[class*='language-'] { + border-radius: 8px 0 0 8px; + } +} + +.vp-doc div[class*='language-'] + div[class*='language-'], +.vp-doc div[class$='-api'] + div[class*='language-'], +.vp-doc div[class*='language-'] + div[class$='-api'] > div[class*='language-'] { + margin-top: -8px; +} + +.vp-doc [class*='language-'] pre, +.vp-doc [class*='language-'] code { + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; +} + +.vp-doc [class*='language-'] pre { + position: relative; + z-index: 1; + margin: 0; + padding: 20px 0; + background: transparent; + overflow-x: auto; + /*rtl:ignore*/ + text-align: left; +} + +.vp-doc [class*='language-'] code { + display: block; + padding: 0 24px; + width: fit-content; + min-width: 100%; + line-height: var(--vp-code-line-height); + font-size: var(--vp-code-font-size); + color: var(--vp-code-block-color); + transition: color 0.5s; +} + +.vp-doc [class*='language-'] code .highlighted { + background-color: var(--vp-code-line-highlight-color); + transition: background-color 0.5s; + margin: 0 -24px; + padding: 0 24px; + width: calc(100% + 2 * 24px); + display: inline-block; +} + +.vp-doc [class*='language-'] code .highlighted.error { + background-color: var(--vp-code-line-error-color); +} + +.vp-doc [class*='language-'] code .highlighted.warning { + background-color: var(--vp-code-line-warning-color); +} + +.vp-doc [class*='language-'] code .diff { + transition: background-color 0.5s; + margin: 0 -24px; + padding: 0 24px; + width: calc(100% + 2 * 24px); + display: inline-block; +} + +.vp-doc [class*='language-'] code .diff::before { + position: absolute; + left: 10px; +} + +.vp-doc [class*='language-'] .has-focused-lines .line:not(.has-focus) { + filter: blur(0.095rem); + opacity: 0.4; + transition: + filter 0.35s, + opacity 0.35s; +} + +.vp-doc [class*='language-'] .has-focused-lines .line:not(.has-focus) { + opacity: 0.7; + transition: + filter 0.35s, + opacity 0.35s; +} + +.vp-doc [class*='language-']:hover .has-focused-lines .line:not(.has-focus) { + filter: blur(0); + opacity: 1; +} + +.vp-doc [class*='language-'] code .diff.remove { + background-color: var(--vp-code-line-diff-remove-color); + opacity: 0.7; +} + +.vp-doc [class*='language-'] code .diff.remove::before { + content: '-'; + color: var(--vp-code-line-diff-remove-symbol-color); +} + +.vp-doc [class*='language-'] code .diff.add { + background-color: var(--vp-code-line-diff-add-color); +} + +.vp-doc [class*='language-'] code .diff.add::before { + content: '+'; + color: var(--vp-code-line-diff-add-symbol-color); +} + +.vp-doc div[class*='language-'].line-numbers-mode { + /*rtl:ignore*/ + padding-left: 32px; +} + +.vp-doc .line-numbers-wrapper { + position: absolute; + top: 0; + bottom: 0; + /*rtl:ignore*/ + left: 0; + z-index: 3; + /*rtl:ignore*/ + border-right: 1px solid var(--vp-code-block-divider-color); + padding-top: 20px; + width: 32px; + text-align: center; + font-family: var(--vp-font-family-mono); + line-height: var(--vp-code-line-height); + font-size: var(--vp-code-font-size); + color: var(--vp-code-line-number-color); + transition: + border-color 0.5s, + color 0.5s; +} + +.vp-doc [class*='language-'] > button.copy { + /*rtl:ignore*/ + direction: ltr; + position: absolute; + top: 12px; + /*rtl:ignore*/ + right: 12px; + z-index: 3; + border: 1px solid var(--vp-code-copy-code-border-color); + border-radius: 4px; + width: 40px; + height: 40px; + background-color: var(--vp-code-copy-code-bg); + opacity: 0; + cursor: pointer; + background-image: var(--vp-icon-copy); + background-position: 50%; + background-size: 20px; + background-repeat: no-repeat; + transition: + border-color 0.25s, + background-color 0.25s, + opacity 0.25s; +} + +.vp-doc [class*='language-']:hover > button.copy, +.vp-doc [class*='language-'] > button.copy:focus { + opacity: 1; +} + +.vp-doc [class*='language-'] > button.copy:hover, +.vp-doc [class*='language-'] > button.copy.copied { + border-color: var(--vp-code-copy-code-hover-border-color); + background-color: var(--vp-code-copy-code-hover-bg); +} + +.vp-doc [class*='language-'] > button.copy.copied, +.vp-doc [class*='language-'] > button.copy:hover.copied { + /*rtl:ignore*/ + border-radius: 0 4px 4px 0; + background-color: var(--vp-code-copy-code-hover-bg); + background-image: var(--vp-icon-copied); +} + +.vp-doc [class*='language-'] > button.copy.copied::before, +.vp-doc [class*='language-'] > button.copy:hover.copied::before { + position: relative; + top: -1px; + /*rtl:ignore*/ + transform: translateX(calc(-100% - 1px)); + display: flex; + justify-content: center; + align-items: center; + border: 1px solid var(--vp-code-copy-code-hover-border-color); + /*rtl:ignore*/ + border-right: 0; + /*rtl:ignore*/ + border-radius: 4px 0 0 4px; + padding: 0 10px; + width: fit-content; + height: 40px; + text-align: center; + font-size: 12px; + font-weight: 500; + color: var(--vp-code-copy-code-active-text); + background-color: var(--vp-code-copy-code-hover-bg); + white-space: nowrap; + content: var(--vp-code-copy-copied-text-content); +} + +.vp-doc [class*='language-'] > span.lang { + position: absolute; + top: 2px; + /*rtl:ignore*/ + right: 8px; + z-index: 2; + font-size: 12px; + font-weight: 500; + user-select: none; + color: var(--vp-code-lang-color); + transition: + color 0.4s, + opacity 0.4s; +} + +.vp-doc [class*='language-']:hover > button.copy + span.lang, +.vp-doc [class*='language-'] > button.copy:focus + span.lang { + opacity: 0; +} + +/** + * Component: Team + * -------------------------------------------------------------------------- */ + +.vp-doc .VPTeamMembers { + margin-top: 24px; +} + +.vp-doc .VPTeamMembers.small.count-1 .container { + margin: 0 !important; + max-width: calc((100% - 24px) / 2) !important; +} + +.vp-doc .VPTeamMembers.small.count-2 .container, +.vp-doc .VPTeamMembers.small.count-3 .container { + max-width: 100% !important; +} + +.vp-doc .VPTeamMembers.medium.count-1 .container { + margin: 0 !important; + max-width: calc((100% - 24px) / 2) !important; +} + +/** + * External links + * -------------------------------------------------------------------------- */ + +/* prettier-ignore */ +:is(.vp-external-link-icon, .vp-doc a[href*='://'], .vp-doc a[target='_blank']):not(:is(.no-icon, svg a, :has(img, svg)))::after { + display: inline-block; + margin-top: -1px; + margin-left: 4px; + width: 11px; + height: 11px; + background: currentColor; + color: var(--vp-c-text-3); + flex-shrink: 0; + --icon: url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' %3E%3Cpath d='M0 0h24v24H0V0z' fill='none' /%3E%3Cpath d='M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5H9z' /%3E%3C/svg%3E"); + -webkit-mask-image: var(--icon); + mask-image: var(--icon); + /*rtl:raw:transform: scaleX(-1);*/ +} + +.vp-external-link-icon::after { + content: ''; +} + +/* prettier-ignore */ +.external-link-icon-enabled :is(.vp-doc a[href*='://'], .vp-doc a[target='_blank']):not(:is(.no-icon, svg a, :has(img, svg)))::after { + content: ''; + color: currentColor; +} diff --git a/src/client/theme-default-v2/styles/components/vp-sponsor.css b/src/client/theme-default-v2/styles/components/vp-sponsor.css new file mode 100644 index 00000000..9e677ab9 --- /dev/null +++ b/src/client/theme-default-v2/styles/components/vp-sponsor.css @@ -0,0 +1,155 @@ +/** + * VPSponsors styles are defined as global because a new class gets + * allied in onMounted` hook and we can't use scoped style. + */ +.vp-sponsor { + border-radius: 16px; + overflow: hidden; +} + +.vp-sponsor.aside { + border-radius: 12px; +} + +.vp-sponsor-section + .vp-sponsor-section { + margin-top: 4px; +} + +.vp-sponsor-tier { + margin: 0 0 4px !important; + text-align: center; + letter-spacing: 1px !important; + line-height: 24px; + width: 100%; + font-weight: 600; + color: var(--vp-c-text-2); + background-color: var(--vp-c-bg-soft); +} + +.vp-sponsor.normal .vp-sponsor-tier { + padding: 13px 0 11px; + font-size: 14px; +} + +.vp-sponsor.aside .vp-sponsor-tier { + padding: 9px 0 7px; + font-size: 12px; +} + +.vp-sponsor-grid + .vp-sponsor-tier { + margin-top: 4px; +} + +.vp-sponsor-grid { + display: flex; + flex-wrap: wrap; + gap: 4px; +} + +.vp-sponsor-grid.xmini .vp-sponsor-grid-link { + height: 64px; +} +.vp-sponsor-grid.xmini .vp-sponsor-grid-image { + max-width: 64px; + max-height: 22px; +} + +.vp-sponsor-grid.mini .vp-sponsor-grid-link { + height: 72px; +} +.vp-sponsor-grid.mini .vp-sponsor-grid-image { + max-width: 96px; + max-height: 24px; +} + +.vp-sponsor-grid.small .vp-sponsor-grid-link { + height: 96px; +} +.vp-sponsor-grid.small .vp-sponsor-grid-image { + max-width: 96px; + max-height: 24px; +} + +.vp-sponsor-grid.medium .vp-sponsor-grid-link { + height: 112px; +} +.vp-sponsor-grid.medium .vp-sponsor-grid-image { + max-width: 120px; + max-height: 36px; +} + +.vp-sponsor-grid.big .vp-sponsor-grid-link { + height: 184px; +} +.vp-sponsor-grid.big .vp-sponsor-grid-image { + max-width: 192px; + max-height: 56px; +} + +.vp-sponsor-grid[data-vp-grid='2'] .vp-sponsor-grid-item { + width: calc((100% - 4px) / 2); +} + +.vp-sponsor-grid[data-vp-grid='3'] .vp-sponsor-grid-item { + width: calc((100% - 4px * 2) / 3); +} + +.vp-sponsor-grid[data-vp-grid='4'] .vp-sponsor-grid-item { + width: calc((100% - 4px * 3) / 4); +} + +.vp-sponsor-grid[data-vp-grid='5'] .vp-sponsor-grid-item { + width: calc((100% - 4px * 4) / 5); +} + +.vp-sponsor-grid[data-vp-grid='6'] .vp-sponsor-grid-item { + width: calc((100% - 4px * 5) / 6); +} + +.vp-sponsor-grid-item { + flex-shrink: 0; + width: 100%; + background-color: var(--vp-c-bg-soft); + transition: background-color 0.25s; +} + +.vp-sponsor-grid-item:hover { + background-color: var(--vp-c-default-soft); +} + +.vp-sponsor-grid-item:hover .vp-sponsor-grid-image { + filter: grayscale(0) invert(0); +} + +.vp-sponsor-grid-item.empty:hover { + background-color: var(--vp-c-bg-soft); +} + +.dark .vp-sponsor-grid-item:hover { + background-color: var(--vp-c-white); +} + +.dark .vp-sponsor-grid-item.empty:hover { + background-color: var(--vp-c-bg-soft); +} + +.vp-sponsor-grid-link { + display: flex; +} + +.vp-sponsor-grid-box { + display: flex; + justify-content: center; + align-items: center; + width: 100%; +} + +.vp-sponsor-grid-image { + max-width: 100%; + filter: grayscale(1); + transition: filter 0.25s; +} + +.dark .vp-sponsor-grid-image { + filter: grayscale(1) invert(1); +} diff --git a/src/client/theme-default-v2/styles/fonts.css b/src/client/theme-default-v2/styles/fonts.css new file mode 100644 index 00000000..2e5521c0 --- /dev/null +++ b/src/client/theme-default-v2/styles/fonts.css @@ -0,0 +1,195 @@ +/* webfont-marker-begin */ +@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap'); +/* webfont-marker-end */ + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url('../fonts/inter-roman-cyrillic-ext.woff2') format('woff2'); + unicode-range: + U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url('../fonts/inter-roman-cyrillic.woff2') format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url('../fonts/inter-roman-greek-ext.woff2') format('woff2'); + unicode-range: U+1F00-1FFF; +} + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url('../fonts/inter-roman-greek.woff2') format('woff2'); + unicode-range: + U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url('../fonts/inter-roman-vietnamese.woff2') format('woff2'); + unicode-range: + U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, + U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, + U+1EA0-1EF9, U+20AB; +} + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url('../fonts/inter-roman-latin-ext.woff2') format('woff2'); + unicode-range: + U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, + U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} + +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url('../fonts/inter-roman-latin.woff2') format('woff2'); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, + U+2212, U+2215, U+FEFF, U+FFFD; +} + +@font-face { + font-family: Inter; + font-style: italic; + font-weight: 100 900; + font-display: swap; + src: url('../fonts/inter-italic-cyrillic-ext.woff2') format('woff2'); + unicode-range: + U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} + +@font-face { + font-family: Inter; + font-style: italic; + font-weight: 100 900; + font-display: swap; + src: url('../fonts/inter-italic-cyrillic.woff2') format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} + +@font-face { + font-family: Inter; + font-style: italic; + font-weight: 100 900; + font-display: swap; + src: url('../fonts/inter-italic-greek-ext.woff2') format('woff2'); + unicode-range: U+1F00-1FFF; +} + +@font-face { + font-family: Inter; + font-style: italic; + font-weight: 100 900; + font-display: swap; + src: url('../fonts/inter-italic-greek.woff2') format('woff2'); + unicode-range: + U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} + +@font-face { + font-family: Inter; + font-style: italic; + font-weight: 100 900; + font-display: swap; + src: url('../fonts/inter-italic-vietnamese.woff2') format('woff2'); + unicode-range: + U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, + U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, + U+1EA0-1EF9, U+20AB; +} + +@font-face { + font-family: Inter; + font-style: italic; + font-weight: 100 900; + font-display: swap; + src: url('../fonts/inter-italic-latin-ext.woff2') format('woff2'); + unicode-range: + U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, + U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} + +@font-face { + font-family: Inter; + font-style: italic; + font-weight: 100 900; + font-display: swap; + src: url('../fonts/inter-italic-latin.woff2') format('woff2'); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, + U+2212, U+2215, U+FEFF, U+FFFD; +} + +@font-face { + font-family: 'Punctuation SC'; + font-weight: 400; + src: + local('PingFang SC Regular'), local('Noto Sans CJK SC'), + local('Microsoft YaHei'); + unicode-range: + U+201C, U+201D, U+2018, U+2019, U+2E3A, U+2014, U+2013, U+2026, U+00B7, + U+007E, U+002F; +} + +@font-face { + font-family: 'Punctuation SC'; + font-weight: 500; + src: + local('PingFang SC Medium'), local('Noto Sans CJK SC'), + local('Microsoft YaHei'); + unicode-range: + U+201C, U+201D, U+2018, U+2019, U+2E3A, U+2014, U+2013, U+2026, U+00B7, + U+007E, U+002F; +} + +@font-face { + font-family: 'Punctuation SC'; + font-weight: 600; + src: + local('PingFang SC Semibold'), local('Noto Sans CJK SC Bold'), + local('Microsoft YaHei Bold'); + unicode-range: + U+201C, U+201D, U+2018, U+2019, U+2E3A, U+2014, U+2013, U+2026, U+00B7, + U+007E, U+002F; +} + +@font-face { + font-family: 'Punctuation SC'; + font-weight: 700; + src: + local('PingFang SC Semibold'), local('Noto Sans CJK SC Bold'), + local('Microsoft YaHei Bold'); + unicode-range: + U+201C, U+201D, U+2018, U+2019, U+2E3A, U+2014, U+2013, U+2026, U+00B7, + U+007E, U+002F; +} + +/* Generate the subsetted fonts using: `pyftsubset .woff2 --unicodes="" --output-file="inter-