vitepress 1.0.0-draft.1 → 1.0.0-draft.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/dist/client/index.d.ts +5 -0
  2. package/dist/client/shared.js +1 -0
  3. package/dist/client/theme-default/Layout.vue +18 -1
  4. package/dist/client/theme-default/components/VPBackdrop.vue +1 -1
  5. package/dist/client/theme-default/components/VPBox.vue +59 -0
  6. package/dist/client/theme-default/components/VPButton.vue +123 -0
  7. package/dist/client/theme-default/components/VPContent.vue +35 -5
  8. package/dist/client/theme-default/components/{VPContentDoc.vue → VPDoc.vue} +13 -13
  9. package/dist/client/theme-default/components/{VPContentDocFooter.vue → VPDocFooter.vue} +3 -2
  10. package/dist/client/theme-default/components/{VPContentDocOutline.vue → VPDocOutline.vue} +2 -2
  11. package/dist/client/theme-default/components/VPFooter.vue +53 -0
  12. package/dist/client/theme-default/components/VPHero.vue +144 -0
  13. package/dist/client/theme-default/components/VPHome.vue +33 -0
  14. package/dist/client/theme-default/components/VPHomeFeatures.vue +96 -0
  15. package/dist/client/theme-default/components/VPHomeHero.vue +17 -0
  16. package/dist/client/theme-default/components/VPHomeSponsors.vue +97 -0
  17. package/dist/client/theme-default/components/VPNavBar.vue +1 -0
  18. package/dist/client/theme-default/components/VPNavBarAppearance.vue +4 -1
  19. package/dist/client/theme-default/components/VPNavBarExtra.vue +2 -2
  20. package/dist/client/theme-default/components/VPNavBarSearch.vue +3 -3
  21. package/dist/client/theme-default/components/VPNavBarTitle.vue +26 -13
  22. package/dist/client/theme-default/components/VPNavScreenAppearance.vue +4 -1
  23. package/dist/client/theme-default/components/VPPage.vue +5 -0
  24. package/dist/client/theme-default/components/VPSponsors.vue +77 -0
  25. package/dist/client/theme-default/components/VPSponsorsGrid.vue +32 -0
  26. package/dist/client/theme-default/components/VPSwitchAppearance.vue +3 -3
  27. package/dist/client/theme-default/components/icons/VPIconHeart.vue +5 -0
  28. package/dist/client/theme-default/composables/outline.js +1 -19
  29. package/dist/client/theme-default/composables/sponsor-grid.js +92 -0
  30. package/dist/client/theme-default/composables/sponsor.js +87 -0
  31. package/dist/client/theme-default/index.js +4 -0
  32. package/dist/client/theme-default/styles/base.css +3 -0
  33. package/dist/client/theme-default/styles/vars.css +86 -1
  34. package/dist/client/theme-default/styles/vp-doc.css +8 -2
  35. package/dist/client/theme-default/styles/vp-sponsor.css +86 -0
  36. package/dist/client/theme-default/support/utils.js +19 -0
  37. package/dist/node/alias.js +60 -0
  38. package/dist/node/alias.js.map +1 -0
  39. package/dist/node/build/build.js +57 -0
  40. package/dist/node/build/build.js.map +1 -0
  41. package/dist/node/build/buildMPAClient.js +44 -0
  42. package/dist/node/build/buildMPAClient.js.map +1 -0
  43. package/dist/node/build/bundle.js +163 -0
  44. package/dist/node/build/bundle.js.map +1 -0
  45. package/dist/node/build/render.js +185 -0
  46. package/dist/node/build/render.js.map +1 -0
  47. package/dist/node/cli.js +37 -294
  48. package/dist/node/cli.js.map +1 -0
  49. package/dist/node/config.js +176 -0
  50. package/dist/node/config.js.map +1 -0
  51. package/dist/node/index.d.ts +19 -1
  52. package/dist/node/index.js +22 -37
  53. package/dist/node/index.js.map +1 -0
  54. package/dist/node/markdown/markdown.js +75 -0
  55. package/dist/node/markdown/markdown.js.map +1 -0
  56. package/dist/node/markdown/plugins/component.js +86 -0
  57. package/dist/node/markdown/plugins/component.js.map +1 -0
  58. package/dist/node/markdown/plugins/containers.js +41 -0
  59. package/dist/node/markdown/plugins/containers.js.map +1 -0
  60. package/dist/node/markdown/plugins/headings.js +25 -0
  61. package/dist/node/markdown/plugins/headings.js.map +1 -0
  62. package/dist/node/markdown/plugins/highlight.js +53 -0
  63. package/dist/node/markdown/plugins/highlight.js.map +1 -0
  64. package/dist/node/markdown/plugins/highlightLines.js +48 -0
  65. package/dist/node/markdown/plugins/highlightLines.js.map +1 -0
  66. package/dist/node/markdown/plugins/hoist.js +22 -0
  67. package/dist/node/markdown/plugins/hoist.js.map +1 -0
  68. package/dist/node/markdown/plugins/image.js +17 -0
  69. package/dist/node/markdown/plugins/image.js.map +1 -0
  70. package/dist/node/markdown/plugins/lineNumbers.js +23 -0
  71. package/dist/node/markdown/plugins/lineNumbers.js.map +1 -0
  72. package/dist/node/markdown/plugins/link.js +85 -0
  73. package/dist/node/markdown/plugins/link.js.map +1 -0
  74. package/dist/node/markdown/plugins/preWrapper.js +22 -0
  75. package/dist/node/markdown/plugins/preWrapper.js.map +1 -0
  76. package/dist/node/markdown/plugins/slugify.js +26 -0
  77. package/dist/node/markdown/plugins/slugify.js.map +1 -0
  78. package/dist/node/markdown/plugins/snippet.js +146 -0
  79. package/dist/node/markdown/plugins/snippet.js.map +1 -0
  80. package/dist/node/markdownToVue.js +166 -0
  81. package/dist/node/markdownToVue.js.map +1 -0
  82. package/dist/node/plugin.js +227 -0
  83. package/dist/node/plugin.js.map +1 -0
  84. package/dist/node/serve/serve.js +59 -0
  85. package/dist/node/serve/serve.js.map +1 -0
  86. package/dist/node/{serve-428d4610.js → serve-b5dc02b2.js} +26 -2
  87. package/dist/node/server.js +18 -0
  88. package/dist/node/server.js.map +1 -0
  89. package/dist/node/shared.js +72 -0
  90. package/dist/node/shared.js.map +1 -0
  91. package/dist/node/staticDataPlugin.js +99 -0
  92. package/dist/node/staticDataPlugin.js.map +1 -0
  93. package/dist/node/utils/getGitTimestamp.js +17 -0
  94. package/dist/node/utils/getGitTimestamp.js.map +1 -0
  95. package/dist/node/utils/parseHeader.js +57 -0
  96. package/dist/node/utils/parseHeader.js.map +1 -0
  97. package/dist/node/utils/slash.js +8 -0
  98. package/dist/node/utils/slash.js.map +1 -0
  99. package/package.json +4 -2
  100. package/types/default-theme.d.ts +12 -0
  101. package/types/shared.d.ts +11 -6
