Skip to content

feat: support custom homepage #304

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 23 additions & 15 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
home: true
home: custom
heroImage: /hero.png
actionText: Get Started →
actionLink: /guide/
Expand All @@ -13,22 +13,30 @@ features:
footer: MIT Licensed | Copyright © 2018-present Evan You
---

### As Easy as 1, 2, 3
<Home>

``` bash
# install
yarn global add vuepress # OR npm install -g vuepress
<slot slot="description">
<i>Vue</i>-powered Static Site Generator
</slot>

### As Easy as 1, 2, 3

``` bash
# install
yarn global add vuepress # OR npm install -g vuepress

# create a markdown file
echo '# Hello VuePress' > README.md

# create a markdown file
echo '# Hello VuePress' > README.md
# start writing
vuepress dev

# start writing
vuepress dev
# build to static files
vuepress build
```

# build to static files
vuepress build
```
::: warning COMPATIBILITY NOTE
VuePress requires Node.js >= 8.
:::

::: warning COMPATIBILITY NOTE
VuePress requires Node.js >= 8.
:::
</Home>
55 changes: 55 additions & 0 deletions docs/default-theme-config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,61 @@ footer: MIT Licensed | Copyright © 2018-present Evan You

Any additional content after the `YAML front matter` will be parsed as normal markdown and rendered after the features section.

### Custom Homepage

In internal, homepage is rendered by a component called `Home`, and the default theme has registered the `Home` component as a global component. To use it, you need to set `home: custom` at `YAML front matter` first.

To customize the default homepage, you also need to know its composition:

1. Hero
2. Features
3. Additional Content
4. Footer

