valaxy-theme-hairy 0.0.1

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 (102) hide show
  1. package/@types/markdown-it.d.ts +1 -0
  2. package/@types/markdown-toc.d.ts +1 -0
  3. package/@types/types.d.ts +1 -0
  4. package/@types/valaxy.d.ts +10 -0
  5. package/LICENSE +21 -0
  6. package/components/HairyAlgoliaSearchBox.vue +118 -0
  7. package/components/HairyArticleImage.vue +17 -0
  8. package/components/HairyArticleImageDefault.vue +127 -0
  9. package/components/HairyArticleImageSmall.vue +49 -0
  10. package/components/HairyArticleSeries.vue +73 -0
  11. package/components/HairyArticleText.vue +38 -0
  12. package/components/HairyArticleTop.vue +0 -0
  13. package/components/HairyBackToTop.vue +72 -0
  14. package/components/HairyBody.vue +55 -0
  15. package/components/HairyBreadcrumb.vue +51 -0
  16. package/components/HairyBreadcrumbItem.vue +14 -0
  17. package/components/HairyCarousel.vue +45 -0
  18. package/components/HairyDivider.vue +0 -0
  19. package/components/HairyHeader.vue +31 -0
  20. package/components/HairyImage.vue +14 -0
  21. package/components/HairyImageGroup.vue +69 -0
  22. package/components/HairyImageViewer.vue +22 -0
  23. package/components/HairyLayout.vue +29 -0
  24. package/components/HairyLink.vue +10 -0
  25. package/components/HairyMenu.vue +15 -0
  26. package/components/HairyMenuItem.vue +40 -0
  27. package/components/HairyMeting.vue +19 -0
  28. package/components/HairyNav.vue +39 -0
  29. package/components/HairyNavBackground.vue +7 -0
  30. package/components/HairyNavSearch.vue +265 -0
  31. package/components/HairyNavTitle.vue +13 -0
  32. package/components/HairyNavToggleDark.vue +16 -0
  33. package/components/HairyPostImageList.vue +28 -0
  34. package/components/HairyPostList.vue +24 -0
  35. package/components/HairyPostTitle.vue +33 -0
  36. package/components/HairySocialLinks.vue +27 -0
  37. package/components/HairyTimelinePostItem.vue +40 -0
  38. package/components/HairyToc.vue +135 -0
  39. package/components/HairyUserCard.vue +30 -0
  40. package/components/HairyUserNav.vue +68 -0
  41. package/components/HairyUserTab.vue +40 -0
  42. package/components/HairyWaline.vue +25 -0
  43. package/components/HairyWaves.vue +67 -0
  44. package/components/ValaxyMain.vue +45 -0
  45. package/hooks/useCategory.ts +18 -0
  46. package/hooks/useCategoryPost.ts +21 -0
  47. package/hooks/useContext.ts +16 -0
  48. package/hooks/useHeaderHeight.ts +9 -0
  49. package/hooks/usePostLayout.ts +9 -0
  50. package/hooks/useYearArchives.ts +43 -0
  51. package/images.json +101 -0
  52. package/index.d.ts +54 -0
  53. package/layouts/archives.vue +11 -0
  54. package/layouts/categories.vue +6 -0
  55. package/layouts/default.vue +9 -0
  56. package/layouts/home.vue +23 -0
  57. package/layouts/month.vue +6 -0
  58. package/layouts/post.vue +26 -0
  59. package/layouts/tag.vue +6 -0
  60. package/layouts/tags.vue +6 -0
  61. package/layouts/year.vue +6 -0
  62. package/locales/en.yml +1 -0
  63. package/locales/zh-CN.yml +3 -0
  64. package/modules/context.ts +5 -0
  65. package/modules/loading.scss +531 -0
  66. package/modules/loading.ts +42 -0
  67. package/modules/scroll.ts +21 -0
  68. package/node/addon-hairy.ts +18 -0
  69. package/node/addon-images.ts +61 -0
  70. package/node/addon-meting.ts +13 -0
  71. package/node/addon-statistics.ts +19 -0
  72. package/node/addon-toc.ts +20 -0
  73. package/node/utils.ts +20 -0
  74. package/package.json +47 -0
  75. package/pages/archives/[year]/[month]/index.vue +52 -0
  76. package/pages/archives/[year]/index.vue +73 -0
  77. package/pages/archives/index.vue +53 -0
  78. package/pages/categories/[...categories].vue +115 -0
  79. package/pages/index.vue +14 -0
  80. package/pages/tags/[tag].vue +40 -0
  81. package/pages/tags/index.vue +31 -0
  82. package/setup/main.ts +11 -0
  83. package/shims.d.ts +8 -0
  84. package/styles/css-vars.scss +161 -0
  85. package/styles/element-plus/index.scss +2 -0
  86. package/styles/element-plus/tabs.scss +26 -0
  87. package/styles/element-plus/timeline.scss +19 -0
  88. package/styles/font-face.scss +20 -0
  89. package/styles/fonts/FrederickatheGreat.ttf +0 -0
  90. package/styles/fonts/Modesty.ttf +0 -0
  91. package/styles/fonts/MountainsofChristmas-Bold.ttf +0 -0
  92. package/styles/fonts/MountainsofChristmas-Regular.ttf +0 -0
  93. package/styles/fonts/Seto.ttf +0 -0
  94. package/styles/index.scss +65 -0
  95. package/styles/markdown.scss +60 -0
  96. package/styles/scrollbar.scss +26 -0
  97. package/unocss.config.ts +29 -0
  98. package/utils/createContext.ts +40 -0
  99. package/utils/index.ts +28 -0
  100. package/utils/loading.scss +531 -0
  101. package/utils/loading.ts +30 -0
  102. package/valaxy.config.ts +26 -0
