valaxy-theme-hairy 0.2.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- package/client/index.ts +1 -0
- package/components/HairyBody.vue +15 -17
- package/components/HairyComment.vue +33 -0
- package/components/HairyContainer.vue +13 -0
- package/components/{HairyUserPopup.vue → HairyDrawer.vue} +14 -13
- package/components/HairyFooter.vue +12 -9
- package/components/HairyHeader.vue +10 -9
- package/components/HairyImage.vue +2 -1
- package/components/HairyImageGroup.vue +12 -16
- package/components/HairyNavbar.vue +56 -0
- package/components/{HairyPostList.vue → HairyPosts.vue} +3 -3
- package/components/{HairyNavSearch.vue → HairySearch.vue} +23 -87
- package/components/{HairyUserCard.vue → HairySidebar.vue} +4 -4
- package/components/{HairyUserTab.vue → HairyTabbar.vue} +27 -11
- package/components/PageTags.vue +48 -0
- package/components/ValaxyMain.vue +3 -3
- package/components/navbar/HairyNav.vue +16 -0
- package/components/navbar/HairyNavExpand.vue +12 -0
- package/components/navbar/HairyNavItem.vue +35 -0
- package/components/navbar/HairyNavbarBackground.vue +7 -0
- package/components/navbar/HairyNavbarSearch.vue +8 -0
- package/components/{HairyNavTitle.vue → navbar/HairyNavbarTitle.vue} +5 -3
- package/components/navbar/HairyNavbarToggleDark.vue +22 -0
- package/components/{HairyBreadcrumb.vue → parts/HairyBreadcrumb.vue} +1 -1
- package/components/{HairyBreadcrumbItem.vue → parts/HairyBreadcrumbItem.vue} +1 -4
- package/components/{lib/fish.js → parts/HairyFootFish.js} +5 -7
- package/components/parts/HairyFootFish.vue +38 -0
- package/components/{HairyPostTitle.vue → parts/HairyHeadHero.vue} +6 -5
- package/components/{HairyWaves.vue → parts/HairyHeadWaves.vue} +5 -5
- package/components/parts/HairyImageGlobal.vue +51 -0
- package/components/{HairyImageViewer.vue → parts/HairyImageViewer.vue} +4 -3
- package/components/parts/HairyLink.vue +21 -0
- package/components/{HairyMenu.vue → parts/HairyMenu.vue} +2 -1
- package/components/{HairyMenuItem.vue → parts/HairyMenuItem.vue} +11 -4
- package/components/parts/HairyOutline.vue +99 -0
- package/components/parts/HairyOutlineItem.vue +48 -0
- package/components/{HairySocialLinks.vue → parts/HairySocialLinks.vue} +2 -2
- package/components/{HairyTimelinePostItem.vue → parts/HairyTimelineContent.vue} +7 -8
- package/components/parts/HairyUserNav.vue +95 -0
- package/components/{article-layout → posts}/HairyArticleImage.vue +18 -19
- package/components/{article-layout → posts}/HairyArticleSeries.vue +8 -5
- package/components/{article-layout → posts}/HairyArticleText.vue +11 -4
- package/components/posts/HairyPostFooter.vue +15 -0
- package/components/{article-layout → posts}/HairyPostImageList.vue +4 -5
- package/components/{article-layout → posts}/HairyPostTextsList.vue +0 -1
- package/components/posts/HairyPostToggleLayout.vue +36 -0
- package/components/third/HairyAlgoliaSearch.vue +17 -0
- package/components/third/HairyFuseSearch.vue +10 -0
- package/components/third/HairyFuseSearchDialog.vue +32 -0
- package/components/third/HairyFuseSearchDropdown.vue +77 -0
- package/components/third/HairyFuseSearchFooter.vue +28 -0
- package/components/third/HairyFuseSearchHeader.vue +30 -0
- package/components/third/HairyFuseSearchHit.vue +52 -0
- package/components/third/HairySearchBtnDisplay.vue +29 -0
- package/components/third/HairySearchBtnInput.vue +20 -0
- package/components/third/HairySearchBtnKeys.vue +19 -0
- package/components/{HairyCarousel.vue → third/HairySwiperCarousel.vue} +6 -6
- package/{hooks/useYearArchives.ts → composables/archives.ts} +4 -3
- package/composables/category.ts +43 -0
- package/composables/config.ts +11 -0
- package/composables/dark.ts +13 -0
- package/composables/fuse.ts +60 -0
- package/composables/index.ts +8 -0
- package/composables/layout.ts +16 -0
- package/composables/outline.ts +49 -0
- package/composables/tags.ts +36 -0
- package/layouts/archive-month.vue +13 -0
- package/layouts/archive-year.vue +13 -0
- package/layouts/archive.vue +11 -0
- package/layouts/categories.vue +11 -4
- package/layouts/default.vue +8 -7
- package/layouts/home.vue +28 -18
- package/layouts/post.vue +41 -35
- package/layouts/tag.vue +8 -4
- package/layouts/tags.vue +11 -4
- package/{modules → library}/loading.ts +18 -6
- package/{modules → library}/scroll.ts +3 -2
- package/locales/zh-CN.yml +0 -2
- package/node/images/default.json +139 -0
- package/node/images/index.ts +46 -0
- package/node/index.ts +2 -0
- package/node/theme/index.ts +78 -0
- package/package.json +22 -28
- package/pages/archives/[year]/[month]/index.vue +15 -16
- package/pages/archives/[year]/index.vue +20 -18
- package/pages/archives/index.vue +10 -8
- package/pages/categories/{[...categories].vue → [...its].vue} +29 -34
- package/pages/index.vue +1 -1
- package/pages/page/[page].vue +2 -2
- package/pages/tags/{[tag].vue → [tag]/index.vue} +12 -12
- package/pages/tags/index.vue +12 -5
- package/setup/main.ts +1 -1
- package/store/index.ts +1 -0
- package/store/modules/global.ts +12 -0
- package/styles/components/index.scss +4 -0
- package/styles/{markdown.scss → components/markdown.scss} +2 -1
- package/styles/components/nprogress.scss +16 -0
- package/styles/css-vars.scss +11 -0
- package/styles/element-plus/tabs.scss +1 -1
- package/styles/element-plus/timeline.scss +1 -1
- package/styles/global.scss +39 -0
- package/styles/index.scss +4 -73
- package/tsconfig.json +27 -0
- package/types/index.d.ts +163 -0
- package/unocss.config.ts +5 -1
- package/utils/index.ts +21 -39
- package/valaxy.config.ts +21 -24
- package/@types/markdown-it.d.ts +0 -1
- package/@types/markdown-toc.d.ts +0 -1
- package/@types/types.d.ts +0 -1
- package/@types/valaxy.d.ts +0 -10
- package/components/HairyAlgoliaSearchBox.vue +0 -118
- package/components/HairyBackToTop.vue +0 -72
- package/components/HairyDivider.vue +0 -0
- package/components/HairyFooterFish.vue +0 -29
- package/components/HairyLayout.vue +0 -28
- package/components/HairyLink.vue +0 -10
- package/components/HairyLinks.vue +0 -69
- package/components/HairyMeting.vue +0 -19
- package/components/HairyNav.vue +0 -42
- package/components/HairyNavBackground.vue +0 -7
- package/components/HairyNavMenu.vue +0 -11
- package/components/HairyNavToggleDark.vue +0 -16
- package/components/HairyPostToggleLayout.vue +0 -33
- package/components/HairyToc.vue +0 -135
- package/components/HairyUserNav.vue +0 -64
- package/components/HairyWaline.vue +0 -44
- package/hooks/setupDefaultDark.ts +0 -11
- package/hooks/useCategory.ts +0 -18
- package/hooks/useCategoryPost.ts +0 -21
- package/hooks/useContext.ts +0 -13
- package/hooks/useHeaderHeight.ts +0 -9
- package/hooks/usePostLayout.ts +0 -16
- package/images.json +0 -140
- package/index.d.ts +0 -100
- package/layouts/archives.vue +0 -11
- package/layouts/hairy.vue +0 -36
- package/layouts/month.vue +0 -6
- package/layouts/year.vue +0 -6
- package/node/addon-hairy.ts +0 -36
- package/node/addon-images.ts +0 -61
- package/node/addon-meting.ts +0 -13
- package/node/addon-statistics.ts +0 -19
- package/node/addon-toc.ts +0 -20
- package/node/utils.ts +0 -20
- package/utils/createContext.ts +0 -40
- package/utils/fonts.ts +0 -15
- /package/components/{HairyUserStats.vue → parts/HairyUserStats.vue} +0 -0
- /package/components/{article-layout → posts}/HairyArticleTop.vue +0 -0
- /package/{modules → library}/loading.scss +0 -0
- /package/{shims.d.ts → node/images/shims.d.ts} +0 -0
- /package/styles/{aplayer.scss → components/aplayer.scss} +0 -0
- /package/styles/{scrollbar.scss → components/scrollbar.scss} +0 -0
package/utils/index.ts
CHANGED
@@ -1,10 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
/**
|
4
|
-
* 跳转到新的页面
|
5
|
-
* @param url 跳转url
|
6
|
-
*/
|
7
|
-
export const ejectWindow = (url: string) => {
|
1
|
+
export function ejectWindow(url: string) {
|
8
2
|
const link = document.createElement('a')
|
9
3
|
link.href = url
|
10
4
|
link.target = '_blank'
|
@@ -12,7 +6,26 @@ export const ejectWindow = (url: string) => {
|
|
12
6
|
link.remove()
|
13
7
|
}
|
14
8
|
|
15
|
-
export
|
9
|
+
export function riposte<T>(...args: [cond: boolean, value: T][]) {
|
10
|
+
for (const [cond, value] of args) {
|
11
|
+
if (cond)
|
12
|
+
return value
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
export function toArray<T>(value: T | T[]): T[] {
|
17
|
+
if (Array.isArray(value))
|
18
|
+
return value as any
|
19
|
+
else return [value].filter(Boolean) as any
|
20
|
+
}
|
21
|
+
|
22
|
+
export function removeTags(content = '') {
|
23
|
+
return content
|
24
|
+
.replace(/<\/?[^>]*>/g, '')
|
25
|
+
.replace(/[|]*\n/, '')
|
26
|
+
}
|
27
|
+
|
28
|
+
export function getArchiveLink(year?: string, month?: string) {
|
16
29
|
if (!year)
|
17
30
|
return '/archives/'
|
18
31
|
if (!month)
|
@@ -22,34 +35,3 @@ export const getArchiveLink = (year?: string, month?: string) => {
|
|
22
35
|
|
23
36
|
return ''
|
24
37
|
}
|
25
|
-
|
26
|
-
export const toArr = <T>(arr: T[] | T): T[] => {
|
27
|
-
if (Array.isArray(arr))
|
28
|
-
return arr as any
|
29
|
-
else return [arr].filter(Boolean) as any
|
30
|
-
}
|
31
|
-
|
32
|
-
export type AtWillNumber = string | number
|
33
|
-
|
34
|
-
export const atWillToUnit = (value: AtWillNumber, unit = 'px') => {
|
35
|
-
if (!(isString(value) || isNumber(value)))
|
36
|
-
return ''
|
37
|
-
return isString(value) && /\D/g.test(value) ? value : value + unit
|
38
|
-
}
|
39
|
-
|
40
|
-
export interface PromiseResolver<T = void> extends Promise<T> {
|
41
|
-
resolve: (value: T) => void
|
42
|
-
reject: Function
|
43
|
-
}
|
44
|
-
export function createPromise<T>(): PromiseResolver<T> {
|
45
|
-
let resolve
|
46
|
-
let reject
|
47
|
-
// eslint-disable-next-line promise/param-names
|
48
|
-
const promise: any = new Promise((_r, _j) => {
|
49
|
-
resolve = _r
|
50
|
-
reject = _j
|
51
|
-
})
|
52
|
-
promise.resolve = resolve
|
53
|
-
promise.reject = reject
|
54
|
-
return promise as PromiseResolver<T>
|
55
|
-
}
|
package/valaxy.config.ts
CHANGED
@@ -1,29 +1,26 @@
|
|
1
|
-
import {
|
2
|
-
import
|
3
|
-
import
|
4
|
-
import
|
5
|
-
import
|
6
|
-
import addonStatistics from './node/addon-statistics'
|
7
|
-
import addonToc from './node/addon-toc'
|
8
|
-
export default defineTheme<HairyTheme>((options) => {
|
9
|
-
const images = addonImages(options)
|
10
|
-
const hairy = addonHairy(options)
|
1
|
+
import type { DefaultTheme, ValaxyTheme } from 'valaxy'
|
2
|
+
import { defineTheme, mergeValaxyConfig } from 'valaxy'
|
3
|
+
import { addonAlgolia } from 'valaxy-addon-algolia'
|
4
|
+
import { withImageConfig, withThemeConfig } from './node'
|
5
|
+
import type { ThemeConfig } from './types'
|
11
6
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
},
|
22
|
-
markdown: {
|
23
|
-
config(md) {
|
24
|
-
md.use(markdownFurigana())
|
7
|
+
export default defineTheme<ThemeConfig>((options) => {
|
8
|
+
let config: ValaxyTheme<ThemeConfig & DefaultTheme.Config> = {
|
9
|
+
addons: [
|
10
|
+
addonAlgolia(),
|
11
|
+
],
|
12
|
+
themeConfig: {
|
13
|
+
valaxyDarkOptions: {
|
14
|
+
useDarkOptions: { disableTransition: false },
|
15
|
+
circleTransition: true,
|
25
16
|
},
|
17
|
+
outline: 2,
|
18
|
+
theme: 'dark',
|
26
19
|
},
|
27
20
|
}
|
28
|
-
})
|
29
21
|
|
22
|
+
config = mergeValaxyConfig(config, withImageConfig(options))
|
23
|
+
config = mergeValaxyConfig(config, withThemeConfig(options))
|
24
|
+
|
25
|
+
return config
|
26
|
+
})
|
package/@types/markdown-it.d.ts
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
declare module "*-markdown-it"
|
package/@types/markdown-toc.d.ts
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
declare module "markdown-toc"
|
package/@types/types.d.ts
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
declare const __ALGOLIA__: boolean
|
package/@types/valaxy.d.ts
DELETED
@@ -1,118 +0,0 @@
|
|
1
|
-
<script setup lang="ts">
|
2
|
-
import docsearch from '@docsearch/js'
|
3
|
-
import type { DocSearchHit } from '@docsearch/react/dist/esm/types'
|
4
|
-
import { onMounted } from 'vue'
|
5
|
-
import type { AlgoliaSearchOptions } from 'valaxy'
|
6
|
-
import { useConfig } from 'valaxy'
|
7
|
-
import { useRoute, useRouter } from 'vue-router'
|
8
|
-
|
9
|
-
const router = useRouter()
|
10
|
-
const route = useRoute()
|
11
|
-
const config = useConfig()
|
12
|
-
|
13
|
-
onMounted(() => {
|
14
|
-
initialize(config.value.search.algolia)
|
15
|
-
setTimeout(poll, 16)
|
16
|
-
})
|
17
|
-
|
18
|
-
/**
|
19
|
-
* poll until open
|
20
|
-
*/
|
21
|
-
function poll() {
|
22
|
-
// programmatically open the search box after initialize
|
23
|
-
const e = new Event('keydown') as any
|
24
|
-
|
25
|
-
e.key = 'k'
|
26
|
-
e.metaKey = true
|
27
|
-
|
28
|
-
window.dispatchEvent(e)
|
29
|
-
|
30
|
-
setTimeout(() => {
|
31
|
-
if (!document.querySelector('.DocSearch-Modal'))
|
32
|
-
poll()
|
33
|
-
}, 16)
|
34
|
-
}
|
35
|
-
|
36
|
-
function initialize(userOptions: AlgoliaSearchOptions) {
|
37
|
-
// note: multi-lang search support is removed since the theme
|
38
|
-
// doesn't support multiple locales as of now.
|
39
|
-
const options = Object.assign({}, userOptions, {
|
40
|
-
container: '#docsearch',
|
41
|
-
navigator: {
|
42
|
-
navigate({ itemUrl }: { itemUrl: string }) {
|
43
|
-
const { pathname: hitPathname } = new URL(
|
44
|
-
window.location.origin + itemUrl,
|
45
|
-
)
|
46
|
-
// router doesn't handle same-page navigation so we use the native
|
47
|
-
// browser location API for anchor navigation
|
48
|
-
if (route.path === hitPathname)
|
49
|
-
window.location.assign(window.location.origin + itemUrl)
|
50
|
-
|
51
|
-
else
|
52
|
-
router.push(itemUrl)
|
53
|
-
},
|
54
|
-
},
|
55
|
-
transformItems(items: DocSearchHit[]) {
|
56
|
-
return items.map((item) => {
|
57
|
-
return Object.assign({}, item, {
|
58
|
-
url: getRelativePath(item.url),
|
59
|
-
})
|
60
|
-
})
|
61
|
-
},
|
62
|
-
hitComponent({ hit, children }: { hit: DocSearchHit; children: any }) {
|
63
|
-
const relativeHit = hit.url.startsWith('http')
|
64
|
-
? getRelativePath(hit.url as string)
|
65
|
-
: hit.url
|
66
|
-
return {
|
67
|
-
__v: null,
|
68
|
-
type: 'a',
|
69
|
-
ref: undefined,
|
70
|
-
constructor: undefined,
|
71
|
-
key: undefined,
|
72
|
-
props: {
|
73
|
-
href: hit.url,
|
74
|
-
onClick(event: MouseEvent) {
|
75
|
-
if (isSpecialClick(event))
|
76
|
-
return
|
77
|
-
|
78
|
-
// we rely on the native link scrolling when user is already on
|
79
|
-
// the right anchor because Router doesn't support duplicated
|
80
|
-
// history entries.
|
81
|
-
if (route.path === relativeHit)
|
82
|
-
return
|
83
|
-
|
84
|
-
// if the hits goes to another page, we prevent the native link
|
85
|
-
// behavior to leverage the Router loading feature.
|
86
|
-
if (route.path !== relativeHit)
|
87
|
-
event.preventDefault()
|
88
|
-
|
89
|
-
router.push(relativeHit)
|
90
|
-
},
|
91
|
-
children,
|
92
|
-
},
|
93
|
-
}
|
94
|
-
},
|
95
|
-
})
|
96
|
-
docsearch(options as any)
|
97
|
-
}
|
98
|
-
|
99
|
-
function isSpecialClick(event: MouseEvent) {
|
100
|
-
return (
|
101
|
-
event.button === 1
|
102
|
-
|| event.altKey
|
103
|
-
|| event.ctrlKey
|
104
|
-
|| event.metaKey
|
105
|
-
|| event.shiftKey
|
106
|
-
)
|
107
|
-
}
|
108
|
-
|
109
|
-
function getRelativePath(absoluteUrl: string) {
|
110
|
-
const { pathname, hash } = new URL(absoluteUrl)
|
111
|
-
return pathname + hash
|
112
|
-
}
|
113
|
-
</script>
|
114
|
-
|
115
|
-
<template>
|
116
|
-
<div id="docsearch" />
|
117
|
-
</template>
|
118
|
-
|
@@ -1,72 +0,0 @@
|
|
1
|
-
<script lang="ts" setup>
|
2
|
-
import { computed } from 'vue'
|
3
|
-
import { useBackToTop } from 'valaxy'
|
4
|
-
|
5
|
-
const { show, percentage } = useBackToTop({ offset: 100 })
|
6
|
-
|
7
|
-
const radius = 48
|
8
|
-
const circumference = 2 * radius * Math.PI
|
9
|
-
|
10
|
-
const strokeOffset = computed(() => {
|
11
|
-
// 周长
|
12
|
-
const val = (1 - percentage.value) * circumference
|
13
|
-
return val < 0 ? 0 : val
|
14
|
-
})
|
15
|
-
|
16
|
-
function toTop() {
|
17
|
-
window.scrollTo({ top: 0, behavior: 'smooth' })
|
18
|
-
}
|
19
|
-
</script>
|
20
|
-
|
21
|
-
<template>
|
22
|
-
<a class="back-to-top cursor-pointer" :class="show && 'show'" @click="toTop">
|
23
|
-
<div w="8" h="8" i-ri-arrow-up-s-line />
|
24
|
-
<svg class="progress-circle-container" viewBox="0 0 100 100">
|
25
|
-
<circle :stroke-dasharray="`${circumference} ${circumference}`" :stroke-dashoffset="strokeOffset" class="progress-circle" cx="50" cy="50" :r="radius" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
|
26
|
-
</svg>
|
27
|
-
</a>
|
28
|
-
</template>
|
29
|
-
|
30
|
-
<style lang="scss">
|
31
|
-
@use "sass:map";
|
32
|
-
|
33
|
-
.back-to-top {
|
34
|
-
position: fixed;
|
35
|
-
width: 32px;
|
36
|
-
height: 32px;
|
37
|
-
right: 0rem;
|
38
|
-
bottom: 1.5rem;
|
39
|
-
z-index: 10;
|
40
|
-
opacity: 0;
|
41
|
-
pointer-events: none;
|
42
|
-
|
43
|
-
color: var(--hy-c-primary);
|
44
|
-
transform: translateX(0) rotate(270deg);
|
45
|
-
// override yun-icon-btn transition
|
46
|
-
transition: transform var(--va-transition-duration), opacity var(--va-transition-duration-fast) !important;
|
47
|
-
|
48
|
-
&.show {
|
49
|
-
transform: translateX(-32px) rotate(360deg);
|
50
|
-
opacity: 1;
|
51
|
-
pointer-events: fill;
|
52
|
-
}
|
53
|
-
|
54
|
-
.icon {
|
55
|
-
width: 2.5rem;
|
56
|
-
height: 2.5rem;
|
57
|
-
}
|
58
|
-
> div {
|
59
|
-
margin-bottom: -2em;
|
60
|
-
}
|
61
|
-
}
|
62
|
-
|
63
|
-
.progress-circle {
|
64
|
-
transition: 0.3s stroke-dashoffset;
|
65
|
-
transform: rotate(-90deg);
|
66
|
-
transform-origin: 50% 50%;
|
67
|
-
|
68
|
-
&-container {
|
69
|
-
position: absolute;
|
70
|
-
}
|
71
|
-
}
|
72
|
-
</style>
|
File without changes
|
@@ -1,29 +0,0 @@
|
|
1
|
-
<!-- eslint-disable no-new -->
|
2
|
-
<script lang="ts" setup>
|
3
|
-
import { onMounted, ref } from 'vue'
|
4
|
-
import { useScriptTag } from '@vueuse/core'
|
5
|
-
import { RENDERER } from './lib/fish'
|
6
|
-
|
7
|
-
const fishContainer = ref()
|
8
|
-
|
9
|
-
const tag = useScriptTag('https://cdn.bootcdn.net/ajax/libs/zepto/1.2.0/zepto.min.js')
|
10
|
-
|
11
|
-
let renderer: RENDERER
|
12
|
-
|
13
|
-
function reset() {
|
14
|
-
const color = 'hsl(0, 0%, 95%)'
|
15
|
-
if (!renderer)
|
16
|
-
renderer = new RENDERER(color)
|
17
|
-
else
|
18
|
-
renderer.setColor(color)
|
19
|
-
}
|
20
|
-
|
21
|
-
onMounted(() => {
|
22
|
-
tag.load()
|
23
|
-
.then(reset)
|
24
|
-
})
|
25
|
-
</script>
|
26
|
-
|
27
|
-
<template>
|
28
|
-
<div id="jsi-flying-fish-container" ref="fishContainer" style="margin-top: -60px;"></div>
|
29
|
-
</template>
|
@@ -1,28 +0,0 @@
|
|
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 min-h-80vh">
|
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>
|
26
|
-
<HairyFooter class="z-1 relative" />
|
27
|
-
</div>
|
28
|
-
</template>
|
package/components/HairyLink.vue
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
<script lang="ts" setup>
|
2
|
-
import { defineProps } from 'vue'
|
3
|
-
defineProps<{
|
4
|
-
links?: {
|
5
|
-
name: string
|
6
|
-
url: string
|
7
|
-
image: string
|
8
|
-
color: string
|
9
|
-
desc?: string
|
10
|
-
}[]
|
11
|
-
}>()
|
12
|
-
</script>
|
13
|
-
|
14
|
-
<template>
|
15
|
-
<div class="min-h-30vh">
|
16
|
-
<div class="links">
|
17
|
-
<div
|
18
|
-
v-for="(item, index) in links" :key="index" class="link-block flex items-center py-0.5rem px-1rem rounded-lg"
|
19
|
-
:style="{ '--block-color': item.color }"
|
20
|
-
>
|
21
|
-
<a :href="item.url" class="w-4rem h-4rem">
|
22
|
-
<HairyImage class="w-full h-full rounded-xl" :src="item.image" />
|
23
|
-
</a>
|
24
|
-
<div class="pl-1rem flex-1">
|
25
|
-
<a :href="item.url" class="font-bold text-lg title">
|
26
|
-
{{ item.name }}
|
27
|
-
</a>
|
28
|
-
<div class="max-w-180px text-sm my-0.5rem truncate desc">
|
29
|
-
{{ item.desc }}
|
30
|
-
</div>
|
31
|
-
</div>
|
32
|
-
</div>
|
33
|
-
</div>
|
34
|
-
</div>
|
35
|
-
</template>
|
36
|
-
|
37
|
-
<style lang="scss" scoped>
|
38
|
-
.link-block {
|
39
|
-
border: 0.0625rem solid #f7f7f7;
|
40
|
-
box-shadow: 0 0.625rem 1.875rem -0.9375rem rgba(0, 0, 0, 0.1);
|
41
|
-
--bg-color: var(--block-color, #666);
|
42
|
-
@apply transition-all;
|
43
|
-
|
44
|
-
.title {
|
45
|
-
color: var(--block-color);
|
46
|
-
}
|
47
|
-
}
|
48
|
-
|
49
|
-
.dark .link-block {
|
50
|
-
background: rgba($color: #989898, $alpha: 0.1);
|
51
|
-
}
|
52
|
-
|
53
|
-
.links .link-block:hover {
|
54
|
-
background-color: var(--bg-color);
|
55
|
-
box-shadow: 0 0.125rem 1.25rem var(--bg-color);
|
56
|
-
border-color: var(--bg-color);
|
57
|
-
|
58
|
-
.title,
|
59
|
-
.desc {
|
60
|
-
color: #fff;
|
61
|
-
}
|
62
|
-
}
|
63
|
-
|
64
|
-
.links {
|
65
|
-
display: grid;
|
66
|
-
grid-template-columns: repeat(auto-fill, 300px);
|
67
|
-
gap: 24px;
|
68
|
-
}
|
69
|
-
</style>
|
@@ -1,19 +0,0 @@
|
|
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>
|
package/components/HairyNav.vue
DELETED
@@ -1,42 +0,0 @@
|
|
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 lt-sm:h-3.5rem top-0 z-20 opacity-0 transition-opacity duration-200" :class="[show && 'opacity-100']">
|
24
|
-
<div class="mx-auto breakpoint flex relative z-1 h-full">
|
25
|
-
<div class="flex items-center lt-sm:order-1 lt-sm:flex-1 justify-center">
|
26
|
-
<HairyNavTitle />
|
27
|
-
</div>
|
28
|
-
<div class="flex items-center sm:flex-1">
|
29
|
-
<HairyNavMenu class="sm:hidden pl-2 pr-13" />
|
30
|
-
<HairyMenu class="lt-sm:hidden" />
|
31
|
-
</div>
|
32
|
-
<div class="flex-center order-1">
|
33
|
-
<HairyNavToggleDark />
|
34
|
-
<HairyNavSearch />
|
35
|
-
</div>
|
36
|
-
</div>
|
37
|
-
<HairyNavBackground />
|
38
|
-
</div>
|
39
|
-
</template>
|
40
|
-
|
41
|
-
<style>
|
42
|
-
</style>
|
@@ -1,11 +0,0 @@
|
|
1
|
-
<script lang="ts" setup>
|
2
|
-
import { useContext } from '../hooks/useContext'
|
3
|
-
|
4
|
-
const { drawerShow } = useContext()
|
5
|
-
</script>
|
6
|
-
|
7
|
-
<template>
|
8
|
-
<button class="yun-icon-btn lt-sm:text-size-xl" @click="drawerShow = true">
|
9
|
-
<div i="ri-menu-fill" />
|
10
|
-
</button>
|
11
|
-
</template>
|
@@ -1,16 +0,0 @@
|
|
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 bg-light-1 p-1 dark:bg-transparent rounded-5 lt-sm:text-size-xl" :title="themeTitle" :style="{ color: isDark ? '' : '#f1cb64' }" @click="toggleDark()">
|
14
|
-
<div i="ri-sun-line dark:ri-moon-line" />
|
15
|
-
</button>
|
16
|
-
</template>
|
@@ -1,33 +0,0 @@
|
|
1
|
-
<script lang="ts" setup>
|
2
|
-
import { useScroll } from '@vueuse/core'
|
3
|
-
import { computed } from 'vue'
|
4
|
-
import { usePostLayout } from '../hooks/usePostLayout'
|
5
|
-
import { useHeaderHeight } from '../hooks/useHeaderHeight'
|
6
|
-
import type { HairyPostLayout } from '..'
|
7
|
-
|
8
|
-
const layout = usePostLayout()
|
9
|
-
const layouts = [
|
10
|
-
{ layout: 'image:slice:reverse' as HairyPostLayout, icon: 'i-fluent-text-align-distributed-24-filled' },
|
11
|
-
{ layout: 'image:slice' as HairyPostLayout, icon: 'i-fluent-text-align-left-16-filled' },
|
12
|
-
{ layout: 'image' as HairyPostLayout, icon: 'i-fluent-text-align-justify-20-filled' },
|
13
|
-
{ layout: 'markdown' as HairyPostLayout, icon: 'i-fluent-markdown-20-filled' },
|
14
|
-
{ layout: 'text' as HairyPostLayout, icon: 'i-fluent-code-text-16-filled' },
|
15
|
-
]
|
16
|
-
|
17
|
-
const headerHeight = useHeaderHeight()
|
18
|
-
const scroll = useScroll(document)
|
19
|
-
|
20
|
-
const show = computed(() => {
|
21
|
-
return scroll.y.value > headerHeight.value
|
22
|
-
})
|
23
|
-
</script>
|
24
|
-
|
25
|
-
<template>
|
26
|
-
<div class="inline-flex gap-2 sticky top-15 inset-0 rounded-2" :class="[show && 'bg-white bg-opacity-85 dark:bg-black dark:bg-opacity-80 z-100']">
|
27
|
-
<div v-for="(item) in layouts" :key="item.layout" class="p-2 rounded-full cursor-pointer" :class="[layout === item.layout && 'text-primary']" @click="layout = item.layout">
|
28
|
-
<div class="text-size-xl" :class="item.icon" />
|
29
|
-
</div>
|
30
|
-
</div>
|
31
|
-
</template>
|
32
|
-
|
33
|
-
<style lang="scss" scoped></style>
|