@sugarat/theme 0.5.11 → 0.5.12-beta.0

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.
@@ -1,12 +1,11 @@
1
1
  <script lang="ts" setup>
2
- import { ElAvatar } from 'element-plus'
3
2
  import { useDark, useIntervalFn } from '@vueuse/core'
4
- import { computed, onMounted, onUnmounted, ref } from 'vue'
5
- import Swiper from 'swiper'
3
+ import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
6
4
  import { useFriendData } from '../composables/config/blog'
7
- import { getImageUrl, shuffleArray } from '../utils/client'
5
+ import { getImageUrl } from '../utils/client'
8
6
  import type { Theme } from '../'
9
7
  import { friendLinkSvgStr } from '../constants/svg'
8
+ import Avatar from './Avatar.vue'
10
9
 
11
10
  const isDark = useDark({
12
11
  storageKey: 'vitepress-theme-appearance'
@@ -37,10 +36,10 @@ const openScroll = computed(() => {
37
36
 
38
37
  const friendList = computed(() => {
39
38
  const data = [...friendConfig.value.list]
40
- // 简单的随机打乱
41
- if (friendConfig.value.random) {
42
- data.splice(0, data.length, ...shuffleArray(data))
43
- }
39
+ // 简单的随机打乱,在数据导入侧打乱,避免SSG与CSR内容不一致
40
+ // if (friendConfig.value.random) {
41
+ // data.splice(0, data.length, ...shuffleArray(data))
42
+ // }
44
43
 
45
44
  // 展示个数限制,删除多余的
46
45
  if (scrollSpeed.value === 0 && limit.value) {
@@ -71,25 +70,55 @@ const containerHeight = computed(() => {
71
70
  return scrollWrapperHeight.value ? `${scrollWrapperHeight.value}px` : 'auto'
72
71
  })
73
72
 
74
- const swiper = ref<Swiper>()
75
- const { resume, pause } = useIntervalFn(() => {
76
- swiper.value?.slideNext()
77
- }, scrollSpeed.value)
73
+ const currentIndex = ref(0)
74
+ const isTransitioning = ref(false)
78
75
 
79
- onMounted(() => {
80
- pause()
76
+ const displayList = computed(() => {
81
77
  if (openScroll.value) {
82
- // eslint-disable-next-line no-new
83
- swiper.value = new Swiper('.scroll-wrapper', {
84
- direction: 'vertical',
85
- slidesPerView: limit.value,
86
- loop: true,
87
- })
78
+ return [...friendList.value, ...friendList.value.slice(0, limit.value)]
79
+ }
80
+ return friendList.value
81
+ })
82
+
83
+ const listStyle = computed(() => {
84
+ const translate = -1 * currentIndex.value * cardHeight
85
+ return {
86
+ transform: `translateY(${translate}px)`,
87
+ transition: isTransitioning.value ? 'transform 0.5s ease-in-out' : 'none'
88
+ }
89
+ })
90
+
91
+ const { resume, pause } = useIntervalFn(() => {
92
+ if (!openScroll.value)
93
+ return
94
+
95
+ currentIndex.value++
96
+ isTransitioning.value = true
97
+
98
+ if (currentIndex.value === friendList.value.length) {
99
+ setTimeout(() => {
100
+ isTransitioning.value = false
101
+ currentIndex.value = 0
102
+ }, 500)
103
+ }
104
+ }, scrollSpeed)
105
+
106
+ watch(openScroll, (val) => {
107
+ if (val) {
88
108
  resume()
89
109
  }
110
+ else {
111
+ pause()
112
+ currentIndex.value = 0
113
+ isTransitioning.value = false
114
+ }
115
+ })
116
+
117
+ onMounted(() => {
118
+ if (openScroll.value)
119
+ resume()
90
120
  })
91
121
 
92
- // TODO: SSR渲染支持
93
122
  onUnmounted(() => {
94
123
  pause()
95
124
  })
@@ -107,10 +136,10 @@ onUnmounted(() => {
107
136
  height: containerHeight,
108
137
  }"
109
138
  >
110
- <ol class="friend-list swiper-wrapper">
111
- <li v-for=" (v, idx) in friendList" :key="idx" class="swiper-slide">
139
+ <ol class="friend-list" :style="listStyle">
140
+ <li v-for="(v, idx) in displayList" :key="idx" class="scroll-item">
112
141
  <a :href="v.url" target="_blank">
113
- <ElAvatar :size="50" :src="v.avatar" :alt="v.alt" />
142
+ <Avatar :size="50" :src="v.avatar" :alt="v.alt" />
114
143
  <div class="info-wrapper">
115
144
  <span class="nickname">{{ v.nickname }}</span>
116
145
  <p class="des">{{ v.des }}</p>
@@ -178,9 +207,7 @@ onUnmounted(() => {
178
207
  box-sizing: border-box;
179
208
  padding: 0 5px;
180
209
  height: 76px;
181
- .el-avatar {
182
- min-width: 50px;
183
- }
210
+ cursor: pointer;
184
211
 
185
212
  a {
186
213
  display: flex;
@@ -14,9 +14,7 @@ import BlogFriendLink from './BlogFriendLink.vue'
14
14
  <BlogHotArticle />
15
15
 
16
16
  <!-- 友链 -->
17
- <ClientOnly>
18
- <BlogFriendLink />
19
- </ClientOnly>
17
+ <BlogFriendLink />
20
18
 
21
19
  <!-- 标签 -->
22
20
  <BlogHomeTags />
@@ -1,7 +1,6 @@
1
1
  <script lang="ts" setup>
2
2
  import { computed, watch } from 'vue'
3
- import { ElTag } from 'element-plus'
4
- import { useBrowserLocation, useDark, useUrlSearchParams } from '@vueuse/core'
3
+ import { useBrowserLocation, useUrlSearchParams } from '@vueuse/core'
5
4
  import { useRoute, useRouter } from 'vitepress'
6
5
  import {
7
6
  useActiveTag,
@@ -10,6 +9,7 @@ import {
10
9
  useHomeTagsConfig,
11
10
  } from '../composables/config/blog'
12
11
  import { tagsSvgStr } from '../constants/svg'
12
+ import Tag from './Tag.vue'
13
13
 
14
14
  const route = useRoute()
15
15
  const docs = useArticles()
@@ -25,12 +25,6 @@ const tags = computed(() => {
25
25
 
26
26
  const activeTag = useActiveTag()
27
27
 
28
- const isDark = useDark({
29
- storageKey: 'vitepress-theme-appearance'
30
- })
31
-
32
- const colorMode = computed(() => (isDark.value ? 'light' : 'dark'))
33
-
34
28
  const tagType: any = ['', 'info', 'success', 'warning', 'danger']
35
29
  const currentPage = useCurrentPageNum()
36
30
  const router = useRouter()
@@ -88,22 +82,22 @@ watch(
88
82
  <!-- 头部 -->
89
83
  <div class="card-header">
90
84
  <span class="title svg-icon" v-html="title" />
91
- <ElTag
92
- v-if="activeTag.label" :type="activeTag.type || 'primary'" :effect="colorMode" closable
85
+ <Tag
86
+ v-if="activeTag.label" :type="activeTag.type || 'primary'" closable
93
87
  @close="handleCloseTag"
94
88
  >
95
89
  {{ activeTag.label }}
96
- </ElTag>
90
+ </Tag>
97
91
  </div>
98
92
  <!-- 标签列表 -->
99
93
  <ul class="tag-list">
100
94
  <li v-for="(tag, idx) in tags" :key="tag">
101
- <ElTag
102
- :type="tagType[idx % tagType.length] || 'primary'" :effect="colorMode"
95
+ <Tag
96
+ :type="tagType[idx % tagType.length] || 'primary'"
103
97
  @click="handleTagClick(tag, tagType[idx % tagType.length])"
104
98
  >
105
99
  {{ tag }}
106
- </ElTag>
100
+ </Tag>
107
101
  </li>
108
102
  </ul>
109
103
  </div>
@@ -1,10 +1,10 @@
1
1
  <script lang="ts" setup>
2
2
  import { computed, ref } from 'vue'
3
- import { ElButton } from 'element-plus'
4
3
  import { useRouter, withBase } from 'vitepress'
5
4
  import { useArticles, useCleanUrls, useFormatShowDate, useHotArticleConfig, useShowHotArticle } from '../composables/config/blog'
6
5
  import { wrapperCleanUrls } from '../utils/client'
7
6
  import { fireSVG } from '../constants/svg'
7
+ import Button from './Button.vue'
8
8
 
9
9
  const formatShowDate = useFormatShowDate()
10
10
 
@@ -59,9 +59,9 @@ const showChangeBtn = computed(() => {
59
59
  <!-- 头部 -->
60
60
  <div class="card-header">
61
61
  <span class="title svg-icon" v-html="title" />
62
- <ElButton v-if="showChangeBtn" size="small" type="primary" text @click="changePage">
62
+ <Button v-if="showChangeBtn" size="small" type="primary" text @click="changePage">
63
63
  {{ nextText }}
64
- </ElButton>
64
+ </Button>
65
65
  </div>
66
66
  <!-- 文章列表 -->
67
67
  <ol v-if="currentWikiData.length" class="recommend-container">
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
- import { ElImageViewer } from 'element-plus'
3
2
  import { onMounted, onUnmounted, reactive, ref } from 'vue'
3
+ import ImageViewer from './ImageViewer.vue'
4
4
 
5
5
  const show = ref(false)
6
6
  const previewImageInfo = reactive<{ url: string; list: string[]; idx: number }>(
@@ -15,7 +15,7 @@ function previewImage(e: Event) {
15
15
  const currentTarget = e.currentTarget as HTMLElement
16
16
  if (target.tagName.toLowerCase() === 'img') {
17
17
  const imgs = currentTarget.querySelectorAll<HTMLImageElement>(
18
- '.content-container .main img'
18
+ '.content-container .main img,.VPPage img'
19
19
  )
20
20
  const idx = Array.from(imgs).findIndex(el => el === target)
21
21
  const urls = Array.from(imgs).map(el => el.src)
@@ -45,7 +45,7 @@ onUnmounted(() => {
45
45
  </script>
46
46
 
47
47
  <template>
48
- <ElImageViewer
48
+ <ImageViewer
49
49
  v-if="show" :infinite="false" hide-on-click-modal teleported :url-list="previewImageInfo.list"
50
50
  :initial-index="previewImageInfo.idx" @close="show = false"
51
51
  />
@@ -1,16 +1,16 @@
1
1
  <script setup lang="ts">
2
2
  import { computed, nextTick, watch } from 'vue'
3
- import { ElPagination } from 'element-plus'
4
3
  import { useData, useRoute, useRouter } from 'vitepress'
5
4
  import {
6
5
  useActiveTag,
7
6
  useArticles,
8
7
  useCurrentPageNum,
9
8
  useGlobalAuthor,
10
- useHomeConfig
9
+ useHomeConfig,
11
10
  } from '../composables/config/blog'
12
11
  import type { Theme } from '../composables/config'
13
12
  import BlogItem from './BlogItem.vue'
13
+ import Pagination from './Pagination.vue'
14
14
 
15
15
  const { frontmatter } = useData<Theme.Config>()
16
16
  const globalAuthor = useGlobalAuthor()
@@ -111,11 +111,10 @@ router.onAfterRouteChange = () => {
111
111
  <!-- 解决element-ui bug -->
112
112
  <ClientOnly>
113
113
  <div class="el-pagination-wrapper">
114
- <ElPagination
114
+ <Pagination
115
115
  v-if="wikiList.length >= pageSize"
116
116
  small
117
117
  background
118
- :default-current-page="1"
119
118
  :current-page="currentPage"
120
119
  :page-size="pageSize"
121
120
  :total="filterData.length"
@@ -128,17 +127,17 @@ router.onAfterRouteChange = () => {
128
127
 
129
128
  <style lang="scss" scoped>
130
129
  .el-pagination-wrapper {
131
- :deep(.el-pagination li.is-active.number) {
130
+ :deep(.sugar-pagination li.is-active.number) {
132
131
  background-color: var(--vp-c-brand-2);
133
132
  }
134
- :deep(.el-pagination button:hover) {
133
+ :deep(.sugar-pagination button:hover) {
135
134
  color: var(--vp-c-brand-2);
136
135
  }
137
136
 
138
- :deep(.el-pager li:not(.is-active):hover) {
137
+ :deep(.sugar-pager li:not(.is-active):hover) {
139
138
  color: var(--vp-c-brand-2);
140
139
  }
141
- :deep(.el-input__wrapper.is-focus) {
140
+ :deep(.sugar-input__wrapper:focus-within) {
142
141
  box-shadow: 0 0 0 1px var(--vp-c-brand-2) inset;
143
142
  }
144
143
  }
@@ -1,11 +1,11 @@
1
1
  <script lang="ts" setup>
2
2
  import { computed, onMounted, ref } from 'vue'
3
3
  import { useRoute, useRouter, withBase } from 'vitepress'
4
- import { ElButton } from 'element-plus'
5
4
  import { wrapperCleanUrls } from '../utils/client'
6
5
  import { useArticles, useCleanUrls, useFormatShowDate, useRecommendConfig, useShowRecommend } from '../composables/config/blog'
7
6
  import { recommendSVG } from '../constants/svg'
8
7
  import type { Theme } from '../composables/config/index'
8
+ import Button from './Button.vue'
9
9
 
10
10
  const formatShowDate = useFormatShowDate()
11
11
 
@@ -162,9 +162,9 @@ function handleLinkClick(link: string) {
162
162
  <!-- 头部 -->
163
163
  <div class="card-header">
164
164
  <span v-if="title" class="title" v-html="title" />
165
- <ElButton v-if="showChangeBtn" size="small" type="primary" text @click="changePage">
165
+ <Button v-if="showChangeBtn" size="small" type="primary" text @click="changePage">
166
166
  {{ nextText }}
167
- </ElButton>
167
+ </Button>
168
168
  </div>
169
169
  <!-- 文章列表 -->
170
170
  <ol
@@ -0,0 +1,165 @@
1
+ <script lang="ts" setup>
2
+ import { computed } from 'vue'
3
+
4
+ const props = defineProps({
5
+ type: {
6
+ type: String,
7
+ default: 'default',
8
+ validator: (val: string) => ['default', 'primary', 'success', 'warning', 'danger', 'info'].includes(val),
9
+ },
10
+ size: {
11
+ type: String,
12
+ default: 'default',
13
+ validator: (val: string) => ['large', 'default', 'small'].includes(val),
14
+ },
15
+ text: {
16
+ type: Boolean,
17
+ default: false,
18
+ },
19
+ round: {
20
+ type: Boolean,
21
+ default: false,
22
+ },
23
+ disabled: {
24
+ type: Boolean,
25
+ default: false,
26
+ },
27
+ })
28
+
29
+ const emit = defineEmits(['click'])
30
+
31
+ function handleClick(evt: MouseEvent) {
32
+ if (props.disabled)
33
+ return
34
+ emit('click', evt)
35
+ }
36
+
37
+ const classes = computed(() => {
38
+ return [
39
+ 'sugar-button',
40
+ `sugar-button--${props.type}`,
41
+ `sugar-button--${props.size}`,
42
+ {
43
+ 'is-text': props.text,
44
+ 'is-round': props.round,
45
+ 'is-disabled': props.disabled,
46
+ },
47
+ ]
48
+ })
49
+ </script>
50
+
51
+ <template>
52
+ <button :class="classes" :disabled="disabled" @click="handleClick">
53
+ <slot />
54
+ </button>
55
+ </template>
56
+
57
+ <style lang="scss" scoped>
58
+ .sugar-button {
59
+ display: inline-flex;
60
+ justify-content: center;
61
+ align-items: center;
62
+ line-height: 1;
63
+ height: 32px;
64
+ white-space: nowrap;
65
+ cursor: pointer;
66
+ color: var(--vp-c-text-1);
67
+ text-align: center;
68
+ box-sizing: border-box;
69
+ outline: none;
70
+ transition: .1s;
71
+ font-weight: 500;
72
+ user-select: none;
73
+ vertical-align: middle;
74
+ -webkit-appearance: none;
75
+ background-color: var(--vp-c-bg);
76
+ border: 1px solid var(--vp-c-divider);
77
+ border-radius: 4px;
78
+ padding: 8px 15px;
79
+ font-size: 14px;
80
+
81
+ &:hover {
82
+ color: var(--vp-c-brand-1);
83
+ border-color: var(--vp-c-brand-2);
84
+ background-color: var(--vp-c-bg-alt);
85
+ }
86
+
87
+ &:active {
88
+ color: var(--vp-c-brand-3);
89
+ border-color: var(--vp-c-brand-3);
90
+ }
91
+
92
+ &.is-disabled {
93
+ cursor: not-allowed;
94
+ opacity: 0.5;
95
+ }
96
+
97
+ /* Types */
98
+ &--primary {
99
+ color: #fff;
100
+ background-color: var(--vp-c-brand-1);
101
+ border-color: var(--vp-c-brand-1);
102
+
103
+ &:hover {
104
+ background-color: var(--vp-c-brand-2);
105
+ border-color: var(--vp-c-brand-2);
106
+ color: #fff;
107
+ }
108
+
109
+ &:active {
110
+ background-color: var(--vp-c-brand-3);
111
+ border-color: var(--vp-c-brand-3);
112
+ color: #fff;
113
+ }
114
+
115
+ &.is-text {
116
+ color: var(--vp-c-brand-1);
117
+ background-color: transparent;
118
+ border-color: transparent;
119
+
120
+ &:hover {
121
+ background-color: var(--vp-c-bg-alt);
122
+ color: var(--vp-c-brand-2);
123
+ }
124
+
125
+ &:active {
126
+ color: var(--vp-c-brand-3);
127
+ }
128
+ }
129
+ }
130
+
131
+ &--danger {
132
+ color: #fff;
133
+ background-color: var(--vp-c-danger-2);
134
+ border-color: var(--vp-c-danger-2);
135
+
136
+ &:hover {
137
+ background-color: var(--vp-c-danger-3);
138
+ border-color: var(--vp-c-danger-3);
139
+ color: #fff;
140
+ }
141
+
142
+ &:active {
143
+ background-color: var(--vp-c-danger-3);
144
+ border-color: var(--vp-c-danger-3);
145
+ color: #fff;
146
+ }
147
+ }
148
+
149
+ // 其它有需要再引入
150
+ /* Sizes */
151
+ &--small {
152
+ height: 24px;
153
+ padding: 5px 11px;
154
+ font-size: 12px;
155
+ border-radius: 3px;
156
+ }
157
+
158
+ &--large {
159
+ height: 40px;
160
+ padding: 12px 19px;
161
+ font-size: 16px;
162
+ border-radius: 4px;
163
+ }
164
+ }
165
+ </style>