feat(default-theme): support customLayout: true in frontmatter

BREAKING CHANGE: the `home` frontmatter option has been removed.
Instead, use `customLayout: true` and custom HTML + `<style>` in the
markdown file to customize the home page (or any other page).
pull/183/head
Evan You 4 years ago
parent 8dea5185f0
commit f32771fe86

@ -72,7 +72,6 @@ function getConfigSidebar() {
{
text: 'Theme Config',
children: [
{ text: 'Homepage', link: '/config/homepage' },
{ text: 'Algolia Search', link: '/config/algolia-search' },
{ text: 'Carbon Ads', link: '/config/carbon-ads' }
]

@ -1,23 +0,0 @@
# Theme Config: Homepage
VitePress provides a homepage layout. To use it, specify `home: true` plus some other metadata in your root `index.md`'s [YAML frontmatter](../guide/frontmatter). This is an example of how it works:
```yaml
---
home: true
heroImage: /logo.png
heroAlt: Logo image
heroText: Hero Title
tagline: Hero subtitle
actionText: Get Started
actionLink: /guide/
features:
- title: Simplicity First
details: Minimal setup with markdown-centered project structure helps you focus on writing.
- title: Vue-Powered
details: Enjoy the dev experience of Vue + webpack, use Vue components in markdown, and develop custom themes with Vue.
- title: Performant
details: VitePress generates pre-rendered static HTML for each page, and runs as an SPA once a page is loaded.
footer: MIT Licensed | Copyright © 2019-present Evan You
---
```

@ -19,18 +19,7 @@
<!-- TODO: make this button accessible -->
<div class="sidebar-mask" @click="toggleSidebar(false)" />
<Home v-if="enableHome">
<template #hero>
<slot name="home-hero" />
</template>
<template #features>
<slot name="home-features" />
</template>
<template #footer>
<slot name="home-footer" />
</template>
</Home>
<Content v-if="isCustomLayout"/>
<Page v-else>
<template #top>
<slot name="page-top-ads">
@ -72,7 +61,6 @@ import type { DefaultTheme } from './config'
// components
import NavBar from './components/NavBar.vue'
import Home from './components/Home.vue'
import SideBar from './components/SideBar.vue'
import Page from './components/Page.vue'
const CarbonAds = defineAsyncComponent(
@ -92,8 +80,8 @@ const siteRouteData = useSiteDataByRoute()
const theme = computed(() => siteData.value.themeConfig)
const page = usePageData()
// home
const enableHome = computed(() => !!route.data.frontmatter.home)
// custom layout
const isCustomLayout = computed(() => !!route.data.frontmatter.customLayout)
// navbar
const showNavbar = computed(() => {
@ -117,7 +105,7 @@ const showSidebar = computed(() => {
const { frontmatter } = route.data
const { themeConfig } = siteRouteData.value
return (
!frontmatter.home &&
!frontmatter.customLayout &&
frontmatter.sidebar !== false &&
((typeof themeConfig.sidebar === 'object' &&
Object.keys(themeConfig.sidebar).length != 0) ||

@ -1,22 +0,0 @@
<template>
<main class="home" aria-labelledby="main-title">
<HomeHero />
<slot name="hero" />
<HomeFeatures />
<slot name="features" />
<HomeFooter />
<slot name="footer" />
</main>
</template>
<script setup lang="ts">
import HomeHero from './HomeHero.vue'
import HomeFeatures from './HomeFeatures.vue'
import HomeFooter from './HomeFooter.vue'
</script>
<style scoped>
.home {
padding-top: var(--header-height);
}
</style>

@ -1,134 +0,0 @@
<template>
<div v-if="hasFeatures" class="home-features">
<div class="wrapper">
<div class="container">
<div class="features">
<section v-for="(feature, index) in features" :key="index" class="feature">
<h2 class="title" v-if="feature.title">{{ feature.title }}</h2>
<p class="details" v-if="feature.details">{{ feature.details }}</p>
</section>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useSiteDataByRoute, useFrontmatter } from 'vitepress'
const data = useFrontmatter()
const hasFeatures = computed(() => {
return data.value.features && data.value.features.length > 0
})
const features = computed(() => {
return data.value.features ? data.value.features : []
})
</script>
<style scoped>
.home-features {
margin: 0 auto;
padding: 2.5rem 0 2.75rem;
max-width: 960px;
}
.home-hero + .home-features {
padding-top: 0;
}
@media (min-width: 420px) {
.home-features {
padding: 3.25rem 0 3.5rem;
}
.home-hero + .home-features {
padding-top: 0;
}
}
@media (min-width: 720px) {
.home-features {
padding-right: 1.5rem;
padding-left: 1.5rem;
}
}
.wrapper {
padding: 0 1.5rem;
}
.home-hero + .home-features .wrapper {
border-top: 1px solid var(--c-divider);
padding-top: 2.5rem;
}
@media (min-width: 420px) {
.home-hero + .home-features .wrapper {
padding-top: 3.25rem;
}
}
@media (min-width: 720px) {
.wrapper {
padding-right: 0;
padding-left: 0;
}
}
.container {
margin: 0 auto;
max-width: 392px;
}
@media (min-width: 720px) {
.container {
max-width: 960px;
}
}
.features {
display: flex;
flex-wrap: wrap;
margin: -20px -24px;
}
.feature {
flex-shrink: 0;
padding: 20px 24px;
width: 100%;
}
@media (min-width: 720px) {
.feature {
width: calc(100% / 3);
}
}
.title {
margin: 0;
border-bottom: 0;
line-height: 1.4;
font-size: 1.25rem;
font-weight: 500;
}
@media (min-width: 420px) {
.title {
font-size: 1.4rem;
}
}
.details {
margin: 0;
line-height: 1.6;
font-size: 1rem;
color: var(--c-text-light);
}
.title + .details {
padding-top: 0.25rem;
}
</style>

@ -1,44 +0,0 @@
<template>
<footer v-if="$frontmatter.footer" class="footer">
<div class="container">
<p class="text">{{ $frontmatter.footer }}</p>
</div>
</footer>
</template>
<style scoped>
.footer {
margin: 0 auto;
max-width: 960px;
}
@media (min-width: 720px) {
.footer {
padding: 0 1.5rem;
}
}
.container {
padding: 2rem 1.5rem 2.25rem;
}
.home-hero + .footer .container,
.home-features + .footer .container,
.home-content + .footer .container {
border-top: 1px solid var(--c-divider);
}
@media (min-width: 420px) {
.container {
padding: 3rem 1.5rem 3.25rem;
}
}
.text {
margin: 0;
text-align: center;
line-height: 1.4;
font-size: .9rem;
color: var(--c-text-light);
}
</style>

@ -1,143 +0,0 @@
<template>
<header v-if="showHero" class="home-hero">
<figure v-if="$frontmatter.heroImage" class="figure">
<img
class="image"
:src="$withBase($frontmatter.heroImage)"
:alt="$frontmatter.heroAlt"
>
</figure>
<h1 v-if="hasHeroText" class="title">{{ heroText }}</h1>
<p v-if="hasTagline" class="description">{{ tagline }}</p>
<div v-if="hasAction" class="action">
<a class="action-link" :href="$frontmatter.actionLink">
{{ $frontmatter.actionText }}
</a>
</div>
</header>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useSiteDataByRoute, useFrontmatter } from 'vitepress'
const site = useSiteDataByRoute()
const data = useFrontmatter()
const showHero = computed(() => {
return data.value.heroImage
|| hasHeroText.value
|| hasTagline.value
|| hasAction.value
})
const hasHeroText = computed(() => data.value.heroText !== null)
const heroText = computed(() => data.value.heroText || site.value.title)
const hasTagline = computed(() => data.value.tagline !== null)
const tagline = computed(() => data.value.tagline || site.value.description)
const hasAction = computed(() => data.value.actionLink && data.value.actionText)
</script>
<style scoped>
.home-hero {
margin: 2.5rem 0 2.75rem;
padding: 0 1.5rem;
text-align: center;
}
@media (min-width: 420px) {
.home-hero {
margin: 3.5rem 0;
}
}
@media (min-width: 720px) {
.home-hero {
margin: 4rem 0 4.25rem;
}
}
.figure {
padding: 0 1.5rem;
}
.image {
display: block;
margin: 0 auto;
width: auto;
max-width: 100%;
max-height: 280px;
}
.title {
margin-top: 1.5rem;
font-size: 2rem;
}
@media (min-width: 420px) {
.title {
font-size: 3rem;
}
}
@media (min-width: 720px) {
.title {
margin-top: 2rem;
}
}
.description {
margin: 0;
margin-top: .25rem;
line-height: 1.3;
font-size: 1.2rem;
color: var(--c-text-light);
}
@media (min-width: 420px) {
.description {
line-height: 1.2;
font-size: 1.6rem;
}
}
.action {
margin-top: 1.5rem;
}
@media (min-width: 420px) {
.action {
margin-top: 2rem;
}
}
.action-link {
display: inline-block;
border-radius: 4px;
padding: 0 20px;
line-height: 48px;
font-size: 1rem;
font-weight: 500;
color: #ffffff;
background-color: var(--c-brand);
transition: background-color .1s ease;
}
.action-link:hover {
text-decoration: none;
background-color: var(--c-brand-light);
}
@media (min-width: 420px) {
.action-link {
padding: 0 24px;
line-height: 56px;
font-size: 1.2rem;
font-weight: 500;
}
}
</style>
Loading…
Cancel
Save