260 lines
5.8 KiB
Vue
260 lines
5.8 KiB
Vue
<script lang="ts" setup>
|
|
import VPLink from '@theme/VPLink.vue'
|
|
import { computed } from 'vue'
|
|
import {
|
|
useContributors,
|
|
useData,
|
|
useEditLink,
|
|
useLastUpdated,
|
|
usePrevNext,
|
|
useThemeData,
|
|
} from '../composables/index.js'
|
|
|
|
const { theme, frontmatter, page } = useData()
|
|
const themeData = useThemeData()
|
|
const editLink = useEditLink()
|
|
const { datetime: lastUpdated, isoDatetime, lastUpdatedText } = useLastUpdated()
|
|
const { contributors, mode } = useContributors()
|
|
const { prev, next } = usePrevNext()
|
|
|
|
const hasChangelog = computed(() =>
|
|
page.value.git?.changelog?.length && (frontmatter.value.changelog ?? !!themeData.value.changelog),
|
|
)
|
|
|
|
const hasEditLink = computed(() =>
|
|
Boolean(themeData.value.editLink && frontmatter.value.editLink !== false && editLink.value),
|
|
)
|
|
const hasLastUpdated = computed(() =>
|
|
Boolean(themeData.value.lastUpdated !== false && frontmatter.value.lastUpdated !== false && lastUpdated.value) && !hasChangelog.value,
|
|
)
|
|
const hasContributors = computed(() => Boolean(contributors.value.length) && mode.value === 'inline')
|
|
|
|
const showFooter = computed(() => {
|
|
return hasEditLink.value
|
|
|| hasLastUpdated.value
|
|
|| hasContributors.value
|
|
|| prev.value?.link
|
|
|| next.value?.link
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<footer v-if="showFooter" class="vp-doc-footer">
|
|
<slot name="doc-footer-before" />
|
|
|
|
<div v-if="hasEditLink || hasLastUpdated" class="edit-info">
|
|
<div v-if="hasEditLink && editLink" class="edit-link">
|
|
<VPLink class="edit-link-button" :href="editLink.link" no-icon>
|
|
<span class="vpi-square-pen edit-link-icon" aria-label="edit icon" />
|
|
{{ editLink.text }}
|
|
</VPLink>
|
|
</div>
|
|
|
|
<div v-if="hasLastUpdated" class="last-updated" aria-label="Last updated">
|
|
<p class="last-updated-text">
|
|
{{ lastUpdatedText }}:
|
|
<time :datetime="isoDatetime" class="last-updated-time">
|
|
{{ lastUpdated }}
|
|
</time>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
v-if="hasContributors && contributors?.length"
|
|
class="contributors" :class="{ right: hasLastUpdated }"
|
|
aria-label="Contributors"
|
|
>
|
|
<span class="contributors-label">
|
|
{{ theme.contributorsText || 'Contributors' }}:
|
|
</span>
|
|
<span class="contributors-info">
|
|
<template v-for="(contributor, index) in contributors" :key="contributor.name + index">
|
|
<span class="contributor">
|
|
{{ contributor.name }}
|
|
</span>
|
|
<template v-if="index !== contributors.length - 1">, </template>
|
|
</template>
|
|
</span>
|
|
</div>
|
|
|
|
<nav v-if="prev?.link || next?.link" class="prev-next">
|
|
<div class="pager">
|
|
<VPLink v-if="prev?.link" class="pager-link prev" :href="prev.link">
|
|
<span class="desc" v-html="theme.prevPageLabel || 'Previous page'" />
|
|
<span class="title">
|
|
<VPIcon v-if="prev.icon" :name="prev.icon" />
|
|
<span v-html="prev.text" />
|
|
</span>
|
|
</VPLink>
|
|
</div>
|
|
<div class="pager">
|
|
<VPLink v-if="next?.link" class="pager-link next" :href="next.link">
|
|
<span class="desc" v-html="theme.nextPageLabel || 'Next page'" />
|
|
<span class="title">
|
|
<VPIcon v-if="next.icon" :name="next.icon" />
|
|
<span v-html="next.text" />
|
|
</span>
|
|
</VPLink>
|
|
</div>
|
|
</nav>
|
|
</footer>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.vp-doc-footer {
|
|
margin-top: 64px;
|
|
}
|
|
|
|
@media (min-width: 640px) {
|
|
.edit-info {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding-bottom: 6px;
|
|
}
|
|
}
|
|
|
|
.edit-link-button {
|
|
display: flex;
|
|
align-items: center;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
line-height: 32px;
|
|
color: var(--vp-c-brand-1);
|
|
border: 0;
|
|
transition: color var(--vp-t-color);
|
|
}
|
|
|
|
.edit-link-button:hover {
|
|
color: var(--vp-c-brand-2);
|
|
}
|
|
|
|
@media print {
|
|
.edit-link-button {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
.edit-link-icon {
|
|
margin-right: 8px;
|
|
fill: currentcolor;
|
|
}
|
|
|
|
.last-updated-text {
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
line-height: 24px;
|
|
color: var(--vp-c-text-2);
|
|
transition: color var(--vp-t-color);
|
|
}
|
|
|
|
@media (min-width: 640px) {
|
|
.last-updated {
|
|
flex: 1 2;
|
|
text-align: right;
|
|
}
|
|
|
|
.last-updated-text {
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
line-height: 32px;
|
|
}
|
|
}
|
|
|
|
.contributors {
|
|
padding-bottom: 6px;
|
|
margin-top: -10px;
|
|
font-size: 14px;
|
|
line-height: 32px;
|
|
text-align: left;
|
|
}
|
|
|
|
@media (min-width: 640px) {
|
|
.contributors.right {
|
|
text-align: right;
|
|
}
|
|
}
|
|
|
|
.contributors-label {
|
|
padding-right: 10px;
|
|
font-weight: 500;
|
|
color: var(--vp-c-text-2);
|
|
transition: color var(--vp-t-color);
|
|
}
|
|
|
|
.contributors-info {
|
|
color: var(--vp-c-text-2);
|
|
transition: color var(--vp-t-color);
|
|
|
|
.contributor {
|
|
color: var(--vp-c-text-3);
|
|
transition: color var(--vp-t-color);
|
|
}
|
|
}
|
|
|
|
.prev-next {
|
|
display: grid;
|
|
row-gap: 8px;
|
|
padding-top: 24px;
|
|
margin-top: 10px;
|
|
border-top: 1px solid var(--vp-c-divider);
|
|
transition: border-top var(--vp-t-color);
|
|
}
|
|
|
|
@media (min-width: 640px) {
|
|
.prev-next {
|
|
grid-template-columns: repeat(2, 1fr);
|
|
column-gap: 16px;
|
|
}
|
|
}
|
|
|
|
@media print {
|
|
.prev-next {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
.pager-link {
|
|
display: block;
|
|
width: 100%;
|
|
height: 100%;
|
|
padding: 11px 16px 13px;
|
|
border: 1px solid var(--vp-c-divider);
|
|
border-radius: 8px;
|
|
transition: border-color var(--vp-t-color);
|
|
}
|
|
|
|
.pager-link:hover {
|
|
border-color: var(--vp-c-brand-1);
|
|
}
|
|
|
|
.pager-link.next {
|
|
margin-left: auto;
|
|
text-align: right;
|
|
}
|
|
|
|
.desc {
|
|
display: block;
|
|
font-size: 12px;
|
|
font-weight: 500;
|
|
line-height: 20px;
|
|
color: var(--vp-c-text-2);
|
|
transition: color var(--vp-t-color);
|
|
}
|
|
|
|
.title {
|
|
display: block;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
line-height: 20px;
|
|
color: var(--vp-c-brand-1);
|
|
transition: color var(--vp-t-color);
|
|
}
|
|
|
|
.title .vp-icon {
|
|
margin-left: 0;
|
|
transform: translateY(-1px);
|
|
}
|
|
</style>
|