@sugarat/theme 0.2.29 → 0.3.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.
package/node.d.ts CHANGED
@@ -93,7 +93,8 @@ declare namespace Theme {
93
93
  label: string;
94
94
  type: string;
95
95
  }
96
- interface CommentConfig extends GiscusConfig {
96
+ type CommentConfig = ((GiscusOption & CommentCommonConfig) | GiscusConfig | ArtalkConfig);
97
+ interface CommentCommonConfig {
97
98
  /**
98
99
  * @default '评论'
99
100
  */
@@ -109,7 +110,15 @@ declare namespace Theme {
109
110
  */
110
111
  mobileMinify?: boolean;
111
112
  }
112
- interface GiscusConfig {
113
+ interface GiscusConfig extends CommentCommonConfig {
114
+ type: 'giscus';
115
+ options: GiscusOption;
116
+ }
117
+ interface ArtalkConfig extends CommentCommonConfig {
118
+ type: 'artalk';
119
+ options: ArtalkOption;
120
+ }
121
+ interface GiscusOption {
113
122
  repo: Repo;
114
123
  repoId: string;
115
124
  category: string;
@@ -119,6 +128,10 @@ declare namespace Theme {
119
128
  lang?: string;
120
129
  loading?: 'lazy' | 'eager';
121
130
  }
131
+ interface ArtalkOption {
132
+ site: string;
133
+ server: string;
134
+ }
122
135
  interface HotArticle {
123
136
  title?: string;
124
137
  pageSize?: number;
@@ -308,7 +321,7 @@ declare namespace Theme {
308
321
  pagesData: PageData[];
309
322
  srcDir?: string;
310
323
  author?: string;
311
- hotArticle?: HotArticle;
324
+ hotArticle?: HotArticle | false;
312
325
  home?: HomeBlog;
313
326
  /**
314
327
  * 本地全文搜索定制
@@ -319,7 +332,8 @@ declare namespace Theme {
319
332
  search?: SearchConfig;
320
333
  /**
321
334
  * 配置评论
322
- * power by https://giscus.app/zh-CN
335
+ * giscus: https://giscus.app/zh-CN
336
+ * artalk: https://artalk.js.org/
323
337
  */
324
338
  comment?: CommentConfig | false;
325
339
  /**
@@ -390,6 +404,8 @@ declare namespace Theme {
390
404
  * 详见 https://oml2d.com/options/Options.html
391
405
  */
392
406
  oml2d?: Options;
407
+ homeTags?: boolean;
408
+ buttonAfterArticle?: ButtonAfterArticleConfig | false;
393
409
  }
394
410
  interface BackToTop {
395
411
  /**
@@ -469,6 +485,22 @@ declare namespace Theme {
469
485
  */
470
486
  handleChangeSlogan?: (oldSlogan: string) => string | Promise<string>;
471
487
  }
488
+ interface ButtonAfterArticleConfig {
489
+ openTitle?: string;
490
+ closeTitle?: string;
491
+ content?: string;
492
+ icon?: 'aliPay' | 'wechatPay' | string;
493
+ /**
494
+ * 按钮尺寸
495
+ * @default 'default'
496
+ */
497
+ size?: 'small' | 'default' | 'large';
498
+ /**
499
+ * 默认展开
500
+ * @default false
501
+ */
502
+ expand?: boolean;
503
+ }
472
504
  }
473
505
 
474
506
  /**
package/node.js CHANGED
@@ -40,7 +40,7 @@ module.exports = __toCommonJS(node_exports);
40
40
  // src/utils/node/mdPlugins.ts
41
41
  var import_module = require("module");
42
42
 
43
- // ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@1.0.1_vue@3.4.21/node_modules/vitepress-plugin-tabs/dist/index.js
43
+ // ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@1.0.2_vue@3.4.21/node_modules/vitepress-plugin-tabs/dist/index.js
44
44
  var tabsMarker = "=tabs";
45
45
  var tabsMarkerLen = tabsMarker.length;
46
46
  var ruleBlockTabs = (state, startLine, endLine, silent) => {
@@ -453,6 +453,16 @@ function getArticles(cfg) {
453
453
  }).filter((v) => v.meta.layout !== "home");
454
454
  return data;
455
455
  }
456
+ function patchVPConfig(vpConfig, cfg) {
457
+ vpConfig.head = vpConfig.head || [];
458
+ if (cfg?.comment && "type" in cfg.comment && cfg?.comment?.type === "artalk") {
459
+ const server = cfg.comment?.options?.server;
460
+ if (server) {
461
+ vpConfig.head.push(["link", { href: `${server}/dist/Artalk.css`, rel: "stylesheet" }]);
462
+ vpConfig.head.push(["script", { src: `${server}/dist/Artalk.js`, id: "artalk-script" }]);
463
+ }
464
+ }
465
+ }
456
466
  function patchVPThemeConfig(cfg, vpThemeConfig = {}) {
457
467
  vpThemeConfig.sidebar = patchDefaultThemeSideBar(cfg)?.sidebar;
458
468
  return vpThemeConfig;
@@ -574,6 +584,7 @@ function getThemeConfig(cfg) {
574
584
  registerMdPlugins(extraVPConfig, markdownPlugin);
575
585
  patchMermaidPluginCfg(extraVPConfig);
576
586
  patchOptimizeDeps(extraVPConfig);
587
+ patchVPConfig(extraVPConfig, cfg);
577
588
  return {
578
589
  themeConfig: {
579
590
  blog: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sugarat/theme",
3
- "version": "0.2.29",
3
+ "version": "0.3.0",
4
4
  "description": "简约风的 Vitepress 博客主题,sugarat vitepress blog theme",
5
5
  "author": "sugar",
6
6
  "license": "MIT",
@@ -42,22 +42,23 @@
42
42
  "gray-matter": "^4.0.3",
43
43
  "markdown-it-task-checkbox": "^1.0.6",
44
44
  "mermaid": "^10.2.4",
45
- "oh-my-live2d": "^0.13.0",
45
+ "oh-my-live2d": "^0.15.2",
46
46
  "swiper": "^11.0.5",
47
47
  "vitepress-markdown-timeline": "^1.2.1",
48
48
  "vitepress-plugin-mermaid": "2.0.13",
49
- "vitepress-plugin-pagefind": "0.2.13",
49
+ "vitepress-plugin-pagefind": "0.2.14",
50
50
  "vitepress-plugin-rss": "0.2.2",
51
51
  "vitepress-plugin-tabs": "0.2.0"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@element-plus/icons-vue": "^2.1.0",
55
+ "artalk": "^2.8.3",
55
56
  "element-plus": "^2.3.4",
56
57
  "javascript-stringify": "^2.1.0",
57
58
  "pagefind": "1.0.3",
58
59
  "sass": "^1.56.1",
59
60
  "typescript": "^4.8.2",
60
- "vitepress": "1.0.1",
61
+ "vitepress": "1.0.2",
61
62
  "vue": "^3.4.21"
62
63
  },
63
64
  "scripts": {
@@ -7,9 +7,6 @@ import { useBlogThemeMode } from '../composables/config/blog'
7
7
  import BlogHomeInfo from './BlogHomeInfo.vue'
8
8
  import BlogHomeBanner from './BlogHomeBanner.vue'
9
9
  import BlogList from './BlogList.vue'
10
- import BlogComment from './BlogComment.vue'
11
-
12
- // import BlogSearch from './BlogSearch.vue'
13
10
  import BlogSidebar from './BlogSidebar.vue'
14
11
  import BlogImagePreview from './BlogImagePreview.vue'
15
12
  import BlogArticleAnalyze from './BlogArticleAnalyze.vue'
@@ -18,6 +15,11 @@ import BlogPopover from './BlogPopover.vue'
18
15
  import BlogFooter from './BlogFooter.vue'
19
16
  import BlogHomeHeaderAvatar from './BlogHomeHeaderAvatar.vue'
20
17
  import BlogBackToTop from './BlogBackToTop.vue'
18
+ import CommentGiscus from './CommentGiscus.vue'
19
+
20
+ import CommentArtalk from './CommentArtalk.vue'
21
+ import BlogButtonAfterArticle from './BlogButtonAfterArticle.vue'
22
+ import BlogCommentWrapper from './BlogCommentWrapper.vue'
21
23
 
22
24
  const { frontmatter } = useData()
23
25
  const layout = computed(() => frontmatter.value.layout)
@@ -75,8 +77,12 @@ useOml2d()
75
77
  <slot name="doc-after" />
76
78
  <!-- 评论 -->
77
79
  <ClientOnly>
80
+ <BlogButtonAfterArticle />
78
81
  <BlogBackToTop />
79
- <BlogComment />
82
+ <BlogCommentWrapper>
83
+ <CommentArtalk />
84
+ <CommentGiscus />
85
+ </BlogCommentWrapper>
80
86
  </ClientOnly>
81
87
  </template>
82
88
  <template #layout-bottom>
@@ -192,6 +198,7 @@ useOml2d()
192
198
  .blog-list-wrapper {
193
199
  width: 100%;
194
200
  }
201
+
195
202
  .blog-info-wrapper {
196
203
  margin-left: 16px;
197
204
  position: sticky;
@@ -0,0 +1,122 @@
1
+ <script lang="ts" setup>
2
+ import { ElButton } from 'element-plus'
3
+ import { computed, ref, watch } from 'vue'
4
+ import { useData } from 'vitepress'
5
+ import { useBlogConfig } from '../composables/config/blog'
6
+ import { aliPaySVG, weChatPaySVG } from '../constants/svg'
7
+
8
+ const { buttonAfterArticle: _buttonAfterArticle } = useBlogConfig()
9
+ const { frontmatter } = useData()
10
+ const frontmatterConfig = computed(() => frontmatter.value.buttonAfterArticle)
11
+
12
+ const buttonAfterArticleConfig = computed(() => {
13
+ if (frontmatterConfig.value === false || (!frontmatterConfig.value && !_buttonAfterArticle)) {
14
+ return false
15
+ }
16
+
17
+ return { ..._buttonAfterArticle, ...frontmatterConfig.value }
18
+ })
19
+
20
+ const showContent = ref(false)
21
+
22
+ watch(buttonAfterArticleConfig, () => {
23
+ showContent.value = !!buttonAfterArticleConfig.value?.expand
24
+ }, {
25
+ immediate: true
26
+ })
27
+
28
+ const svg = computed(() => {
29
+ const icon = buttonAfterArticleConfig.value?.icon
30
+ if (icon === 'aliPay') {
31
+ return aliPaySVG
32
+ }
33
+ else if (icon === 'wechatPay') {
34
+ return weChatPaySVG
35
+ }
36
+ else {
37
+ return icon as string
38
+ }
39
+ })
40
+
41
+ function toggleContent() {
42
+ showContent.value = !showContent.value
43
+ }
44
+ </script>
45
+
46
+ <template>
47
+ <div v-if="buttonAfterArticleConfig" class="appreciation-container">
48
+ <ElButton :size="buttonAfterArticleConfig.size || 'default'" class="content-button" :type="showContent ? 'danger' : 'primary'" @click="toggleContent">
49
+ <span class="content-icon" v-html="svg" />
50
+ {{ showContent ? buttonAfterArticleConfig.closeTitle : buttonAfterArticleConfig.openTitle }}
51
+ </ElButton>
52
+ <transition name="content">
53
+ <div v-if="showContent" class="content-container" v-html="buttonAfterArticleConfig.content" />
54
+ </transition>
55
+ </div>
56
+ </template>
57
+
58
+ <style scoped lang="scss">
59
+ .appreciation-container {
60
+ text-align: center;
61
+ padding: 20px;
62
+ font-size: 14px;
63
+ color: #606266;
64
+
65
+ :deep(.el-button.el-button--primary){
66
+ background-color: var(--vp-c-brand-2);
67
+ border-color: var(--vp-c-brand-2);
68
+ }
69
+ }
70
+
71
+ .content-container {
72
+ position: relative;
73
+ display: flex;
74
+ justify-content: center;
75
+ align-items: center;
76
+ margin-top: 20px;
77
+ :deep(img){
78
+ height: 260px;
79
+ }
80
+ }
81
+
82
+ .content-icon {
83
+ font-family: "iconfont" !important;
84
+ font-size: 16px;
85
+ margin-right: 8px;
86
+ font-style: normal;
87
+ -webkit-font-smoothing: antialiased;
88
+ -moz-osx-font-smoothing: grayscale;
89
+ }
90
+
91
+ /* 进入动画 */
92
+ .content-enter-active {
93
+ animation: fadeIn 0.5s ease forwards;
94
+ }
95
+
96
+ /* 离开动画 */
97
+ .content-leave-active {
98
+ animation: fadeOut 0.3s ease forwards;
99
+ }
100
+
101
+ /* 淡入 */
102
+ @keyframes fadeIn {
103
+ from {
104
+ opacity: 0;
105
+ }
106
+
107
+ to {
108
+ opacity: 1;
109
+ }
110
+ }
111
+
112
+ /* 淡出 */
113
+ @keyframes fadeOut {
114
+ from {
115
+ opacity: 1;
116
+ }
117
+
118
+ to {
119
+ opacity: 0;
120
+ }
121
+ }
122
+ </style>
@@ -1,66 +1,33 @@
1
1
  <script setup lang="ts">
2
2
  import { useElementSize, useElementVisibility, useWindowSize } from '@vueuse/core'
3
- import { useData, useRoute } from 'vitepress'
4
- import { computed, h, ref, watch } from 'vue'
3
+ import { useData } from 'vitepress'
4
+ import { computed, h, ref } from 'vue'
5
5
  import { ElIcon } from 'element-plus'
6
6
  import { Comment } from '@element-plus/icons-vue'
7
- import Giscus from '@giscus/vue'
8
- import { useGiscusConfig } from '../composables/config/blog'
9
- import type { Theme } from '../composables/config/index'
7
+ import { useBlogConfig } from '../composables/config/blog'
10
8
 
11
9
  const { frontmatter } = useData()
12
10
  const commentEl = ref(null)
13
11
  const commentIsVisible = useElementVisibility(commentEl)
14
12
 
15
13
  function handleScrollToComment() {
16
- document.querySelector('#giscus-comment')?.scrollIntoView({
14
+ document.querySelector('#blog-comment-wrapper')?.scrollIntoView({
17
15
  behavior: 'smooth',
18
16
  block: 'start'
19
17
  })
20
18
  }
21
- const giscusConfig = useGiscusConfig()
22
19
 
23
- const commentConfig = computed<Theme.CommentConfig>(() => {
24
- if (!giscusConfig) {
25
- return {} as any
26
- }
27
- return giscusConfig
28
- })
20
+ const { comment: _comment } = useBlogConfig()
21
+ const commentConfig = computed(() =>
22
+ _comment === false ? undefined : _comment
23
+ )
29
24
 
30
25
  const show = computed(() => {
31
- if (frontmatter.value.comment === false) {
32
- return frontmatter.value.comment
33
- }
34
- if (!giscusConfig) {
35
- return giscusConfig
36
- }
37
- return (
38
- giscusConfig.repo
39
- && giscusConfig.repoId
40
- && giscusConfig.category
41
- && giscusConfig.categoryId
42
- )
26
+ return _comment && frontmatter.value.comment !== false
43
27
  })
44
28
 
45
- const { isDark } = useData()
46
-
47
- const route = useRoute()
48
- const showComment = ref(true)
49
- watch(
50
- () => route.path,
51
- () => {
52
- showComment.value = false
53
- setTimeout(() => {
54
- showComment.value = true
55
- }, 200)
56
- },
57
- {
58
- immediate: true
59
- }
60
- )
61
-
62
29
  const { width } = useWindowSize()
63
- const mobileMinify = computed(() => width.value < 768 && (commentConfig.value.mobileMinify ?? true))
30
+ const mobileMinify = computed(() => width.value < 768 && (commentConfig.value?.mobileMinify ?? true))
64
31
 
65
32
  const CommentIcon = commentConfig.value?.icon
66
33
  ? h('i', {
@@ -78,20 +45,13 @@ const { width: _docWidth } = useElementSize(el)
78
45
  const docWidth = computed(() => `${_docWidth.value}px`)
79
46
 
80
47
  const labelText = computed(() => {
81
- return commentConfig.value.label ?? '评论'
48
+ return commentConfig.value?.label ?? '评论'
82
49
  })
83
50
  </script>
84
51
 
85
52
  <template>
86
- <div v-if="show && _docWidth" id="giscus-comment" ref="commentEl" class="comment" data-pagefind-ignore="all">
87
- <Giscus
88
- v-if="showComment" :repo="commentConfig.repo" :repo-id="commentConfig.repoId"
89
- :category="commentConfig.category" :category-id="commentConfig.categoryId"
90
- :mapping="commentConfig.mapping || 'pathname'" reactions-enabled="1" emit-metadata="0"
91
- :input-position="commentConfig.inputPosition || 'top'" :theme="isDark ? 'dark' : 'light'"
92
- :lang="commentConfig.lang || 'zh-CN'" :loading="commentConfig.loading || 'eager'"
93
- />
94
-
53
+ <div v-if="show && _docWidth" id="blog-comment-wrapper" ref="commentEl" class="blog-comment-wrapper" data-pagefind-ignore="all">
54
+ <slot />
95
55
  <div v-show="!commentIsVisible" class="comment-btn-wrapper">
96
56
  <span v-if="!mobileMinify && labelText" class="icon-wrapper-text" @click="handleScrollToComment">
97
57
  <ElIcon :size="20">
@@ -151,7 +111,7 @@ const labelText = computed(() => {
151
111
  border-radius: 2px;
152
112
  padding: 2px 6px;
153
113
 
154
- span.text{
114
+ span.text {
155
115
  font-size: 12px;
156
116
  margin-left: 4px;
157
117
  }
@@ -2,16 +2,17 @@
2
2
  import { computed, watch } from 'vue'
3
3
  import { ElTag } from 'element-plus'
4
4
  import { useBrowserLocation, useDark, useUrlSearchParams } from '@vueuse/core'
5
- import { useRouter, useRoute } from 'vitepress'
5
+ import { useRoute, useRouter } from 'vitepress'
6
6
  import {
7
7
  useActiveTag,
8
8
  useArticles,
9
- useCurrentPageNum
9
+ useConfig,
10
+ useCurrentPageNum,
10
11
  } from '../composables/config/blog'
11
12
 
12
13
  const route = useRoute()
13
14
  const docs = useArticles()
14
-
15
+ const showTags = useConfig()?.config?.blog?.homeTags ?? true
15
16
  const tags = computed(() => {
16
17
  return [...new Set(docs.value.map(v => v.meta.tag || []).flat(3))]
17
18
  })
@@ -77,7 +78,7 @@ watch(
77
78
  </script>
78
79
 
79
80
  <template>
80
- <div v-if="tags.length" class="card tags" data-pagefind-ignore="all">
81
+ <div v-if="showTags && tags.length" class="card tags" data-pagefind-ignore="all">
81
82
  <!-- 头部 -->
82
83
  <div class="card-header">
83
84
  <span class="title svg-icon"><svg
@@ -6,11 +6,16 @@ import { useArticles, useBlogConfig, useCleanUrls } from '../composables/config/
6
6
  import { formatShowDate, wrapperCleanUrls } from '../utils/client'
7
7
  import { fireSVG } from '../constants/svg'
8
8
 
9
- const { hotArticle } = useBlogConfig()
10
- const title = computed(() => hotArticle?.title || (`<span class="svg-icon">${fireSVG}</span>` + ' 精选文章'))
11
- const nextText = computed(() => hotArticle?.nextText || '换一组')
12
- const pageSize = computed(() => hotArticle?.pageSize || 9)
13
- const empty = computed(() => hotArticle?.empty ?? '暂无精选内容')
9
+ const { hotArticle: _hotArticle } = useBlogConfig()
10
+
11
+ const hotArticle = computed(() =>
12
+ _hotArticle === false ? undefined : _hotArticle
13
+ )
14
+
15
+ const title = computed(() => hotArticle.value?.title || (`<span class="svg-icon">${fireSVG}</span>` + ' 精选文章'))
16
+ const nextText = computed(() => hotArticle.value?.nextText || '换一组')
17
+ const pageSize = computed(() => hotArticle.value?.pageSize || 9)
18
+ const empty = computed(() => hotArticle.value?.empty ?? '暂无精选内容')
14
19
 
15
20
  const docs = useArticles()
16
21
 
@@ -43,7 +48,7 @@ const showChangeBtn = computed(() => {
43
48
  </script>
44
49
 
45
50
  <template>
46
- <div v-if="recommendList.length || empty" class="card recommend" data-pagefind-ignore="all">
51
+ <div v-if="_hotArticle !== false && (recommendList.length || empty) " class="card recommend" data-pagefind-ignore="all">
47
52
  <!-- 头部 -->
48
53
  <div class="card-header">
49
54
  <span class="title" v-html="title" />
@@ -1,7 +1,6 @@
1
1
  <script lang="ts" setup>
2
2
  import { withBase } from 'vitepress'
3
3
  import { computed } from 'vue'
4
- import { useWindowSize } from '@vueuse/core'
5
4
  import { formatShowDate, wrapperCleanUrls } from '../utils/client'
6
5
  import { useCleanUrls } from '../composables/config/blog'
7
6
 
@@ -17,8 +16,6 @@ const props = defineProps<{
17
16
  cover?: string | boolean
18
17
  pin?: number
19
18
  }>()
20
- const { width } = useWindowSize()
21
- const inMobile = computed(() => width.value <= 500)
22
19
  const showTime = computed(() => {
23
20
  return formatShowDate(props.date)
24
21
  })
@@ -28,15 +25,16 @@ const link = computed(() => withBase(wrapperCleanUrls(!!cleanUrls, props.route))
28
25
  </script>
29
26
 
30
27
  <template>
28
+ <!-- TODO: 响应式优化使用纯 CSS -->
31
29
  <a class="blog-item" :href="link">
32
30
  <i v-if="!!pin" class="pin" />
33
31
  <!-- 标题 -->
34
- <p v-if="inMobile" class="title">{{ title }}</p>
32
+ <p class="title mobile-visible">{{ title }}</p>
35
33
  <div class="info-container">
36
34
  <!-- 左侧信息 -->
37
35
  <div class="info-part">
38
36
  <!-- 标题 -->
39
- <p v-if="!inMobile" class="title">{{ title }}</p>
37
+ <p class="title pc-visible">{{ title }}</p>
40
38
  <!-- 简短描述 -->
41
39
  <p v-if="!descriptionHTML && !!description" class="description">
42
40
  {{ description }}
@@ -45,21 +43,17 @@ const link = computed(() => withBase(wrapperCleanUrls(!!cleanUrls, props.route))
45
43
  <div class="description-html" v-html="descriptionHTML" />
46
44
  </template>
47
45
  <!-- 底部补充描述 -->
48
- <div v-if="!inMobile" class="badge-list">
46
+ <div class="badge-list pc-visible">
49
47
  <span v-if="author" class="split">{{ author }}</span>
50
48
  <span class="split">{{ showTime }}</span>
51
49
  <span v-if="tag?.length" class="split">{{ tag.join(' · ') }}</span>
52
50
  </div>
53
51
  </div>
54
52
  <!-- 右侧封面图 -->
55
- <div
56
- v-if="cover"
57
- class="cover-img"
58
- :style="`background-image: url(${withBase(`${cover}`)});`"
59
- />
53
+ <div v-if="cover" class="cover-img" :style="`background-image: url(${withBase(`${cover}`)});`" />
60
54
  </div>
61
55
  <!-- 底部补充描述 -->
62
- <div v-if="inMobile" class="badge-list">
56
+ <div class="badge-list mobile-visible">
63
57
  <span v-if="author" class="split">{{ author }}</span>
64
58
  <span class="split">{{ showTime }}</span>
65
59
  <span v-if="tag?.length" class="split">{{ tag.join(' · ') }}</span>
@@ -77,19 +71,19 @@ const link = computed(() => withBase(wrapperCleanUrls(!!cleanUrls, props.route))
77
71
  left: -4px;
78
72
  opacity: 0.5;
79
73
  }
74
+
80
75
  .blog-item:hover .pin {
81
76
  opacity: 1;
82
77
  }
78
+
83
79
  .blog-item .pin::before {
84
80
  content: '';
85
81
  position: absolute;
86
82
  width: 120%;
87
83
  height: 30px;
88
- background-image: linear-gradient(
89
- 45deg,
90
- var(--blog-theme-color),
91
- var(--blog-theme-color)
92
- );
84
+ background-image: linear-gradient(45deg,
85
+ var(--blog-theme-color),
86
+ var(--blog-theme-color));
93
87
  transform: rotate(-45deg) translateY(-20px);
94
88
  display: flex;
95
89
  align-items: center;
@@ -111,10 +105,12 @@ const link = computed(() => withBase(wrapperCleanUrls(!!cleanUrls, props.route))
111
105
  cursor: pointer;
112
106
  display: flex;
113
107
  flex-direction: column;
108
+
114
109
  &:hover {
115
110
  box-shadow: var(--box-shadow-hover);
116
111
  }
117
112
  }
113
+
118
114
  .info-container {
119
115
  display: flex;
120
116
  align-items: center;
@@ -124,11 +120,13 @@ const link = computed(() => withBase(wrapperCleanUrls(!!cleanUrls, props.route))
124
120
  .info-part {
125
121
  flex: 1;
126
122
  }
123
+
127
124
  .title {
128
125
  font-size: 18px;
129
126
  font-weight: 600;
130
127
  margin-bottom: 8px;
131
128
  }
129
+
132
130
  .description {
133
131
  color: var(--description-font-color);
134
132
  font-size: 14px;
@@ -140,13 +138,16 @@ const link = computed(() => withBase(wrapperCleanUrls(!!cleanUrls, props.route))
140
138
  -webkit-line-clamp: 2;
141
139
  -webkit-box-orient: vertical;
142
140
  }
141
+
143
142
  .description-html {
144
143
  font-size: 14px;
145
144
  }
145
+
146
146
  .badge-list {
147
147
  font-size: 13px;
148
148
  color: var(--badge-font-color);
149
149
  margin-top: 8px;
150
+
150
151
  .split:not(:last-child) {
151
152
  &::after {
152
153
  content: '';
@@ -158,20 +159,39 @@ const link = computed(() => withBase(wrapperCleanUrls(!!cleanUrls, props.route))
158
159
  }
159
160
  }
160
161
  }
162
+
161
163
  .cover-img {
162
164
  width: 120px;
163
165
  height: 80px;
164
166
  margin-left: 24px;
165
167
  border-radius: 2px;
166
168
  background-repeat: no-repeat;
167
- background-size: 120px 80px;
169
+ background-size: contain;
170
+ background-position: center;
171
+ }
172
+
173
+ .pc-visible {
174
+ display: block;
175
+ }
176
+
177
+ .mobile-visible {
178
+ display: none;
168
179
  }
169
180
 
170
181
  @media screen and (max-width: 500px) {
171
182
  .cover-img {
172
183
  width: 100px;
173
184
  height: 60px;
174
- background-size: 100px 60px;
185
+ background-size: contain;
186
+ background-position: center;
187
+ }
188
+
189
+ .pc-visible {
190
+ display: none;
191
+ }
192
+
193
+ .mobile-visible {
194
+ display: block;
175
195
  }
176
196
  }
177
197
  </style>