Initalize
This commit is contained in:
138
node_modules/@lando/vitepress-theme-default-plus/components/VPLAlert.vue
generated
vendored
Normal file
138
node_modules/@lando/vitepress-theme-default-plus/components/VPLAlert.vue
generated
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="showAlert && props.content !== ''"
|
||||
:class="`alert-banner alert-${props.type}`"
|
||||
>
|
||||
<div class="alert-content">
|
||||
<button
|
||||
v-if="props.closeable"
|
||||
aria-label="Close"
|
||||
class="alert-dismiss-button"
|
||||
@click="dismissAlert"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M6 18 18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<div
|
||||
class="content"
|
||||
v-html="props.content"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {onMounted, onUnmounted, ref, watch} from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
content: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: true,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'tip',
|
||||
},
|
||||
closeable: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
|
||||
const isAlertMode = ref(props.content !== '');
|
||||
const showAlert = ref(isAlertMode.value);
|
||||
|
||||
const update = (value = isAlertMode.value) => {
|
||||
const htmlEl = window.document.querySelector('html');
|
||||
htmlEl.classList.toggle('alert', value);
|
||||
showAlert.value = value;
|
||||
};
|
||||
|
||||
const dismissAlert = () => update(false);
|
||||
|
||||
onMounted(() => watch(isAlertMode, update, {immediate: true}));
|
||||
onUnmounted(() => update(false));
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:root {
|
||||
--vpl-alert-height: 40px;
|
||||
}
|
||||
|
||||
.alert-banner {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: var(--vpl-alert-height);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 9999;
|
||||
|
||||
.alert-content {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 1px;
|
||||
|
||||
.content {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.alert-dismiss-button {
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
font-weight: 700;
|
||||
width: 13px;
|
||||
}
|
||||
|
||||
&.alert-brand {
|
||||
background-color: var(--vp-c-brand-soft-hex);
|
||||
color: var(--vp-c-brand-hard);
|
||||
}
|
||||
|
||||
&.alert-danger {
|
||||
background-color: var(--vp-c-red-soft-hex);
|
||||
color: var(--vp-c-red-hard);
|
||||
}
|
||||
|
||||
&.alert-tip {
|
||||
background-color: var(--vp-c-indigo-soft-hex);
|
||||
color: var(--vp-c-indigo-hard);
|
||||
}
|
||||
|
||||
&.alert-info {
|
||||
background-color: var(--vp-c-gray-soft-hex);
|
||||
color: var(--vp-c-gray-hard);
|
||||
}
|
||||
|
||||
&.alert-success {
|
||||
background-color: var(--vp-c-green-soft-hex);
|
||||
color: var(--vp-c-green-hard);
|
||||
}
|
||||
|
||||
&.alert-warning {
|
||||
background-color: var(--vp-c-yellow-soft-hex);
|
||||
color: var(--vp-c-yellow-hard);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
86
node_modules/@lando/vitepress-theme-default-plus/components/VPLAlgoliaSearchBox.vue
generated
vendored
Normal file
86
node_modules/@lando/vitepress-theme-default-plus/components/VPLAlgoliaSearchBox.vue
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div id="docsearch" />
|
||||
</template>
|
||||
|
||||
|
||||
<script setup>
|
||||
import docsearch from '@docsearch/js';
|
||||
import {useData, useRoute, useRouter} from 'vitepress';
|
||||
import {nextTick, onMounted, watch} from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
algolia: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const {site, localeIndex, lang} = useData();
|
||||
|
||||
onMounted(update);
|
||||
watch(localeIndex, update);
|
||||
|
||||
async function update() {
|
||||
await nextTick();
|
||||
const options = {
|
||||
...props.algolia,
|
||||
...props.algolia.locales?.[localeIndex.value],
|
||||
};
|
||||
const rawFacetFilters = options.searchParameters?.facetFilters ?? [];
|
||||
const facetFilters = [
|
||||
...(Array.isArray(rawFacetFilters)
|
||||
? rawFacetFilters
|
||||
: [rawFacetFilters]
|
||||
).filter(f => !f.startsWith('lang:')),
|
||||
`lang:${lang.value}`,
|
||||
];
|
||||
initialize({
|
||||
...options,
|
||||
searchParameters: {
|
||||
...options.searchParameters,
|
||||
facetFilters,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function initialize(userOptions = {}) {
|
||||
const options = Object.assign({}, userOptions, {
|
||||
container: '#docsearch',
|
||||
navigator: {
|
||||
navigate({itemUrl}) {
|
||||
const {pathname: hitPathname} = new URL(window.location.origin + itemUrl);
|
||||
|
||||
// router doesn't handle same-page navigation so we use the native
|
||||
// browser location API for anchor navigation
|
||||
if (route.path === hitPathname) window.location.assign(window.location.origin + itemUrl);
|
||||
else router.go(itemUrl);
|
||||
},
|
||||
},
|
||||
|
||||
transformItems(items) {
|
||||
return items.map(item => Object.assign({}, item, {url: getRelativePath(item.url)}));
|
||||
},
|
||||
|
||||
hitComponent({hit, children}) {
|
||||
return {
|
||||
__v: null,
|
||||
type: 'a',
|
||||
ref: undefined,
|
||||
constructor: undefined,
|
||||
target: '_blank',
|
||||
key: undefined,
|
||||
props: {href: hit.url, children, target: '_self'},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
docsearch(options);
|
||||
}
|
||||
|
||||
function getRelativePath(url) {
|
||||
const {pathname, hash} = new URL(url, location.origin);
|
||||
return pathname.replace(/\.html$/, site.value.cleanUrls ? '' : '.html') + hash;
|
||||
}
|
||||
</script>
|
||||
59
node_modules/@lando/vitepress-theme-default-plus/components/VPLCats.vue
generated
vendored
Normal file
59
node_modules/@lando/vitepress-theme-default-plus/components/VPLCats.vue
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<Page>
|
||||
<template #doc-top>
|
||||
<img src="https://i.pinimg.com/originals/4c/d9/ce/4cd9ce636c6d5f23688f0fda99cd81cf.gif">
|
||||
</template>
|
||||
<template #doc-before>
|
||||
<img src="https://i.pinimg.com/originals/4c/d9/ce/4cd9ce636c6d5f23688f0fda99cd81cf.gif">
|
||||
</template>
|
||||
<template #doc-after>
|
||||
<img src="https://i.pinimg.com/originals/4c/d9/ce/4cd9ce636c6d5f23688f0fda99cd81cf.gif">
|
||||
</template>
|
||||
<template #doc-bottom>
|
||||
<img src="https://i.pinimg.com/originals/4c/d9/ce/4cd9ce636c6d5f23688f0fda99cd81cf.gif">
|
||||
</template>
|
||||
<template #aside-top>
|
||||
<img src="https://i.pinimg.com/originals/4c/d9/ce/4cd9ce636c6d5f23688f0fda99cd81cf.gif">
|
||||
</template>
|
||||
<template #aside-outline-before>
|
||||
<img src="https://i.pinimg.com/originals/4c/d9/ce/4cd9ce636c6d5f23688f0fda99cd81cf.gif">
|
||||
</template>
|
||||
<template #aside-outline-after>
|
||||
<img src="https://i.pinimg.com/originals/4c/d9/ce/4cd9ce636c6d5f23688f0fda99cd81cf.gif">
|
||||
</template>
|
||||
<template #aside-ads-before>
|
||||
<img src="https://i.pinimg.com/originals/4c/d9/ce/4cd9ce636c6d5f23688f0fda99cd81cf.gif">
|
||||
</template>
|
||||
<template #aside-ads-after>
|
||||
<img src="https://i.pinimg.com/originals/4c/d9/ce/4cd9ce636c6d5f23688f0fda99cd81cf.gif">
|
||||
</template>
|
||||
<template #aside-bottom>
|
||||
<img src="https://i.pinimg.com/originals/4c/d9/ce/4cd9ce636c6d5f23688f0fda99cd81cf.gif">
|
||||
</template>
|
||||
|
||||
<div class="cat-container">
|
||||
<Content />
|
||||
</div>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Page from 'vitepress/dist/client/theme-default/components/VPDoc.vue';
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.contributors {
|
||||
float: left;
|
||||
max-width: 70%;
|
||||
overflow: hidden;
|
||||
max-height: 70px;
|
||||
}
|
||||
.contributors-flex {
|
||||
height: 65px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
|
||||
96
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionHeader.vue
generated
vendored
Normal file
96
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionHeader.vue
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<div class="collection-header">
|
||||
<div class="collection-type">
|
||||
<Icon
|
||||
v-if="collection !== false"
|
||||
:icon="icon"
|
||||
:link="iconLink"
|
||||
:title="collection"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="authors.length > 0"
|
||||
class="collection-avatars"
|
||||
>
|
||||
<div class="label">
|
||||
By
|
||||
<Link
|
||||
v-for="(author, index) in authors"
|
||||
:key="author.name"
|
||||
:href="author.link"
|
||||
no-icon
|
||||
>
|
||||
<span class="underline">{{ author.name }}</span><span class="separator">{{ getSeparator(index, authors.length) }}</span>
|
||||
</Link>
|
||||
</div>
|
||||
<Author
|
||||
v-for="author in authors"
|
||||
:key="author.name"
|
||||
size="icon"
|
||||
:member="author"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {computed} from 'vue';
|
||||
import {useData} from 'vitepress';
|
||||
|
||||
import Author from './VPLTeamMembersItem.vue';
|
||||
import Icon from './VPLCollectionIcon.vue';
|
||||
import Link from './VPLLink.vue';
|
||||
|
||||
const {frontmatter, page} = useData();
|
||||
|
||||
const authors = computed(() => frontmatter.value?.authors ?? []);
|
||||
const collection = computed(() => frontmatter.value?.collection ?? false);
|
||||
const icon = computed(() => page.value?.collection?.icon ?? false);
|
||||
const iconLink = computed(() => page.value?.collection?.iconLink ?? false);
|
||||
|
||||
const getSeparator = (index, end = 0) => {
|
||||
return index + 1 === end ? '' : ', ';
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.collection-header {
|
||||
margin-bottom: 24px;
|
||||
font-size: .75em;
|
||||
align-items: flex-start;
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: color-mix(in srgb, var(--vp-c-brand-1) 90%, white);
|
||||
.underline {
|
||||
text-underline-offset: 2px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.separator {
|
||||
color: var(--vp-c-text-3);
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
.collection-type {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
.collection-avatars {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
.label {
|
||||
margin-right: 14px;
|
||||
}
|
||||
.VPTeamMembersItem.icon {
|
||||
overflow: visible;
|
||||
margin-left: -14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
59
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionIcon.vue
generated
vendored
Normal file
59
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionIcon.vue
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div class="collection-icon">
|
||||
<Link
|
||||
:href="link"
|
||||
rel="noopener"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
v-html="icon"
|
||||
/>{{ title }}
|
||||
</Link>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Link from './VPLLink.vue';
|
||||
|
||||
const {title, icon, link} = defineProps({
|
||||
icon: {
|
||||
type: String,
|
||||
default: () => {
|
||||
return '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z" /></svg>';
|
||||
},
|
||||
},
|
||||
link: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: 'doc',
|
||||
},
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.collection-icon {
|
||||
gap: 2px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
font-weight: 500;
|
||||
text-transform: capitalize;
|
||||
color: var(--vp-c-text-3);
|
||||
a.VPLink.link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
&:hover {
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
.icon {
|
||||
width: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
188
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionItem.vue
generated
vendored
Normal file
188
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionItem.vue
generated
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
<template>
|
||||
<article
|
||||
class="collection-article-card"
|
||||
:class="`${page.type} ${size}`"
|
||||
>
|
||||
<Icon
|
||||
v-if="icon !== false"
|
||||
:icon="icon"
|
||||
:link="iconLink"
|
||||
:title="page.type"
|
||||
/>
|
||||
<Link :href="page.url">
|
||||
<h2 class="title">
|
||||
{{ page.title }}
|
||||
</h2>
|
||||
</Link>
|
||||
<div
|
||||
class="summary"
|
||||
>
|
||||
{{ page.summary }}
|
||||
</div>
|
||||
<div class="attribution">
|
||||
<div class="authors">
|
||||
<div
|
||||
v-if="page.authors && page.authors.length > 0"
|
||||
class="avatars"
|
||||
>
|
||||
<Author
|
||||
v-for="author in page.authors"
|
||||
:key="author.name"
|
||||
size="icon"
|
||||
:member="author"
|
||||
/>
|
||||
</div>
|
||||
<Link
|
||||
v-for="(author, index) in page.authors"
|
||||
:key="author.name"
|
||||
class="names"
|
||||
:href="author.link"
|
||||
no-icon
|
||||
>
|
||||
<span class="underline">{{ author.name }}</span><span class="separator">{{ getSeparator(index, page.authors.length) }} </span>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<time
|
||||
v-if="more === 'date'"
|
||||
class="date"
|
||||
:datetime="page.datetime"
|
||||
>
|
||||
{{ hdate }}
|
||||
</time>
|
||||
<Link
|
||||
v-else
|
||||
:href="page.url"
|
||||
class="read-more"
|
||||
>
|
||||
<time :datetime="page.datetime" />
|
||||
Read More ->
|
||||
</Link>
|
||||
</div>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {computed} from 'vue';
|
||||
import {useData} from 'vitepress';
|
||||
|
||||
import Link from './VPLLink.vue';
|
||||
import Author from './VPLTeamMembersItem.vue';
|
||||
import Icon from './VPLCollectionIcon.vue';
|
||||
|
||||
const {more, page, size} = defineProps({
|
||||
page: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: 'medium',
|
||||
},
|
||||
more: {
|
||||
type: String,
|
||||
default: 'readmore',
|
||||
},
|
||||
});
|
||||
|
||||
const {theme} = useData();
|
||||
const collection = computed(() => page?.collection ?? false);
|
||||
|
||||
const icon = computed(() => theme.value?.collections[collection.value]?.icon ?? false);
|
||||
const iconLink = computed(() => theme.value?.collections[collection.value]?.iconLink ?? false);
|
||||
|
||||
const hdate = computed(() => {
|
||||
return new Date(page.date ?? page.timestamp).toLocaleDateString(undefined, {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
});
|
||||
});
|
||||
|
||||
const getSeparator = (index, end = 0) => {
|
||||
return index + 1 === end ? '' : ',';
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.collection-article-card {
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
border-radius: var(--vpl-c-border-radius);
|
||||
border: 1px solid var(--vp-c-bg-soft);
|
||||
padding: 24px 24px 20px 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
h2 {
|
||||
color: var(--vp-c-brand-1);
|
||||
margin-top: -18px;
|
||||
line-height: 24px;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
max-width: 80%;
|
||||
}
|
||||
.collection-icon {
|
||||
font-weight: 500;
|
||||
font-size: 10px;
|
||||
position: relative;
|
||||
top: -20px;
|
||||
right: -16px;
|
||||
color: var(--vp-c-text-3);
|
||||
.icon {
|
||||
width: 10px;
|
||||
}
|
||||
}
|
||||
.summary {
|
||||
padding-top: 1em;
|
||||
padding-bottom: 2em;
|
||||
line-height: 24px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-2);
|
||||
flex-grow: 1;
|
||||
}
|
||||
.attribution {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-3);
|
||||
|
||||
.authors {
|
||||
display: flex;
|
||||
.avatars {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
.VPTeamMembersItem.icon {
|
||||
overflow: visible;
|
||||
&:not(:first-child) {
|
||||
margin-left: -14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.date {
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
.read-more {
|
||||
color: var(--vp-c-brand-3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.collection-article-card {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 420px) {
|
||||
.attribution .authors .names {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
66
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionItemTags.vue
generated
vendored
Normal file
66
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionItemTags.vue
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="tags.length > 0"
|
||||
class="aside-tags-wrapper"
|
||||
>
|
||||
<span class="ad-header">Tags</span>
|
||||
<div class="aside-tags">
|
||||
<Link
|
||||
v-for="tag in tags"
|
||||
:key="tag.key"
|
||||
:no-icon="true"
|
||||
:href="tag.href"
|
||||
target="_self"
|
||||
>
|
||||
<Tag :text="tag.name" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {computed} from 'vue';
|
||||
import {useData} from 'vitepress';
|
||||
import encodeTag from '../utils/encode-tag.js';
|
||||
|
||||
import Link from './VPLLink.vue';
|
||||
import Tag from './VPLCollectionTag.vue';
|
||||
|
||||
const {frontmatter, theme} = useData();
|
||||
const ptags = frontmatter?.value?.tags ?? [];
|
||||
const tagLinkPattern = theme?.value?.tagLink;
|
||||
|
||||
const tags = computed(() => ptags.map(tag => {
|
||||
// get tag details
|
||||
const details = theme?.value?.tags?.[tag];
|
||||
// set the link data
|
||||
const data = {key: tag, name: tag, href: details?.link};
|
||||
// if href is unset and we have a tagLinkPattern then use that
|
||||
if (!data.href && tagLinkPattern && tagLinkPattern.includes(':tag-id')) data.href = tagLinkPattern.replace(':tag-id', encodeTag(tag));
|
||||
// if href is unset and we have a tagLinkPattern then use that
|
||||
if (!data.href && tagLinkPattern && tagLinkPattern.includes(':tag')) data.href = tagLinkPattern.replace(':tag', tag);
|
||||
// just use the tagLink pattern
|
||||
if (!data.href && tagLinkPattern) data.href = tagLinkPattern;
|
||||
// return
|
||||
return data;
|
||||
}).filter(tag => tag.href !== undefined));
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.aside-tags-wrapper .ad-header {
|
||||
margin: 0;
|
||||
}
|
||||
.aside-tags {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
padding: 12px 0;
|
||||
gap: 5px;
|
||||
|
||||
.tag {
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
137
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionItems.vue
generated
vendored
Normal file
137
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionItems.vue
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
:key="key"
|
||||
class="collection-articles"
|
||||
>
|
||||
<div
|
||||
v-for="(page, index) in pagination()"
|
||||
:key="page.key"
|
||||
:class="{'collection-article': true, grower: getGrower(index)}"
|
||||
>
|
||||
<Article
|
||||
:page="page"
|
||||
:size="props.size"
|
||||
:more="props.more"
|
||||
class="collection-page-article"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<VPButton
|
||||
v-if="pages.length > amount"
|
||||
size="medium"
|
||||
text="load more"
|
||||
theme="alt"
|
||||
class="load-more-button"
|
||||
@click="adder"
|
||||
>
|
||||
load more
|
||||
</VPButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {defineAsyncComponent, onMounted, ref, watch} from 'vue';
|
||||
import {VPButton} from 'vitepress/theme';
|
||||
|
||||
import Item from './VPLCollectionItem.vue';
|
||||
|
||||
const Article = defineAsyncComponent({
|
||||
loader: async () => Item,
|
||||
});
|
||||
|
||||
const props = defineProps({
|
||||
items: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
more: {
|
||||
type: String,
|
||||
default: 'readmore',
|
||||
},
|
||||
pager: {
|
||||
type: Number,
|
||||
default: 10,
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: 'medium',
|
||||
},
|
||||
tags: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
// Hardcoded pager value for now
|
||||
const amount = ref(props.pager);
|
||||
const key = ref(0);
|
||||
|
||||
// normalize data and sort
|
||||
let pages = props.items
|
||||
.map(item => Object.assign(item, {show: true, timestamp: item.date ? item.date : item.timestamp}))
|
||||
.sort((a, b) => a.timestamp < b.timestamp ? 1 : -1);
|
||||
|
||||
const adder = () => amount.value += props.pager;
|
||||
const getGrower = i => pagination()[i + 1] === undefined && (i + 1) % 2 !== 0;
|
||||
const pagination = () => pages.slice(0, amount.value);
|
||||
|
||||
const filter = () => {
|
||||
const tagList = Object.entries(props.tags).filter(pair => pair[1].selected === true).map(pair => pair[0]);
|
||||
if (tagList.length === 0) return props.items;
|
||||
return props.items.filter(item => Array.isArray(item.tags) && tagList.every(tag => item.tags.includes(tag)));
|
||||
};
|
||||
|
||||
// recompute filter when tags change
|
||||
watch(props.tags, () => {
|
||||
pages = filter();
|
||||
key.value++;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
pages = filter();
|
||||
key.value++;
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.collection-articles {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
|
||||
.collection-article {
|
||||
max-width: 50%;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
padding: 6px;
|
||||
&.grower {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.load-more-button {
|
||||
margin: 24px 6px;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.collection-articles {
|
||||
.collection-article {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 420px) {
|
||||
.collection-articles {
|
||||
.collection-article {
|
||||
padding: 6px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
72
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionPage.vue
generated
vendored
Normal file
72
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionPage.vue
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<div class="collection-page">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.collection-page {
|
||||
padding: 0 16px 96px;
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.collection-page {
|
||||
padding-bottom: 128px;
|
||||
}
|
||||
}
|
||||
|
||||
:slotted(.collection-page-section + .collection-page-section),
|
||||
:slotted(.collection-page-article + .collection-page-section) {
|
||||
margin-top: 64px;
|
||||
}
|
||||
|
||||
:slotted(.collection-page-article + .collection-page-article) {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
:slotted(.collection-page-title + .collection-page-section) {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
:slotted(.collection-page-section + .collection-page-section),
|
||||
:slotted(.collection-page-article + .collection-page-section) {
|
||||
margin-top: 96px;
|
||||
}
|
||||
}
|
||||
|
||||
:slotted(.collection-page-article) {
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.collection-page {
|
||||
padding: 0 32px 128px;
|
||||
}
|
||||
:slotted(.collection-page-article) {
|
||||
padding: 0 48px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.collection-page {
|
||||
padding: 0 64px 128px;
|
||||
}
|
||||
:slotted(.collection-page-article) {
|
||||
padding: 0 64px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
.collection-page {
|
||||
order: 1;
|
||||
min-width: 640px;
|
||||
max-width: 1200px;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
86
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionPageSection.vue
generated
vendored
Normal file
86
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionPageSection.vue
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<section class="collection-page-section">
|
||||
<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.items"
|
||||
class="items"
|
||||
>
|
||||
<slot name="items" />
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.collection-page-section {
|
||||
padding: 0 32px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.collection-page-section {
|
||||
padding: 0 48px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.collection-page-section {
|
||||
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);
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
|
||||
.items {
|
||||
padding-top: 40px;
|
||||
}
|
||||
</style>
|
||||
52
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionPageTags.vue
generated
vendored
Normal file
52
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionPageTags.vue
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<div class="collection-page-tags">
|
||||
<Tag
|
||||
v-for="(tag, name) in tags"
|
||||
:key="name"
|
||||
:type="tag.selected ? 'selected' : 'info'"
|
||||
:text="name"
|
||||
v-bind="tag"
|
||||
@click="toggle(name)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {onMounted} from 'vue';
|
||||
import {useRoute} from 'vitepress';
|
||||
import encodeTag from '../utils/encode-tag.js';
|
||||
|
||||
import Tag from './VPLCollectionTag.vue';
|
||||
|
||||
const tags = defineModel();
|
||||
|
||||
const toggle = tag => {
|
||||
tags.value[tag].selected = !tags.value[tag].selected;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
const route = useRoute();
|
||||
const params = route.tags ?? [];
|
||||
for (const [tag] of Object.entries(tags.value)) {
|
||||
tags.value[tag].selected = params.includes(tag) || params.includes(encodeTag(tag));
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.collection-page-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 12px 0;
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.collection-page-tags {
|
||||
padding: 12px 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
69
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionPageTitle.vue
generated
vendored
Normal file
69
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionPageTitle.vue
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div class="collection-page-title">
|
||||
<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>
|
||||
.collection-page-title {
|
||||
padding: 48px 32px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.collection-page-title {
|
||||
padding: 64px 48px 48px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.collection-page-title {
|
||||
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>
|
||||
78
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionTag.vue
generated
vendored
Normal file
78
node_modules/@lando/vitepress-theme-default-plus/components/VPLCollectionTag.vue
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<Badge
|
||||
:class="`tag ${props.tagClass}`"
|
||||
:style="props.type !== 'selected' ? styles : {}"
|
||||
:type="props.type"
|
||||
>
|
||||
<span
|
||||
v-if="icon"
|
||||
class="icon"
|
||||
v-html="icon"
|
||||
/>
|
||||
{{ props.text }}
|
||||
</Badge>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {computed} from 'vue';
|
||||
import {useData} from 'vitepress';
|
||||
|
||||
const {theme} = useData();
|
||||
const {tags} = theme.value;
|
||||
|
||||
const props = defineProps({
|
||||
color: {
|
||||
type: String,
|
||||
default: 'none',
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
styles: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
tagClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'info',
|
||||
},
|
||||
});
|
||||
|
||||
const details = Object.assign({color: props.color, styles: props.styles}, tags[props.text] ?? {});
|
||||
|
||||
const styles = computed(() => Object.assign({
|
||||
'background-color': details.color,
|
||||
'border-color': details.color,
|
||||
}, details.styles));
|
||||
|
||||
const icon = computed(() => props.icon ?? details.icon ?? false);
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tag {
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 4px;
|
||||
font-size: 14px;
|
||||
.icon {
|
||||
width: 16px;
|
||||
}
|
||||
}
|
||||
.VPBadge.selected {
|
||||
border-color: var(--vpl-badge-selected-border);
|
||||
color: var(--vpl-badge-selected-text);
|
||||
background-color: var(--vpl-badge-selected-bg);
|
||||
}
|
||||
</style>
|
||||
290
node_modules/@lando/vitepress-theme-default-plus/components/VPLDocFooter.vue
generated
vendored
Normal file
290
node_modules/@lando/vitepress-theme-default-plus/components/VPLDocFooter.vue
generated
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
<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>
|
||||
58
node_modules/@lando/vitepress-theme-default-plus/components/VPLDocFooterLastUpdated.vue
generated
vendored
Normal file
58
node_modules/@lando/vitepress-theme-default-plus/components/VPLDocFooterLastUpdated.vue
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<ClientOnly>
|
||||
<p class="VPLastUpdated">
|
||||
{{ theme.lastUpdated?.text || theme.lastUpdatedText || 'Last updated' }}
|
||||
<time :datetime="isoDatetime">{{ datetime }}</time>
|
||||
</p>
|
||||
</ClientOnly>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref, computed, watchEffect, onMounted} from 'vue';
|
||||
import {useData} from 'vitepress';
|
||||
import {format as timeago} from 'timeago.js';
|
||||
|
||||
const {theme, page, frontmatter, lang} = useData();
|
||||
|
||||
// handle time
|
||||
const date = computed(() => new Date(frontmatter.value.lastUpdated ?? page.value.lastUpdated));
|
||||
const isoDatetime = computed(() => date.value.toISOString());
|
||||
const datetime = ref('');
|
||||
|
||||
// set time on mounted hook to avoid hydration mismatch due to
|
||||
// potential differences in timezones of the server and clients
|
||||
onMounted(() => {
|
||||
watchEffect(() => {
|
||||
// allow for timeago style
|
||||
// @TODO: timeago has localization support but only en_US and zh_CN by default if we add support for this we need
|
||||
// to do this in the component so the localization is relative to the users browser and not the build server
|
||||
if (theme.value.lastUpdated?.formatOptions?.dateStyle === 'timeago') {
|
||||
datetime.value = timeago(date.value.toLocaleDateString());
|
||||
|
||||
// otherwis the usual
|
||||
} else {
|
||||
datetime.value = new Intl.DateTimeFormat(
|
||||
theme.value.lastUpdated?.formatOptions?.forceLocale ? lang.value : undefined,
|
||||
theme.value.lastUpdated?.formatOptions ?? {dateStyle: 'short', timeStyle: 'short'},
|
||||
).format(date.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.VPLastUpdated {
|
||||
line-height: 24px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.VPLastUpdated {
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
60
node_modules/@lando/vitepress-theme-default-plus/components/VPLDogs.vue
generated
vendored
Normal file
60
node_modules/@lando/vitepress-theme-default-plus/components/VPLDogs.vue
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<Page>
|
||||
<template #doc-top>
|
||||
<img src="https://i.pinimg.com/originals/4c/d9/ce/4cd9ce636c6d5f23688f0fda99cd81cf.gif">
|
||||
</template>
|
||||
<template #doc-before>
|
||||
<img src="https://i.pinimg.com/originals/4c/d9/ce/4cd9ce636c6d5f23688f0fda99cd81cf.gif">
|
||||
</template>
|
||||
<template #doc-after>
|
||||
<img src="https://i.pinimg.com/originals/4c/d9/ce/4cd9ce636c6d5f23688f0fda99cd81cf.gif">
|
||||
</template>
|
||||
<template #doc-bottom>
|
||||
<img src="https://i.pinimg.com/originals/4c/d9/ce/4cd9ce636c6d5f23688f0fda99cd81cf.gif">
|
||||
</template>
|
||||
<template #aside-top>
|
||||
aside-top
|
||||
</template>
|
||||
<template #aside-outline-before>
|
||||
aside-outline-before
|
||||
</template>
|
||||
<template #aside-outline-after>
|
||||
aside-outline-after
|
||||
</template>
|
||||
<template #aside-ads-before>
|
||||
aside-ads-before
|
||||
</template>
|
||||
<template #aside-ads-after>
|
||||
aside-ads-after
|
||||
</template>
|
||||
<template #aside-bottom>
|
||||
aside-bottom
|
||||
</template>
|
||||
|
||||
<div class="cat-container">
|
||||
CATVIBES
|
||||
<Content />
|
||||
</div>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Page from 'vitepress/dist/client/theme-default/components/VPDoc.vue';
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.contributors {
|
||||
float: left;
|
||||
max-width: 70%;
|
||||
overflow: hidden;
|
||||
max-height: 70px;
|
||||
}
|
||||
.contributors-flex {
|
||||
height: 65px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
|
||||
108
node_modules/@lando/vitepress-theme-default-plus/components/VPLJobs.vue
generated
vendored
Normal file
108
node_modules/@lando/vitepress-theme-default-plus/components/VPLJobs.vue
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="hasJobs"
|
||||
class="jobs"
|
||||
>
|
||||
<span
|
||||
v-if="props.title"
|
||||
class="ad-header"
|
||||
>
|
||||
{{ props.title }}
|
||||
</span>
|
||||
<div
|
||||
v-for="(job, index) in jobs"
|
||||
:key="index"
|
||||
class="job"
|
||||
>
|
||||
<a
|
||||
:href="job.link"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<div class="job-image">
|
||||
<img
|
||||
:src="job.logo"
|
||||
:alt="job.company"
|
||||
>
|
||||
</div>
|
||||
<div class="job-info">
|
||||
<div class="job-title">{{ job.title }}</div>
|
||||
<div class="job-aux">
|
||||
{{ job.company }} - {{ job.aux }}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {computed} from 'vue';
|
||||
import {useData} from 'vitepress';
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: [String, Boolean],
|
||||
default: 'Jobs',
|
||||
},
|
||||
});
|
||||
|
||||
const {theme, frontmatter} = useData();
|
||||
const jobs = frontmatter.value.jobs ?? theme.value.jobs ?? [];
|
||||
|
||||
// Compute whether we end up with any jobs or not
|
||||
const hasJobs = computed(() => jobs !== false && jobs.length > 0);
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.job {
|
||||
background-color: var(--vp-carbon-ads-bg-color);
|
||||
padding: 10px;
|
||||
border-radius: var(--vpl-c-border-radius);
|
||||
font-weight: 400;
|
||||
margin-bottom: 10px;
|
||||
a {
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--vp-c-text-1);
|
||||
font-weight: 700;
|
||||
}
|
||||
.job-image {
|
||||
width: 34px;
|
||||
margin-right: 5px;
|
||||
text-decoration: none;
|
||||
img {
|
||||
max-height: 24px;
|
||||
max-width: 24px;
|
||||
}
|
||||
}
|
||||
.job-info {
|
||||
width: 100%;
|
||||
.job-title {
|
||||
font-size: 14px;
|
||||
}
|
||||
.job-aux {
|
||||
font-size: 10px;
|
||||
letter-spacing: .3px;
|
||||
color: var(--vp-c-brand-1);
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1500px) {
|
||||
.rightbar {
|
||||
.jobs {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.read-mode {
|
||||
.jobs {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
97
node_modules/@lando/vitepress-theme-default-plus/components/VPLLayout.vue
generated
vendored
Normal file
97
node_modules/@lando/vitepress-theme-default-plus/components/VPLLayout.vue
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<Layout :class="headerClass">
|
||||
<template #layout-top>
|
||||
<Alert
|
||||
v-if="alert"
|
||||
:key="alertKey"
|
||||
:content="alert.content"
|
||||
:closeable="alert.closeable"
|
||||
:type="alert.type"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #sidebar-nav-after>
|
||||
<div
|
||||
v-if="sidebarEnder !== false"
|
||||
class="sidebar-end"
|
||||
>
|
||||
<VPSideBarItem
|
||||
:depth="0"
|
||||
:item="sidebarEnder"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #doc-before>
|
||||
<div
|
||||
v-if="header !== ''"
|
||||
class="collection-header"
|
||||
>
|
||||
<PostHeader v-if="header === 'post'" />
|
||||
<CollectionHeader v-else />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #aside-ads-before>
|
||||
<Tags :key="tagsKey" />
|
||||
<Jobs :key="jobsKey" />
|
||||
<Sponsors :key="sponsorsKey" />
|
||||
</template>
|
||||
|
||||
<template #doc-footer-before>
|
||||
<Tags
|
||||
v-if="header === 'post'"
|
||||
:key="tagsKey"
|
||||
/>
|
||||
<div
|
||||
v-if="mailchimp"
|
||||
class="newsletter-wrapper"
|
||||
>
|
||||
<MailChimp v-bind="mailchimp" />
|
||||
</div>
|
||||
</template>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {useData} from 'vitepress';
|
||||
import {computed, ref, watch} from 'vue';
|
||||
|
||||
import DefaultTheme from 'vitepress/theme';
|
||||
import VPSideBarItem from 'vitepress/dist/client/theme-default/components/VPSidebarItem.vue';
|
||||
|
||||
import Alert from './VPLAlert.vue';
|
||||
import CollectionHeader from './VPLCollectionHeader.vue';
|
||||
import MailChimp from './VPLMailChimp.vue';
|
||||
import PostHeader from './VPLPostHeader.vue';
|
||||
import Tags from './VPLCollectionItemTags.vue';
|
||||
|
||||
const {Layout} = DefaultTheme;
|
||||
|
||||
let alertKey = ref(0);
|
||||
let jobsKey = ref(0);
|
||||
let sponsorsKey = ref(0);
|
||||
let tagsKey = ref(0);
|
||||
const {frontmatter, page, theme} = useData();
|
||||
|
||||
const alert = computed(() => frontmatter.value.alert ?? theme.value.alert ?? false);
|
||||
const header = computed(() => frontmatter.value.collection || '');
|
||||
const headerClass = computed(() => frontmatter.value.collection ? `collection-${frontmatter.value.collection}` : '');
|
||||
const mailchimp = computed(() => frontmatter.value?.mailchimp?.action ? frontmatter.value.mailchimp : false);
|
||||
const sidebarEnder = computed(() => theme.value.sidebarEnder ?? false);
|
||||
|
||||
watch(() => page.value.relativePath, () => {
|
||||
alertKey = page.value.relativePath;
|
||||
jobsKey = page.value.relativePath;
|
||||
sponsorsKey = page.value.relativePath;
|
||||
tagsKey = page.value.relativePath;
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.newsletter-wrapper {
|
||||
border-top: 1px solid var(--vp-c-divider);
|
||||
padding: 16px 0 ;
|
||||
}
|
||||
</style>
|
||||
73
node_modules/@lando/vitepress-theme-default-plus/components/VPLLink.vue
generated
vendored
Normal file
73
node_modules/@lando/vitepress-theme-default-plus/components/VPLLink.vue
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<component
|
||||
:is="tag"
|
||||
class="VPLink"
|
||||
:class="{
|
||||
link: props.href,
|
||||
'lando': true,
|
||||
'vp-external-link-icon': isExternal,
|
||||
'no-icon': noIcon
|
||||
}"
|
||||
:href="getLink(props.href)"
|
||||
:target="target ?? (isExternal ? '_blank' : isFauxInternal ? '_self' : undefined)"
|
||||
:rel="relation ?? (isExternal ? 'noreferrer' : undefined)"
|
||||
>
|
||||
<slot />
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {useData} from 'vitepress';
|
||||
import {computed} from 'vue';
|
||||
import {normalizeLink} from 'vitepress/dist/client/theme-default/support/utils.js';
|
||||
|
||||
import {default as checkIsFauxInternal} from '../utils/is-faux-internal';
|
||||
import {default as normalizeMvb} from '../utils/normalize-mvblink';
|
||||
import {default as normalizeRoot} from '../utils/normalize-rootlink';
|
||||
|
||||
const EXTERNAL_URL_RE = /^(?:[a-z]+:|\/\/)/i;
|
||||
|
||||
const {theme, site} = useData();
|
||||
const {internalDomains} = theme.value;
|
||||
|
||||
const props = defineProps({
|
||||
tag: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
href: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
noIcon: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
target: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
rel: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
const relation = computed(() => {
|
||||
if (props.rel === 'mvb') return 'alternate';
|
||||
else if (props.rel === 'root' || props.rel === 'none') return undefined;
|
||||
return props.rel;
|
||||
});
|
||||
const tag = computed(() => props.tag ?? (props.href ? 'a' : 'span'));
|
||||
const target = computed(() => props.target ?? (props.rel === 'mvb' || props.rel === 'root' ? '_self' : undefined));
|
||||
|
||||
const isFauxInternal = computed(() => props.href && checkIsFauxInternal(props.href, internalDomains));
|
||||
const isExternal = computed(() => !isFauxInternal.value && props.href && EXTERNAL_URL_RE.test(props.href));
|
||||
|
||||
const getLink = href => {
|
||||
if (props.rel === 'mvb' && href) return normalizeMvb(href, site.value);
|
||||
else if (props.rel === 'root' && href) return normalizeRoot(href, site.value);
|
||||
return href ? normalizeLink(href) : undefined;
|
||||
};
|
||||
|
||||
</script>
|
||||
175
node_modules/@lando/vitepress-theme-default-plus/components/VPLMailChimp.vue
generated
vendored
Normal file
175
node_modules/@lando/vitepress-theme-default-plus/components/VPLMailChimp.vue
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
<template>
|
||||
<div class="newsletter post-subscribe">
|
||||
<div class="newsletter__wrap">
|
||||
<div class="newsletter__title">
|
||||
<h3>{{ props.title }}</h3>
|
||||
</div>
|
||||
<div class="newsletter__content">
|
||||
{{ props.byline }}
|
||||
</div>
|
||||
<div id="mc_embed_signup">
|
||||
<form
|
||||
id="mc-embedded-subscribe-form"
|
||||
:action="props.action"
|
||||
method="post"
|
||||
name="mc-embedded-subscribe-form"
|
||||
class="validate subscribe-form"
|
||||
target="_blank"
|
||||
novalidate
|
||||
>
|
||||
<input
|
||||
id="mce-EMAIL"
|
||||
v-model="email"
|
||||
type="email"
|
||||
placeholder="Email address"
|
||||
name="EMAIL"
|
||||
class="subscribe-input"
|
||||
>
|
||||
<div
|
||||
id="mce-responses"
|
||||
class="clear"
|
||||
>
|
||||
<div
|
||||
id="mce-error-response"
|
||||
class="response"
|
||||
style="display:none"
|
||||
/>
|
||||
<div
|
||||
id="mce-success-response"
|
||||
class="response"
|
||||
style="display:none"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style="position: absolute; left: -5000px;"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
name="b_59874b4d6910fa65e724a4648_613837077f"
|
||||
tabindex="-1"
|
||||
value=""
|
||||
>
|
||||
</div>
|
||||
<VPButton
|
||||
size="big"
|
||||
:text="props.button"
|
||||
>
|
||||
<input
|
||||
id="mc-embedded-subscribe"
|
||||
:class="{ disabled: !email }"
|
||||
:disabled="!email"
|
||||
type="submit"
|
||||
name="subscribe"
|
||||
value=""
|
||||
>
|
||||
</VPButton>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref} from 'vue';
|
||||
import {VPButton} from 'vitepress/theme';
|
||||
|
||||
const props = defineProps({
|
||||
action: {
|
||||
required: true,
|
||||
type: String,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: 'Subscribe to the newsletter!',
|
||||
},
|
||||
byline: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
button: {
|
||||
type: String,
|
||||
default: 'Subscribe',
|
||||
},
|
||||
});
|
||||
|
||||
const email = ref(null);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.newsletter {
|
||||
text-align: center;
|
||||
color: var(--vp-c-text-1);
|
||||
margin: 16px 0;
|
||||
}
|
||||
.newsletter__wrap {
|
||||
padding: 32px 32px;
|
||||
border-radius: var(--vpl-c-border-radius);
|
||||
box-sizing: border-box;
|
||||
width: auto;
|
||||
font-size: 14px;
|
||||
input[type=email], input[type=text], textarea {
|
||||
border: 0 solid #f8f8f8;
|
||||
box-sizing: border-box;
|
||||
height: 50px;
|
||||
width: 100%;
|
||||
padding: 1em;
|
||||
&:focus {
|
||||
outline: 1px solid var(--vp-c-brand-soft);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.newsletter__title {
|
||||
h3 {
|
||||
margin: 0;
|
||||
color: var(--vp-custom-block-brand-title);
|
||||
font-weight: 600;
|
||||
font-size: 18px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
.newsletter__content {
|
||||
margin: 16px 0;
|
||||
line-height: 28px;
|
||||
}
|
||||
.post-subscribe {
|
||||
.subscribe {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
.subscribe-input {
|
||||
background-color: var(--vp-c-bg);
|
||||
font-size: inherit;
|
||||
border: 1px solid var(--vp-c-bg-alt);
|
||||
width: 100%;
|
||||
padding: 0.6rem 1.2rem;
|
||||
box-sizing: border-box;
|
||||
border-radius: var(--vpl-c-border-radius);
|
||||
outline: none;
|
||||
height: auto;
|
||||
margin: 1em 0;
|
||||
}
|
||||
.newsletter__wrap {
|
||||
background-color: var(--vp-c-brand-soft);
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.post-subscribe .subscribe-form {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 420px) {
|
||||
.newsletter {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
border-radius: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.newsletter__wrap {
|
||||
margin: 0.85rem -1.5rem;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
116
node_modules/@lando/vitepress-theme-default-plus/components/VPLMenuGroup.vue
generated
vendored
Normal file
116
node_modules/@lando/vitepress-theme-default-plus/components/VPLMenuGroup.vue
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div :class="`VPMenuGroup ${getItemColumnsClass(props.columns)}`">
|
||||
<p
|
||||
v-if="props.text"
|
||||
class="title"
|
||||
>
|
||||
{{ props.text }}
|
||||
</p>
|
||||
|
||||
<div :class="{'VPMenuGroup-flex-wrapper': props.columns > 1}">
|
||||
<template v-for="item in props.items">
|
||||
<MenuLink
|
||||
v-if="'link' in item"
|
||||
:key="item.href"
|
||||
:item="item"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import MenuLink from './VPLMenuLink.vue';
|
||||
|
||||
const props = defineProps({
|
||||
columns: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
items: {
|
||||
type: Array,
|
||||
default: () => ([]),
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
const getItemColumnsClass = columns => {
|
||||
switch (columns) {
|
||||
case 1:
|
||||
return 'VPMenuGroup-columns-full';
|
||||
case 2:
|
||||
return 'VPMenuGroup-columns-half';
|
||||
case 3:
|
||||
return 'VPMenuGroup-columns-third';
|
||||
case 4:
|
||||
return 'VPMenuGroup-columns-quarter';
|
||||
default:
|
||||
return 'VPMenuGroup-colums-third';
|
||||
};
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.VPMenuGroup {
|
||||
margin: 12px -12px 0;
|
||||
border-top: 1px solid var(--vp-c-divider);
|
||||
padding: 12px 12px 0;
|
||||
}
|
||||
|
||||
.VPMenuGroup .title {
|
||||
color: var(--vp-c-text-3);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.VPMenuGroup .VPMenuGroup-flex-wrapper {
|
||||
width: 500px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.VPMenuGroup-columns-full .VPMenuLink {
|
||||
width: unset;
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.VPMenuGroup-columns-half .VPMenuLink {
|
||||
min-width: 49%;
|
||||
max-width: 50%;
|
||||
}
|
||||
|
||||
.VPMenuGroup-columns-third .VPMenuLink {
|
||||
min-width: 32%;
|
||||
max-width: 33%;
|
||||
}
|
||||
|
||||
.VPMenuGroup-columns-quarter .VPMenuLink {
|
||||
min-width: 24%;
|
||||
max-width: 25%;
|
||||
}
|
||||
|
||||
.VPMenuGroup:first-child {
|
||||
margin-top: 0;
|
||||
border-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.VPMenuGroup + .VPMenuGroup {
|
||||
margin-top: 12px;
|
||||
border-top: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.title {
|
||||
display: block;
|
||||
padding: 0 12px;
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
white-space: nowrap;
|
||||
transition: color 0.25s;
|
||||
}
|
||||
</style>
|
||||
87
node_modules/@lando/vitepress-theme-default-plus/components/VPLMenuLink.vue
generated
vendored
Normal file
87
node_modules/@lando/vitepress-theme-default-plus/components/VPLMenuLink.vue
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div class="VPMenuLink">
|
||||
<Link
|
||||
:class="{ active: isActive(page.relativePath, item.activeMatch || item.link, !!item.activeMatch) }"
|
||||
:href="item.link"
|
||||
:target="item.target"
|
||||
:rel="item.rel"
|
||||
>
|
||||
{{ item.text }}
|
||||
<Badge
|
||||
v-if="hasAlert(item.alert) && isActiveAlert(item.alert)"
|
||||
v-bind="getAlert(item.alert)"
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {toRefs} from 'vue';
|
||||
import {useData} from 'vitepress';
|
||||
import isActive from '../utils/is-active.js';
|
||||
|
||||
import Link from './VPLLink.vue';
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: [Array, Object],
|
||||
default: () => ([]),
|
||||
},
|
||||
});
|
||||
|
||||
const {item} = toRefs(props);
|
||||
const {page} = useData();
|
||||
|
||||
const getAlert = alert => {
|
||||
if (typeof alert === 'string') alert = {text: alert};
|
||||
return {type: 'info', expires: 2000000000000, ...alert};
|
||||
};
|
||||
|
||||
const hasAlert = alert => {
|
||||
return (
|
||||
alert
|
||||
&& alert !== null
|
||||
&& alert !== undefined
|
||||
&& (typeof alert === 'string' || typeof alert == 'object')
|
||||
);
|
||||
};
|
||||
|
||||
const isActiveAlert = alert => {
|
||||
const {expires} = getAlert(alert);
|
||||
return new Date().getTime() < expires;
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.VPMenuGroup + .VPMenuLink {
|
||||
margin: 12px -12px 0;
|
||||
border-top: 1px solid var(--vp-c-divider);
|
||||
padding: 12px 12px 0;
|
||||
}
|
||||
|
||||
.VPMenuLink .VPBadge {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.link {
|
||||
display: block;
|
||||
border-radius: 6px;
|
||||
padding: 0 12px;
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-1);
|
||||
white-space: nowrap;
|
||||
transition: background-color 0.25s, color 0.25s;
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
color: var(--vp-c-brand-1);
|
||||
background-color: var(--vp-c-default-soft);
|
||||
}
|
||||
|
||||
.link.active {
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
</style>
|
||||
123
node_modules/@lando/vitepress-theme-default-plus/components/VPLNavBarMenuGroup.vue
generated
vendored
Normal file
123
node_modules/@lando/vitepress-theme-default-plus/components/VPLNavBarMenuGroup.vue
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div class="maybe">
|
||||
<span
|
||||
v-if="treeHasNewAlerts"
|
||||
class="alert-circle"
|
||||
/>
|
||||
<VPFlyout
|
||||
:class="styles"
|
||||
:button="item.text"
|
||||
:items="item.items"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {computed, toRefs} from 'vue';
|
||||
import {useData} from 'vitepress';
|
||||
import isActive from '../utils/is-active.js';
|
||||
|
||||
import VPFlyout from 'vitepress/dist/client/theme-default/components/VPFlyout.vue';
|
||||
|
||||
const {page} = useData();
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: [Array, Object],
|
||||
default: () => ([]),
|
||||
},
|
||||
});
|
||||
|
||||
const {item} = toRefs(props);
|
||||
|
||||
const getAlert = alert => {
|
||||
if (typeof alert === 'string') alert = {text: alert};
|
||||
return {type: 'success', expires: 2000000000000, ...alert};
|
||||
};
|
||||
|
||||
const isChildActive = navItem => {
|
||||
if ('link' in navItem) {
|
||||
return isActive(
|
||||
page.value.relativePath,
|
||||
props.item.activeMatch,
|
||||
!!props.item.activeMatch,
|
||||
);
|
||||
} else {
|
||||
return navItem.items.some(isChildActive);
|
||||
}
|
||||
};
|
||||
|
||||
const flattenTree = (data, collect = []) => {
|
||||
// break up children and items
|
||||
const {items, ...item} = data;
|
||||
// collec the item
|
||||
collect.push(item);
|
||||
// if we have children we need to recurse and add
|
||||
if (items && items.length > 0) {
|
||||
items.map(child => {
|
||||
collect.push(flattenTree(child));
|
||||
});
|
||||
};
|
||||
|
||||
// faltten and return
|
||||
return collect.flat(Infinity);
|
||||
};
|
||||
|
||||
const getClasses = item => {
|
||||
const list = item.value.classes ?? item.value.class;
|
||||
|
||||
// if list is nully then
|
||||
if (!list || list === null) return [];
|
||||
|
||||
// return
|
||||
return Array.isArray(list) ? list : [list];
|
||||
};
|
||||
|
||||
const hasAlert = item => {
|
||||
const {alert} = item;
|
||||
return (
|
||||
alert
|
||||
&& alert !== null
|
||||
&& alert !== undefined
|
||||
&& (typeof alert === 'string' || typeof alert == 'object')
|
||||
);
|
||||
};
|
||||
|
||||
const treeHasNewAlerts = computed(() => {
|
||||
const items = flattenTree(item.value);
|
||||
const activeAlerts = items
|
||||
.filter(item => hasAlert(item))
|
||||
.map(item => getAlert(item.alert))
|
||||
.filter(alert => alert.type === 'new')
|
||||
.filter(alert => alert && alert.expires > new Date().getTime());
|
||||
|
||||
return activeAlerts.length > 0;
|
||||
});
|
||||
|
||||
const styles = computed(() => {
|
||||
// get active status
|
||||
const active = isActive(page.relativePath, item.activeMatch, !!item.activeMatch) || isChildActive(props.item);
|
||||
// build class list
|
||||
const classes = {active, VPNavBarMenuGroup: true, test: treeHasNewAlerts};
|
||||
// handle custom classes
|
||||
for (const style of getClasses(item)) classes[style] = true;
|
||||
|
||||
return classes;
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.maybe {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.alert-circle {
|
||||
height: 8px;
|
||||
width: 8px;
|
||||
background-color: var(--vp-c-brand-1);
|
||||
border-radius: 50%;
|
||||
margin-right: -7px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
||||
119
node_modules/@lando/vitepress-theme-default-plus/components/VPLPostHeader.vue
generated
vendored
Normal file
119
node_modules/@lando/vitepress-theme-default-plus/components/VPLPostHeader.vue
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
<template>
|
||||
<div class="post-header">
|
||||
<Icon
|
||||
v-if="collection !== false"
|
||||
:icon="icon"
|
||||
:link="iconLink"
|
||||
:title="collection"
|
||||
/>
|
||||
<span v-if="authors.length > 0">by</span>
|
||||
<div
|
||||
v-if="authors.length > 0"
|
||||
class="post-avatars"
|
||||
>
|
||||
<Author
|
||||
v-for="author in authors"
|
||||
:key="author.name"
|
||||
size="icon"
|
||||
:member="author"
|
||||
/>
|
||||
</div>
|
||||
<Link
|
||||
v-for="(author, index) in authors"
|
||||
:key="author.name"
|
||||
:href="author.link"
|
||||
no-icon
|
||||
>
|
||||
<span class="underline">{{ author.name }}</span><span class="separator">{{ getSeparator(index, authors.length) }}</span>
|
||||
</Link>
|
||||
<span v-if="hlocation">from</span>
|
||||
<span
|
||||
v-if="hlocation"
|
||||
class="location"
|
||||
>
|
||||
{{ hlocation }}
|
||||
</span>
|
||||
on
|
||||
<time
|
||||
class="date"
|
||||
:datetime="datetime"
|
||||
>
|
||||
{{ hdate }}
|
||||
</time>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {computed} from 'vue';
|
||||
import {useData} from 'vitepress';
|
||||
|
||||
import Author from './VPLTeamMembersItem.vue';
|
||||
import Icon from './VPLCollectionIcon.vue';
|
||||
import Link from './VPLLink.vue';
|
||||
|
||||
const {frontmatter, page} = useData();
|
||||
|
||||
const authors = computed(() => frontmatter.value?.authors ?? false);
|
||||
const collection = computed(() => frontmatter.value?.collection ?? false);
|
||||
const datetime = computed(() => page.value?.datetime ?? false);
|
||||
const icon = computed(() => page.value?.collection?.icon ?? false);
|
||||
const iconLink = computed(() => page.value?.collection?.iconLink ?? false);
|
||||
|
||||
const getSeparator = (index, end = 0) => {
|
||||
return index + 1 === end ? '' : ', ';
|
||||
};
|
||||
|
||||
const hdate = computed(() => {
|
||||
return new Date(frontmatter.value?.date ?? page.value?.lastUpdated ?? page.value?.timestamp).toLocaleDateString(undefined, {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
});
|
||||
});
|
||||
|
||||
const hlocation = computed(() => {
|
||||
return frontmatter.value?.location ?? authors?.[0]?.location ?? false;
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.post-header {
|
||||
align-items: flex-start;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
font-size: .75em;
|
||||
margin-bottom: 24px;
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: color-mix(in srgb, var(--vp-c-brand-1) 90%, white);
|
||||
.underline {
|
||||
text-underline-offset: 2px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.separator {
|
||||
color: var(--vp-c-text-3);
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.location, .date {
|
||||
font-weight: 700;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.post-avatars {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
.VPTeamMembersItem.icon {
|
||||
overflow: visible;
|
||||
&:not(:first-child) {
|
||||
margin-left: -14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
213
node_modules/@lando/vitepress-theme-default-plus/components/VPLSponsors.vue
generated
vendored
Normal file
213
node_modules/@lando/vitepress-theme-default-plus/components/VPLSponsors.vue
generated
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="hasSponsors"
|
||||
class="sponsors"
|
||||
>
|
||||
<span
|
||||
v-if="props.title"
|
||||
class="ad-header"
|
||||
>
|
||||
{{ props.title }}
|
||||
</span>
|
||||
<div class="sponsors-wrapper">
|
||||
<div
|
||||
v-for="(sponsor, index) in sponsorList"
|
||||
:key="index"
|
||||
:class="sponsor.classes"
|
||||
>
|
||||
<div class="sponsor-inner">
|
||||
<a
|
||||
:href="sponsor.url"
|
||||
target="_blank"
|
||||
>
|
||||
<div class="sponsor-image"><img
|
||||
:src="sponsor.logo"
|
||||
:alt="sponsor.name"
|
||||
></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="props.text || props.link"
|
||||
class="sponsor-footer"
|
||||
>
|
||||
<a
|
||||
:href="props.link"
|
||||
target="_blank"
|
||||
>
|
||||
<div class="sponsor sponsor-full">
|
||||
<span class="sponsor-link">
|
||||
{{ props.text }}
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import yaml from 'js-yaml';
|
||||
|
||||
import {computed, onMounted, ref} from 'vue';
|
||||
import {useData} from 'vitepress';
|
||||
|
||||
const extname = path => {
|
||||
const file = path.split('/')[path.split('/').length - 1];
|
||||
const fileparts = file.split('.');
|
||||
return fileparts.length > 1 ? `.${fileparts[fileparts.length - 1]}` : undefined;
|
||||
};
|
||||
|
||||
const {theme, frontmatter} = useData();
|
||||
const sponsors = frontmatter.value.sponsors ?? theme.value.sponsors ?? [];
|
||||
|
||||
const props = defineProps({
|
||||
text: {
|
||||
type: [String, Boolean],
|
||||
default: () => {
|
||||
const {theme, frontmatter} = useData();
|
||||
const sponsors = frontmatter.value.sponsors ?? theme.value.sponsors ?? [];
|
||||
return sponsors.text ?? 'your logo?';
|
||||
},
|
||||
},
|
||||
link: {
|
||||
type: [String, Boolean],
|
||||
default: () => {
|
||||
const {theme, frontmatter} = useData();
|
||||
const sponsors = frontmatter.value.sponsors ?? theme.value.sponsors ?? [];
|
||||
return sponsors.link;
|
||||
},
|
||||
},
|
||||
title: {
|
||||
type: [String, Boolean],
|
||||
default: 'SPONSORS',
|
||||
},
|
||||
});
|
||||
|
||||
// Set sponsor data to some reactive thing
|
||||
const data = ref(sponsors.data ?? []);
|
||||
|
||||
// if data is a string/needs to be fetched then do that here
|
||||
onMounted(async () => {
|
||||
// if data is already an array then we good
|
||||
if (Array.isArray(data.value)) return;
|
||||
|
||||
// otherwise it SHOULD be a url string
|
||||
try {
|
||||
const url = new URL(data.value);
|
||||
const response = await fetch(url.href);
|
||||
|
||||
// allow special file extension handling
|
||||
switch (extname(url.pathname)) {
|
||||
case '.yaml':
|
||||
case '.yml':
|
||||
data.value = yaml.load(await response.text());
|
||||
break;
|
||||
default:
|
||||
data.value = await response.json();
|
||||
break;
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`could not fetch and parse data from ${data.value}`);
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
|
||||
// Compute sponsor list
|
||||
const sponsorList = computed(() => {
|
||||
if (Array.isArray(data.value)) {
|
||||
return data.value.map(sponsor => ({...sponsor, classes: `sponsor sponsor-${sponsor.type}`}));
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
// Compute whether we end up with any sponsors or not
|
||||
const hasSponsors = computed(() => sponsors !== false && sponsors && sponsors.data && sponsors.data.length > 0);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sponsors-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.sponsor {
|
||||
height: 50px;
|
||||
width: 33%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
margin-top: 2px;
|
||||
cursor: pointer;
|
||||
border-radius: var(--vpl-c-border-radius);
|
||||
.sponsor-inner {
|
||||
background-color: var(--vp-carbon-ads-bg-color);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-left: 1px;
|
||||
margin-right: 1px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
border-radius: var(--vpl-c-border-radius);
|
||||
}
|
||||
&.sponsor-half {
|
||||
width: 50%;
|
||||
}
|
||||
&.sponsor-full {
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.sponsor-image {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
padding: 5px;
|
||||
img {
|
||||
max-height: 40px;
|
||||
max-width: 80%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.sponsor-footer {
|
||||
margin-top: 10px;
|
||||
.sponsor {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
width: auto;
|
||||
background-color: var(--vp-carbon-ads-bg-color);
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
margin-left: 1px;
|
||||
margin-right: 1px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
.sponsor-link {
|
||||
color: var(--vp-c-text-3);
|
||||
display: block;
|
||||
font-weight: 700;
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (max-width: 1500px) {
|
||||
.rightbar {
|
||||
.sponsors {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.read-mode {
|
||||
.sponsors {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
225
node_modules/@lando/vitepress-theme-default-plus/components/VPLTeamMembers.vue
generated
vendored
Normal file
225
node_modules/@lando/vitepress-theme-default-plus/components/VPLTeamMembers.vue
generated
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
<template>
|
||||
<VPTeamMembers
|
||||
:size="size"
|
||||
:members="members"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import useTeam from '../client/use-team.js';
|
||||
|
||||
import {VPTeamMembers} from 'vitepress/theme';
|
||||
|
||||
const {members, size} = defineProps({
|
||||
size: {
|
||||
type: String,
|
||||
default: 'medium',
|
||||
},
|
||||
members: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return useTeam() ?? [];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.VPTeamMembersItem {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
border-radius: 12px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.icon {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
border-radius: 12px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.icon .profile {
|
||||
padding: 0px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.icon .data {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.icon .avatar {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.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-1);
|
||||
}
|
||||
|
||||
.desc {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.desc :deep(a) {
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-brand-1);
|
||||
text-decoration-style: dotted;
|
||||
transition: color 0.25s;
|
||||
}
|
||||
|
||||
.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 .sp-link.link:hover,
|
||||
.sp .sp-link.link:focus {
|
||||
outline: none;
|
||||
color: var(--vp-c-white);
|
||||
background-color: var(--vp-c-sponsor);
|
||||
}
|
||||
|
||||
.sp-icon {
|
||||
margin-right: 8px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
392
node_modules/@lando/vitepress-theme-default-plus/components/VPLTeamMembersItem.vue
generated
vendored
Normal file
392
node_modules/@lando/vitepress-theme-default-plus/components/VPLTeamMembersItem.vue
generated
vendored
Normal file
@@ -0,0 +1,392 @@
|
||||
<template>
|
||||
<article
|
||||
class="VPTeamMembersItem"
|
||||
:class="[size, maintainerClass]"
|
||||
>
|
||||
<div class="profile">
|
||||
<div
|
||||
v-if="(member.commits || member.maintainer) && size !== 'icon'"
|
||||
class="top-hat"
|
||||
>
|
||||
<div class="maintainer-role">
|
||||
{{ member.maintainer ? 'Maintainer' : '' }}
|
||||
</div>
|
||||
<div class="commits">
|
||||
{{ member.commits ? member.commits : '' }}
|
||||
</div>
|
||||
</div>
|
||||
<figure class="avatar">
|
||||
<Link
|
||||
:href="getLink(member)"
|
||||
no-icon
|
||||
>
|
||||
<img
|
||||
class="avatar-img"
|
||||
:src="avatar"
|
||||
:alt="`Picture of ${member.name}`"
|
||||
:title="getAvatarTitle(member)"
|
||||
>
|
||||
</Link>
|
||||
</figure>
|
||||
<div class="data">
|
||||
<div class="name">
|
||||
{{ member.name }}
|
||||
</div>
|
||||
<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>
|
||||
<Link
|
||||
v-if="member.org"
|
||||
class="org"
|
||||
:class="{ link: member.orgLink }"
|
||||
:href="member.orgLink"
|
||||
no-icon
|
||||
>
|
||||
{{ member.org }}
|
||||
</Link>
|
||||
</p>
|
||||
<p
|
||||
v-if="member.desc"
|
||||
class="desc"
|
||||
v-html="member.desc"
|
||||
/>
|
||||
<div
|
||||
v-if="member.links"
|
||||
class="links"
|
||||
>
|
||||
<VPSocialLinks :links="member.links" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="member.sponsor"
|
||||
class="sp"
|
||||
>
|
||||
<Link
|
||||
class="sp-link"
|
||||
:href="member.sponsor"
|
||||
no-icon
|
||||
>
|
||||
<VPIconHeart class="sp-icon" /> Sponsor
|
||||
</Link>
|
||||
</div>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {computed} from 'vue';
|
||||
import VPIconHeart from 'vitepress/dist/client/theme-default/components/icons/VPIconHeart.vue';
|
||||
import VPSocialLinks from 'vitepress/dist/client/theme-default/components/VPSocialLinks.vue';
|
||||
import Link from './VPLLink.vue';
|
||||
|
||||
const {member, size} = defineProps({
|
||||
size: {
|
||||
type: String,
|
||||
default: 'medium',
|
||||
},
|
||||
member: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
// compute avatar url with correct size
|
||||
const avatar = computed(() => {
|
||||
const src = member.avatar ?? member.pic;
|
||||
switch (size) {
|
||||
case 'icon':
|
||||
return `${src}?size=24`;
|
||||
case 'small':
|
||||
return `${src}?size=64`;
|
||||
case 'medium':
|
||||
return `${src}?size=120`;
|
||||
case 'large':
|
||||
return `${src}?size=256`;
|
||||
default:
|
||||
return src;
|
||||
};
|
||||
});
|
||||
|
||||
const maintainerClass = computed(() => member.maintainer ? 'maintainer' : '');
|
||||
|
||||
const getLink = member => {
|
||||
if (member.link) return member.link;
|
||||
else if (Array.isArray(member?.links) && member.links[0]) return member.links[0].link;
|
||||
else if (member.email) return `mailto:${member.email}`;
|
||||
};
|
||||
|
||||
const getAvatarTitle = member => {
|
||||
let avatarTitle = `${member.name}`;
|
||||
if (member.email) avatarTitle += ` <${member.email}>`;
|
||||
if (member.commits) avatarTitle += ` - ${Number.parseInt(member.commits, 10)} commits`;
|
||||
return avatarTitle;
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.VPTeamMembersItem {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
border-radius: 12px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.icon {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
border-radius: 12px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.icon .profile {
|
||||
padding: 0px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.icon .top-hat {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.icon .maintainer-role {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.icon .commits {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.icon .data {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.icon .avatar {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.icon .sp {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.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: 12px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.small .desc {
|
||||
padding-top: 12px;
|
||||
line-height: 20px;
|
||||
font-size: 14px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.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: 14px;
|
||||
}
|
||||
|
||||
.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(--vpl-c-bg-contributor);
|
||||
}
|
||||
|
||||
.maintainer .profile {
|
||||
background-color: var(--vpl-c-bg-maintainer);
|
||||
}
|
||||
.maintainer .sp-link {
|
||||
background-color: var(--vpl-c-bg-maintainer);
|
||||
}
|
||||
|
||||
|
||||
.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;
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.at {
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.top-hat {
|
||||
position: relative;
|
||||
top: -30px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.commits {
|
||||
color: var(--vp-c-text-3);
|
||||
position: relative;
|
||||
right: -25px;
|
||||
font-size: 10px
|
||||
}
|
||||
|
||||
.maintainer-role {
|
||||
color: var(--vp-c-text-3);
|
||||
position: relative;
|
||||
font-size: 10px;
|
||||
left: -25px;
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.org.link {
|
||||
color: var(--vp-c-text-3);
|
||||
transition: color 0.25s;
|
||||
}
|
||||
|
||||
.org.link:hover {
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.desc {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.desc :deep(a) {
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-brand-1);
|
||||
text-decoration-style: dotted;
|
||||
transition: color 0.25s;
|
||||
}
|
||||
|
||||
.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 .sp-link.link:hover,
|
||||
.sp .sp-link.link:focus {
|
||||
outline: none;
|
||||
color: var(--vp-c-white);
|
||||
background-color: var(--vp-c-sponsor);
|
||||
}
|
||||
|
||||
.sp-icon {
|
||||
margin-right: 8px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
100
node_modules/@lando/vitepress-theme-default-plus/components/VPLVersionLink.vue
generated
vendored
Normal file
100
node_modules/@lando/vitepress-theme-default-plus/components/VPLVersionLink.vue
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<a
|
||||
class="VPLink"
|
||||
:class="{
|
||||
'prerelease': props.prerelease,
|
||||
link: props.version ?? props.text,
|
||||
'vp-external-link-icon': props.target === '_blank',
|
||||
'no-icon': props.noIcon
|
||||
}"
|
||||
:href="getLink(props.version ?? props.text)"
|
||||
:target="props.target"
|
||||
>
|
||||
{{ props.version ?? props.text }}
|
||||
<Badge
|
||||
v-if="props.stable"
|
||||
type="success"
|
||||
text="STABLE"
|
||||
vertical="middle"
|
||||
/>
|
||||
<Badge
|
||||
v-if="props.edge"
|
||||
type="warning"
|
||||
text="EDGE"
|
||||
vertical="middle"
|
||||
/>
|
||||
<Badge
|
||||
v-if="props.dev"
|
||||
type="tip"
|
||||
text="DEV"
|
||||
vertical="middle"
|
||||
/>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {default as normalizeMvb} from '../utils/normalize-mvblink';
|
||||
import {useData} from 'vitepress';
|
||||
|
||||
const {site} = useData();
|
||||
|
||||
const props = defineProps({
|
||||
dev: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
edge: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
noIcon: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
prerelease: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
stable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
target: {
|
||||
type: String,
|
||||
default: '_blank',
|
||||
},
|
||||
version: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
|
||||
// DEPRECATED but kept for backwards compat
|
||||
text: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
const getLink = version => {
|
||||
if (props.dev === true) return normalizeMvb('/dev/', site.value);
|
||||
return normalizeMvb(`/${version}/`, site.value);
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.version-link {
|
||||
a {
|
||||
color: var(--vp-c-green-3);
|
||||
&:hover {
|
||||
color: var(--vp-c-green-3);
|
||||
}
|
||||
}
|
||||
a.prerelease {
|
||||
color: var(--vp-c-yellow-3);
|
||||
&:hover {
|
||||
color: var(--vp-c-yellow-3);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
57
node_modules/@lando/vitepress-theme-default-plus/components/VPLYouTube.vue
generated
vendored
Normal file
57
node_modules/@lando/vitepress-theme-default-plus/components/VPLYouTube.vue
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="url"
|
||||
class="video-responsive"
|
||||
>
|
||||
<iframe
|
||||
width="100%"
|
||||
height="400"
|
||||
:src="url"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {computed} from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const url = computed(() => `https://www.youtube.com/embed/${props.id}`);
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.video-responsive {
|
||||
margin-top: 1em;
|
||||
overflow: hidden;
|
||||
padding-bottom: 56.25%;
|
||||
position: relative;
|
||||
height: 0;
|
||||
iframe {
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.video-responsive {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
border-radius: 0;
|
||||
width: auto;
|
||||
margin: 0.85rem -1.5rem;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user