Among them, `hero`, `features`, `footer` are [named slots](https://vuejs.org/v2/guide/components-slots.html#Named-Slots) while `additional content` is the default slot that serves as a catch-all outlet for any unmatched content:

``` md
---
home: custom
---

<Home>

<slot slot="hero">
<h1> I am <b>Custom</b> Hero </h1>
</slot>

<slot slot="features">
<h1> I am <b>Custom</b> features </h1>
</slot>

# Content

I am `additional` content

<slot slot="footer">
I am <b>Custom</b> footer
</slot>

</Home>
```

::: warning SYNTAX
When using Vue's `slot` at markdown, there should be at least one blank line after the component's opening tag, and the same before the component's closing tag.
:::

In addition, there are two extra slots for you to custom the `title` and `description` at homepage:

``` md
<slot slot="title">
I am <b>custom</b> title
</slot>

<slot slot="description">
I am <b>custom</b> description
</slot>
```

If you want to use a completely custom homepage layout, you can also use a [Custom Layout](#custom-layout-for-specific-pages).

## Navbar
Expand Down
57 changes: 57 additions & 0 deletions docs/zh/default-theme-config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,63 @@ footer: MIT Licensed | Copyright © 2018-present Evan You

任何 `YAML front matter` 之后额外的内容将会以普通的 markdown 被渲染,并插入到 `features` 的后面。

### 自定义首页

在内部,首页实际上是由一个名为 `Home` 的组件渲染的,VuePress 已经将 `Home` 注册到全局。想要使用它,首先你需要在 `YAML front matter` 中设置 `home: custom`。

为了自定义默认的首页,你也需要了解一下它的组成部分:

1. Hero
2. Features
3. Additional Content
4. Footer

其中, `hero`, `features`, `footer` 是 [具名插槽](https://cn.vuejs.org/v2/guide/components-slots.html#%E5%85%B7%E5%90%8D%E6%8F%92%E6%A7%BD), 而 `additional content` 是默认插槽,它会作为所有未匹配到插槽的内容的统一出口:

``` md
---
home: custom
---

<Home>

<slot slot="hero">
<h1> I am <b>Custom</b> Hero </h1>
</slot>

<slot slot="features">
<h1> I am <b>Custom</b> features </h1>
</slot>

# Content

I am `additional` content

<slot slot="footer">
I am <b>Custom</b> footer
</slot>

</Home>
```

::: warning 语法
当在 markdown 中使用 Vue 的 `插槽` 时,在组件标签开合之后,以及闭合之前都必须至少保留一个空行。
:::

此外,还有两个额外的插槽可以让你自定义首页的 `title` 和 `description`:

``` md
<slot slot="title">
I am <b>custom</b> title
</slot>

<slot slot="description">
I am <b>custom</b> description
</slot>
```

如果你想自定义一个完全不同的首页,你可以使用 [特定页面的自定义布局](#特定页面的自定义布局)。

## 导航栏

导航栏可能包含你的页面标题、[搜索框](#搜索框)、 [导航栏链接](#导航栏链接)、[多语言切换](../guide/i18n.md)、[仓库链接](#git-仓库和编辑链接),它们均取决于你的配置。
Expand Down
47 changes: 28 additions & 19 deletions lib/default-theme/Home.vue
Original file line number Diff line number Diff line change
@@ -1,25 +1,34 @@
<template>
<div class="home">
<div class="hero">
<img v-if="data.heroImage" :src="$withBase(data.heroImage)" alt="hero">
<h1>{{ data.heroText || $title || 'Hello' }}</h1>
<p class="description">
{{ data.tagline || $description || 'Welcome to your VuePress site' }}
</p>
<p class="action" v-if="data.actionText && data.actionLink">
<NavLink class="action-button" :item="actionLink"/>
</p>
</div>
<div class="features" v-if="data.features && data.features.length">
<div class="feature" v-for="feature in data.features">
<h2>{{ feature.title }}</h2>
<p>{{ feature.details }}</p>
<slot name="hero">
<div class="hero">
<img v-if="data.heroImage" :src="$withBase(data.heroImage)" alt="hero">
<h1>
<slot name="title">{{ data.heroText || $title || 'Hello' }}</slot>
</h1>
<p class="description">
<slot name="description">{{ data.tagline || $description || 'Welcome to your VuePress site' }}</slot>
</p>
<p class="action" v-if="data.actionText && data.actionLink">
<NavLink class="action-button" :item="actionLink"/>
</p>
</div>
</div>
<Content custom/>
<div class="footer" v-if="data.footer">
{{ data.footer }}
</div>
</slot>
<slot name="features">
<div class="features" v-if="data.features && data.features.length">
<div class="feature" v-for="feature in data.features">
<h2>{{ feature.title }}</h2>
<p>{{ feature.details }}</p>
</div>
</div>
</slot>
<Content v-if="data.home === true" custom/>
<slot></slot>
<slot name="footer">
<div class="footer" v-if="data.footer">
{{ data.footer }}
</div>
</slot>
</div>
</template>

Expand Down
6 changes: 4 additions & 2 deletions lib/default-theme/Layout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<div class="custom-layout" v-if="$page.frontmatter.layout">
<component :is="$page.frontmatter.layout"/>
</div>
<Home v-else-if="$page.frontmatter.home"/>
<Home v-else-if="$page.frontmatter.home === true"/>
<Page v-else :sidebar-items="sidebarItems">
<slot name="page-top" slot="top"/>
<slot name="page-bottom" slot="bottom"/>
Expand All @@ -31,6 +31,8 @@ import { pathToComponentName } from '@app/util'
import { resolveSidebarItems } from './util'
import throttle from 'lodash.throttle'

Vue.component('Home', Home)

export default {
components: { Home, Page, Sidebar, Navbar },
data () {
Expand Down Expand Up @@ -165,7 +167,7 @@ export default {
const sidebarLinks = [].slice.call(document.querySelectorAll('.sidebar-link'))
const anchors = [].slice.call(document.querySelectorAll('.header-anchor'))
.filter(anchor => sidebarLinks.some(sidebarLink => sidebarLink.hash === anchor.hash))

const scrollTop = Math.max(window.pageYOffset, document.documentElement.scrollTop, document.body.scrollTop)

for (let i = 0; i < anchors.length; i++) {
Expand Down
2 changes: 1 addition & 1 deletion lib/default-theme/Page.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div class="page">
<Content :custom="false"/>
<Content :custom="$page.frontmatter.home === 'custom'"/>
<div class="content edit-link" v-if="editLink">
<a :href="editLink" target="_blank" rel="noopener noreferrer">{{ editLinkText }}</a>
<OutboundLink/>
Expand Down