mirror of https://github.com/vuejs/vitepress
commit
19fa1e29c2
@ -0,0 +1,13 @@
|
||||
import { describe, test, expect } from 'vitest'
|
||||
import * as Utils from 'client/theme-default/support/utils'
|
||||
|
||||
describe('client/theme-default/utils', () => {
|
||||
describe('ensureStartingSlash', () => {
|
||||
test('it adds slash to the beginning of the given path', () => {
|
||||
expect(Utils.ensureStartingSlash('path')).toBe('/path')
|
||||
expect(Utils.ensureStartingSlash('path/nested')).toBe('/path/nested')
|
||||
expect(Utils.ensureStartingSlash('/path')).toBe('/path')
|
||||
expect(Utils.ensureStartingSlash('/path/nested')).toBe('/path/nested')
|
||||
})
|
||||
})
|
||||
})
|
@ -0,0 +1 @@
|
||||
export default '{}'
|
@ -1,3 +1,24 @@
|
||||
# Migration from VuePress
|
||||
|
||||
Coming soon...
|
||||
## Markdown
|
||||
|
||||
### Images
|
||||
|
||||
Unlike VuePress, VitePress handles [`base`](/guide/asset-handling.html#base-url) of your config automatically when you use static image.
|
||||
|
||||
Hence, now you can render images without `img` tag.
|
||||
|
||||
```diff
|
||||
- <img :src="$withBase('/foo.png')" alt="foo">
|
||||
+ 
|
||||
```
|
||||
|
||||
::: warning
|
||||
For dynamic images you still need `withBase` as shown in [Base URL guide](/guide/asset-handling.html#base-url).
|
||||
:::
|
||||
|
||||
Use `<img.*withBase\('(.*)'\).*alt="([^"]*)".*>` regex to find and replace it with `` to replace all the images with `` syntax.
|
||||
|
||||
---
|
||||
|
||||
more to follow...
|
||||
|
@ -1,3 +1,28 @@
|
||||
# Edit Link
|
||||
|
||||
Documentation coming soon...
|
||||
Edit Link lets you display a link to edit the page on Git management services such as GitHub, or GitLab. To enable it, add `themeConfig.editLink` options to your config.
|
||||
|
||||
```js
|
||||
export default {
|
||||
themeConfig: {
|
||||
editLink: {
|
||||
pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `pattern` option defines the URL structure for the link, and `:path` is going to be replaced with the page path.
|
||||
|
||||
By default, this will add the link text "Edit this page" at the bottom of the doc page. You may customize this text by defining the `text` option.
|
||||
|
||||
```js
|
||||
export default {
|
||||
themeConfig: {
|
||||
editLink: {
|
||||
pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',
|
||||
text: 'Edit this page on GitHub'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -1,3 +1,29 @@
|
||||
# Prev Next Link
|
||||
|
||||
Documentation coming soon...
|
||||
You can customize the text of previous and next links. This is helpful if you want to show different text on previous/next links than what you have on your sidebar.
|
||||
|
||||
## prev
|
||||
|
||||
- Type: `string`
|
||||
|
||||
- Details:
|
||||
|
||||
Specify the text to show on the link to the previous page.
|
||||
|
||||
If you don't set this in frontmatter, the text will be inferred from the sidebar config.
|
||||
|
||||
- Example:
|
||||
|
||||
```yaml
|
||||
---
|
||||
prev: 'Get Started | Markdown'
|
||||
---
|
||||
```
|
||||
|
||||
## next
|
||||
|
||||
- Type: `string`
|
||||
|
||||
- Details:
|
||||
|
||||
Same as `prev` but for the next page.
|
||||
|
@ -0,0 +1,255 @@
|
||||
<script setup>
|
||||
import { VPTeamMembers } from 'vitepress/theme'
|
||||
|
||||
const members = [
|
||||
{
|
||||
avatar: 'https://github.com/yyx990803.png',
|
||||
name: 'Evan You',
|
||||
title: 'Creator',
|
||||
links: [
|
||||
{ icon: 'github', link: 'https://github.com/yyx990803' },
|
||||
{ icon: 'twitter', link: 'https://twitter.com/youyuxi' }
|
||||
]
|
||||
},
|
||||
{
|
||||
avatar: 'https://github.com/kiaking.png',
|
||||
name: 'Kia King Ishii',
|
||||
title: 'Developer',
|
||||
links: [
|
||||
{ icon: 'github', link: 'https://github.com/kiaking' },
|
||||
{ icon: 'twitter', link: 'https://twitter.com/KiaKing85' }
|
||||
]
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
||||
# Team Page
|
||||
|
||||
If you would like to introduce your team, you may use Team components to construct the Team Page. There're 2 ways of using these components. One is to embbed it in doc page, and another is to create a full Team Page.
|
||||
|
||||
## Show team members in a page
|
||||
|
||||
You may use `<VPTeamMembers>` component exposed from `vitepress/theme` to display a list of team members on any page.
|
||||
|
||||
```html
|
||||
<script setup>
|
||||
import { VPTeamMembers } from 'vitepress/theme'
|
||||
|
||||
const members = [
|
||||
{
|
||||
avatar: 'https://www.github.com/yyx990803.png',
|
||||
name: 'Evan You',
|
||||
title: 'Creator',
|
||||
links: [
|
||||
{ icon: 'github', link: 'https://github.com/yyx990803' },
|
||||
{ icon: 'twitter', link: 'https://twitter.com/youyuxi' }
|
||||
]
|
||||
},
|
||||
...
|
||||
]
|
||||
</script>
|
||||
|
||||
# Our Team
|
||||
|
||||
Say hello to our awesome team.
|
||||
|
||||
<VPTeamMembers size="small" :members="members" />
|
||||
```
|
||||
|
||||
The above will display a team member in card looking element. It should display something similar to below.
|
||||
|
||||
<VPTeamMembers size="small" :members="members" />
|
||||
|
||||
`<VPTeamMembers>` component comes in 2 different sizes, `small` and `medium`. While it boils down to your preference, usually `small` size should fit better when used in doc page. Also, you may add more properties to each member such as adding "description" or "sponsor" button. Learn more about it in [`<VPTeamMembers>`](#vpteammembers).
|
||||
|
||||
Embbeding team members in doc page is good for small size team where having dedicated full team page might be too much, or introducing partial members as a reference to documentation context.
|
||||
|
||||
If you have large number of members, or simply would like to have more space to show team members, consider [creating a full team page](#create-a-full-team-page).
|
||||
|
||||
## Create a full Team Page
|
||||
|
||||
Instead of adding team members to doc page, you may also create a full Team Page, similar to how you can create a custom [Home Page](./theme-home-page).
|
||||
|
||||
To create a team page, first, create a new md file. The file name doesn't matter, but here lets call it `team.md`. In this file, set frontmatter option `layout: page`, and then you may compose your page structure using `TeamPage` components.
|
||||
|
||||
```html
|
||||
---
|
||||
layout: page
|
||||
---
|
||||
<script setup>
|
||||
import {
|
||||
VPTeamPage,
|
||||
VPTeamPageTitle,
|
||||
VPTeamMembers
|
||||
} from 'vitepress/theme'
|
||||
|
||||
const members = [
|
||||
{
|
||||
avatar: 'https://www.github.com/yyx990803.png',
|
||||
name: 'Evan You',
|
||||
title: 'Creator',
|
||||
links: [
|
||||
{ icon: 'github', link: 'https://github.com/yyx990803' },
|
||||
{ icon: 'twitter', link: 'https://twitter.com/youyuxi' }
|
||||
]
|
||||
},
|
||||
...
|
||||
]
|
||||
</script>
|
||||
|
||||
<VPTeamPage>
|
||||
<VPTeamPageTitle>
|
||||
<template #title>
|
||||
Our Team
|
||||
</template>
|
||||
<template #lead>
|
||||
The development of VitePress is guided by an international
|
||||
team, some of whom have chosen to be featured below.
|
||||
</template>
|
||||
</VPTeamPageTitle>
|
||||
<VPTeamMembers
|
||||
:members="members"
|
||||
/>
|
||||
</VPTeamPage>
|
||||
```
|
||||
|
||||
When creating a full team page, remember to wrap all components with `<VPTeamPage>` component. This component will ensure all nested team related components get the proper layout structure like spacings.
|
||||
|
||||
`<VPPageTitle>` component adds the page title section. The title being `<h1>` heading. Use `#title` and `#lead` slot to document about your team.
|
||||
|
||||
`<VPMembers>` works as same as when used in a doc page. It will display list of members.
|
||||
|
||||
### Add sections to divide team members
|
||||
|
||||
You may add "sections" to the team page. For example, you may have different types of team members such as Core Team Members and Community Partners. You can devide these members into sections to better explain the roles of each group.
|
||||
|
||||
To do so, add `<VPTeamPageSection>` component to the `team.md` file we created previously.
|
||||
|
||||
```html
|
||||
---
|
||||
layout: page
|
||||
---
|
||||
<script setup>
|
||||
import {
|
||||
VPTeamPage,
|
||||
VPTeamPageTitle,
|
||||
VPTeamMembers,
|
||||
VPTeamPageSection
|
||||
} from 'vitepress/theme'
|
||||
|
||||
const coreMembers = [...]
|
||||
const partners = [...]
|
||||
</script>
|
||||
|
||||
<VPTeamPage>
|
||||
<VPTeamPageTitle>
|
||||
<template #title>Our Team</template>
|
||||
<template #lead>...</template>
|
||||
</VPTeamPageTitle>
|
||||
<VPTeamMembers size="medium" :members="coreMembers" />
|
||||
<VPTeamPageSection>
|
||||
<template #title>Partners</template>
|
||||
<template #lead>...</template>
|
||||
<template #members>
|
||||
<VPTeamMembers size="small" :members="partners" />
|
||||
</template>
|
||||
</VPTeamPageSection>
|
||||
</VPTeamPage>
|
||||
```
|
||||
|
||||
The `<VPTeamPageSection>` component can have `#title` and `#lead` slot similar to `VPTeamPageTitle` component, and also `#members` slot for displaying team members.
|
||||
|
||||
Remember to put in `<VPTeamMembers>` component within `#members` slot.
|
||||
|
||||
## `<VPTeamMembers>`
|
||||
|
||||
The `<VPTeamMembers>` component displays a given list of members.
|
||||
|
||||
```html
|
||||
<VPTeamMembers
|
||||
size="medium"
|
||||
:members="[
|
||||
{ avatar: '...', name: '...' },
|
||||
{ avatar: '...', name: '...' },
|
||||
...
|
||||
]"
|
||||
/>
|
||||
```
|
||||
|
||||
```ts
|
||||
interface Props {
|
||||
// Size of each members. Defaults to `medium`.
|
||||
size?: 'small' | 'meidum'
|
||||
|
||||
// List of members to display.
|
||||
members: TeamMember[]
|
||||
}
|
||||
|
||||
interface TeamMember {
|
||||
// Avatar image for the member.
|
||||
avatar: string
|
||||
|
||||
// Name of the member.
|
||||
name: string
|
||||
|
||||
// Title to be shown below member's name.
|
||||
// e.g. Developer, Software Engineer, etc.
|
||||
title?: string
|
||||
|
||||
// Organization that the member belongs.
|
||||
org?: string
|
||||
|
||||
// URL for the organization.
|
||||
orgLink?: string
|
||||
|
||||
// Description for the member.
|
||||
desc?: string
|
||||
|
||||
// Social links. e.g. GitHub, Twitter, etc. You may pass in
|
||||
// the Social Links object here.
|
||||
// See: https://vitepress.vuejs.org/config/theme-configs.html#sociallinks
|
||||
links?: SocialLink[]
|
||||
|
||||
// URL for the sponsor page for the member.
|
||||
sponsor?: string
|
||||
}
|
||||
```
|
||||
|
||||
## `<VPTeamPage>`
|
||||
|
||||
The root component when creating a full team page. It only accepts a single slot. It will style all passed in team related components.
|
||||
|
||||
## `<VPTeamPageTitle>`
|
||||
|
||||
Adds "title" section of the page. Best use at the very beginning under `<VPTeamPage>`. It accepts `#title` and `#lead` slot.
|
||||
|
||||
```html
|
||||
<VPTeamPage>
|
||||
<VPTeamPageTitle>
|
||||
<template #title>
|
||||
Our Team
|
||||
</template>
|
||||
<template #lead>
|
||||
The development of VitePress is guided by an international
|
||||
team, some of whom have chosen to be featured below.
|
||||
</template>
|
||||
</VPTeamPageTitle>
|
||||
</VPTeamPage>
|
||||
```
|
||||
|
||||
## `<VPTeamPageSection>`
|
||||
|
||||
Creates a "section" with in team page. It accepts `#title`, `#lead`, and `#members` slot. You may add as many sections as you like inside `<VPTeamPage>`.
|
||||
|
||||
```html
|
||||
<VPTeamPage>
|
||||
...
|
||||
<VPTeamPageSection>
|
||||
<template #title>Partners</template>
|
||||
<template #lead>Lorem ipsum...</template>
|
||||
<template #members>
|
||||
<VPTeamMembers :members="data" />
|
||||
</template>
|
||||
</VPTeamPageSection>
|
||||
</VPTeamPage>
|
||||
```
|
Before Width: | Height: | Size: 139 KiB |
Before Width: | Height: | Size: 223 KiB |
Before Width: | Height: | Size: 37 KiB |
@ -1,7 +1,9 @@
|
||||
import { copy } from 'fs-extra'
|
||||
import fg from 'fast-glob'
|
||||
|
||||
fg.sync('src/shared/**/*.ts').map(async (file) => {
|
||||
await copy(file, file.replace(/^src\/shared\//, 'src/node/'))
|
||||
await copy(file, file.replace(/^src\/shared\//, 'src/client/'))
|
||||
fg.sync('src/shared/**/*.ts').forEach(async (file) => {
|
||||
await Promise.all([
|
||||
copy(file, file.replace(/^src\/shared\//, 'src/node/')),
|
||||
copy(file, file.replace(/^src\/shared\//, 'src/client/'))
|
||||
])
|
||||
})
|
||||
|
@ -1,86 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, reactive } from 'vue'
|
||||
import { useData } from '../data'
|
||||
|
||||
const data = useData()
|
||||
const el = ref<HTMLElement | null>(null)
|
||||
const open = ref(false)
|
||||
|
||||
// FIXME: remove in next Vue release
|
||||
const tempData = reactive(data)
|
||||
|
||||
watch(open, (value) => {
|
||||
if (!value) {
|
||||
el.value!.scrollTop = 0
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="debug" :class="{ open }" ref="el" @click="open = !open">
|
||||
<p class="title">Debug</p>
|
||||
<pre class="block">{{ tempData }}</pre>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.debug {
|
||||
box-sizing: border-box;
|
||||
position: fixed;
|
||||
right: 8px;
|
||||
bottom: 8px;
|
||||
z-index: 9999;
|
||||
border-radius: 4px;
|
||||
width: 74px;
|
||||
height: 32px;
|
||||
color: #eeeeee;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
background-color: rgba(0, 0, 0, 0.85);
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
|
||||
.debug:hover {
|
||||
background-color: rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
|
||||
.debug.open {
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-top: 0;
|
||||
border-radius: 0;
|
||||
padding: 0 0;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
@media (min-width: 512px) {
|
||||
.debug.open {
|
||||
width: 512px;
|
||||
}
|
||||
}
|
||||
|
||||
.debug.open:hover {
|
||||
background-color: rgba(0, 0, 0, 0.85);
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
padding: 6px 16px 6px;
|
||||
line-height: 20px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.block {
|
||||
margin: 2px 0 0;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.16);
|
||||
padding: 8px 16px;
|
||||
font-family: Hack, monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.block + .block {
|
||||
margin-top: 8px;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,41 @@
|
||||
import { setupDevtoolsPlugin } from '@vue/devtools-api'
|
||||
import type { App } from 'vue'
|
||||
import type { Router } from './router'
|
||||
import type { VitePressData } from './data'
|
||||
|
||||
const COMPONENT_STATE_TYPE = 'VitePress'
|
||||
|
||||
export const setupDevtools = (
|
||||
app: App,
|
||||
router: Router,
|
||||
data: VitePressData
|
||||
): void => {
|
||||
setupDevtoolsPlugin(
|
||||
{
|
||||
// fix recursive reference
|
||||
app: app as any,
|
||||
id: 'org.vuejs.vitepress',
|
||||
label: 'VitePress',
|
||||
packageName: 'vitepress',
|
||||
homepage: 'https://vitepress.vuejs.org',
|
||||
componentStateTypes: [COMPONENT_STATE_TYPE]
|
||||
},
|
||||
(api) => {
|
||||
api.on.inspectComponent((payload) => {
|
||||
payload.instanceData.state.push({
|
||||
type: COMPONENT_STATE_TYPE,
|
||||
key: 'route',
|
||||
value: router.route,
|
||||
editable: false
|
||||
})
|
||||
|
||||
payload.instanceData.state.push({
|
||||
type: COMPONENT_STATE_TYPE,
|
||||
key: 'data',
|
||||
value: data,
|
||||
editable: false
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import VPFeature from './VPFeature.vue'
|
||||
|
||||
export interface Feature {
|
||||
icon?: string
|
||||
title: string
|
||||
details: string
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
features: Feature[]
|
||||
}>()
|
||||
|
||||
const grid = computed(() => {
|
||||
const length = props.features.length
|
||||
|
||||
if (!length) {
|
||||
return
|
||||
} 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 % 2 === 0) {
|
||||
return 'grid-4'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="features" class="VPFeatures">
|
||||
<div class="container">
|
||||
<div class="items">
|
||||
<div v-for="feature in features" :key="feature.title" class="item" :class="[grid]">
|
||||
<VPFeature
|
||||
:icon="feature.icon"
|
||||
:title="feature.title"
|
||||
:details="feature.details"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.VPFeatures {
|
||||
position: relative;
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.VPFeatures {
|
||||
padding: 0 48px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.VPFeatures {
|
||||
padding: 0 64px;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: 0 auto;
|
||||
max-width: 1152px;
|
||||
}
|
||||
|
||||
.items {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: -8px;
|
||||
}
|
||||
|
||||
.item {
|
||||
padding: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@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>
|
@ -0,0 +1,38 @@
|
||||
<script setup lang="ts">
|
||||
import type { DefaultTheme } from 'vitepress/theme'
|
||||
import { withBase } from 'vitepress'
|
||||
|
||||
defineProps<{
|
||||
image: DefaultTheme.ThemeableImage
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
inheritAttrs: false
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<template v-if="image">
|
||||
<img
|
||||
v-if="typeof image === 'string' || 'src' in image"
|
||||
class="VPImage"
|
||||
v-bind="typeof image === 'string' ? $attrs : { ...image, ...$attrs }"
|
||||
:src="withBase(typeof image === 'string' ? image : image.src)"
|
||||
/>
|
||||
<template v-else>
|
||||
<VPImage class="dark" :image="image.dark" v-bind="$attrs" />
|
||||
<VPImage class="light" :image="image.light" v-bind="$attrs" />
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
html:not(.dark) .VPImage.dark {
|
||||
display: none;
|
||||
}
|
||||
.dark .VPImage.light {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
@ -1,12 +1,27 @@
|
||||
<script lang="ts" setup>
|
||||
import { DefaultTheme } from '../config'
|
||||
import { useData } from 'vitepress'
|
||||
import type { DefaultTheme } from 'vitepress/theme'
|
||||
import { isActive } from '../support/utils'
|
||||
import VPFlyout from './VPFlyout.vue'
|
||||
|
||||
defineProps<{
|
||||
item: DefaultTheme.NavItemWithChildren
|
||||
}>()
|
||||
|
||||
const { page } = useData()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VPFlyout :button="item.text" :items="item.items" />
|
||||
<VPFlyout
|
||||
:class="{
|
||||
VPNavBarMenuGroup: true,
|
||||
active: isActive(
|
||||
page.relativePath,
|
||||
item.activeMatch,
|
||||
!!item.activeMatch
|
||||
)
|
||||
}"
|
||||
:button="item.text"
|
||||
:items="item.items"
|
||||
/>
|
||||
</template>
|
||||
|
@ -0,0 +1,55 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import type { DefaultTheme } from '..'
|
||||
import VPTeamMembersItem from './VPTeamMembersItem.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
size?: 'small' | 'medium'
|
||||
members: DefaultTheme.TeamMember[]
|
||||
}>()
|
||||
|
||||
const classes = computed(() => [
|
||||
props.size ?? 'medium',
|
||||
`count-${props.members.length}`
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="VPTeamMembers" :class="classes">
|
||||
<div class="container">
|
||||
<div v-for="member in members" :key="member.name" class="item">
|
||||
<VPTeamMembersItem :size="size" :member="member" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.VPTeamMembers.small .container {
|
||||
grid-template-columns: repeat(auto-fit, minmax(224px, 1fr));
|
||||
}
|
||||
|
||||
.VPTeamMembers.small.count-1 .container { max-width: 276px; }
|
||||
.VPTeamMembers.small.count-2 .container { max-width: calc(276px * 2 + 24px); }
|
||||
.VPTeamMembers.small.count-3 .container { max-width: calc(276px * 3 + 24px * 2); }
|
||||
|
||||
.VPTeamMembers.medium .container {
|
||||
grid-template-columns: repeat(auto-fit, minmax(256px, 1fr));
|
||||
}
|
||||
|
||||
@media (min-width: 375px) {
|
||||
.VPTeamMembers.medium .container {
|
||||
grid-template-columns: repeat(auto-fit, minmax(288px, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
.VPTeamMembers.medium.count-1 .container { max-width: 368px; }
|
||||
.VPTeamMembers.medium.count-2 .container { max-width: calc(368px * 2 + 24px); }
|
||||
|
||||
.container {
|
||||
display: grid;
|
||||
gap: 24px;
|
||||
margin: 0 auto;
|
||||
max-width: 1152px;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,215 @@
|
||||
<script setup lang="ts">
|
||||
import type { DefaultTheme } from '..'
|
||||
import VPIconHeart from './icons/VPIconHeart.vue'
|
||||
import VPLink from './VPLink.vue'
|
||||
import VPSocialLinks from './VPSocialLinks.vue'
|
||||
|
||||
defineProps<{
|
||||
size?: 'small' | 'medium'
|
||||
member: DefaultTheme.TeamMember
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<article class="VPTeamMembersItem" :class="[size ?? 'medium']">
|
||||
<div class="profile">
|
||||
<figure class="avatar">
|
||||
<img class="avatar-img" :src="member.avatar" :alt="member.name">
|
||||
</figure>
|
||||
<div class="data">
|
||||
<h1 class="name">
|
||||
{{ member.name }}
|
||||
</h1>
|
||||
<p v-if="member.title || member.org" class="affiliation">
|
||||
<span v-if="member.title" class="title">
|
||||
{{ member.title }}
|
||||
</span>
|
||||
<span v-if="member.title && member.org" class="at">
|
||||
@
|
||||
</span>
|
||||
<VPLink v-if="member.org" class="org" :class="{ link: member.orgLink }" :href="member.orgLink" no-icon>
|
||||
{{ member.org }}
|
||||
</VPLink>
|
||||
</p>
|
||||
<p v-if="member.desc" class="desc">
|
||||
{{ member.desc }}
|
||||
</p>
|
||||
<div v-if="member.links" class="links">
|
||||
<VPSocialLinks :links="member.links" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="member.sponsor" class="sp">
|
||||
<VPLink class="sp-link" :href="member.sponsor" no-icon>
|
||||
<VPIconHeart class="sp-icon" /> Sponsor
|
||||
</VPLink>
|
||||
</div>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.VPTeamMembersItem {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
border-radius: 12px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.small .profile {
|
||||
padding: 32px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.small .data {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.small .avatar {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.small .name {
|
||||
line-height: 24px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.small .affiliation {
|
||||
padding-top: 4px;
|
||||
line-height: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.small .desc {
|
||||
padding-top: 12px;
|
||||
line-height: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.small .links {
|
||||
margin: 0 -16px -20px;
|
||||
padding: 10px 0 0;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.medium .profile {
|
||||
padding: 48px 32px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.medium .data {
|
||||
padding-top: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.medium .avatar {
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.medium .name {
|
||||
letter-spacing: 0.15px;
|
||||
line-height: 28px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.medium .affiliation {
|
||||
padding-top: 4px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.medium .desc {
|
||||
padding-top: 16px;
|
||||
max-width: 288px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.medium .links {
|
||||
margin: 0 -16px -12px;
|
||||
padding: 16px 12px 0;
|
||||
}
|
||||
|
||||
.profile {
|
||||
flex-grow: 1;
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
}
|
||||
|
||||
.data {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
margin: 0 auto;
|
||||
border-radius: 50%;
|
||||
box-shadow: var(--vp-shadow-3);
|
||||
}
|
||||
|
||||
.avatar-img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.name {
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.affiliation {
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.org.link {
|
||||
color: var(--vp-c-text-2);
|
||||
transition: color 0.25s;
|
||||
}
|
||||
|
||||
.org.link:hover {
|
||||
color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.desc {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.links {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 56px;
|
||||
}
|
||||
|
||||
.sp-link {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
padding: 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-sponsor);
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
transition: color 0.25s, background-color 0.25s;
|
||||
}
|
||||
|
||||
.sp-link:hover,
|
||||
.sp-link:focus {
|
||||
outline: none;
|
||||
color: var(--vp-c-text-dark-1);
|
||||
background-color: var(--vp-c-sponsor);
|
||||
}
|
||||
|
||||
.sp-icon {
|
||||
margin-right: 8px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<div class="VPTeamPage">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.VPTeamPage {
|
||||
padding-bottom: 96px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.VPTeamPage {
|
||||
padding-bottom: 128px;
|
||||
}
|
||||
}
|
||||
|
||||
:slotted(.VPTeamPageSection + .VPTeamPageSection),
|
||||
:slotted(.VPTeamMembers + .VPTeamPageSection) {
|
||||
margin-top: 64px;
|
||||
}
|
||||
|
||||
:slotted(.VPTeamMembers + .VPTeamMembers) {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
:slotted(.VPTeamPageTitle + .VPTeamPageSection) {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
:slotted(.VPTeamPageSection + .VPTeamPageSection),
|
||||
:slotted(.VPTeamMembers + .VPTeamPageSection) {
|
||||
margin-top: 96px;
|
||||
}
|
||||
}
|
||||
|
||||
:slotted(.VPTeamMembers) {
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
:slotted(.VPTeamMembers) {
|
||||
padding: 0 48px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
:slotted(.VPTeamMembers) {
|
||||
padding: 0 64px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<section class="VPTeamPageSection">
|
||||
<div class="title">
|
||||
<div class="title-line" />
|
||||
<h2 v-if="$slots.title" class="title-text">
|
||||
<slot name="title" />
|
||||
</h2>
|
||||
</div>
|
||||
<p v-if="$slots.lead" class="lead">
|
||||
<slot name="lead" />
|
||||
</p>
|
||||
<div v-if="$slots.members" class="members">
|
||||
<slot name="members" />
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.VPTeamPageSection {
|
||||
padding: 0 32px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.VPTeamPageSection {
|
||||
padding: 0 48px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.VPTeamPageSection {
|
||||
padding: 0 64px;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
max-width: 1152px;
|
||||
text-align: center;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.title-line {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: var(--vp-c-divider-light);
|
||||
}
|
||||
|
||||
.title-text {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
padding: 0 24px;
|
||||
letter-spacing: 0;
|
||||
line-height: 32px;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
background-color: var(--vp-c-bg);
|
||||
}
|
||||
|
||||
.lead {
|
||||
margin: 0 auto;
|
||||
max-width: 480px;
|
||||
padding-top: 12px;
|
||||
text-align: center;
|
||||
line-height: 24px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.members {
|
||||
padding-top: 40px;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div class="VPTeamPageTitle">
|
||||
<h1 v-if="$slots.title" class="title">
|
||||
<slot name="title" />
|
||||
</h1>
|
||||
<p v-if="$slots.lead" class="lead">
|
||||
<slot name="lead" />
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.VPTeamPageTitle {
|
||||
padding: 48px 32px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.VPTeamPageTitle {
|
||||
padding: 64px 48px 48px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.VPTeamPageTitle {
|
||||
padding: 80px 64px 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
letter-spacing: 0;
|
||||
line-height: 44px;
|
||||
font-size: 36px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.title {
|
||||
letter-spacing: -0.5px;
|
||||
line-height: 56px;
|
||||
font-size: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.lead {
|
||||
margin: 0 auto;
|
||||
max-width: 512px;
|
||||
padding-top: 12px;
|
||||
line-height: 24px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.lead {
|
||||
max-width: 592px;
|
||||
letter-spacing: 0.15px;
|
||||
line-height: 28px;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1 +0,0 @@
|
||||
export { DefaultTheme } from '../shared'
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue