valaxy-theme-yun 0.14.60 → 0.15.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/App.vue CHANGED
@@ -1,6 +1,7 @@
1
1
  <script lang="ts" setup>
2
2
  import { useHead } from '@vueuse/head'
3
- import { useSiteConfig } from 'valaxy'
3
+ import { useAppStore, useSiteConfig } from 'valaxy'
4
+ import { onMounted } from 'vue'
4
5
  import { useThemeConfig } from './composables'
5
6
 
6
7
  useHead({
@@ -14,6 +15,11 @@ useHead({
14
15
 
15
16
  const siteConfig = useSiteConfig()
16
17
  const themeConfig = useThemeConfig()
18
+
19
+ const app = useAppStore()
20
+ onMounted(() => {
21
+ app.showLoading = false
22
+ })
17
23
  </script>
18
24
 
19
25
  <template>
@@ -22,4 +28,7 @@ const themeConfig = useThemeConfig()
22
28
  <YunBg v-if="themeConfig.bg_image.enable" />
23
29
  </slot>
24
30
  <YunSearchTrigger v-if="siteConfig.search.enable" />
31
+ <Transition name="fade">
32
+ <YunLoading v-if="app.showLoading" />
33
+ </Transition>
25
34
  </template>
Binary file
Binary file
@@ -74,7 +74,7 @@ onContentUpdated(() => {
74
74
  </script>
75
75
 
76
76
  <template>
77
- <main class="yun-main lt-md:ml-0" flex="~">
77
+ <main class="yun-main md:pl-$va-sidebar-width lt-md:ml-0" flex="~">
78
78
  <div w="full" flex="~">
79
79
  <slot name="main">
80
80
  <div class="content" :class="!aside && 'no-aside'" flex="~ col grow" w="full" p="l-4 lt-md:0">
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import type { CSSProperties } from 'vue'
9
- import { computed } from 'vue'
9
+ import { computed, ref } from 'vue'
10
10
  import { random } from 'valaxy'
11
11
  import { useThemeConfig } from '../composables'
12
12
 
@@ -28,12 +28,19 @@ const bannerStyles = computed<CSSProperties>(() => {
28
28
  '--banner-line-height': `calc(var(--banner-height, 100vh) / 2 - ${lineH.value}rem)`,
29
29
  }
30
30
  })
31
+
32
+ const playExtendLine = ref(true)
31
33
  </script>
32
34
 
33
35
  <template>
34
- <div id="banner" :style="bannerStyles">
36
+ <div id="yun-banner" :style="bannerStyles">
35
37
  <div class="banner-line-container">
36
- <div class="banner-line vertical-line-top" />
38
+ <div
39
+ class="banner-line vertical-line-top"
40
+ :class="{
41
+ active: playExtendLine,
42
+ }"
43
+ />
37
44
  </div>
38
45
  <div class="banner-char-container">
39
46
  <div v-for="c, i in themeConfig.banner.title" :key="i" class="char-box">
@@ -49,7 +56,12 @@ const bannerStyles = computed<CSSProperties>(() => {
49
56
  </div>
50
57
  </div>
51
58
  <div class="banner-line-container bottom">
52
- <div class="banner-line vertical-line-bottom" />
59
+ <div
60
+ class="banner-line vertical-line-bottom"
61
+ :class="{
62
+ active: playExtendLine,
63
+ }"
64
+ />
53
65
  </div>
54
66
  <YunCloud v-if="themeConfig.banner.cloud?.enable" />
55
67
  <YunGoDown />
@@ -6,37 +6,39 @@ import { useThemeConfig } from '../composables'
6
6
 
7
7
  const themeConfig = useThemeConfig()
8
8
 
9
- const bgImgOpacity = useCssVar('--va-bg-img-opacity')
10
- if (themeConfig.value.bg_image.opacity)
11
- bgImgOpacity.value = themeConfig.value.bg_image.opacity.toString() || '1'
9
+ if (typeof themeConfig.value.bg_image.url !== 'undefined') {
10
+ const bgImgOpacity = useCssVar('--yun-bg-img-opacity')
11
+ if (themeConfig.value.bg_image.opacity)
12
+ bgImgOpacity.value = themeConfig.value.bg_image.opacity.toString() || '1'
12
13
 
13
- const bgImgUrl = computed(() => {
14
- return isDark.value
15
- ? themeConfig.value.bg_image.dark
16
- : themeConfig.value.bg_image.url
17
- })
14
+ const bgImgUrl = computed(() => {
15
+ return isDark.value
16
+ ? themeConfig.value.bg_image.dark
17
+ : themeConfig.value.bg_image.url
18
+ })
18
19
 
19
- const bgImgCssVar = useCssVar('--va-bg-img')
20
+ const bgImgCssVar = useCssVar('--yun-bg-img')
20
21
 
21
- watch(() => bgImgUrl.value, () => {
22
- bgImgCssVar.value = `url('${bgImgUrl.value}')`
23
- }, { immediate: true })
22
+ watch(() => bgImgUrl.value, () => {
23
+ bgImgCssVar.value = `url('${bgImgUrl.value}')`
24
+ }, { immediate: true })
25
+ }
24
26
  </script>
25
27
 
26
28
  <template>
27
- <div class="va-bg" />
29
+ <div class="yun-bg" />
28
30
  </template>
29
31
 
30
32
  <style lang="scss">
31
33
  @use 'valaxy/client/styles/mixins/index.scss' as *;
32
34
 
33
- .va-bg {
35
+ .yun-bg {
34
36
  position: fixed;
35
37
  width: 100%;
36
38
  height: 100%;
37
39
  z-index: -1;
38
40
 
39
- background-image: var(--va-bg-img);
41
+ background-image: var(--yun-bg-img);
40
42
  background-size: cover;
41
43
  background-position: center;
42
44
  background-repeat: no-repeat;
@@ -44,12 +46,12 @@ watch(() => bgImgUrl.value, () => {
44
46
  background-attachment: fixed;
45
47
  animation-name: bgFadeIn;
46
48
  animation-duration: 2s;
47
- opacity: var(--va-bg-img-opacity, 1);
49
+ opacity: var(--yun-bg-img-opacity, 1);
48
50
  }
49
51
 
50
52
  // for ios
51
53
  @include ios {
52
- .va-bg {
54
+ .yun-bg {
53
55
  background-attachment: scroll;
54
56
  }
55
57
  }
@@ -60,7 +62,7 @@ watch(() => bgImgUrl.value, () => {
60
62
  }
61
63
 
62
64
  to {
63
- opacity: var(--va-bg-img-opacity, 1);
65
+ opacity: var(--yun-bg-img-opacity, 1);
64
66
  }
65
67
  }
66
68
  </style>
@@ -3,11 +3,12 @@ defineProps<{ cover?: string }>()
3
3
  </script>
4
4
 
5
5
  <template>
6
- <div class="yun-card flex-center" flex="col" min-h="100px" bg="$va-c-bg-light">
6
+ <div class="yun-card flex-center rounded" flex="col" min-h="100px" bg="$va-c-bg-light">
7
7
  <img
8
8
  v-if="cover"
9
9
  width="640" height="360"
10
- class="object-cover select-none" h="64 md:sm" w="full" :src="cover"
10
+ class="object-cover select-none" h="64 md:sm" w="full"
11
+ :src="cover"
11
12
  >
12
13
 
13
14
  <div v-if="$slots.header" class="yun-card-header">
@@ -7,6 +7,8 @@ import { useBodyScrollLock, useSiteConfig } from 'valaxy'
7
7
  import { useRouter } from 'vue-router'
8
8
  import type { FuseListItem } from 'valaxy/types'
9
9
 
10
+ import { onClickOutside } from '@vueuse/core'
11
+
10
12
  const props = defineProps<{
11
13
  open: boolean
12
14
  }>()
@@ -69,6 +71,10 @@ function jumpToLink(link: string) {
69
71
  router.push(link)
70
72
  emit('close')
71
73
  }
74
+
75
+ onClickOutside(searchInputRef, () => {
76
+ // emit('close')
77
+ })
72
78
  </script>
73
79
 
74
80
  <template>
@@ -79,7 +85,9 @@ function jumpToLink(link: string) {
79
85
  >
80
86
  <div
81
87
  v-if="open" ref="searchContainer"
82
- class="yun-popup yun-search-popup yun-fuse-search flex-center" flex="col"
88
+ class="yun-popup yun-search-popup yun-fuse-search flex-center pointer-events-auto" flex="col"
89
+ justify="start"
90
+ pt-12
83
91
  >
84
92
  <div class="yun-search-input-container flex-center" w="full">
85
93
  <input ref="searchInputRef" v-model="input" class="yun-search-input" :placeholder="t('search.placeholder')">
@@ -87,27 +95,25 @@ function jumpToLink(link: string) {
87
95
  <div v-if="input" class="flex-center" w="full" py="4">
88
96
  {{ t('search.hits', results.length || 0) }}
89
97
  </div>
90
- <div overflow="auto" flex="~ 1" w="full">
98
+ <div v-if="results.length > 0" overflow="auto" flex="~" w="full">
91
99
  <div class="yun-fuse-result-container" flex="~ col" w="full">
92
- <template v-if="results.length > 0">
93
- <div
94
- v-for="result in results" :key="result.item.title"
95
- :to="result.item.link"
96
- class="yun-fuse-result-item text-$va-c-text hover:(text-$va-c-bg bg-$va-c-text-dark bg-opacity-100)"
97
- flex="~ col" pb-2
98
- @click="jumpToLink(result.item.link)"
99
- >
100
- <h3 font="serif black">
101
- {{ result.item.title }}
102
- </h3>
103
- <span text="sm" opacity="80">
104
- {{ result.item.excerpt }}
105
- </span>
106
- <span text-xs opacity-50 mt="1">
107
- Score Index: {{ result.refIndex }}
108
- </span>
109
- </div>
110
- </template>
100
+ <div
101
+ v-for="result in results" :key="result.item.title"
102
+ :to="result.item.link"
103
+ class="yun-fuse-result-item text-$va-c-text hover:(text-$va-c-bg bg-$va-c-text-dark bg-opacity-100)"
104
+ flex="~ col" pb-2
105
+ @click="jumpToLink(result.item.link)"
106
+ >
107
+ <h3 font="serif black">
108
+ {{ result.item.title }}
109
+ </h3>
110
+ <span text="sm" opacity="80">
111
+ {{ result.item.excerpt }}
112
+ </span>
113
+ <span text-xs opacity-50 mt="1">
114
+ Score Index: {{ result.refIndex }}
115
+ </span>
116
+ </div>
111
117
  </div>
112
118
  </div>
113
119
  </div>
@@ -126,7 +132,6 @@ function jumpToLink(link: string) {
126
132
  -webkit-backdrop-filter: blur(30px);
127
133
 
128
134
  text-align: center;
129
- padding-top: 3.5rem;
130
135
  margin: 0;
131
136
  z-index: var(--yun-z-search-popup);
132
137
  transition: 0.6s;
@@ -14,9 +14,17 @@ interface LinkType {
14
14
  const props = defineProps<{
15
15
  links: string | LinkType[]
16
16
  random: boolean
17
+ /**
18
+ * @description: 图片加载失败时显示的图片
19
+ */
20
+ errorImg?: string
17
21
  }>()
18
22
 
19
23
  const { data } = useRandomData(props.links, props.random)
24
+
25
+ function onError(e: Event) {
26
+ onImgError(e, props.errorImg)
27
+ }
20
28
  </script>
21
29
 
22
30
  <template>
@@ -25,7 +33,11 @@ const { data } = useRandomData(props.links, props.random)
25
33
  <li v-for="link, i in data" :key="i" class="link-item" :style="`--primary-color: ${link.color}`">
26
34
  <a class="link-url" p="x-4 y-2" :href="link.url" :title="link.name" alt="portrait" rel="friend">
27
35
  <div class="link-left">
28
- <img class="link-avatar" w="16" h="16" loading="lazy" :src="link.avatar" :alt="link.name" :onError="onImgError">
36
+ <img
37
+ class="link-avatar" width="64" height="64" w="16" h="16"
38
+ loading="lazy" :src="link.avatar" :alt="link.name"
39
+ @error="onError"
40
+ >
29
41
  </div>
30
42
  <div class="link-info" m="l-2">
31
43
  <div class="link-blog" font="serif black">{{ link.blog }}</div>
@@ -0,0 +1,37 @@
1
+ <template>
2
+ <div
3
+ class="yun-page-loading"
4
+ absolute left-0 right-0 bottom-0 top-0 flex justify="center" items-center
5
+ z-10
6
+ bg="$va-c-bg"
7
+ >
8
+ <div class="spinner" />
9
+ </div>
10
+ </template>
11
+
12
+ <style scoped lang="scss">
13
+ .spinner {
14
+ width: 60px;
15
+ height: 60px;
16
+ border: 1px solid var(--va-c-primary);
17
+ margin: 100px auto;
18
+ animation: rotateplane 1.2s infinite ease-in-out;
19
+ }
20
+
21
+ @keyframes rotateplane {
22
+ 0% {
23
+ transform: perspective(120px) rotateX(0deg) rotateY(0deg);
24
+ -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg);
25
+ }
26
+
27
+ 50% {
28
+ transform: perspective(120px) rotateX(-180deg) rotateY(0deg);
29
+ -webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
30
+ }
31
+
32
+ 100% {
33
+ transform: perspective(120px) rotateX(-180deg) rotateY(-180deg);
34
+ -webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-180deg);
35
+ }
36
+ }
37
+ </style>
@@ -5,7 +5,7 @@ defineProps<{
5
5
  </script>
6
6
 
7
7
  <template>
8
- <div class="yun-notice">
8
+ <div class="yun-notice m-auto">
9
9
  <span v-html="content" />
10
10
  <slot />
11
11
  </div>
@@ -34,7 +34,7 @@ const { locale } = useI18n()
34
34
 
35
35
  &:hover,
36
36
  &.active {
37
- color: var(--va-c-brand);
37
+ color: var(--va-c-primary-lighter);
38
38
  transition: color 0.25s;
39
39
  }
40
40
 
@@ -34,9 +34,9 @@ const router = useRouter()
34
34
  </div>
35
35
 
36
36
  <YunSidebarNav />
37
- <hr m="t-4 b-2">
37
+ <hr m="t-4 b-2" op="20">
38
38
  <YunSocialLinks />
39
- <hr m="y-2">
39
+ <hr m="y-2" op="20">
40
40
  <YunSidebarLinks />
41
41
  <br>
42
42
  </div>
@@ -14,7 +14,7 @@ const { icon, styles } = usePostProperty(props.post.type)
14
14
  </script>
15
15
 
16
16
  <template>
17
- <YunCard m="y-4 auto" :class="post.cover ? 'post-card-image' : 'post-card'" :style="styles as StyleValue">
17
+ <YunCard m="y-4 auto" :class="post.cover ? 'post-card-image' : 'post-card'" overflow="hidden" :style="styles as StyleValue">
18
18
  <div class="flex flex-1 of-hidden justify-start items-start post-card-info" w="full">
19
19
  <img
20
20
  v-if="post.cover"
@@ -25,7 +25,7 @@ const { icon, styles } = usePostProperty(props.post.type)
25
25
  class="cover object-cover object-center md:shadow"
26
26
  >
27
27
 
28
- <div class="flex flex-col flex-1 items-center" :class="post.cover && 'max-h-54'" w="full">
28
+ <div class="flex flex-col items-center justify-center" :class="post.cover && 'h-54'" w="full">
29
29
  <AppLink
30
30
  class="post-title-link cursor-pointer"
31
31
  :to="post.path || ''"
@@ -38,9 +38,13 @@ const { icon, styles } = usePostProperty(props.post.type)
38
38
 
39
39
  <YunPostMeta :frontmatter="post" />
40
40
 
41
- <div v-if="post.excerpt_type === 'text'" py="1" />
42
- <div v-if="post.excerpt" class="markdown-body" text="left" w="full" p="x-6 lt-sm:4 y-1" v-html="post.excerpt" />
43
- <div m="b-5" />
41
+ <div class="flex flex-grow" justify="center" items="center">
42
+ <div v-if="post.excerpt_type === 'text'" py="1" />
43
+ <div v-if="post.excerpt" class="markdown-body" op="80" text="left" w="full" p="x-6 lt-sm:4 y-2" v-html="post.excerpt" />
44
+ <div v-else m="b-5" />
45
+ </div>
46
+
47
+ <!-- <div m="b-5" /> -->
44
48
 
45
49
  <a
46
50
  v-if="post.url"
@@ -56,12 +60,19 @@ const { icon, styles } = usePostProperty(props.post.type)
56
60
  </div>
57
61
 
58
62
  <!-- always show -->
59
- <div w="full" class="yun-card-actions flex justify-between" border="t" text="sm">
60
- <div class="post-categories inline-flex" flex="wrap 1">
63
+ <div
64
+ w="full" class="yun-card-actions flex justify-between"
65
+ min-h="10"
66
+ border="t" text="sm"
67
+ >
68
+ <div class="post-categories inline-flex" flex="wrap 1" items="center">
61
69
  <YunPostCategories m="l-1" :categories="post.categories" />
62
70
  </div>
63
71
 
64
- <div class="post-tags inline-flex" flex="wrap 1" justify="end" m="1">
72
+ <div
73
+ class="post-tags inline-flex" items="center"
74
+ flex="wrap 1" justify="end" m="1"
75
+ >
65
76
  <template v-if="post.tags">
66
77
  <YunPostTags :tags="post.tags" />
67
78
  </template>
@@ -12,7 +12,10 @@ defineProps<{
12
12
  path: '/categories/',
13
13
  query: { category: Array.isArray(categories) ? categories[categories.length - 1] : categories },
14
14
  }"
15
- class="post-category inline-flex-center"
15
+ class="transition post-category inline-flex-center text-xs border-$va-c-divider hover:(text-blue-500 border-blue-500)"
16
+ px-2 h="7"
17
+ border rounded-full
18
+ bg="hover:(blue-500 opacity-10)"
16
19
  >
17
20
  <div m="x-1" inline-flex i-ri-folder-2-line />
18
21
  <span>
@@ -46,6 +46,5 @@ const displayedPosts = computed(() =>
46
46
  <style>
47
47
  .yun-card-actions {
48
48
  border-top: 1px solid rgba(122, 122, 122, 0.15);
49
- min-height: 2.5rem;
50
49
  }
51
50
  </style>
@@ -8,10 +8,14 @@ defineProps<{
8
8
 
9
9
  <template>
10
10
  <router-link
11
- v-for="tag, i in tags" :key="i" :to="{ path: '/tags/', query: { tag } }" m="x-1"
12
- class="post-tag inline-flex-center"
11
+ v-for="tag, i in tags" :key="i" :to="{ path: '/tags/', query: { tag } }" ml-1
12
+ class="transition post-tag inline-flex-center text-xs border-$va-c-divider hover:(text-blue-500 border-blue-500)"
13
+ px-2 h="7"
14
+ rounded-full
15
+ border
16
+ bg="hover:(blue-500 opacity-10)"
13
17
  >
14
- <div m="r-1" i-ri-price-tag-3-line />
18
+ <!-- <div m="r-1" i-ri-price-tag-3-line /> -->
15
19
  <span>{{ tag }}</span>
16
20
  </router-link>
17
21
  </template>
@@ -1,17 +1,26 @@
1
1
  <script lang="ts" setup>
2
2
  import { useI18n } from 'vue-i18n'
3
3
 
4
- withDefaults(defineProps<{
4
+ const props = withDefaults(defineProps<{
5
5
  open?: boolean
6
6
  }>(), {
7
7
  open: false,
8
8
  })
9
9
 
10
+ const emit = defineEmits(['close', 'open'])
11
+
10
12
  const { t } = useI18n()
13
+
14
+ function onClick() {
15
+ if (props.open)
16
+ emit('close')
17
+ else
18
+ emit('open')
19
+ }
11
20
  </script>
12
21
 
13
22
  <template>
14
- <button class="yun-search-btn popup-trigger yun-icon-btn" :title="t('menu.search')">
23
+ <button class="yun-search-btn popup-trigger yun-icon-btn" :title="t('menu.search')" @click="onClick">
15
24
  <div v-if="!open" i-ri-search-line />
16
25
  <div v-else text="!2xl" i-ri-close-line />
17
26
  </button>
@@ -21,14 +21,22 @@ watch(Meta_K, (val) => {
21
21
  togglePopup()
22
22
  })
23
23
 
24
+ function openSearch() {
25
+ open.value = true
26
+ }
27
+
28
+ function closeSearch() {
29
+ open.value = false
30
+ }
31
+
24
32
  const YunAlgoliaSearch = isAlgolia.value
25
33
  ? defineAsyncComponent(() => import('./third/YunAlgoliaSearch.vue'))
26
34
  : () => null
27
35
  </script>
28
36
 
29
37
  <template>
30
- <YunSearchBtn :open="open && !isAlgolia" @click="togglePopup" />
38
+ <YunSearchBtn :open="open && !isAlgolia" @open="openSearch" @close="closeSearch" />
31
39
 
32
- <YunAlgoliaSearch v-if="isAlgolia" :open="open" @close="open = false" />
33
- <YunFuseSearch v-else-if="isFuse" :open="open" @close="open = false" />
40
+ <YunAlgoliaSearch v-if="isAlgolia" :open="open" @close="closeSearch" />
41
+ <YunFuseSearch v-else-if="isFuse" :open="open" @close="closeSearch" />
34
42
  </template>
@@ -1,10 +1,13 @@
1
1
  <script lang="ts" setup>
2
2
  import { ref } from 'vue'
3
- import { useAppStore, useLayout } from 'valaxy'
3
+ import { useAppStore } from 'valaxy'
4
+
5
+ defineProps<{
6
+ showHamburger?: boolean
7
+ }>()
4
8
 
5
9
  const app = useAppStore()
6
10
  const showOverview = ref(false)
7
- const isHome = useLayout('home')
8
11
  </script>
9
12
 
10
13
  <template>
@@ -14,12 +17,12 @@ const isHome = useLayout('home')
14
17
  :active="app.isSidebarOpen"
15
18
  class="menu-btn sidebar-toggle yun-icon-btn leading-4 fixed left-0.8rem top-0.6rem"
16
19
  inline-flex cursor="pointer" z="$yun-z-menu-btn"
17
- :class="isHome ? '' : 'md:hidden'" @click="app.toggleSidebar()"
20
+ :class="showHamburger ? '' : 'md:hidden'" @click="app.toggleSidebar()"
18
21
  />
19
22
 
20
23
  <aside
21
24
  class="va-card transition sidebar fixed inset-y-0 left-0 overflow-y-auto"
22
- :class="[app.isSidebarOpen && 'open', !isHome && 'md:translate-x-0']"
25
+ :class="[app.isSidebarOpen && 'open', !showHamburger && 'md:translate-x-0']"
23
26
  text="center" bg="$yun-sidebar-bg-color contain no-repeat" z="$yun-z-sidebar"
24
27
  >
25
28
  <div v-if="$slots.default" class="sidebar-nav" m="t-6">
@@ -4,7 +4,6 @@ import type { YunTheme } from '../types'
4
4
 
5
5
  /**
6
6
  * getThemeConfig
7
- * @returns
8
7
  */
9
8
  export function useThemeConfig<ThemeConfig = YunTheme.Config>() {
10
9
  const config = useValaxyConfig<ThemeConfig>()
@@ -5,7 +5,6 @@ import { isClient } from '@vueuse/core'
5
5
  * fetch data from source, and random
6
6
  * @param source
7
7
  * @param random
8
- * @returns
9
8
  */
10
9
  export function useRandomData<T>(source: string | T[], random = false) {
11
10
  const data = ref<T[]>()
@@ -53,6 +53,7 @@ export default defineConfig<ThemeConfig>({
53
53
 
54
54
  - `links`: 友情链接信息(可以是 YAML 数组形式,也可以是一个 JSON 文件链接)
55
55
  - `random`: 是否随机展示
56
+ - `errorImg`: 图片加载失败时的图片链接
56
57
 
57
58
  譬如:
58
59
 
@@ -81,5 +82,20 @@ links:
81
82
  random: true
82
83
  ---
83
84
 
84
- <YunLinks :links="frontmatter.links" :random="frontmatter.random" />
85
+ <YunLinks :links="frontmatter.links" :random="frontmatter.random" errorImg="https://cdn.yunyoujun.cn/img/avatar/none.jpg" />
86
+ ```
87
+
88
+ ## 样式
89
+
90
+ ### 覆盖背景、侧边栏图片
91
+
92
+ 您可以新建 `styles/css-vars.scss`,覆盖默认 CSS 变量。
93
+
94
+ ```css
95
+ :root {
96
+ /* 背景图片 */
97
+ --yun-bg-img: url("https://cdn.yunyoujun.cn/img/bg/stars-timing-0-blur-30px.jpg");
98
+ /* 侧边栏背景图片 */
99
+ --yun-sidebar-bg-img: url("https://cdn.yunyoujun.cn/img/bg/alpha-stars-timing-1.webp");
100
+ }
85
101
  ```
@@ -0,0 +1,33 @@
1
+ <script setup lang="ts">
2
+ import { useI18n } from 'vue-i18n'
3
+ import { useBack } from 'valaxy'
4
+
5
+ const { t } = useI18n()
6
+ const { back } = useBack()
7
+ </script>
8
+
9
+ <template>
10
+ <YunSidebar :show-hamburger="true" />
11
+
12
+ <main class="va-main w-full h-screen" text="center" flex="~ col" justify="center" items="center">
13
+ <div class="not-found" title="404" font="mono">
14
+ 404
15
+ </div>
16
+
17
+ <router-view />
18
+
19
+ <div>
20
+ <button class="btn rounded-full" p="x-6 y-2" text="sm" m="3 t8" :title="t('button.back')" @click="back">
21
+ {{ t('button.back') }}
22
+ </button>
23
+ </div>
24
+ </main>
25
+ </template>
26
+
27
+ <style lang="scss" scoped>
28
+ // inspired by https://codepen.io/pgalor/pen/OeRWJQ
29
+ .not-found {
30
+ font-size: 10rem;
31
+ text-shadow: 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15);
32
+ }
33
+ </style>
package/layouts/home.vue CHANGED
@@ -15,9 +15,9 @@ const isPage = computed(() => route.path.startsWith('/page'))
15
15
  <template>
16
16
  <main
17
17
  class="yun-main flex-center"
18
- :class="(isHome && !app.isSidebarOpen) && 'pl-0'" flex="~ col" w="full"
18
+ :class="(isHome && !app.isSidebarOpen) ? 'pl-0' : 'md:pl-$va-sidebar-width'" flex="~ col" w="full"
19
19
  >
20
- <YunSidebar />
20
+ <YunSidebar :show-hamburger="true" />
21
21
 
22
22
  <template v-if="!isPage">
23
23
  <YunBanner v-if="themeConfig.banner.enable" />
package/node/config.ts CHANGED
@@ -18,15 +18,16 @@ export const defaultThemeConfig: ThemeConfig = {
18
18
 
19
19
  bg_image: {
20
20
  enable: true,
21
- url: 'https://cdn.yunyoujun.cn/img/bg/stars-timing-0-blur-30px.jpg',
21
+ // url: bgImg,
22
22
  // dark: 'https://cdn.yunyoujun.cn/img/bg/dark-stars-timing-0-blur-30px.png',
23
23
  },
24
24
 
25
25
  say: {
26
26
  enable: true,
27
- api: 'https://el-bot-api.elpsy.cn/api/words/young',
27
+ api: '',
28
+ // api: 'https://el-bot-api.elpsy.cn/api/words/young',
28
29
  hitokoto: {
29
- enable: false,
30
+ enable: true,
30
31
  api: 'https://v1.hitokoto.cn',
31
32
  },
32
33
  },
package/node/unocss.ts CHANGED
@@ -3,8 +3,6 @@ import type { UserThemeConfig } from '../types'
3
3
 
4
4
  /**
5
5
  * generateSafelist by config
6
- * @param themeConfig
7
- * @returns
8
6
  */
9
7
  export function generateSafelist(options: ResolvedValaxyOptions<UserThemeConfig>) {
10
8
  const themeConfig = options.config.themeConfig || {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "valaxy-theme-yun",
3
- "version": "0.14.60",
3
+ "version": "0.15.0",
4
4
  "author": {
5
5
  "email": "me@yunyoujun.cn",
6
6
  "name": "YunYouJun",
@@ -19,12 +19,12 @@
19
19
  "dependencies": {
20
20
  "@explosions/fireworks": "^0.0.2",
21
21
  "@iconify-json/ant-design": "^1.1.10",
22
- "@iconify-json/simple-icons": "^1.1.70",
22
+ "@iconify-json/simple-icons": "^1.1.73",
23
23
  "animejs": "^3.2.1"
24
24
  },
25
25
  "devDependencies": {
26
- "@types/animejs": "^3.1.7",
27
- "valaxy": "0.14.60",
28
- "valaxy-addon-waline": "0.1.0"
26
+ "@types/animejs": "^3.1.8",
27
+ "valaxy": "0.15.0",
28
+ "valaxy-addon-waline": "0.1.1"
29
29
  }
30
30
  }
@@ -57,4 +57,39 @@
57
57
  margin-bottom: 1rem;
58
58
  }
59
59
  }
60
+
61
+ hr {
62
+ opacity: 0.6;
63
+ height: 2px;
64
+ border-top-width: 0;
65
+ background-color: var(--va-c-text);
66
+ }
67
+ }
68
+
69
+ .markdown-body {
70
+ div[class*='language-'].line-numbers-mode {
71
+ /*rtl:ignore*/
72
+ padding-left: 32px;
73
+ }
74
+
75
+ .line-numbers-wrapper {
76
+ position: absolute;
77
+ top: 0;
78
+ bottom: 0;
79
+ /*rtl:ignore*/
80
+ left: 0;
81
+ z-index: 3;
82
+ /*rtl:ignore*/
83
+ border-right: 1px solid var(--va-code-block-divider-color);
84
+ padding-top: 20px;
85
+ width: 32px;
86
+ text-align: center;
87
+ font-family: var(--va-font-family-mono);
88
+ line-height: var(--va-code-line-height);
89
+ font-size: var(--va-code-font-size);
90
+ color: var(--va-code-line-number-color);
91
+ transition:
92
+ border-color 0.5s,
93
+ color 0.5s;
94
+ }
60
95
  }
package/styles/index.scss CHANGED
@@ -9,3 +9,5 @@
9
9
 
10
10
  // override the default style of star-markdown-css
11
11
  @use "./common/markdown.scss" as *;
12
+ @use 'valaxy/client/styles/components/code-group.scss' as *;
13
+ @use 'valaxy/client/styles/components/custom-block.scss' as *;
@@ -6,7 +6,5 @@ html {
6
6
  }
7
7
 
8
8
  .yun-main {
9
- padding-left: var(--va-sidebar-width);
10
9
  transition: padding-left var(--va-transition-duration);
11
- box-sizing: border-box;
12
10
  }
package/styles/vars.scss CHANGED
@@ -5,10 +5,10 @@ $light: () !default;
5
5
  $light: map.merge(
6
6
  (
7
7
  "bg-img":
8
- url("https://cdn.yunyoujun.cn/img/bg/stars-timing-0-blur-30px.jpg"),
8
+ url("../assets/images/light/bg-img.jpg"),
9
9
  "sidebar-bg-color": var(--va-c-bg-light),
10
10
  "sidebar-bg-img":
11
- url("https://cdn.yunyoujun.cn/img/bg/alpha-stars-timing-1.webp"),
11
+ url("../assets/images/light/sidebar-bg-img.webp"),
12
12
  ),
13
13
  $light
14
14
  );
@@ -1,7 +1,7 @@
1
1
  $banner-animation-duration: 1s;
2
2
  $char-animation-duration: 0.4s;
3
3
 
4
- #banner {
4
+ #yun-banner {
5
5
  --banner-line-height: 0;
6
6
  --line-animation-duration: 0.4s;
7
7
 
@@ -26,6 +26,7 @@ $char-animation-duration: 0.4s;
26
26
  flex-direction: column;
27
27
  align-items: center;
28
28
  height: var(--banner-line-height);
29
+ transition: height 2s;
29
30
 
30
31
  &.bottom {
31
32
  justify-content: end;
@@ -43,11 +44,20 @@ $char-animation-duration: 0.4s;
43
44
  animation-duration: var(--line-animation-duration);
44
45
  animation-fill-mode: forwards;
45
46
  animation-timing-function: ease-in;
47
+ animation-iteration-count: 1;
46
48
  }
47
49
 
48
50
  &-bottom {
49
51
  flex-direction: column-reverse;
50
52
  }
53
+
54
+ &.active {
55
+ animation-name: extend-line;
56
+ animation-duration: var(--line-animation-duration);
57
+ animation-fill-mode: forwards;
58
+ animation-timing-function: ease-in;
59
+ animation-iteration-count: 1;
60
+ }
51
61
  }
52
62
 
53
63
  @keyframes extend-line {
package/tsconfig.json CHANGED
@@ -2,26 +2,26 @@
2
2
  // we need tsconfig.json to compile without
3
3
  // error: This is likely not portable. A type annotation is necessary.
4
4
  "compilerOptions": {
5
- "allowJs": true,
6
- "baseUrl": ".",
7
- "module": "ESNext",
8
5
  "target": "ESNext",
9
6
  "lib": ["DOM", "ESNext"],
10
- "strict": true,
11
- "esModuleInterop": true,
12
7
  "jsx": "preserve",
13
- "skipLibCheck": true,
8
+ "module": "ESNext",
14
9
  "moduleResolution": "node",
15
- "resolveJsonModule": true,
16
- "noUnusedLocals": true,
17
- "strictNullChecks": true,
18
- "forceConsistentCasingInFileNames": true,
10
+ "baseUrl": ".",
19
11
  "types": [
20
12
  "vite/client",
21
13
  "vue/ref-macros",
22
14
  "vite-plugin-pages/client",
23
15
  "vite-plugin-vue-layouts/client"
24
- ]
16
+ ],
17
+ "resolveJsonModule": true,
18
+ "allowJs": true,
19
+ "esModuleInterop": true,
20
+ "forceConsistentCasingInFileNames": true,
21
+ "strict": true,
22
+ "strictNullChecks": true,
23
+ "noUnusedLocals": true,
24
+ "skipLibCheck": true
25
25
  },
26
26
  "exclude": ["**/dist/**", "node_modules"]
27
27
  }
package/types/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export namespace YunTheme {
4
4
  export type Config = ThemeConfig
5
5
  export type Sidebar = any
6
6
 
7
- export type Banner = {
7
+ export interface Banner {
8
8
  /**
9
9
  * 是否启用
10
10
  */
@@ -48,7 +48,7 @@ export interface ThemeConfig {
48
48
  colors: {
49
49
  /**
50
50
  * @en primary color
51
- *
51
+ *
52
52
  * @zh 主题色
53
53
  * @default '#0078E7'
54
54
  */
@@ -72,7 +72,7 @@ export interface ThemeConfig {
72
72
  /**
73
73
  * @en Image url
74
74
  */
75
- url: string
75
+ url?: string
76
76
  /**
77
77
  * @en Image url when dark mode
78
78
  */
@@ -84,9 +84,9 @@ export interface ThemeConfig {
84
84
  }
85
85
 
86
86
  /**
87
- * @en
87
+ * @en
88
88
  * say something
89
- *
89
+ *
90
90
  * @zh 说点什么
91
91
  * - 自定义 API 链接,如 https://el-bot-api.elpsy.cn/api/words/young
92
92
  * 你可以通过在 public 下新建 json 的方式来使用, 如 public/young.json
package/unocss.config.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { defineConfig } from 'unocss'
1
+ import { defineConfig, presetWebFonts } from 'unocss'
2
2
 
3
3
  export default defineConfig({
4
4
  shortcuts: [
@@ -20,4 +20,13 @@ export default defineConfig({
20
20
  ],
21
21
  ],
22
22
  // web fonts is so big, let the user decide
23
+ presets: [
24
+ presetWebFonts({
25
+ fonts: {
26
+ sans: 'DM Sans',
27
+ serif: 'DM Serif Display',
28
+ mono: 'DM Mono',
29
+ },
30
+ }),
31
+ ],
23
32
  })
package/utils/index.ts CHANGED
@@ -1,10 +1,10 @@
1
- export const anonymousImage = 'https://cdn.yunyoujun.cn/img/avatar/none.jpg'
1
+ import noneImg from '../assets/images/none.jpg'
2
2
 
3
3
  /**
4
4
  * set default img
5
5
  * @param e
6
6
  */
7
- export function onImgError(e: Event, defaultImg = anonymousImage) {
7
+ export function onImgError(e: Event, defaultImg = noneImg) {
8
8
  const targetEl = e.target as HTMLImageElement
9
9
  targetEl.setAttribute('data-src', targetEl.src)
10
10
  targetEl.src = defaultImg