@@ -0,0 +1,45 @@
1
+ <script lang="ts" setup>
2
+ import images from '@hairy:images:home'
3
+ import { Swiper, SwiperSlide } from 'swiper/vue'
4
+ import { Autoplay, EffectFade } from 'swiper'
5
+ import 'swiper/css'
6
+ import 'swiper/css/autoplay'
7
+ import 'swiper/css/effect-fade'
8
+
9
+ images.sort(() => Math.random() - 0.5)
10
+ </script>
11
+
12
+ <template>
13
+ <swiper
14
+ effect="fade" :speed="2000" :fade-effect="{ crossFade: true }" :modules="[Autoplay, EffectFade]"
15
+ :slides-per-view="1" :space-between="50" :autoplay="{
16
+ delay: 4000,
17
+ }" class="HairyCarousel swiper-no-swiping"
18
+ >
19
+ <swiper-slide v-for="(item, index) in images" :key="index" class="w-full h-full">
20
+ <img class="w-full h-full object-cover" :src="item" />
21
+ </swiper-slide>
22
+ </swiper>
23
+ </template>
24
+
25
+ <style lang="scss">
26
+ .HairyCarousel {
27
+ &::before {
28
+ content: '';
29
+ display: block;
30
+ position: absolute;
31
+ top: 0;
32
+ left: 0;
33
+ width: 100%;
34
+ height: 100%;
35
+ background-color: rgba(0, 0, 0, .2);
36
+ z-index: 2;
37
+ transition: all .2s ease-in-out 0s;
38
+ }
39
+ }
40
+ .dark {
41
+ .HairyCarousel::before {
42
+ background-color: rgba(0,0,0,.4);
43
+ }
44
+ }
45
+ </style>
File without changes
@@ -0,0 +1,31 @@
1
+ <script lang="ts" setup>
2
+ import { useContext } from '../hooks/useContext'
3
+
4
+ defineProps<{
5
+ headline?: String
6
+ title?: String
7
+ description?: string
8
+ }>()
9
+
10
+ const { headerRef } = useContext()
11
+ </script>
12
+
13
+ <template>
14
+ <header ref="headerRef" class="HairyHeader relative">
15
+ <div class="h-30vh lt-md:h-60vh min-h-80 flex-center">
16
+ <HairyPostTitle v-if="title" class="relative z-2" :title="title" v-bind="$props">
17
+ <template #description>
18
+ <slot name="description" />
19
+ </template>
20
+ </HairyPostTitle>
21
+ </div>
22
+ <HairyCarousel class="inset-0" style="position: absolute" />
23
+ <HairyWaves class="relative z-10" />
24
+ </header>
25
+ </template>
26
+
27
+ <style>
28
+ .HairyHeader {
29
+ position: relative;
30
+ }
31
+ </style>
@@ -0,0 +1,14 @@
1
+ <script lang="ts" setup>
2
+ import { ElImage, imageProps } from 'element-plus/es/components/image/index'
3
+ import 'element-plus/es/components/image/style/index'
4
+ import { inject } from 'vue'
5
+ const props = defineProps(imageProps)
6
+
7
+ const preview = inject<(url: string) => void>('HairyImageGroup:preview')
8
+ </script>
9
+
10
+ <template>
11
+ <ElImage v-bind="props" class="HairyImage" :class="[preview && 'cursor-pointer rounded']" @click="preview?.(src)" />
12
+ </template>
13
+
14
+ <style lang="scss" scoped></style>
@@ -0,0 +1,69 @@
1
+ <script lang="ts" setup>
2
+ import { computed, provide, useCssVars, useSlots } from 'vue'
3
+ import { executeOverlay } from 'unoverlay-vue'
4
+ import type { ImageViewerProps } from 'element-plus/es/components/image-viewer/index'
5
+ import type { AtWillNumber } from '@hairy/libcore'
6
+ import { atWillToUnit } from '@hairy/libcore'
7
+ import HairyImageViewer from './HairyImageViewer.vue'
8
+
9
+ const props = withDefaults(defineProps<{
10
+ row?: AtWillNumber
11
+ col?: AtWillNumber
12
+ gap?: AtWillNumber
13
+ justify?: string
14
+ align?: string
15
+ }>(),
16
+ {
17
+ row: 'auto',
18
+ col: 'auto',
19
+ gap: 10,
20
+ justify: 'space-evenly',
21
+ align: 'initial',
22
+ })
23
+
24
+ useCssVars(() => ({
25
+ width: atWillToUnit(props.row),
26
+ height: atWillToUnit(props.col),
27
+ gap: atWillToUnit(props.gap),
28
+ justify: props.justify,
29
+ align: props.align,
30
+ }))
31
+
32
+ const slots = useSlots()
33
+ const paths = computed(() => slots
34
+ .default?.()
35
+ .map(v => v.props?.src)
36
+ .filter(Boolean) as string[],
37
+ )
38
+
39
+ const preview = (url: string) => {
40
+ const initialIndex = paths.value.findIndex(v => v === url) || 0
41
+ executeOverlay<Partial<ImageViewerProps>>(HairyImageViewer, {
42
+ props: {
43
+ urlList: paths.value,
44
+ initialIndex,
45
+ },
46
+ })
47
+ }
48
+
49
+ provide('HairyImageGroup:preview', preview)
50
+ </script>
51
+
52
+ <template>
53
+ <div class="HairyImageGroup">
54
+ <slot></slot>
55
+ </div>
56
+ </template>
57
+
58
+ <style lang="scss" scoped>
59
+ .HairyImageGroup {
60
+ display: grid;
61
+ grid-template-columns: repeat(auto-fill, var(--width, auto));
62
+ gap: var(--gap);
63
+ justify-content: var(--justify);
64
+ align-items: var(--align);
65
+ :deep(.HairyImage) {
66
+ height: var(--height, auto);
67
+ }
68
+ }
69
+ </style>
@@ -0,0 +1,22 @@
1
+ <script lang="ts" setup>
2
+ import { useOverlayMeta } from 'unoverlay-vue'
3
+ import { ElImageViewer, imageViewerProps } from 'element-plus/es/components/image-viewer/index'
4
+ import 'element-plus/es/components/image-viewer/style/index'
5
+ import { onMounted, onUnmounted } from 'vue'
6
+ const props = defineProps(imageViewerProps)
7
+
8
+ const { visible, confirm } = useOverlayMeta()
9
+
10
+ onMounted(() => {
11
+ document.body.style.overflow = 'hidden'
12
+ })
13
+ onUnmounted(() => {
14
+ document.body.style.overflow = ''
15
+ })
16
+ </script>
17
+
18
+ <template>
19
+ <div class="HairyImageViewer fixed inset-0 z-2000">
20
+ <ElImageViewer v-if="visible" v-bind="props" @close="confirm()"></ElImageViewer>
21
+ </div>
22
+ </template>
@@ -0,0 +1,29 @@
1
+ <script lang="ts" setup>
2
+ defineProps<{
3
+ header?: {
4
+ title?: string
5
+ headline?: string
6
+ description?: string
7
+ }
8
+ }>()
9
+ </script>
10
+
11
+ <template>
12
+ <div class="HairyLayout">
13
+ <HairyNav />
14
+ <HairyHeader v-bind="header">
15
+ <template #description>
16
+ <slot name="header-description" />
17
+ </template>
18
+ </HairyHeader>
19
+ <HairyBody>
20
+ <slot />
21
+
22
+ <template v-if="$slots['body-slide']" #slide>
23
+ <slot name="body-slide" />
24
+ </template>
25
+ </HairyBody>1
26
+ <HairyBackToTop />
27
+ <HairyMeting />
28
+ </div>
29
+ </template>
@@ -0,0 +1,10 @@
1
+ <script lang="ts" setup>
2
+ </script>
3
+
4
+ <template>
5
+ <span class="HairyLink cursor-pointer border-b border-dashed hover:border-primary hover:text-primary transition-all">
6
+ <slot />
7
+ </span>
8
+ </template>
9
+
10
+ <style lang="scss" scoped></style>
@@ -0,0 +1,15 @@
1
+ <script lang="ts" setup>
2
+ import type { HairyTheme } from 'valaxy-theme-hairy'
3
+ import { useThemeConfig } from 'valaxy'
4
+ import { computed } from 'vue'
5
+ const themeConfig = useThemeConfig<HairyTheme>()
6
+ const nav = computed(() => themeConfig.value.nav || [])
7
+ </script>
8
+
9
+ <template>
10
+ <div class="flex items-center h-12.5">
11
+ <HairyMenuItem v-for="(item, index) in nav" :key="index" :item="item" />
12
+ </div>
13
+ </template>
14
+
15
+ <style lang="scss" scoped></style>
@@ -0,0 +1,40 @@
1
+ <script lang="ts" setup>
2
+ import type { NavItem } from 'valaxy-theme-hairy'
3
+ import { computed } from 'vue'
4
+ import { useRoute, useRouter } from 'vue-router'
5
+ import { ejectWindow } from '../utils'
6
+ const props = defineProps<{
7
+ item: NavItem
8
+ }>()
9
+ const urlReg = /^(((ht|f)tps?):\/\/)?([^!@#$%^&*?.\s-]([^!@#$%^&*?.\s]{0,63}[^!@#$%^&*?.\s])?\.)+[a-z]{2,6}\/?/
10
+ const isLink = computed(() => urlReg.test(props.item?.link || ''))
11
+ const isPointer = computed(() => Boolean(props.item.link) || isLink.value)
12
+ const router = useRouter()
13
+ const route = useRoute()
14
+ const toLink = () => {
15
+ if (isLink.value)
16
+ return ejectWindow(props.item.link!)
17
+ if (props.item.link)
18
+ router.push(props.item.link)
19
+ }
20
+ const isActive = computed(() => {
21
+ if (isLink.value)
22
+ return false
23
+ if (props.item.link === '/')
24
+ return route.path === props.item.link
25
+ return route.path.includes(props.item.link!)
26
+ })
27
+ </script>
28
+
29
+ <template>
30
+ <div class="px-2.5 HairyMenuItem" :class="[isPointer ? 'cursor-pointer' : 'select-none', isActive && 'text-primary active']">
31
+ <div class="flex items-center hover:text-primary" @click="toLink">
32
+ <div v-if="item.icon" class="mr-1 icon" :class="item.icon" />
33
+ <div class="question">
34
+ {{ item.text }}
35
+ </div>
36
+ </div>
37
+ </div>
38
+ </template>
39
+
40
+ <style lang="scss" scoped></style>
@@ -0,0 +1,19 @@
1
+ <script lang="ts" setup>
2
+ import { useAplayer, useThemeConfig } from 'valaxy'
3
+
4
+ import type { HairyTheme } from 'valaxy-theme-hairy'
5
+
6
+ const config = useThemeConfig<HairyTheme>()
7
+
8
+ if (config.value.meting)
9
+ useAplayer()
10
+ </script>
11
+
12
+ <template>
13
+ <meting-js
14
+ v-if="config.meting && config.meting.fixed !== false"
15
+ v-bind="config.meting"
16
+ :fixed="true"
17
+ >
18
+ </meting-js>
19
+ </template>
@@ -0,0 +1,39 @@
1
+ <script lang="ts" setup>
2
+ import { useScroll, whenever } from '@vueuse/core'
3
+ import { computed, ref } from 'vue'
4
+ import { useHeaderHeight } from '../hooks/useHeaderHeight'
5
+
6
+ const headerHeight = useHeaderHeight()
7
+ const cache = ref<'top' | 'bottom'>('top')
8
+ const scroll = useScroll(document)
9
+
10
+ whenever(() => scroll.directions.top, () => {
11
+ cache.value = 'top'
12
+ })
13
+ whenever(() => scroll.directions.bottom, () => {
14
+ cache.value = 'bottom'
15
+ })
16
+
17
+ const show = computed(() => {
18
+ return scroll.y.value < (headerHeight.value / 2) || cache.value === 'top'
19
+ })
20
+ </script>
21
+
22
+ <template>
23
+ <div class="HairyNav fixed w-full h-3.125rem top-0 z-20 opacity-0 transition-opacity duration-200" :class="[show && 'opacity-100']">
24
+ <div class="mx-auto breakpoint flex relative z-1">
25
+ <div class="flex-1 flex items-center">
26
+ <HairyNavTitle class="lt-sm:hidden" />
27
+ <HairyMenu />
28
+ </div>
29
+ <div class="flex-center lt-sm:hidden">
30
+ <HairyNavToggleDark />
31
+ <HairyNavSearch />
32
+ </div>
33
+ </div>
34
+ <HairyNavBackground />
35
+ </div>
36
+ </template>
37
+
38
+ <style>
39
+ </style>
@@ -0,0 +1,7 @@
1
+ <template>
2
+ <div class="HairyNavBackground transition-colors absolute inset-0 bg-white bg-opacity-80 dark:bg-black dark:bg-opacity-80 blur-5" />
3
+ </template>
4
+
5
+ <style>
6
+
7
+ </style>
@@ -0,0 +1,265 @@
1
+ <script lang="ts" setup>
2
+ import '@docsearch/css'
3
+ import { computed, defineAsyncComponent, onMounted, onUnmounted, ref } from 'vue'
4
+ import { useConfig } from 'valaxy'
5
+
6
+ const HairyAlgoliaSearchBox = __ALGOLIA__
7
+ ? defineAsyncComponent(() => import('./HairyAlgoliaSearchBox.vue'))
8
+ : () => null
9
+
10
+ const config = useConfig()
11
+ const search = computed(() => config.value.search)
12
+ const enable = computed(() => search.value.algolia.enable)
13
+
14
+ // to avoid loading the docsearch js upfront (which is more than 1/3 of the
15
+ // payload), we delay initializing it until the user has actually clicked or
16
+ // hit the hotkey to invoke it.
17
+ const loaded = ref(false)
18
+
19
+ const metaKey = ref()
20
+
21
+ onMounted(() => {
22
+ if (!search.value.enable || !search.value.algolia.enable)
23
+ return
24
+
25
+ // meta key detect (same logic as in @docsearch/js)
26
+ metaKey.value.textContent = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)
27
+ ? '⌘'
28
+ : 'Ctrl'
29
+
30
+ const handleSearchHotKey = (e: KeyboardEvent) => {
31
+ if (e.key === 'k' && (e.ctrlKey || e.metaKey)) {
32
+ e.preventDefault()
33
+ load()
34
+ remove()
35
+ }
36
+ }
37
+ function remove() {
38
+ window.removeEventListener('keydown', handleSearchHotKey)
39
+ }
40
+
41
+ window.addEventListener('keydown', handleSearchHotKey)
42
+ onUnmounted(remove)
43
+ })
44
+ function load() {
45
+ if (!loaded.value)
46
+ loaded.value = true
47
+ }
48
+ </script>
49
+
50
+ <template>
51
+ <div v-if="enable" class="VPNavBarSearch">
52
+ <HairyAlgoliaSearchBox v-if="loaded" />
53
+ <div v-else id="docsearch" @click="load">
54
+ <button
55
+ type="button"
56
+ class="DocSearch DocSearch-Button"
57
+ aria-label="Search"
58
+ >
59
+ <span class="DocSearch-Button-Container">
60
+ <svg
61
+ class="DocSearch-Search-Icon"
62
+ width="20"
63
+ height="20"
64
+ viewBox="0 0 20 20"
65
+ >
66
+ <path
67
+ d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z"
68
+ stroke="currentColor"
69
+ fill="none"
70
+ fill-rule="evenodd"
71
+ stroke-linecap="round"
72
+ stroke-linejoin="round"
73
+ />
74
+ </svg>
75
+ <span class="DocSearch-Button-Placeholder">Search</span>
76
+ </span>
77
+ <span class="DocSearch-Button-Keys">
78
+ <kbd ref="metaKey" class="DocSearch-Button-Key">Meta</kbd>
79
+ <kbd class="DocSearch-Button-Key">K</kbd>
80
+ </span>
81
+ </button>
82
+ </div>
83
+ </div>
84
+ </template>
85
+
86
+ <style>
87
+ .VPNavBarSearch {
88
+ display: flex;
89
+ align-items: center;
90
+ }
91
+
92
+ @media (min-width: 768px) {
93
+ .VPNavBarSearch {
94
+ flex-grow: 1;
95
+ padding-left: 24px;
96
+ }
97
+ }
98
+
99
+ @media (min-width: 960px) {
100
+ .VPNavBarSearch {
101
+ padding-left: 32px;
102
+ }
103
+ }
104
+
105
+ .DocSearch {
106
+ --docsearch-primary-color: var(--hy-c-brand);
107
+ --docsearch-highlight-color: var(--docsearch-primary-color);
108
+ --docsearch-text-color: var(--hy-c-text-1);
109
+ --docsearch-muted-color: var(--hy-c-text-2);
110
+ --docsearch-searchbox-shadow: none;
111
+ --docsearch-searchbox-focus-background: transparent;
112
+ --docsearch-key-gradient: transparent;
113
+ --docsearch-key-shadow: none;
114
+ --docsearch-modal-background: var(--hy-c-bg-soft);
115
+ --docsearch-footer-background: var(--hy-c-bg);
116
+ }
117
+
118
+ .dark .DocSearch {
119
+ --docsearch-modal-shadow: none;
120
+ --docsearch-footer-shadow: none;
121
+ --docsearch-logo-color: var(--hy-c-text-2);
122
+ --docsearch-hit-background: var(--hy-c-bg-mute);
123
+ --docsearch-hit-color: var(--hy-c-text-2);
124
+ --docsearch-hit-shadow: none;
125
+ }
126
+
127
+ .DocSearch-Button {
128
+ display: flex;
129
+ justify-content: center;
130
+ align-items: center;
131
+ margin: 0;
132
+ padding: 0;
133
+ width: 32px;
134
+ height: 55px;
135
+ background: transparent;
136
+ transition: border-color 0.25s;
137
+ }
138
+
139
+ .DocSearch-Button:hover {
140
+ background: transparent;
141
+ }
142
+
143
+ .DocSearch-Button:focus {
144
+ outline: 1px dotted;
145
+ outline: 5px auto -webkit-focus-ring-color;
146
+ }
147
+
148
+ .DocSearch-Button:focus:not(:focus-visible) {
149
+ outline: none !important;
150
+ }
151
+
152
+ @media (min-width: 768px) {
153
+ .DocSearch-Button {
154
+ justify-content: flex-start;
155
+ border: 1px solid transparent;
156
+ border-radius: 8px;
157
+ padding: 0 10px 0 12px;
158
+ width: 100%;
159
+ height: 40px;
160
+ /* background-color: var(--hy-c-bg-alt); */
161
+ }
162
+
163
+ .DocSearch-Button:hover {
164
+ border-color: var(--hy-c-brand);
165
+ /* background: var(--hy-c-bg-alt); */
166
+ }
167
+ }
168
+
169
+ .DocSearch-Button .DocSearch-Button-Container {
170
+ display: flex;
171
+ align-items: center;
172
+ }
173
+
174
+ .DocSearch-Button .DocSearch-Search-Icon {
175
+ position: relative;
176
+ width: 16px;
177
+ height: 16px;
178
+ color: var(--hy-c-text-1);
179
+ fill: currentColor;
180
+ transition: color 0.5s;
181
+ }
182
+
183
+ .DocSearch-Button:hover .DocSearch-Search-Icon {
184
+ color: var(--hy-c-text-1);
185
+ }
186
+
187
+ @media (min-width: 768px) {
188
+ .DocSearch-Button .DocSearch-Search-Icon {
189
+ top: 1px;
190
+ margin-right: 8px;
191
+ width: 14px;
192
+ height: 14px;
193
+ color: var(--hy-c-text-2);
194
+ }
195
+ }
196
+
197
+ .DocSearch-Button .DocSearch-Button-Placeholder {
198
+ display: none;
199
+ margin-top: 2px;
200
+ padding: 0 16px 0 0;
201
+ font-size: 13px;
202
+ font-weight: 500;
203
+ color: var(--hy-c-text-2);
204
+ transition: color 0.5s;
205
+ }
206
+
207
+ .DocSearch-Button:hover .DocSearch-Button-Placeholder {
208
+ color: var(--hy-c-text-1);
209
+ }
210
+
211
+ @media (min-width: 768px) {
212
+ .DocSearch-Button .DocSearch-Button-Placeholder {
213
+ display: inline-block;
214
+ }
215
+ }
216
+
217
+ .DocSearch-Button .DocSearch-Button-Keys {
218
+ display: none;
219
+ min-width: auto;
220
+ }
221
+
222
+ @media (min-width: 768px) {
223
+ .DocSearch-Button .DocSearch-Button-Keys {
224
+ display: flex;
225
+ align-items: center;
226
+ }
227
+ }
228
+
229
+ .DocSearch-Button .DocSearch-Button-Key {
230
+ display: block;
231
+ margin: 2px 0 0 0;
232
+ border: 1px solid var(--hy-c-divider);
233
+ border-right: none;
234
+ border-radius: 4px 0 0 4px;
235
+ padding-left: 6px;
236
+ min-width: 0;
237
+ width: auto;
238
+ height: 22px;
239
+ line-height: 22px;
240
+ font-size: 12px;
241
+ font-weight: 500;
242
+ transition: color 0.5s, border-color 0.5s;
243
+ }
244
+
245
+ .DocSearch-Button .DocSearch-Button-Key + .DocSearch-Button-Key {
246
+ border-right: 1px solid var(--hy-c-divider);
247
+ border-left: none;
248
+ border-radius: 0 4px 4px 0;
249
+ padding-left: 2px;
250
+ padding-right: 6px;
251
+ }
252
+
253
+ .dark .DocSearch-Footer {
254
+ border-top: 1px solid var(--hy-c-divider);
255
+ }
256
+
257
+ .DocSearch-Form {
258
+ border: 1px solid var(--hy-c-brand);
259
+ background-color: var(--hy-c-white);
260
+ }
261
+
262
+ .dark .DocSearch-Form {
263
+ background-color: var(--hy-c-bg-mute);
264
+ }
265
+ </style>
@@ -0,0 +1,13 @@
1
+ <script lang="ts" setup>
2
+ import { useConfig } from 'valaxy'
3
+ const config = useConfig()
4
+ const hrefToUrl = () => {
5
+ location.href = config.value.url
6
+ }
7
+ </script>
8
+
9
+ <template>
10
+ <div class="px-2.5">
11
+ <span class="cursor-pointer hover:text-primary" @click="hrefToUrl">{{ config.title }}</span>
12
+ </div>
13
+ </template>
@@ -0,0 +1,16 @@
1
+ <script lang="ts" setup>
2
+ import { useI18n } from 'vue-i18n'
3
+ import { computed } from 'vue'
4
+ import { isDark, toggleDark } from 'valaxy'
5
+
6
+ const { t } = useI18n()
7
+ const themeTitle = computed(() => {
8
+ return isDark.value ? t('button.toggle_light') : t('button.toggle_dark')
9
+ })
10
+ </script>
11
+
12
+ <template>
13
+ <button class="yun-icon-btn" :title="themeTitle" :style="{ color: isDark ? '' : '#f1cb64' }" @click="toggleDark()">
14
+ <div i="ri-sun-line dark:ri-moon-line" />
15
+ </button>
16
+ </template>
@@ -0,0 +1,28 @@
1
+ <script lang="ts" setup>
2
+ import type { Ref } from 'vue'
3
+ import { computed } from 'vue'
4
+ import type { Post } from 'valaxy'
5
+ import { usePostList } from 'valaxy'
6
+
7
+ import { usePostLayout } from '../hooks/usePostLayout'
8
+
9
+ const props = withDefaults(defineProps<{
10
+ type?: string
11
+ posts?: Post[]
12
+ }>(), {
13
+ })
14
+
15
+ const routes = usePostList() as any as Ref<Post[]>
16
+ const posts = computed(() => props.posts || routes.value)
17
+ const layout = usePostLayout()
18
+ const reverse = computed(() => layout.value.includes('reverse'))
19
+ </script>
20
+
21
+ <template>
22
+ <ul class="divide-y divide-gray-200 dark:divide-gray-700">
23
+ <Transition v-for="post, i in posts" :key="i" name="fade">
24
+ <HairyArticleImage :post="post" :reverse="reverse && (i % 2) === 0" />
25
+ </Transition>
26
+ </ul>
27
+ </template>
28
+