Files
Your Name 38652eb9b5 Initalize
2026-05-03 12:12:57 -04:00

291 lines
6.3 KiB
Vue

<template>
<footer
v-if="showFooter"
class="VPDocFooter"
>
<slot name="doc-footer-before" />
<div class="footer-box">
<div
v-if="hasBackLink"
class="back-link"
>
<Link :href="backLink.link">
{{ backLink.text ?? '<- Back' }}
</Link>
</div>
<div
v-if="hasContributors"
class="contributors"
>
<div class="contributors-flex">
<Contributor
v-for="contributor in contributors"
:key="contributor.key"
size="icon"
:member="contributor"
/>
</div>
</div>
<div class="empty" />
<div
v-if="hasEditLink || hasLastUpdated"
class="edit-info"
>
<div
v-if="hasEditLink"
class="edit-link"
>
<Link
class="edit-link-button"
:href="editLink?.url ?? editLink"
:no-icon="true"
>
<VPIconEdit
class="edit-link-icon"
aria-label="edit icon"
/>
{{ editLink?.text ?? theme?.value?.editLink?.text ?? 'Edit this page' }}
</Link>
</div>
<div
v-if="hasLastUpdated"
class="last-updated"
>
<DocFooterLastUpdated />
</div>
</div>
</div>
<nav
v-if="control.prev?.link || control.next?.link"
class="prev-next"
>
<div class="pager">
<Link
v-if="control.prev?.link"
class="pager-link prev"
:href="control.prev.link"
>
<span
class="desc"
v-html="theme.docFooter?.prev || 'Previous page'"
/>
<span
class="title"
v-html="control.prev.text"
/>
</Link>
</div>
<div class="pager">
<Link
v-if="control.next?.link"
class="pager-link next"
:href="control.next.link"
>
<span
class="desc"
v-html="theme.docFooter?.next || 'Next page'"
/>
<span
class="title"
v-html="control.next.text"
/>
</Link>
</div>
</nav>
</footer>
</template>
<script setup>
import {computed} from 'vue';
import {useData} from 'vitepress';
import {useEditLink} from 'vitepress/dist/client/theme-default/composables/edit-link';
import {usePrevNext} from 'vitepress/dist/client/theme-default/composables/prev-next';
import useCollection from '../client/use-collection.js';
import VPIconEdit from 'vitepress/dist/client/theme-default/components/icons/VPIconEdit.vue';
import Contributor from './VPLTeamMembersItem.vue';
import DocFooterLastUpdated from './VPLDocFooterLastUpdated.vue';
import Link from './VPLLink.vue';
const useBackLink = () => {
// if its a string then assume its the link
if (typeof frontmatter.value?.backLink === 'string') {
return computed(() => ({link: frontmatter.value.backLink}));
}
return computed(() => frontmatter.value.backLink);
};
const {theme, page, frontmatter} = useData();
const collection = computed(() => frontmatter.value?.collection ?? false);
const {prevnext} = useCollection(collection.value);
const oprevnext = usePrevNext();
const cprevnext = computed(() => {
const links = frontmatter.value?.collection ? prevnext : oprevnext;
return links.value;
});
const control = computed(() => ({
prev: frontmatter.value?.prev ? oprevnext.value.prev : cprevnext.value.prev,
next: frontmatter.value?.next ? oprevnext.value.next : cprevnext.value.next,
}));
const backLink = useBackLink();
const contributors = computed(() => frontmatter.value.contributors ?? page.value.contributors);
const editLink = frontmatter.value?.editLink ? computed(() => frontmatter.value?.editLink) : useEditLink();
const hasBackLink = computed(() => {
return frontmatter.value?.backLink?.link;
});
const hasContributors = computed(() => {
return contributors.value && contributors.value.length > 0;
});
const hasEditLink = computed(() => {
return theme.value.editLink && frontmatter.value.editLink !== false;
});
const hasLastUpdated = computed(() => {
return page.value.lastUpdated && frontmatter.value.lastUpdated !== false;
});
const showFooter = computed(() => {
return hasEditLink.value || hasLastUpdated.value || control.value.prev || control.value.next;
});
</script>
<style scoped>
.VPDocFooter {
margin-top: 64px;
}
.back-link {
display: flex;
align-items: flex-end;
border: 0;
line-height: 32px;
font-size: 14px;
font-weight: 500;
color: var(--vp-c-brand-1);
transition: color 0.25s;
}
.contributors {
max-width: 420px;
overflow: hidden;
max-height: 70px;
}
.contributors-flex {
height: 65px;
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: flex-end;
}
.desc {
display: block;
line-height: 20px;
font-size: 12px;
font-weight: 500;
color: var(--vp-c-text-2);
}
.edit-link-button {
display: flex;
align-items: center;
border: 0;
line-height: 32px;
font-size: 14px;
font-weight: 500;
color: var(--vp-c-brand-1);
transition: color 0.25s;
}
.edit-link-button:hover {
color: var(--vp-c-brand-2);
}
.edit-link-icon {
margin-right: 8px;
width: 14px;
height: 14px;
fill: currentColor;
}
.footer-box {
display: flex;
justify-content: space-between;
align-items: stretch;
}
.prev-next {
border-top: 1px solid var(--vp-c-divider);
padding-top: 24px;
display: grid;
grid-row-gap: 8px;
}
.pager-link {
display: block;
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 11px 16px 13px;
width: 100%;
height: 100%;
transition: border-color 0.25s;
}
.pager-link:hover {
border-color: var(--vp-c-brand-1);
}
.pager-link.next {
margin-left: auto;
text-align: right;
}
.title {
display: block;
line-height: 20px;
font-size: 14px;
font-weight: 500;
color: var(--vp-c-brand-1);
transition: color 0.25s;
}
@media (max-width: 767px) {
.contributors {
max-width: 300px;
}
}
@media (max-width: 640px) {
.contributors {
display: none;
}
}
@media (min-width: 640px) {
.edit-info {
display: flex;
justify-content: space-between;
align-items: center;
}
}
@media (min-width: 640px) {
.prev-next {
grid-template-columns: repeat(2, 1fr);
grid-column-gap: 16px;
}
}
</style>