@@ -0,0 +1,96 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import { useData } from 'vitepress'
4
+ import VPBox from './VPBox.vue'
5
+
6
+ const { frontmatter: fm } = useData()
7
+
8
+ const grid = computed(() => {
9
+ const length = fm.value.features?.length
10
+
11
+ if (!length) {
12
+ return
13
+ }
14
+
15
+ if (length === 2) {
16
+ return 'grid-2'
17
+ } else if (length === 3) {
18
+ return 'grid-3'
19
+ } else if (length % 3 === 0) {
20
+ return 'grid-6'
21
+ } else if (length % 2 === 0) {
22
+ return 'grid-4'
23
+ }
24
+ })
25
+ </script>
26
+
27
+ <template>
28
+ <div v-if="fm.features" class="VPHomeFeatures">
29
+ <div class="container">
30
+ <div class="items">
31
+ <div v-for="feature in fm.features" :key="feature.title" class="item" :class="[grid]">
32
+ <VPBox
33
+ :icon="feature.icon"
34
+ :title="feature.title"
35
+ :details="feature.details"
36
+ />
37
+ </div>
38
+ </div>
39
+ </div>
40
+ </div>
41
+ </template>
42
+
43
+ <style scoped>
44
+ .VPHomeFeatures {
45
+ padding: 0 24px;
46
+ }
47
+
48
+ @media (min-width: 640px) {
49
+ .VPHomeFeatures {
50
+ padding: 0 48px;
51
+ }
52
+ }
53
+
54
+ .container {
55
+ margin: 0 auto;
56
+ max-width: 960px;
57
+ }
58
+
59
+ .items {
60
+ display: flex;
61
+ flex-wrap: wrap;
62
+ margin: -8px;
63
+ }
64
+
65
+ .item {
66
+ padding: 8px;
67
+ width: 100%;
68
+ }
69
+
70
+ @media (min-width: 640px) {
71
+ .item.grid-2,
72
+ .item.grid-4,
73
+ .item.grid-6 {
74
+ width: calc(100% / 2);
75
+ }
76
+ }
77
+
78
+ @media (min-width: 768px) {
79
+ .item.grid-2,
80
+ .item.grid-4 {
81
+ width: calc(100% / 2);
82
+ }
83
+
84
+ .item.grid-3,
85
+ .item.grid-6 {
86
+ width: calc(100% / 3);
87
+ }
88
+ }
89
+
90
+ @media (min-width: 960px) {
91
+ .item.grid-4 {
92
+ width: calc(100% / 4);
93
+ }
94
+ }
95
+
96
+ </style>
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ import { useData } from 'vitepress'
3
+ import VPHero from './VPHero.vue'
4
+
5
+ const { frontmatter: fm } = useData()
6
+ </script>
7
+
8
+ <template>
9
+ <div v-if="fm.hero" class="VPHomeHero">
10
+ <VPHero
11
+ :name="fm.hero.name"
12
+ :text="fm.hero.text"
13
+ :tagline="fm.hero.tagline"
14
+ :actions="fm.hero.actions"
15
+ />
16
+ </div>
17
+ </template>
@@ -0,0 +1,97 @@
1
+ <script setup lang="ts">
2
+ import VPIconHeart from './icons/VPIconHeart.vue'
3
+ import VPButton from './VPButton.vue'
4
+ import VPSponsors from './VPSponsors.vue'
5
+
6
+ interface Sponsors {
7
+ tier: string
8
+ size?: 'medium' | 'big'
9
+ items: Sponsor[]
10
+ }
11
+
12
+ interface Sponsor {
13
+ name: string
14
+ img: string
15
+ url: string
16
+ }
17
+
18
+ defineProps<{
19
+ message?: string
20
+ actionText?: string
21
+ actionLink?: string
22
+ data: Sponsors[]
23
+ }>()
24
+ </script>
25
+
26
+ <template>
27
+ <section class="VPHomeSponsors">
28
+ <div class="container">
29
+ <div class="header">
30
+ <div class="love"><VPIconHeart class="icon" /></div>
31
+ <h2 v-if="message" class="message">{{ message }}</h2>
32
+ </div>
33
+
34
+ <div class="sponsors">
35
+ <VPSponsors :data="data" />
36
+ </div>
37
+
38
+ <div v-if="actionLink" class="action">
39
+ <VPButton
40
+ theme="sponsor"
41
+ :text="actionText ?? 'Become a sponsor'"
42
+ :href="actionLink"
43
+ />
44
+ </div>
45
+ </div>
46
+ </section>
47
+ </template>
48
+
49
+ <style scoped>
50
+ .VPHomeSponsors {
51
+ border-top: 1px solid var(--vp-c-divider-light);
52
+ padding: 88px 24px 96px;
53
+ background-color: var(--vp-c-bg-content);
54
+ }
55
+
56
+ .container {
57
+ margin: 0 auto;
58
+ max-width: 960px;
59
+ }
60
+
61
+ .love {
62
+ margin: 0 auto;
63
+ width: 28px;
64
+ height: 28px;
65
+ color: var(--vp-c-text-3);
66
+ }
67
+
68
+ .icon {
69
+ width: 28px;
70
+ height: 28px;
71
+ fill: currentColor;
72
+ }
73
+
74
+ .message {
75
+ margin: 0 auto;
76
+ padding-top: 10px;
77
+ max-width: 320px;
78
+ text-align: center;
79
+ line-height: 24px;
80
+ font-size: 16px;
81
+ font-weight: 500;
82
+ color: var(--vp-c-text-2);
83
+ }
84
+
85
+ .sponsors {
86
+ padding-top: 32px;
87
+ }
88
+
89
+ .sponsor + .sponsor {
90
+ padding-top: 0px;
91
+ }
92
+
93
+ .action {
94
+ padding-top: 40px;
95
+ text-align: center;
96
+ }
97
+ </style>
@@ -84,6 +84,7 @@ defineEmits<{
84
84
 
85
85
  .menu + .translations::before,
86
86
  .menu + .appearance::before,
87
+ .menu + .social-links::before,
87
88
  .translations + .appearance::before,
88
89
  .appearance + .social-links::before {
89
90
  margin-right: 8px;
@@ -1,9 +1,12 @@
1
1
  <script lang="ts" setup>
2
+ import { useData } from 'vitepress'
2
3
  import VPSwitchAppearance from './VPSwitchAppearance.vue'
4
+
5
+ const { site } = useData()
3
6
  </script>
4
7
 
5
8
  <template>
6
- <div class="VPNavBarAppearance">
9
+ <div v-if="site.appearance" class="VPNavBarAppearance">
7
10
  <VPSwitchAppearance />
8
11
  </div>
9
12
  </template>
@@ -4,7 +4,7 @@ import VPFlyout from './VPFlyout.vue'
4
4
  import VPSwitchAppearance from './VPSwitchAppearance.vue'
5
5
  import VPSocialLinks from './VPSocialLinks.vue'
6
6
 
7
- const { theme } = useData()
7
+ const { site, theme } = useData()
8
8
  </script>
9
9
 
10
10
  <template>
@@ -23,7 +23,7 @@ const { theme } = useData()
23
23
  </div>
24
24
  </div>
25
25
 
26
- <div class="group">
26
+ <div v-if="site.appearance" class="group">
27
27
  <div class="item">
28
28
  <p class="label">Appearance</p>
29
29
  <div class="appearance-action">
@@ -3,9 +3,9 @@ import '@docsearch/css'
3
3
  import { useData } from 'vitepress'
4
4
  import { defineAsyncComponent, ref, onMounted, onUnmounted } from 'vue'
5
5
 
6
- const VPAlgoliaSearchBox = defineAsyncComponent(
7
- () => import('./VPAlgoliaSearchBox.vue')
8
- )
6
+ const VPAlgoliaSearchBox = defineAsyncComponent(() => {
7
+ return import('./VPAlgoliaSearchBox.vue')
8
+ })
9
9
 
10
10
  const { theme } = useData()
11
11
 
@@ -1,39 +1,52 @@
1
1
  <script setup lang="ts">
2
2
  import { useData } from 'vitepress'
3
+ import { useSidebar } from '../composables/sidebar'
3
4
 
4
5
  const { site, theme } = useData()
6
+ const { hasSidebar } = useSidebar()
5
7
  </script>
6
8
 
7
9
  <template>
8
- <a class="VPNavBarTitle" href="/">
9
- <img v-if="theme.logo" class="logo" :src="theme.logo" :alt="site.title">
10
- {{ site.title }}
11
- </a>
10
+ <div class="VPNavBarTitle" :class="{ 'has-sidebar': hasSidebar }">
11
+ <a class="title" href="/">
12
+ <img v-if="theme.logo" class="logo" :src="theme.logo" :alt="site.title">
13
+ {{ site.title }}
14
+ </a>
15
+ </div>
12
16
  </template>
13
17
 
14
18
  <style scoped>
15
19
  .VPNavBarTitle {
20
+ flex-shrink: 0;
21
+ }
22
+
23
+ @media (min-width: 960px) {
24
+ .VPNavBarTitle.has-sidebar {
25
+ margin-right: 32px;
26
+ width: calc(var(--vp-sidebar-width) - 64px);
27
+ border-bottom: 1px solid var(--vp-c-divider-light);
28
+ background-color: var(--vp-c-bg-sidebar);
29
+ }
30
+ }
31
+
32
+ .title {
16
33
  display: flex;
17
34
  align-items: center;
18
- height: var(--vp-nav-height-mobile);
35
+ width: 100%;
36
+ height: var(--vp-nav-height);
19
37
  font-size: 16px;
20
38
  font-weight: 600;
21
39
  color: var(--vp-c-text-1);
22
- transition: background-color 0.5s, opacity 0.25s;
40
+ transition: opacity 0.25s;
23
41
  }
24
42
 
25
- .VPNavBarTitle:hover {
43
+ .title:hover {
26
44
  opacity: 0.6;
27
45
  }
28
46
 
29
47
  @media (min-width: 960px) {
30
- .VPNavBarTitle {
48
+ .title {
31
49
  flex-shrink: 0;
32
- margin-right: 32px;
33
- border-bottom: 1px solid var(--vp-c-divider-light);
34
- width: calc(var(--vp-sidebar-width) - 64px);
35
- height: var(--vp-nav-height-desktop);
36
- background-color: var(--vp-c-bg-sidebar);
37
50
  }
38
51
  }
39
52
 
@@ -1,9 +1,12 @@
1
1
  <script lang="ts" setup>
2
+ import { useData } from 'vitepress'
2
3
  import VPSwitchAppearance from './VPSwitchAppearance.vue'
4
+
5
+ const { site } = useData()
3
6
  </script>
4
7
 
5
8
  <template>
6
- <div class="VPNavScreenAppearance">
9
+ <div v-if="site.appearance" class="VPNavScreenAppearance">
7
10
  <p class="text">Appearance</p>
8
11
  <VPSwitchAppearance />
9
12
  </div>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <div class="VPPage">
3
+ <Content />
4
+ </div>
5
+ </template>
@@ -0,0 +1,77 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import VPSponsorsGrid from './VPSponsorsGrid.vue'
4
+
5
+ interface Sponsors {
6
+ tier?: string
7
+ size?: 'small' | 'medium' | 'big'
8
+ items: Sponsor[]
9
+ }
10
+
11
+ interface Sponsor {
12
+ name: string
13
+ img: string
14
+ url: string
15
+ }
16
+
17
+ const props = defineProps<{
18
+ tier?: string
19
+ size?: 'small' | 'medium' | 'big'
20
+ data: Sposors[] | Sponsor[]
21
+ }>()
22
+
23
+ const sponsors = computed(() => {
24
+ const isSponsors = props.data.some((s: any) => s.items)
25
+
26
+ if (isSponsors) {
27
+ return props.data
28
+ }
29
+
30
+ return [{
31
+ tier: props.tier,
32
+ size: props.size,
33
+ items: props.data
34
+ }]
35
+ })
36
+ </script>
37
+
38
+ <template>
39
+ <div class="VPSponsors">
40
+ <section v-for="(sponsor, index) in sponsors" :key="index" class="section">
41
+ <h3 v-if="sponsor.tier" class="tier">{{ sponsor.tier }}</h3>
42
+ <VPSponsorsGrid :size="sponsor.size" :data="sponsor.items" />
43
+ </section>
44
+ </div>
45
+ </template>
46
+
47
+ <style scoped>
48
+ .VPSponsors {
49
+ border-radius: 16px;
50
+ overflow: hidden;
51
+ }
52
+
53
+ .section + .section {
54
+ margin-top: 4px;
55
+ }
56
+
57
+ .tier {
58
+ margin-bottom: 4px;
59
+ padding: 13px 0 11px;
60
+ text-align: center;
61
+ letter-spacing: 1px;
62
+ line-height: 24px;
63
+ width: 100%;
64
+ font-size: 14px;
65
+ font-weight: 600;
66
+ color: var(--vp-c-text-2);
67
+ background-color: var(--vp-c-white-soft);
68
+ }
69
+
70
+ .dark .tier {
71
+ background-color: var(--vp-c-black-mute);
72
+ }
73
+
74
+ .VPSponsorsGrid + .tier {
75
+ margin-top: 4px;
76
+ }
77
+ </style>
@@ -0,0 +1,32 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+ import { useSponsorsGrid } from '../composables/sponsor-grid'
4
+
5
+ interface Sponsor {
6
+ name: string
7
+ img: string
8
+ url: string
9
+ }
10
+
11
+ const props = defineProps<{
12
+ size?: 'small' | 'medium' | 'big'
13
+ data: Sponsor[]
14
+ }>()
15
+
16
+ const el = ref(null)
17
+
18
+ useSponsorsGrid({ el, size: props.size })
19
+ </script>
20
+
21
+ <template>
22
+ <div class="VPSponsorsGrid vp-sponsor-grid" :class="[props.size ?? 'medium']" ref="el">
23
+ <div v-for="sponsor in data" :key="sponsor.tier" class="vp-sponsor-grid-item">
24
+ <a class="vp-sponsor-grid-link" :href="sponsor.url" target="_blank" rel="sponsored noopener">
25
+ <article class="vp-sponsor-grid-box">
26
+ <h4 class="visually-hidden">{{ sponsor.name }}</h4>
27
+ <img class="vp-sponsor-grid-image" :src="sponsor.img" :alt="sponsor.name" />
28
+ </article>
29
+ </a>
30
+ </div>
31
+ </div>
32
+ </template>
@@ -1,4 +1,5 @@
1
1
  <script lang="ts" setup>
2
+ import { APPEARANCE_KEY } from '../../shared'
2
3
  import VPSwitch from './VPSwitch.vue'
3
4
  import VPIconSun from './icons/VPIconSun.vue'
4
5
  import VPIconMoon from './icons/VPIconMoon.vue'
@@ -6,11 +7,10 @@ import VPIconMoon from './icons/VPIconMoon.vue'
6
7
  const toggle = typeof localStorage !== 'undefined' ? useAppearance() : () => {}
7
8
 
8
9
  function useAppearance() {
9
- const storageKey = 'vitepress-theme-appearance'
10
10
  const query = window.matchMedia('(prefers-color-scheme: dark)')
11
11
  const classList = document.documentElement.classList
12
12
 
13
- let userPreference = localStorage.getItem(storageKey) || 'auto'
13
+ let userPreference = localStorage.getItem(APPEARANCE_KEY) || 'auto'
14
14
 
15
15
  let isDark = userPreference === 'auto'
16
16
  ? query.matches
@@ -29,7 +29,7 @@ function useAppearance() {
29
29
  ? query.matches ? 'auto' : 'dark'
30
30
  : query.matches ? 'light' : 'auto'
31
31
 
32
- localStorage.setItem(storageKey, userPreference)
32
+ localStorage.setItem(APPEARANCE_KEY, userPreference)
33
33
  }
34
34
 
35
35
  function setClass(dark: boolean): void {
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
3
+ <path d="M12,22.2c-0.3,0-0.5-0.1-0.7-0.3l-8.8-8.8c-2.5-2.5-2.5-6.7,0-9.2c2.5-2.5,6.7-2.5,9.2,0L12,4.3l0.4-0.4c0,0,0,0,0,0C13.6,2.7,15.2,2,16.9,2c0,0,0,0,0,0c1.7,0,3.4,0.7,4.6,1.9l0,0c1.2,1.2,1.9,2.9,1.9,4.6c0,1.7-0.7,3.4-1.9,4.6l-8.8,8.8C12.5,22.1,12.3,22.2,12,22.2zM7,4C5.9,4,4.7,4.4,3.9,5.3c-1.8,1.8-1.8,4.6,0,6.4l8.1,8.1l8.1-8.1c0.9-0.9,1.3-2,1.3-3.2c0-1.2-0.5-2.3-1.3-3.2l0,0C19.3,4.5,18.2,4,17,4c0,0,0,0,0,0c-1.2,0-2.3,0.5-3.2,1.3c0,0,0,0,0,0l-1.1,1.1c-0.4,0.4-1,0.4-1.4,0l-1.1-1.1C9.4,4.4,8.2,4,7,4z" />
4
+ </svg>
5
+ </template>
@@ -1,5 +1,6 @@
1
1
  import { onMounted, onUpdated, onUnmounted } from 'vue';
2
2
  import { useMediaQuery } from '@vueuse/core';
3
+ import { throttleAndDebounce } from '../support/utils';
3
4
  // magic number to avoid repeated retrieval
4
5
  const PAGE_OFFSET = 56;
5
6
  export function resolveHeaders(headers) {
@@ -109,22 +110,3 @@ function isAnchorActive(index, anchor, nextAnchor) {
109
110
  }
110
111
  return [false, null];
111
112
  }
112
- function throttleAndDebounce(fn, delay) {
113
- let timeout;
114
- let called = false;
115
- return () => {
116
- if (timeout) {
117
- clearTimeout(timeout);
118
- }
119
- if (!called) {
120
- fn();
121
- called = true;
122
- setTimeout(() => {
123
- called = false;
124
- }, delay);
125
- }
126
- else {
127
- timeout = setTimeout(fn, delay);
128
- }
129
- };
130
- }
@@ -0,0 +1,92 @@
1
+ import { onMounted, onUnmounted } from 'vue';
2
+ import { throttleAndDebounce } from '../support/utils';
3
+ /**
4
+ * Defines grid configuration for each sponsor size in touple.
5
+ *
6
+ * [Screen widh, Column size]
7
+ *
8
+ * It sets grid size on matching screen size. For example, `[768, 5]` will set
9
+ * 5 columns when screen size is bigger or equal to 768px.
10
+ *
11
+ * Column will set only when item size is bigger than the column size. For
12
+ * example, even we want 5 columns, if we only have 1 sponsor yet, we would
13
+ * like to show it in 1 column.
14
+ */
15
+ const GridSettings = {
16
+ small: [
17
+ [920, 6],
18
+ [768, 5],
19
+ [640, 4],
20
+ [480, 3],
21
+ [0, 2]
22
+ ],
23
+ medium: [
24
+ [960, 5],
25
+ [832, 4],
26
+ [640, 3],
27
+ [480, 2]
28
+ ],
29
+ big: [
30
+ [832, 3],
31
+ [640, 2]
32
+ ]
33
+ };
34
+ export function useSponsorsGrid(options) {
35
+ const onResize = throttleAndDebounce(manage, 100);
36
+ onMounted(() => {
37
+ manage();
38
+ window.addEventListener('resize', onResize);
39
+ });
40
+ onUnmounted(() => {
41
+ window.removeEventListener('resize', onResize);
42
+ });
43
+ function manage() {
44
+ adjustSlots(options.el.value, options.size);
45
+ }
46
+ }
47
+ function adjustSlots(el, size) {
48
+ const tsize = el.children.length;
49
+ const asize = el.querySelectorAll('.vp-sponsor-grid-item:not(.empty)').length;
50
+ const grid = setGrid(el, size, asize);
51
+ manageSlots(el, grid, tsize, asize);
52
+ }
53
+ function setGrid(el, size, items) {
54
+ const settings = GridSettings[size];
55
+ const screen = window.innerWidth;
56
+ let grid = 1;
57
+ settings.some(([breakpoint, value]) => {
58
+ if (screen >= breakpoint) {
59
+ grid = items < value ? items : value;
60
+ return true;
61
+ }
62
+ });
63
+ setGridData(el, grid);
64
+ return grid;
65
+ }
66
+ function setGridData(el, value) {
67
+ el.dataset.vpGrid = String(value);
68
+ }
69
+ function manageSlots(el, grid, tsize, asize) {
70
+ const diff = tsize - asize;
71
+ const rem = asize % grid;
72
+ const drem = rem === 0 ? rem : grid - rem;
73
+ neutralizeSlots(el, drem - diff);
74
+ }
75
+ function neutralizeSlots(el, count) {
76
+ if (count === 0) {
77
+ return;
78
+ }
79
+ count > 0 ? addSlots(el, count) : removeSlots(el, count * -1);
80
+ }
81
+ function addSlots(el, count) {
82
+ for (let i = 0; i < count; i++) {
83
+ const slot = document.createElement('div');
84
+ slot.classList.add('vp-sponsor-grid-item', 'empty');
85
+ el.append(slot);
86
+ }
87
+ }
88
+ function removeSlots(el, count) {
89
+ for (let i = 0; i < count; i++) {
90
+ el.removeChild(el.lastElementChild);
91
+ }
92
+ }