feat(theme): add Home Features

This commit is contained in:
pengzhanbo 2024-03-03 00:41:09 +08:00
parent 09bbd7eb99
commit bc8f5aded3
2 changed files with 267 additions and 0 deletions

View File

@ -0,0 +1,115 @@
<script setup lang="ts">
import type { PlumeThemeHomeFeature } from '../../../shared/index.js'
import AutoLink from '../AutoLink.vue'
import VImage from '../VImage.vue'
defineProps<PlumeThemeHomeFeature>()
</script>
<template>
<AutoLink
class="home-feature"
:href="link"
:rel="rel"
:target="target"
:no-icon="true"
:tag="link ? 'a' : 'div'"
>
<article class="box">
<div v-if="typeof icon === 'object' && icon.wrap" class="icon">
<VImage
:image="icon"
:alt="icon.alt"
:height="icon.height || 48"
:width="icon.width || 48"
/>
</div>
<VImage
v-else-if="typeof icon === 'object'"
:image="icon"
:alt="icon.alt"
:height="icon.height || 48"
:width="icon.width || 48"
/>
<div v-else-if="icon" class="icon" v-html="icon" />
<h2 class="title" v-html="title" />
<p v-if="details" class="details" v-html="details" />
<div v-if="linkText" class="link-text">
<p class="link-text-value">
{{ linkText }} <span class="vpi-arrow-right link-text-icon" />
</p>
</div>
</article>
</AutoLink>
</template>
<style scoped>
.home-feature {
display: block;
height: 100%;
background-color: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-bg-soft);
border-radius: 12px;
transition: border-color var(--t-color), background-color var(--t-color);
}
.home-feature.link:hover {
border-color: var(--vp-c-brand-1);
}
.box {
display: flex;
flex-direction: column;
height: 100%;
padding: 24px;
}
.box > :deep(.VPImage) {
margin-bottom: 20px;
}
.icon {
display: flex;
align-items: center;
justify-content: center;
width: 48px;
height: 48px;
margin-bottom: 20px;
font-size: 24px;
background-color: var(--vp-c-default-soft);
border-radius: 6px;
transition: background-color var(--t-color);
}
.title {
font-size: 16px;
font-weight: 600;
line-height: 24px;
}
.details {
flex-grow: 1;
padding-top: 8px;
font-size: 14px;
font-weight: 500;
line-height: 24px;
color: var(--vp-c-text-2);
}
.link-text {
padding-top: 8px;
}
.link-text-value {
display: flex;
align-items: center;
font-size: 14px;
font-weight: 500;
color: var(--vp-c-brand-1);
}
.link-text-icon {
margin-left: 6px;
}
</style>

View File

@ -0,0 +1,152 @@
<script setup lang="ts">
import { computed } from 'vue'
import type { PlumeThemeHomeFeatures } from '../../../shared/index.js'
import HomeFeature from './HomeFeature.vue'
const props = defineProps<{
onlyOnce?: boolean
} & PlumeThemeHomeFeatures>()
const grid = computed(() => {
const length = props.features?.length
if (!length)
return undefined
else if (length === 2)
return 'grid-2'
else if (length === 3)
return 'grid-3'
else if (length % 3 === 0)
return 'grid-6'
else if (length > 3)
return 'grid-4'
return undefined
})
</script>
<template>
<div v-if="features" class="home-features">
<div class="container">
<h2 v-if="title" class="title" v-html="title" />
<p v-if="description" class="description" v-html="description" />
<div class="items">
<div
v-for="feature in features"
:key="feature.title"
class="item"
:class="[grid]"
>
<HomeFeature
:icon="feature.icon"
:title="feature.title"
:details="feature.details"
:link="feature.link"
:link-text="feature.linkText"
:rel="feature.rel"
:target="feature.target"
/>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.home-features {
position: relative;
padding: 24px;
}
@media (min-width: 640px) {
.home-features {
padding: 24px 48px 48px;
}
}
@media (min-width: 960px) {
.home-features {
padding: 48px 64px 64px;
}
}
.container {
max-width: 1152px;
margin: 0 auto;
}
.container .title {
margin-bottom: 20px;
font-size: 20px;
font-weight: 900;
color: var(--vp-c-text-1);
text-align: center;
transition: color var(--t-color);
}
.container .description {
margin-bottom: 20px;
font-size: 16px;
line-height: 1.7;
color: var(--vp-c-text-1);
text-align: center;
transition: color var(--t-color);
}
@media (min-width: 768px) {
.container .title {
font-size: 24px;
}
.container .description {
font-size: 18px;
}
}
@media (min-width: 960px) {
.container .title {
font-size: 28px;
}
}
.items {
display: flex;
flex-wrap: wrap;
margin: -8px;
}
.item {
width: 100%;
padding: 8px;
}
@media (min-width: 640px) {
.item.grid-2,
.item.grid-4,
.item.grid-6 {
width: calc(100% / 2);
}
}
@media (min-width: 768px) {
.item.grid-2,
.item.grid-4 {
width: calc(100% / 2);
}
.item.grid-3,
.item.grid-6 {
width: calc(100% / 3);
}
}
@media (min-width: 960px) {
.item.grid-4 {
width: calc(100% / 4);
}
}
</style>