valaxy-theme-hairy 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- package/LICENSE +21 -21
- package/client/index.ts +1 -1
- package/components/HairyBody.vue +49 -49
- package/components/HairyCodepen.vue +40 -40
- package/components/HairyComment.vue +33 -33
- package/components/HairyContainer.vue +17 -17
- package/components/HairyDrawer.vue +44 -44
- package/components/HairyFooter.vue +62 -62
- package/components/HairyHeader.vue +32 -32
- package/components/HairyImage.vue +15 -15
- package/components/HairyImageGroup.vue +65 -65
- package/components/HairyNavbar.vue +56 -56
- package/components/HairyPageArchives.vue +59 -59
- package/components/HairyPageTags.vue +48 -48
- package/components/HairyPosts.vue +54 -54
- package/components/HairySearch.vue +201 -201
- package/components/HairySidebar.vue +30 -30
- package/components/HairyTabbar.vue +56 -56
- package/components/PageTags.vue +48 -48
- package/components/ValaxyMain.vue +45 -45
- package/components/navbar/HairyNav.vue +16 -16
- package/components/navbar/HairyNavExpand.vue +12 -12
- package/components/navbar/HairyNavItem.vue +35 -35
- package/components/navbar/HairyNavbarBackground.vue +7 -7
- package/components/navbar/HairyNavbarSearch.vue +8 -8
- package/components/navbar/HairyNavbarTitle.vue +15 -15
- package/components/navbar/HairyNavbarToggleDark.vue +22 -22
- package/components/parts/HairyBreadcrumb.vue +51 -51
- package/components/parts/HairyBreadcrumbItem.vue +11 -11
- package/components/parts/HairyFootFish.js +352 -352
- package/components/parts/HairyFootFish.vue +38 -38
- package/components/parts/HairyHeadHero.vue +34 -34
- package/components/parts/HairyHeadWaves.vue +67 -67
- package/components/parts/HairyImageGlobal.vue +51 -51
- package/components/parts/HairyImageViewer.vue +23 -23
- package/components/parts/HairyLink.vue +21 -21
- package/components/parts/HairyMenu.vue +16 -16
- package/components/parts/HairyMenuItem.vue +47 -47
- package/components/parts/HairyOutline.vue +99 -99
- package/components/parts/HairyOutlineItem.vue +48 -48
- package/components/parts/HairySocialLinks.vue +27 -27
- package/components/parts/HairyTimelineContent.vue +39 -39
- package/components/parts/HairyUserNav.vue +95 -95
- package/components/parts/HairyUserStats.vue +18 -18
- package/components/posts/HairyArticleImage.vue +126 -126
- package/components/posts/HairyArticleSeries.vue +89 -89
- package/components/posts/HairyArticleText.vue +43 -43
- package/components/posts/HairyPostFooter.vue +15 -15
- package/components/posts/HairyPostImageList.vue +27 -27
- package/components/posts/HairyPostTextsList.vue +22 -22
- package/components/posts/HairyPostToggleLayout.vue +36 -36
- package/components/third/HairyAlgoliaSearch.vue +17 -17
- package/components/third/HairyFuseSearch.vue +10 -10
- package/components/third/HairyFuseSearchDialog.vue +32 -32
- package/components/third/HairyFuseSearchDropdown.vue +77 -77
- package/components/third/HairyFuseSearchFooter.vue +28 -28
- package/components/third/HairyFuseSearchHeader.vue +30 -30
- package/components/third/HairyFuseSearchHit.vue +52 -52
- package/components/third/HairySearchBtnDisplay.vue +29 -29
- package/components/third/HairySearchBtnInput.vue +20 -20
- package/components/third/HairySearchBtnKeys.vue +19 -19
- package/components/third/HairySwiperCarousel.vue +45 -45
- package/composables/archives.ts +48 -48
- package/composables/category.ts +43 -43
- package/composables/config.ts +11 -11
- package/composables/dark.ts +13 -13
- package/composables/fuse.ts +60 -60
- package/composables/index.ts +7 -7
- package/composables/layout.ts +16 -16
- package/composables/outline.ts +49 -49
- package/composables/tags.ts +36 -36
- package/layouts/archive-month.vue +13 -13
- package/layouts/archive-year.vue +13 -13
- package/layouts/archives.vue +11 -11
- package/layouts/categories.vue +13 -13
- package/layouts/default.vue +13 -15
- package/layouts/home.vue +33 -33
- package/layouts/post.vue +54 -54
- package/layouts/tag.vue +10 -10
- package/layouts/tags.vue +10 -14
- package/library/loading.scss +535 -535
- package/library/loading.ts +60 -60
- package/library/scroll.ts +22 -22
- package/locales/en.yml +1 -1
- package/locales/zh-CN.yml +1 -1
- package/node/images/default.json +139 -139
- package/node/images/index.ts +46 -46
- package/node/images/shims.d.ts +8 -8
- package/node/index.ts +2 -2
- package/node/theme/index.ts +78 -78
- package/package.json +1 -1
- package/pages/archives/[year]/[month]/index.vue +48 -48
- package/pages/archives/[year]/index.vue +73 -73
- package/pages/archives/index.md +6 -0
- package/pages/categories/[...its].vue +108 -108
- package/pages/index.vue +8 -8
- package/pages/page/[page].vue +12 -12
- package/pages/tags/[tag]/index.vue +38 -38
- package/pages/tags/index.md +7 -0
- package/setup/main.ts +9 -9
- package/store/index.ts +1 -1
- package/store/modules/global.ts +12 -12
- package/styles/components/aplayer.scss +75 -75
- package/styles/components/index.scss +3 -3
- package/styles/components/markdown.scss +89 -89
- package/styles/components/nprogress.scss +15 -15
- package/styles/components/scrollbar.scss +25 -25
- package/styles/css-vars.scss +171 -171
- package/styles/element-plus/index.scss +1 -1
- package/styles/element-plus/tabs.scss +25 -25
- package/styles/element-plus/timeline.scss +18 -18
- package/styles/font-face.scss +19 -19
- package/styles/global.scss +38 -38
- package/styles/index.scss +3 -3
- package/tsconfig.json +27 -27
- package/types/index.d.ts +163 -163
- package/unocss.config.ts +43 -43
- package/utils/index.ts +37 -37
- package/valaxy.config.ts +26 -26
- package/pages/archives/index.vue +0 -6
- package/pages/tags/index.vue +0 -6
@@ -1,38 +1,38 @@
|
|
1
|
-
<!-- eslint-disable no-new -->
|
2
|
-
<script lang="ts" setup>
|
3
|
-
import { computed, onMounted, ref, watch } from 'vue'
|
4
|
-
import { useScriptTag } from '@vueuse/core'
|
5
|
-
import { useAppStore } from 'valaxy'
|
6
|
-
import { RENDERER } from './HairyFootFish'
|
7
|
-
|
8
|
-
const fishContainer = ref()
|
9
|
-
|
10
|
-
const tag = useScriptTag('https://cdn.bootcdn.net/ajax/libs/zepto/1.2.0/zepto.min.js')
|
11
|
-
const appStore = useAppStore()
|
12
|
-
const dark = computed(() => appStore.isDark)
|
13
|
-
|
14
|
-
let renderer: RENDERER
|
15
|
-
|
16
|
-
function reset() {
|
17
|
-
const color = dark.value ? 'hsl(0, 0%, 95%)' : 'hsl(0, 0%, 80%)'
|
18
|
-
if (!renderer)
|
19
|
-
renderer = new RENDERER(color)
|
20
|
-
else
|
21
|
-
renderer.setColor(color)
|
22
|
-
}
|
23
|
-
|
24
|
-
onMounted(() => {
|
25
|
-
tag.load()
|
26
|
-
.then(reset)
|
27
|
-
})
|
28
|
-
watch(dark, reset)
|
29
|
-
</script>
|
30
|
-
|
31
|
-
<template>
|
32
|
-
<div
|
33
|
-
id="jsi-flying-fish-container"
|
34
|
-
ref="fishContainer"
|
35
|
-
class="z-1 relative"
|
36
|
-
style="margin-top: -60px;"
|
37
|
-
/>
|
38
|
-
</template>
|
1
|
+
<!-- eslint-disable no-new -->
|
2
|
+
<script lang="ts" setup>
|
3
|
+
import { computed, onMounted, ref, watch } from 'vue'
|
4
|
+
import { useScriptTag } from '@vueuse/core'
|
5
|
+
import { useAppStore } from 'valaxy'
|
6
|
+
import { RENDERER } from './HairyFootFish'
|
7
|
+
|
8
|
+
const fishContainer = ref()
|
9
|
+
|
10
|
+
const tag = useScriptTag('https://cdn.bootcdn.net/ajax/libs/zepto/1.2.0/zepto.min.js')
|
11
|
+
const appStore = useAppStore()
|
12
|
+
const dark = computed(() => appStore.isDark)
|
13
|
+
|
14
|
+
let renderer: RENDERER
|
15
|
+
|
16
|
+
function reset() {
|
17
|
+
const color = dark.value ? 'hsl(0, 0%, 95%)' : 'hsl(0, 0%, 80%)'
|
18
|
+
if (!renderer)
|
19
|
+
renderer = new RENDERER(color)
|
20
|
+
else
|
21
|
+
renderer.setColor(color)
|
22
|
+
}
|
23
|
+
|
24
|
+
onMounted(() => {
|
25
|
+
tag.load()
|
26
|
+
.then(reset)
|
27
|
+
})
|
28
|
+
watch(dark, reset)
|
29
|
+
</script>
|
30
|
+
|
31
|
+
<template>
|
32
|
+
<div
|
33
|
+
id="jsi-flying-fish-container"
|
34
|
+
ref="fishContainer"
|
35
|
+
class="z-1 relative"
|
36
|
+
style="margin-top: -60px;"
|
37
|
+
/>
|
38
|
+
</template>
|
@@ -1,34 +1,34 @@
|
|
1
|
-
<script lang="ts" setup>
|
2
|
-
import { useFrontmatter } from 'valaxy'
|
3
|
-
import { computed } from 'vue'
|
4
|
-
|
5
|
-
const props = defineProps<{
|
6
|
-
headline?: string
|
7
|
-
title: string
|
8
|
-
description?: string
|
9
|
-
}>()
|
10
|
-
|
11
|
-
const post = useFrontmatter()
|
12
|
-
|
13
|
-
const headline = computed(() => props.headline || post.value.headline)
|
14
|
-
const title = computed(() => props.title || post.value.title)
|
15
|
-
</script>
|
16
|
-
|
17
|
-
<template>
|
18
|
-
<div class="flex-center flex-col text-shadow-lg text-white mx-12px text-center">
|
19
|
-
<div v-if="headline" class="font-frederick text-size-3.35em lt-sm:text-size-3rem leading-snug">
|
20
|
-
{{ headline }}
|
21
|
-
</div>
|
22
|
-
<div class="text-size-2.5em lt-sm:text-size-2rem font-bold title tracking-1">
|
23
|
-
{{ title }}
|
24
|
-
</div>
|
25
|
-
<p v-if="description || $slots.description" class="text-size-sm">
|
26
|
-
<template v-if="description">
|
27
|
-
{{ description }}
|
28
|
-
</template>
|
29
|
-
<slot v-else name="description" />
|
30
|
-
</p>
|
31
|
-
</div>
|
32
|
-
</template>
|
33
|
-
|
34
|
-
<style lang="scss" scoped></style>
|
1
|
+
<script lang="ts" setup>
|
2
|
+
import { useFrontmatter } from 'valaxy'
|
3
|
+
import { computed } from 'vue'
|
4
|
+
|
5
|
+
const props = defineProps<{
|
6
|
+
headline?: string
|
7
|
+
title: string
|
8
|
+
description?: string
|
9
|
+
}>()
|
10
|
+
|
11
|
+
const post = useFrontmatter()
|
12
|
+
|
13
|
+
const headline = computed(() => props.headline || post.value.headline)
|
14
|
+
const title = computed(() => props.title || post.value.title)
|
15
|
+
</script>
|
16
|
+
|
17
|
+
<template>
|
18
|
+
<div class="flex-center flex-col text-shadow-lg text-white mx-12px text-center">
|
19
|
+
<div v-if="headline" class="font-frederick text-size-3.35em lt-sm:text-size-3rem leading-snug">
|
20
|
+
{{ headline }}
|
21
|
+
</div>
|
22
|
+
<div class="text-size-2.5em lt-sm:text-size-2rem font-bold title tracking-1">
|
23
|
+
{{ title }}
|
24
|
+
</div>
|
25
|
+
<p v-if="description || $slots.description" class="text-size-sm">
|
26
|
+
<template v-if="description">
|
27
|
+
{{ description }}
|
28
|
+
</template>
|
29
|
+
<slot v-else name="description" />
|
30
|
+
</p>
|
31
|
+
</div>
|
32
|
+
</template>
|
33
|
+
|
34
|
+
<style lang="scss" scoped></style>
|
@@ -1,67 +1,67 @@
|
|
1
|
-
<template>
|
2
|
-
<svg
|
3
|
-
class="waves w-full min-h-100px max-h-150px"
|
4
|
-
viewBox="0 24 150 28" preserveAspectRatio="none" shape-rendering="auto"
|
5
|
-
>
|
6
|
-
<defs>rgba(250,250,250,var(--un-bg-opacity))
|
7
|
-
<path id="gentle-wave" d="M-160 44c30 0 58-18 88-18s 58 18 88 18 58-18 88-18 58 18 88 18 v44h-352z" />
|
8
|
-
</defs>
|
9
|
-
<g class="parallax">
|
10
|
-
<use class="" xlink:href="#gentle-wave" x="48" y="0" fill="var(--hy-c-waves-dimm-1)" />
|
11
|
-
<use class="" xlink:href="#gentle-wave" x="48" y="3" fill="var(--hy-c-waves-dimm-2)" />
|
12
|
-
<use class="" xlink:href="#gentle-wave" x="48" y="5" fill="var(--hy-c-waves-dimm-3)" />
|
13
|
-
<use class="" xlink:href="#gentle-wave" x="48" y="7" fill="var(--hy-c-waves-dimm)" />
|
14
|
-
</g>
|
15
|
-
</svg>
|
16
|
-
</template>
|
17
|
-
|
18
|
-
<style lang="scss" scoped>
|
19
|
-
.waves {
|
20
|
-
height: max(100px, min(150px, 15vh));
|
21
|
-
margin-bottom: -7px;
|
22
|
-
}
|
23
|
-
|
24
|
-
/* Animation */
|
25
|
-
.parallax > use {
|
26
|
-
animation: move-forever 25s cubic-bezier(.55, .5, .45, .5) infinite;
|
27
|
-
}
|
28
|
-
|
29
|
-
.parallax > use:nth-child(1) {
|
30
|
-
animation-delay: -2s;
|
31
|
-
animation-duration: 7s;
|
32
|
-
}
|
33
|
-
|
34
|
-
.parallax > use:nth-child(2) {
|
35
|
-
animation-delay: -3s;
|
36
|
-
animation-duration: 10s;
|
37
|
-
}
|
38
|
-
|
39
|
-
.parallax > use:nth-child(3) {
|
40
|
-
animation-delay: -4s;
|
41
|
-
animation-duration: 13s;
|
42
|
-
}
|
43
|
-
|
44
|
-
.parallax > use:nth-child(4) {
|
45
|
-
animation-delay: -5s;
|
46
|
-
animation-duration: 20s;
|
47
|
-
}
|
48
|
-
|
49
|
-
@keyframes move-forever {
|
50
|
-
0% {
|
51
|
-
transform: translate3d(-90px, 0, 0);
|
52
|
-
}
|
53
|
-
100% {
|
54
|
-
transform: translate3d(85px, 0, 0);
|
55
|
-
}
|
56
|
-
}
|
57
|
-
|
58
|
-
/*Shrinking for mobile*/
|
59
|
-
@media (max-width: 768px) {
|
60
|
-
.waves {
|
61
|
-
margin-top: -40px;
|
62
|
-
height: 40px;
|
63
|
-
min-height: 40px;
|
64
|
-
}
|
65
|
-
|
66
|
-
}
|
67
|
-
</style>
|
1
|
+
<template>
|
2
|
+
<svg
|
3
|
+
class="waves w-full min-h-100px max-h-150px"
|
4
|
+
viewBox="0 24 150 28" preserveAspectRatio="none" shape-rendering="auto"
|
5
|
+
>
|
6
|
+
<defs>rgba(250,250,250,var(--un-bg-opacity))
|
7
|
+
<path id="gentle-wave" d="M-160 44c30 0 58-18 88-18s 58 18 88 18 58-18 88-18 58 18 88 18 v44h-352z" />
|
8
|
+
</defs>
|
9
|
+
<g class="parallax">
|
10
|
+
<use class="" xlink:href="#gentle-wave" x="48" y="0" fill="var(--hy-c-waves-dimm-1)" />
|
11
|
+
<use class="" xlink:href="#gentle-wave" x="48" y="3" fill="var(--hy-c-waves-dimm-2)" />
|
12
|
+
<use class="" xlink:href="#gentle-wave" x="48" y="5" fill="var(--hy-c-waves-dimm-3)" />
|
13
|
+
<use class="" xlink:href="#gentle-wave" x="48" y="7" fill="var(--hy-c-waves-dimm)" />
|
14
|
+
</g>
|
15
|
+
</svg>
|
16
|
+
</template>
|
17
|
+
|
18
|
+
<style lang="scss" scoped>
|
19
|
+
.waves {
|
20
|
+
height: max(100px, min(150px, 15vh));
|
21
|
+
margin-bottom: -7px;
|
22
|
+
}
|
23
|
+
|
24
|
+
/* Animation */
|
25
|
+
.parallax > use {
|
26
|
+
animation: move-forever 25s cubic-bezier(.55, .5, .45, .5) infinite;
|
27
|
+
}
|
28
|
+
|
29
|
+
.parallax > use:nth-child(1) {
|
30
|
+
animation-delay: -2s;
|
31
|
+
animation-duration: 7s;
|
32
|
+
}
|
33
|
+
|
34
|
+
.parallax > use:nth-child(2) {
|
35
|
+
animation-delay: -3s;
|
36
|
+
animation-duration: 10s;
|
37
|
+
}
|
38
|
+
|
39
|
+
.parallax > use:nth-child(3) {
|
40
|
+
animation-delay: -4s;
|
41
|
+
animation-duration: 13s;
|
42
|
+
}
|
43
|
+
|
44
|
+
.parallax > use:nth-child(4) {
|
45
|
+
animation-delay: -5s;
|
46
|
+
animation-duration: 20s;
|
47
|
+
}
|
48
|
+
|
49
|
+
@keyframes move-forever {
|
50
|
+
0% {
|
51
|
+
transform: translate3d(-90px, 0, 0);
|
52
|
+
}
|
53
|
+
100% {
|
54
|
+
transform: translate3d(85px, 0, 0);
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
/*Shrinking for mobile*/
|
59
|
+
@media (max-width: 768px) {
|
60
|
+
.waves {
|
61
|
+
margin-top: -40px;
|
62
|
+
height: 40px;
|
63
|
+
min-height: 40px;
|
64
|
+
}
|
65
|
+
|
66
|
+
}
|
67
|
+
</style>
|
@@ -1,51 +1,51 @@
|
|
1
|
-
<script lang="ts" setup>
|
2
|
-
import { provide, useCssVars } from 'vue'
|
3
|
-
import { renderOverlay } from '@overlastic/vue'
|
4
|
-
import type { ImageViewerProps } from 'element-plus
|
5
|
-
import { atWillToUnit } from '@hairy/utils'
|
6
|
-
import HairyImageViewer from './HairyImageViewer.vue'
|
7
|
-
|
8
|
-
const props = withDefaults(defineProps<{
|
9
|
-
row?: string | number
|
10
|
-
col?: string | number
|
11
|
-
gap?: string | number
|
12
|
-
justify?: string
|
13
|
-
align?: string
|
14
|
-
}>(), {
|
15
|
-
row: 'auto',
|
16
|
-
col: 'auto',
|
17
|
-
gap: 10,
|
18
|
-
justify: 'space-evenly',
|
19
|
-
align: 'initial',
|
20
|
-
})
|
21
|
-
|
22
|
-
useCssVars(() => ({
|
23
|
-
width: atWillToUnit(props.row),
|
24
|
-
height: atWillToUnit(props.col),
|
25
|
-
gap: atWillToUnit(props.gap),
|
26
|
-
justify: props.justify,
|
27
|
-
align: props.align,
|
28
|
-
}))
|
29
|
-
|
30
|
-
// TODO global find images
|
31
|
-
// const slots = useSlots()
|
32
|
-
// const paths = computed(() => slots
|
33
|
-
// .default?.()
|
34
|
-
// .map(v => v.props?.src)
|
35
|
-
// .filter(Boolean) as string[],
|
36
|
-
// )
|
37
|
-
|
38
|
-
function preview(url: string) {
|
39
|
-
// const initialIndex = paths.value.findIndex(v => v === url) || 0
|
40
|
-
renderOverlay<Partial<ImageViewerProps>>(HairyImageViewer, {
|
41
|
-
urlList: [url],
|
42
|
-
initialIndex: 0,
|
43
|
-
})
|
44
|
-
}
|
45
|
-
|
46
|
-
provide('HairyImageGroup:preview', preview)
|
47
|
-
</script>
|
48
|
-
|
49
|
-
<template>
|
50
|
-
<slot />
|
51
|
-
</template>
|
1
|
+
<script lang="ts" setup>
|
2
|
+
import { provide, useCssVars } from 'vue'
|
3
|
+
import { renderOverlay } from '@overlastic/vue'
|
4
|
+
import type { ImageViewerProps } from 'element-plus'
|
5
|
+
import { atWillToUnit } from '@hairy/utils'
|
6
|
+
import HairyImageViewer from './HairyImageViewer.vue'
|
7
|
+
|
8
|
+
const props = withDefaults(defineProps<{
|
9
|
+
row?: string | number
|
10
|
+
col?: string | number
|
11
|
+
gap?: string | number
|
12
|
+
justify?: string
|
13
|
+
align?: string
|
14
|
+
}>(), {
|
15
|
+
row: 'auto',
|
16
|
+
col: 'auto',
|
17
|
+
gap: 10,
|
18
|
+
justify: 'space-evenly',
|
19
|
+
align: 'initial',
|
20
|
+
})
|
21
|
+
|
22
|
+
useCssVars(() => ({
|
23
|
+
width: atWillToUnit(props.row),
|
24
|
+
height: atWillToUnit(props.col),
|
25
|
+
gap: atWillToUnit(props.gap),
|
26
|
+
justify: props.justify,
|
27
|
+
align: props.align,
|
28
|
+
}))
|
29
|
+
|
30
|
+
// TODO global find images
|
31
|
+
// const slots = useSlots()
|
32
|
+
// const paths = computed(() => slots
|
33
|
+
// .default?.()
|
34
|
+
// .map(v => v.props?.src)
|
35
|
+
// .filter(Boolean) as string[],
|
36
|
+
// )
|
37
|
+
|
38
|
+
function preview(url: string) {
|
39
|
+
// const initialIndex = paths.value.findIndex(v => v === url) || 0
|
40
|
+
renderOverlay<Partial<ImageViewerProps>>(HairyImageViewer, {
|
41
|
+
urlList: [url],
|
42
|
+
initialIndex: 0,
|
43
|
+
})
|
44
|
+
}
|
45
|
+
|
46
|
+
provide('HairyImageGroup:preview', preview)
|
47
|
+
</script>
|
48
|
+
|
49
|
+
<template>
|
50
|
+
<slot />
|
51
|
+
</template>
|
@@ -1,23 +1,23 @@
|
|
1
|
-
<script lang="ts" setup>
|
2
|
-
import { usePrograms } from '@overlastic/vue'
|
3
|
-
import { ElImageViewer, imageViewerProps } from 'element-plus
|
4
|
-
import 'element-plus/theme-chalk/el-image-viewer.css'
|
5
|
-
import { onMounted, onUnmounted } from 'vue'
|
6
|
-
|
7
|
-
const props = defineProps(imageViewerProps)
|
8
|
-
|
9
|
-
const { visible, resolve } = usePrograms()
|
10
|
-
|
11
|
-
onMounted(() => {
|
12
|
-
document.body.style.overflow = 'hidden'
|
13
|
-
})
|
14
|
-
onUnmounted(() => {
|
15
|
-
document.body.style.overflow = ''
|
16
|
-
})
|
17
|
-
</script>
|
18
|
-
|
19
|
-
<template>
|
20
|
-
<div class="HairyImageViewer fixed inset-0 z-2000">
|
21
|
-
<ElImageViewer v-if="visible" v-bind="props" @close="resolve()" />
|
22
|
-
</div>
|
23
|
-
</template>
|
1
|
+
<script lang="ts" setup>
|
2
|
+
import { usePrograms } from '@overlastic/vue'
|
3
|
+
import { ElImageViewer, imageViewerProps } from 'element-plus'
|
4
|
+
import 'element-plus/theme-chalk/el-image-viewer.css'
|
5
|
+
import { onMounted, onUnmounted } from 'vue'
|
6
|
+
|
7
|
+
const props = defineProps(imageViewerProps)
|
8
|
+
|
9
|
+
const { visible, resolve } = usePrograms()
|
10
|
+
|
11
|
+
onMounted(() => {
|
12
|
+
document.body.style.overflow = 'hidden'
|
13
|
+
})
|
14
|
+
onUnmounted(() => {
|
15
|
+
document.body.style.overflow = ''
|
16
|
+
})
|
17
|
+
</script>
|
18
|
+
|
19
|
+
<template>
|
20
|
+
<div class="HairyImageViewer fixed inset-0 z-2000">
|
21
|
+
<ElImageViewer v-if="visible" v-bind="props" @close="resolve()" />
|
22
|
+
</div>
|
23
|
+
</template>
|
@@ -1,21 +1,21 @@
|
|
1
|
-
<script lang="ts" setup>
|
2
|
-
defineProps<{
|
3
|
-
type?: 'white' | 'normal'
|
4
|
-
bordered?: boolean
|
5
|
-
}>()
|
6
|
-
</script>
|
7
|
-
|
8
|
-
<template>
|
9
|
-
<a
|
10
|
-
class="cursor-pointer" :class="[
|
11
|
-
type === 'white'
|
12
|
-
? 'text-black hover:text-primary dark:text-white'
|
13
|
-
: 'text:text-primary-light hover:text-primary-dark',
|
14
|
-
bordered && 'border-b border-dashed hover:border-primary',
|
15
|
-
]"
|
16
|
-
>
|
17
|
-
<slot />
|
18
|
-
</a>
|
19
|
-
</template>
|
20
|
-
|
21
|
-
<style lang="scss" scoped></style>
|
1
|
+
<script lang="ts" setup>
|
2
|
+
defineProps<{
|
3
|
+
type?: 'white' | 'normal'
|
4
|
+
bordered?: boolean
|
5
|
+
}>()
|
6
|
+
</script>
|
7
|
+
|
8
|
+
<template>
|
9
|
+
<a
|
10
|
+
class="cursor-pointer" :class="[
|
11
|
+
type === 'white'
|
12
|
+
? 'text-black hover:text-primary dark:text-white'
|
13
|
+
: 'text:text-primary-light hover:text-primary-dark',
|
14
|
+
bordered && 'border-b border-dashed hover:border-primary',
|
15
|
+
]"
|
16
|
+
>
|
17
|
+
<slot />
|
18
|
+
</a>
|
19
|
+
</template>
|
20
|
+
|
21
|
+
<style lang="scss" scoped></style>
|
@@ -1,16 +1,16 @@
|
|
1
|
-
<script lang="ts" setup>
|
2
|
-
import type { HairyTheme } from 'valaxy-theme-hairy'
|
3
|
-
import { useThemeConfig } from 'valaxy'
|
4
|
-
import { computed } from 'vue'
|
5
|
-
|
6
|
-
const themeConfig = useThemeConfig<HairyTheme.Config>()
|
7
|
-
const nav = computed(() => themeConfig.value.nav || [])
|
8
|
-
</script>
|
9
|
-
|
10
|
-
<template>
|
11
|
-
<div class="flex items-center h-12.5">
|
12
|
-
<HairyMenuItem v-for="(item, index) in nav" :key="index" :item="item" />
|
13
|
-
</div>
|
14
|
-
</template>
|
15
|
-
|
16
|
-
<style lang="scss" scoped></style>
|
1
|
+
<script lang="ts" setup>
|
2
|
+
import type { HairyTheme } from 'valaxy-theme-hairy'
|
3
|
+
import { useThemeConfig } from 'valaxy'
|
4
|
+
import { computed } from 'vue'
|
5
|
+
|
6
|
+
const themeConfig = useThemeConfig<HairyTheme.Config>()
|
7
|
+
const nav = computed(() => themeConfig.value.nav || [])
|
8
|
+
</script>
|
9
|
+
|
10
|
+
<template>
|
11
|
+
<div class="flex items-center h-12.5">
|
12
|
+
<HairyMenuItem v-for="(item, index) in nav" :key="index" :item="item" />
|
13
|
+
</div>
|
14
|
+
</template>
|
15
|
+
|
16
|
+
<style lang="scss" scoped></style>
|
@@ -1,47 +1,47 @@
|
|
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 { storeToRefs } from 'pinia'
|
6
|
-
import { ejectWindow } from '../../utils'
|
7
|
-
import { useGlobalStore } from '../../store'
|
8
|
-
|
9
|
-
const props = defineProps<{
|
10
|
-
item: NavItem
|
11
|
-
}>()
|
12
|
-
const { showDrawer } = storeToRefs(useGlobalStore())
|
13
|
-
const urlReg = /^(((ht|f)tps?):\/\/)?([^!@#$%^&*?.\s-]([^!@#$%^&*?.\s]{0,63}[^!@#$%^&*?.\s])?\.)+[a-z]{2,6}\/?/
|
14
|
-
const isLink = computed(() => urlReg.test(props.item?.link || ''))
|
15
|
-
const isPointer = computed(() => Boolean(props.item.link) || isLink.value)
|
16
|
-
const router = useRouter()
|
17
|
-
const route = useRoute()
|
18
|
-
|
19
|
-
function toLink() {
|
20
|
-
if (isLink.value)
|
21
|
-
return ejectWindow(props.item.link!)
|
22
|
-
if (props.item.link)
|
23
|
-
router.push(props.item.link)
|
24
|
-
showDrawer.value = false
|
25
|
-
}
|
26
|
-
|
27
|
-
const isActive = computed(() => {
|
28
|
-
if (isLink.value)
|
29
|
-
return false
|
30
|
-
if (props.item.link === '/')
|
31
|
-
return route.path === props.item.link
|
32
|
-
return route.path.includes(props.item.link!)
|
33
|
-
})
|
34
|
-
</script>
|
35
|
-
|
36
|
-
<template>
|
37
|
-
<button class="px-2.5 HairyMenuItem" :class="[isPointer ? 'cursor-pointer' : 'select-none', isActive && 'text-primary active']">
|
38
|
-
<div class="flex items-center hover:text-primary" @click="toLink">
|
39
|
-
<div v-if="item.icon" class="mr-1 icon" :class="item.icon" />
|
40
|
-
<div class="question">
|
41
|
-
{{ item.text }}
|
42
|
-
</div>
|
43
|
-
</div>
|
44
|
-
</button>
|
45
|
-
</template>
|
46
|
-
|
47
|
-
<style lang="scss" scoped></style>
|
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 { storeToRefs } from 'pinia'
|
6
|
+
import { ejectWindow } from '../../utils'
|
7
|
+
import { useGlobalStore } from '../../store'
|
8
|
+
|
9
|
+
const props = defineProps<{
|
10
|
+
item: NavItem
|
11
|
+
}>()
|
12
|
+
const { showDrawer } = storeToRefs(useGlobalStore())
|
13
|
+
const urlReg = /^(((ht|f)tps?):\/\/)?([^!@#$%^&*?.\s-]([^!@#$%^&*?.\s]{0,63}[^!@#$%^&*?.\s])?\.)+[a-z]{2,6}\/?/
|
14
|
+
const isLink = computed(() => urlReg.test(props.item?.link || ''))
|
15
|
+
const isPointer = computed(() => Boolean(props.item.link) || isLink.value)
|
16
|
+
const router = useRouter()
|
17
|
+
const route = useRoute()
|
18
|
+
|
19
|
+
function toLink() {
|
20
|
+
if (isLink.value)
|
21
|
+
return ejectWindow(props.item.link!)
|
22
|
+
if (props.item.link)
|
23
|
+
router.push(props.item.link)
|
24
|
+
showDrawer.value = false
|
25
|
+
}
|
26
|
+
|
27
|
+
const isActive = computed(() => {
|
28
|
+
if (isLink.value)
|
29
|
+
return false
|
30
|
+
if (props.item.link === '/')
|
31
|
+
return route.path === props.item.link
|
32
|
+
return route.path.includes(props.item.link!)
|
33
|
+
})
|
34
|
+
</script>
|
35
|
+
|
36
|
+
<template>
|
37
|
+
<button class="px-2.5 HairyMenuItem" :class="[isPointer ? 'cursor-pointer' : 'select-none', isActive && 'text-primary active']">
|
38
|
+
<div class="flex items-center hover:text-primary" @click="toLink">
|
39
|
+
<div v-if="item.icon" class="mr-1 icon" :class="item.icon" />
|
40
|
+
<div class="question">
|
41
|
+
{{ item.text }}
|
42
|
+
</div>
|
43
|
+
</div>
|
44
|
+
</button>
|
45
|
+
</template>
|
46
|
+
|
47
|
+
<style lang="scss" scoped></style>
|