16 |
--------------------------------------------------------------------------------
/utils/is-faux-internal.js:
--------------------------------------------------------------------------------
1 |
2 | export default function(path, domains = []) {
3 | // filter out non-strings
4 | domains = domains.filter(domain => typeof domain === 'string');
5 |
6 | // separate out strings and regex
7 | const regexers = domains.map(domain => new RegExp(domain)) ?? [];
8 |
9 | return false
10 | || domains.find(domain => path.startsWith(domain)) !== undefined
11 | || regexers.map(regexer => regexer.test(path)).find(matched => matched === true) !== undefined;
12 | }
13 |
--------------------------------------------------------------------------------
/.lando.yml:
--------------------------------------------------------------------------------
1 | name: vitepress-theme-default-plus
2 | proxy:
3 | cli:
4 | - vitepress-theme-default-plus.lndo.site:5173
5 | services:
6 | cli:
7 | api: 4
8 | image: node:18
9 | command: sleep infinity
10 | ports:
11 | - 5173:5173/http
12 | scanner: false
13 | user: node
14 | build:
15 | app: |
16 | npm install
17 | tooling:
18 | node:
19 | service: cli
20 | npm:
21 | service: cli
22 | vitepress:
23 | service: cli
24 | cmd: npx vitepress
25 |
--------------------------------------------------------------------------------
/utils/get-item-nl.js:
--------------------------------------------------------------------------------
1 | import {default as normalize} from './normalize-2base.js';
2 |
3 | export default function getItemNormalizedLink(item, site) {
4 | // if we dont have what we need just return that garbage
5 | if (!item.link) return item.link;
6 |
7 | // if this is not a special mvb then just return
8 | if (item.rel !== 'mvb') return item.link;
9 |
10 | // otherwise normalize on version base
11 | return normalize(item.link, site?.themeConfig?.multiVersionBuild?.base ?? '/', site);
12 | };
13 |
--------------------------------------------------------------------------------
/docs/markdown/cards.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Learn about custom card markdown containers in VitePress Default Theme +
3 | ---
4 |
5 | # Card Containers
6 |
7 | ::: card WAIT... ANOTHER WHAT?
8 | 
9 | Another happy landing of course!
10 | :::
11 |
12 | ```md
13 | ::: card WAIT... ANOTHER WHAT?
14 | 
15 | Another happy landing of course!
16 | :::
17 | ```
18 |
--------------------------------------------------------------------------------
/utils/parse-layouts.js:
--------------------------------------------------------------------------------
1 | import {resolve, basename} from 'node:path';
2 |
3 | export default function(layouts = {}) {
4 | return Object.entries(layouts)
5 | .map(([name, layout]) => ({
6 | name,
7 | var: basename(layout, '.vue'),
8 | from: layout,
9 | }))
10 | .map((layout, index) => ({
11 | ...layout,
12 | add: ` app.component('${layout.name}', ${layout.var});`,
13 | index,
14 | import: `import ${layout.var} from '${resolve(layout.from)}';`,
15 | }));
16 | }
17 |
--------------------------------------------------------------------------------
/utils/get-hubspot-headers.js:
--------------------------------------------------------------------------------
1 |
2 | export default function(id) {
3 | return [
4 | ['script', {
5 | async: true,
6 | defer: true,
7 | id: 'hs-script-loader',
8 | src: `//js.hs-scripts.com/${id}.js`,
9 | }],
10 | ['script', {}, [
11 | 'window.dataLayer = window.dataLayer || [];',
12 | 'window.hubspot = function(){dataLayer.push(arguments);}',
13 | `hubspot('js', new Date());`,
14 | `hubspot('config', '${id}');`,
15 | ].join('\n'),
16 | ],
17 | ];
18 | };
19 |
--------------------------------------------------------------------------------
/docs/markdown/thumbnails.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Learn about custom thumbnail markdown containers in VitePress Default Theme +
3 | ---
4 |
5 | # Thumbnail Containers
6 |
7 | :::: thumbnail
8 | 
9 | ::: caption
10 | Kalabox Version 1 Dashboard
11 | :::
12 | ::::
13 |
14 | ```md
15 | :::: thumbnail
16 | 
17 | ::: caption
18 | Kalabox Version 1 Dashboard
19 | :::
20 | ::::
21 | ```md
22 |
--------------------------------------------------------------------------------
/vite/patch-vp-menu-columns-plugin.js:
--------------------------------------------------------------------------------
1 | import Debug from 'debug';
2 |
3 | export default function({debug = Debug('@lando/vite-plugin')}) { // eslint-disable-line
4 | return {
5 | name: 'vp-menugroup-columns',
6 | enforce: 'pre',
7 | transform: (code, id) => {
8 | const menufile = 'VPMenu.vue';
9 | if (id.endsWith(menufile)) {
10 | debug('patched %o to add columns support to dropdown menu groups', menufile);
11 | return code.replace(':items="item.items"', ':items="item.items" :columns="item.columns"');
12 | }
13 | },
14 | };
15 | };
16 |
--------------------------------------------------------------------------------
/client/tags.data.js:
--------------------------------------------------------------------------------
1 |
2 | import Debug from 'debug';
3 |
4 | import {default as getTags} from '../utils/get-tags.js';
5 |
6 | const debug = Debug('@lando/tags.data.js'); // eslint-disable-line
7 | const siteConfig = globalThis.VITEPRESS_CONFIG;
8 |
9 | export default {
10 | async load() {
11 | const config = siteConfig?.userConfig?.themeConfig?.multiVersionBuild ?? {};
12 | const root = siteConfig?.userConfig?.gitRoot;
13 | const tags = await getTags(root, config, {debug: debug.extend('get-tags')});
14 | debug('loading tag data %o', tags);
15 | return tags;
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/docs/components/youtube.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Learn about the VitePress Default Theme + global YouTube components.
3 | contributors:
4 | merge: name
5 | debotify: true
6 | exclude:
7 | - John Ouellet
8 | - name: Bob
9 | email: frank@frank.com
10 |
11 | ---
12 |
13 | # YouTube
14 |
15 | ### Usage
16 |
17 | All you should need is the `id` of the YouTube video and you'll get a responsive full width embed.
18 |
19 | ```html
20 |
21 | ```
22 |
23 | ### Example
24 |
25 | ```html
26 |
27 | ```
28 |
29 |
30 |
--------------------------------------------------------------------------------
/client/collections.data.js:
--------------------------------------------------------------------------------
1 | import Debug from 'debug';
2 | import {default as createContentLoader} from '../utils/create-content-loader.js';
3 |
4 | const config = globalThis.VITEPRESS_CONFIG?.site?.themeConfig?.collections ?? {};
5 | const debug = Debug('@lando/collections.data.js'); // eslint-disable-line
6 | const siteConfig = globalThis.VITEPRESS_CONFIG;
7 |
8 | const patterns = Object.entries(config)
9 | .map(([type, config]) => config.patterns)
10 | .flat(Number.POSITIVE_INFINITY);
11 |
12 | debug('loading collections data with patterns config %o', patterns);
13 |
14 | export default createContentLoader(patterns, {siteConfig}, {debug});
15 |
--------------------------------------------------------------------------------
/client/team.data.js:
--------------------------------------------------------------------------------
1 |
2 | import Debug from 'debug';
3 |
4 | import {default as getContributors} from '../utils/get-contributors.js';
5 |
6 | const debug = Debug('@lando/team.data.js'); // eslint-disable-line
7 | const siteConfig = globalThis.VITEPRESS_CONFIG;
8 |
9 | export default {
10 | async load() {
11 | const contributors = siteConfig?.userConfig?.themeConfig?.contributors ?? false;
12 | const root = siteConfig?.userConfig?.gitRoot;
13 | const team = contributors !== false ? await getContributors(root, contributors, {debug: debug.extend('get-contribs'), paths: []}) : [];
14 | debug('loading team data %o', team);
15 | return team;
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/utils/merge-promise.js:
--------------------------------------------------------------------------------
1 | const nativePromisePrototype = (async () => {})().constructor.prototype;
2 | const descriptors = ['then', 'catch', 'finally']
3 | .map(property => [
4 | property,
5 | Reflect.getOwnPropertyDescriptor(nativePromisePrototype, property),
6 | ]);
7 |
8 | export default function(thing, promise) {
9 | for (const [property, descriptor] of descriptors) {
10 | // eslint-disable-next-line max-len
11 | const value = typeof promise === 'function' ? (...args) => Reflect.apply(descriptor.value, promise(), args) : descriptor.value.bind(promise);
12 | Reflect.defineProperty(thing, property, {...descriptor, value});
13 | }
14 |
15 | return thing;
16 | };
17 |
--------------------------------------------------------------------------------
/docs/team.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Learn about the team that made VitePress Default Theme Plus.
3 | layout: page
4 | title: Team
5 | ---
6 |
7 |
8 |
9 |
10 | Contributors
11 |
12 |
13 | We are the people who made this thing.
14 |
15 |
16 |
17 |
18 |
19 |
25 |
--------------------------------------------------------------------------------
/utils/is-active.js:
--------------------------------------------------------------------------------
1 | const EXT_RE = /(index)?\.(md|html)$/;
2 | const HASH_RE = /#.*$/;
3 | const inBrowser = typeof document !== 'undefined';
4 | const normalize = path => decodeURI(path).replace(HASH_RE, '').replace(EXT_RE, '');
5 |
6 | export default function isActive(currentPath, matchPath, asRegex) {
7 | if (matchPath === undefined) return false;
8 |
9 | currentPath = normalize(`/${currentPath}`);
10 |
11 | if (asRegex) return new RegExp(matchPath).test(currentPath);
12 | if (normalize(matchPath) !== currentPath) return false;
13 |
14 | const hashMatch = matchPath.match(HASH_RE);
15 |
16 | if (hashMatch) return (inBrowser ? location.hash : '') === hashMatch[0];
17 |
18 | return true;
19 | };
20 |
--------------------------------------------------------------------------------
/docs/support.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Contact Us
3 | description: Get help and support for VitePress Default Theme +.
4 | ---
5 |
6 | # Contact Us
7 |
8 | If you need priority and dedicated support, expediated bug fixes or more features then please contact us below.
9 |
10 |
25 |
--------------------------------------------------------------------------------
/docs/config/create-content-loader.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Learn about the VitePress Default Theme + createContentLoader util.
3 | ---
4 |
5 | # createContentLoader
6 |
7 | If you are doing any [build-time data loading](https://vitepress.dev/guide/data-loading) we have a wrapper for `createContentLoader` which you can use instead of the [default one](https://vitepress.dev/guide/data-loading#createcontentloader).
8 |
9 | It works *more-or-less* the same way but you *should* pass in the `siteConfig` as part of the options as below:
10 |
11 | ```js
12 | import createContentLoader from '@lando/vitepress-theme-default-plus/ccl';
13 |
14 | const siteConfig = globalThis.VITEPRESS_CONFIG;
15 |
16 | export default createContentLoader('posts/*.md', {siteConfig});
17 | ```
18 |
--------------------------------------------------------------------------------
/utils/normalize-mvb.js:
--------------------------------------------------------------------------------
1 | export default function({
2 | base = '/v/',
3 | build = 'stable',
4 | cache = true,
5 | match = 'v[0-9].*',
6 | mvbase = undefined,
7 | satisfies = '*',
8 | siteBase = '/',
9 | } = {}) {
10 | // if no mvbase then combine it with sitebase as usual, this is probabyl base reality
11 | if (!mvbase) mvbase = `/${siteBase}/${base}/`.replace(/\/{2,}/g, '/');
12 |
13 | // if we are in a MVB then the OG base can get lost so rebase on that
14 | if (process.env.VPL_MVB_BUILD) mvbase = `/${process.env.VPL_MVB_BASE}/${base}/`.replace(/\/{2,}/g, '/');
15 | if (process.env.LANDO_MVB_BUILD) mvbase = `/${process.env.LANDO_MVB_BASE}/${base}/`.replace(/\/{2,}/g, '/');
16 |
17 | // return
18 | return {base, build, cache, match, mvbase, satisfies};
19 | };
20 |
--------------------------------------------------------------------------------
/.github/workflows/pr-linter.yml:
--------------------------------------------------------------------------------
1 | name: Lint Code
2 |
3 | on:
4 | pull_request:
5 |
6 | jobs:
7 | lint:
8 | runs-on: ${{ matrix.os }}
9 | strategy:
10 | matrix:
11 | os:
12 | - ubuntu-24.04
13 | node-version:
14 | - '20'
15 | steps:
16 | # Install deps and cache
17 | - name: Checkout code
18 | uses: actions/checkout@v4
19 | - name: Install node ${{ matrix.node-version }}
20 | uses: actions/setup-node@v4
21 | with:
22 | node-version: ${{ matrix.node-version }}
23 | cache: npm
24 | - name: Install dependencies
25 | run: npm clean-install --prefer-offline --frozen-lockfile
26 |
27 | # Run the linter
28 | - name: Run code linter
29 | run: npm run lint
30 |
--------------------------------------------------------------------------------
/docs/public/lando/favicon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/public/lando/icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/guides.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Home helpful guides for the VitePress Default Theme Plus.
3 | layout: page
4 | title: Guides
5 | sidebar: false
6 | ---
7 |
8 |
9 |
10 | Guides
11 |
12 |
13 | Helpful tutorial-like content!
14 |
15 |
16 |
17 |
18 |
19 |
20 |
26 |
--------------------------------------------------------------------------------
/docs/blog.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Home helpful guides for the VitePress Default Theme Plus.
3 | layout: page
4 | title: Blog
5 | sidebar: false
6 | ---
7 |
8 |
9 |
10 | DAT BLOG
11 |
12 |
13 | Refined and sophisticated content for the modern developer.
14 |
15 |
16 |
17 |
18 |
19 |
20 |
26 |
--------------------------------------------------------------------------------
/utils/is-dev-release.js:
--------------------------------------------------------------------------------
1 | import * as semver from 'es-semver';
2 |
3 | export default function(version) {
4 | // throw error if not a valid version
5 | if (semver.valid(semver.clean(version)) === null) {
6 | throw new Error(`${version} must be a semantic version for this to work!`);
7 | }
8 |
9 | // parse the version
10 | version = semver.parse(version);
11 |
12 | // if prerelease is empty then this is stable version
13 | if (version.prerelease.length === 0) return false;
14 |
15 | // if prerelease is length 2 with string and integer parts then this is a non-dev prerelease
16 | if (version.prerelease.length === 2 && typeof version.prerelease[0] === 'string' && Number.isInteger(version.prerelease[1])) {
17 | return false;
18 | }
19 |
20 | // if we get here then lets just assume its a dev release?
21 | return true;
22 | }
23 |
--------------------------------------------------------------------------------
/utils/get-timestamp.js:
--------------------------------------------------------------------------------
1 | import {existsSync} from 'node:fs';
2 | import {basename, dirname} from 'node:path';
3 |
4 | import Debug from 'debug';
5 |
6 | import {default as execSync} from './parse-stdout.js';
7 |
8 | export default function async(file,
9 | {
10 | debug = Debug('@lando/get-timestamp'), // eslint-disable-line
11 | } = {},
12 | ) {
13 | // blow up
14 | const cwd = dirname(file);
15 | const fileName = basename(file);
16 |
17 | // if this is a new file then i guess just return now?
18 | if (!existsSync(cwd)) return Date.now();
19 |
20 | // command and opts
21 | const command = ['git', 'log', '-1', '--pretty="%ai"', fileName];
22 | const opts = {cwd, stdin: 'inherit'};
23 |
24 | // run
25 | debug('running command %o with exec options %o', command, opts);
26 | const stdout = execSync(command.join(' '), opts);
27 | return stdout.trim();
28 | }
29 |
--------------------------------------------------------------------------------
/utils/get-base-url.js:
--------------------------------------------------------------------------------
1 | // @TODO: support other platforms besides netlify?
2 |
3 | export default function(landoPlugin) {
4 | // if VPL_BASE_URL is set then use that
5 | if (process.env?.VPL_BASE_URL) return process.env?.VPL_BASE_URL;
6 |
7 | // otherwise we can try other stuff if we are on something like netlify
8 | if (process.env?.NETLIFY && process.env.CONTEXT === 'production' && landoPlugin) return 'https://docs.lando.dev';
9 | if (process.env?.NETLIFY && process.env.CONTEXT === 'production') return process.env.URL;
10 | if (process.env?.NETLIFY && process.env.CONTEXT !== 'production') return process.env.DEPLOY_PRIME_URL;
11 |
12 | // if we get here and its a lando plugin we can safely assume https://docs.lando.dev, this is mostly for github actions testing
13 | if (landoPlugin) return 'https://docs.lando.dev';
14 |
15 | // return nothing
16 | return undefined;
17 | };
18 |
--------------------------------------------------------------------------------
/docs/composables/use-collection.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Learn about the VitePress Default Theme + useCollection composable.
3 | ---
4 |
5 | # useCollection
6 |
7 | You can `import` the `useCollection()` composable from `@lando/vitepress-theme-default-plus` and use it to create things like index `pages`, `prev` and `next` links and more.
8 |
9 | ```js
10 | const {
11 | hasItems,
12 | pages,
13 | page,
14 | nextPage,
15 | prevnext,
16 | prevPage,
17 | path,
18 | tags,
19 | } = useCollection();
20 | ```
21 |
22 | Or target a specific collection:
23 |
24 | ```js
25 | const data = useCollection('post');
26 | ```
27 |
28 | Here is how we generate our `/all` index page which contains a good mix of the most useful things above:
29 |
30 | ```html
31 |
32 | ```
33 |
34 | For more detail on `Collections` components you can check [this](/pages/collections).
35 |
--------------------------------------------------------------------------------
/docs/v/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: All Other documentation versions
3 | title: Docuverse
4 | contributors: false
5 | lastUpdated: false
6 | editLink: false
7 | next: false
8 | prev: false
9 | ---
10 | # Docuverse
11 |
12 |
13 |
14 |
15 |
20 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
40 |
--------------------------------------------------------------------------------
/docs/composables/use-tags.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Learn about the VitePress Default Theme + useTags composable.
3 | ---
4 |
5 | # useTags
6 |
7 | You can `import` the `useTags()` composable from `@lando/vitepress-theme-default-plus` and use it to create a docs version index page or to show other taggy things.
8 |
9 | ```js
10 | const {
11 | // alias:ref pairs
12 | aliases,
13 | // alias:link pairs
14 | aliasLinks,
15 | // extended version information
16 | extended,
17 | // versions prepared for injection into `VPLVersionLink`
18 | links,
19 | // a list of all matched and satisfied versions
20 | versions,
21 | } = useTeam();
22 | ```
23 |
24 | Note that `aliasLinks` and `links` will _only_ be available if you've configured [Multiversion Build](./../config/config.md#multiversion-build).
25 |
26 | Here is how we generate our version [index page](/v/) at `/v/`.
27 |
28 | ```md
29 |
30 | ```
31 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "node": true,
4 | "mocha": true,
5 | "es6": true
6 | },
7 | "parser": "vue-eslint-parser",
8 | "parserOptions": {
9 | "parser": "babel-eslint",
10 | "allowImportExportEverywhere": true,
11 | "sourceType": "module",
12 | "ecmaVersion": 9
13 | },
14 | "extends": [
15 | "plugin:vue/recommended",
16 | "google"
17 | ],
18 | "rules": {
19 | "vue/multi-word-component-names": 0,
20 | "linebreak-style": 0,
21 | "arrow-parens": ["error",
22 | "as-needed"
23 | ],
24 | "max-len": ["error", {
25 | "code": 12000,
26 | "ignoreComments": true
27 | }],
28 | "require-jsdoc": ["error", {
29 | "require": {
30 | "FunctionDeclaration": false,
31 | "MethodDefinition": false,
32 | "ClassDeclaration": false,
33 | "ArrowFunctionExpression": false,
34 | "FunctionExpression": false
35 | }
36 | }]
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/docs/markdown/boxes.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Learn about custom boxes markdown containers in VitePress Default Theme +
3 | ---
4 |
5 | # Box Containers
6 |
7 | Boxes are basically [admonitions](./admonitions.md) without the title and are about the _color_ instead of the _type_.
8 |
9 | ::: box
10 | This is a box.
11 | :::
12 |
13 | ::: box-blue
14 | This is a blue box.
15 | :::
16 |
17 | ::: box-brand
18 | This is a brand box.
19 | :::
20 |
21 | ::: box-green
22 | This is a green box.
23 | :::
24 |
25 | ::: box-red
26 | This is a red box.
27 | :::
28 |
29 | ::: box-yellow
30 | This is a yellow box.
31 | :::
32 |
33 | The above is achieved with the following markdown:
34 |
35 | ```md
36 | ::: box
37 | This is a box.
38 | :::
39 |
40 | ::: box-blue
41 | This is a blue box.
42 | :::
43 |
44 | ::: box-brand
45 | This is a brand box.
46 | :::
47 |
48 | ::: box-green
49 | This is a green box.
50 | :::
51 |
52 | ::: box-red
53 | This is a red box.
54 | :::
55 |
56 | ::: box-yellow
57 | This is a yellow box.
58 | :::
59 | ```
60 |
61 |
--------------------------------------------------------------------------------
/node/build-collections.js:
--------------------------------------------------------------------------------
1 | import fg from 'fast-glob';
2 | import Debug from 'debug';
3 |
4 | export default async function(siteConfig, {debug = Debug('@lando/build-collections')} = {}) { // eslint-disable-line
5 | // ensure siteConfig.collections is at least an empty object
6 | if (!siteConfig.collections || typeof siteConfig.collections !== 'object') siteConfig.collections = {};
7 |
8 | // before we start lets make sure we have a list of paths for each collection
9 | // we do it like this to minimize running fastglob a bunch of times
10 | for (const [collection, config] of Object.entries(siteConfig?.site?.themeConfig?.collections ?? {})) {
11 | if (!Array.isArray(siteConfig.collections[collection])) {
12 | siteConfig.collections[collection] = fg.globSync(config.patterns ?? [], {
13 | dot: true,
14 | cwd: siteConfig.srcDir,
15 | onlyFiles: true,
16 | });
17 | debug('built collection %o with page listing %o', collection, siteConfig.collections[collection]);
18 | }
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/docs/composables/use-team.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Learn about the VitePress Default Theme + useTeam composable.
3 | ---
4 |
5 | # useTeam
6 |
7 | You can `import` the `useTeam()` composable from `@lando/vitepress-theme-default-plus` and use it to create a team or contributors page.
8 |
9 | ```js
10 | const members = useTeam();
11 | ```
12 |
13 | Here is how we generate our `/team` page:
14 |
15 | ```html
16 |
17 |
18 |
19 | Contributors
20 |
21 |
22 | We are the people who made this thing.
23 |
24 |
25 |
26 |
27 |
28 |
35 | ```
36 |
37 | For more detail on `Team` components you can check [this](/pages/teams).
38 |
--------------------------------------------------------------------------------
/markdown/tabs-override-plugin.js:
--------------------------------------------------------------------------------
1 | import container from 'markdown-it-container';
2 | import Debug from 'debug';
3 |
4 | const parseTabsParams = input => {
5 | const match = input.match(/key:(\S+)/);
6 | return {shareStateKey: match?.[1]};
7 | };
8 |
9 | export default function(md, {debug = Debug('@lando/markdown-plugin')}) { // eslint-disable-line
10 | md.use(container, 'tabs', {
11 | render(tokens, index, _options, env) {
12 | const token = tokens[index];
13 | const style = token.info.trim().slice(4).trim();
14 |
15 | if (token.nesting === 1) {
16 | const params = parseTabsParams(token.info);
17 | const shareStateKeyProp = params.shareStateKey
18 | ? `sharedStateKey="${md.utils.escapeHtml(params.shareStateKey)}"`
19 | : '';
20 | return `\n`;
21 | } else {
22 | return `\n`;
23 | }
24 | },
25 | });
26 | debug('override custom markdown container %o with styling support', 'vitepress-plugin-tabs');
27 | };
28 |
--------------------------------------------------------------------------------
/docs/install.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Learn how to install and get started with VitePress Default Theme Plus!
3 | ---
4 |
5 | # Installation
6 |
7 | * [Node.js](https://nodejs.org/) version 18 or higher.
8 | * Terminal for accessing VitePress via its command line interface (CLI).
9 | * Text Editor with [Markdown](https://en.wikipedia.org/wiki/Markdown) syntax support.
10 | * [VSCode](https://code.visualstudio.com/) is recommended, along with the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar).
11 |
12 | VitePress can be used on its own, or be installed into an existing project. In both cases, you can install it with:
13 |
14 | ::: code-group
15 | ```sh [npm]
16 | $ npm install -D vitepress @lando/vitepress-theme-default-plus
17 | ```
18 |
19 | ```sh [pnpm]
20 | $ pnpm add -D vitepress @lando/vitepress-theme-default-plus
21 | ```
22 |
23 | ```sh [yarn]
24 | $ yarn add -D vitepress @lando/vitepress-theme-default-plus
25 | ```
26 |
27 | ```sh [bun]
28 | $ bun add -D vitepress @lando/vitepress-theme-default-plus
29 | ```
30 | :::
31 |
--------------------------------------------------------------------------------
/utils/create-container.js:
--------------------------------------------------------------------------------
1 | import container from 'markdown-it-container';
2 |
3 | export default function(name, opts = {}, md) {
4 | return [container, name, {
5 | render(tokens, index, _options, env) {
6 | const token = tokens[index];
7 | const info = token.info.trim().slice(name.length).trim() || opts.defaultTitle;
8 | const attrs = md.renderer.renderAttrs(token);
9 |
10 | // opening tag
11 | if (token.nesting === 1) {
12 | const title = info ? md.renderInline(info, {references: env.references}) : undefined;
13 | const titleMarkdown = title ? `
${title ? title : ''}
` : '';
14 |
15 | // special handling for details
16 | if (name === 'details') return `${title}\n`;
17 | // otherwise
18 | return `
${titleMarkdown}\n`;
19 |
20 | // closing tag
21 | } else return name === 'details' ? `\n` : `
\n`;
22 | }},
23 | ];
24 | };
25 |
--------------------------------------------------------------------------------
/client/use-tags.js:
--------------------------------------------------------------------------------
1 | import {data as tags} from './tags.data.js';
2 |
3 | import {useData} from 'vitepress';
4 |
5 | export default function useTags() {
6 | // get version path data
7 | const {theme} = useData();
8 | // if no mvb then just return tags
9 | if (!theme.value.multiVersionBuild) return tags;
10 |
11 | // otherwise lets augment it with links and shit!
12 | const {base} = theme.value.multiVersionBuild;
13 |
14 | // generate links we can pass into VPLVersionLink
15 | const links = tags.versions
16 | .map(version => ({
17 | text: version,
18 | href: `/${base}/${version}/`.replace(/\/{2,}/g, '/'),
19 | prerelease: /^v?\d+\.\d+\.\d+-\S+$/.test(version),
20 | stable: tags?.aliases?.stable === version,
21 | edge: tags?.aliases?.edge === version,
22 | }));
23 |
24 | // also generate alias linkes
25 | const aliasLinks = {
26 | dev: `/${base}/dev/`.replace(/\/{2,}/g, '/'),
27 | edge: `/${base}/edge/`.replace(/\/{2,}/g, '/'),
28 | stable: `/${base}/stable/`.replace(/\/{2,}/g, '/'),
29 | };
30 |
31 | return {...tags, links, aliasLinks};
32 | }
33 |
--------------------------------------------------------------------------------
/utils/get-branch.js:
--------------------------------------------------------------------------------
1 | import {default as getStdOut} from './parse-stdout.js';
2 |
3 | export default function async(cwd = process.cwd()) {
4 | // lando build env directly
5 | if (process.env?.VPL_MVB_BRANCH) return process.env?.VPL_MVB_BRANCH;
6 | // lando build env directly
7 | else if (process.env?.LANDO_MVB_BRANCH) return process.env?.LANDO_MVB_BRANCH;
8 | // or from source
9 | else if (process.env?.VPL_MVB_SOURCE) return getStdOut('git rev-parse --abbrev-ref HEAD', {cwd: process.env?.VPL_MVB_SOURCE, trim: true});
10 | // or from source
11 | else if (process.env?.LANDO_MVB_SOURCE) return getStdOut('git rev-parse --abbrev-ref HEAD', {cwd: process.env?.LANDO_MVB_SOURCE, trim: true});
12 | // or if we are on netlify
13 | else if (process.env?.NETLIFY) return process.env.HEAD;
14 | // or GHA PR
15 | else if (process.env?.GITHUB_HEAD_REF) return process.env.GITHUB_HEAD_REF;
16 | // or GHA branch
17 | else if (process.env?.GITHUB_REF_NAME) return process.env.GITHUB_REF_NAME;
18 | // otherwise try to get it from git
19 | else return getStdOut('git rev-parse --abbrev-ref HEAD', {cwd, trim: true});
20 | };
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Lando Alliance
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/docs/components/jobs.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Learn about the VitePress Default Theme + global Jobs components.
3 | jobs:
4 | - title: 'Lando Developer'
5 | logo: 'https://docs.lando.dev/images/icon.svg'
6 | link: 'https://docs.google.com/forms/d/e/1FAIpQLSc2vkesq59BblKo8ZX-R1hKTrHphh1kmsg4FgWV1WH5BKEjHQ/viewform'
7 | company: 'Lando Alliance'
8 | aux: 'DC, Remote'
9 | ---
10 |
11 | # Jobs
12 |
13 | ### Usage
14 |
15 | To populate `` you will want to set the theme config [here](../config/config.html#jobs).
16 |
17 | You can also customize or disable the jobs on a per-page basis with [frontmatter](../config/frontmatter.html#jobs).
18 |
19 | ```html
20 |
21 | ```
22 |
23 | ### Example - Defaults
24 |
25 | ```html
26 |
27 | ```
28 |
29 |
30 |
31 | ### Example - Custom Title
32 |
33 |
34 | ```html
35 |
36 | ```
37 |
38 |
39 |
40 | ### Example - No Title
41 |
42 | ```html
43 |
44 | ```
45 |
46 |
47 |
48 | ::: tip NOTE
49 | You must use `:title` and not `title` to parse `"false"` correctly.
50 | :::
51 |
--------------------------------------------------------------------------------
/docs/guides/making-a-guide.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Learn how to automatically populate guide content using the VitePress Default Theme Plus.
3 | image: https://external-preview.redd.it/mj-2SFKKXAMK3tXrlo1smwLCSIantySqxSgfgMoJH2U.jpg?width=640&crop=smart&auto=webp&s=4f983b744fba16877e80218131a917b92904af26
4 | tag: tag 2
5 | ---
6 |
7 | # Making a guide
8 |
9 | Guides are _how tos_ or _tutorials_ that fit somewhere in between technical documentation and blog posts. They generally
10 | seek to answer a single question such as "How do I create a guide using this theme?" and are heavy on code snippets.
11 |
12 | In this case there are actually two ways to create a guide:
13 |
14 | * Autopopulating data from the `git log`.
15 | * [Manually entering data](./making-a-guide-2.html)
16 |
17 | ## Autopopulating data from `git log`
18 |
19 | You don't really have to do anything. Just make a commit to this page and you will show up like `Mike Pirog` does for this one. If you want to augment the `git log` data you should check out [this](../config/config#contributors).
20 |
21 | If you are interested in manually setting the `authors`, `date` and edit link then check out [Making a Guide 2](./making-a-guide-2.html)
22 |
--------------------------------------------------------------------------------
/node/augment-authors.js:
--------------------------------------------------------------------------------
1 | import Debug from 'debug';
2 |
3 | const getContributor = (id, contributors = []) => contributors.find(contributor => contributor.email === id)
4 | ?? contributors.find(contributor => contributor.name === id);
5 |
6 | const getLink = author => {
7 | if (author.link) return author.link;
8 | else if (Array.isArray(author?.links) && author.links[0]) return author.links[0].link;
9 | else if (author.email) return `mailto:${author.email}`;
10 | };
11 |
12 | export default async function(pageData, {
13 | team,
14 | debug = Debug('@lando/augment-authors'), // eslint-disable-line
15 | } = {}) {
16 | debug = debug.extend(`${pageData.relativePath}`);
17 | const {frontmatter} = pageData;
18 |
19 | // normalize and augment author info
20 | if (Array.isArray(frontmatter.authors)) {
21 | frontmatter.authors = frontmatter.authors
22 | .map(author => typeof author === 'string' ? getContributor(author, team) : author)
23 | .filter(author => author && author !== false && author !== null)
24 | .map(author => ({...author, link: getLink(author)}));
25 | }
26 |
27 | // log
28 | debug('augmented author information to %o', {authors: frontmatter.authors});
29 | };
30 |
--------------------------------------------------------------------------------
/docs/usage.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Learn how to install and get started with VitePress Default Theme Plus!
3 | ---
4 |
5 | # Usage
6 |
7 | Before starting make sure you are familiar with [the basics](https://vitepress.dev/guide/getting-started#file-structure) of VitePress theme installation.
8 |
9 | To start using the theme you will want to create `.vitepress/theme/index.mjs` and `.vitepress/config.mjs` as below:
10 |
11 | ## .vitepress/theme/index.mjs
12 |
13 | ```js
14 | import {VPLTheme} from '@lando/vitepress-theme-default-plus';
15 | export default VPLTheme;
16 | ```
17 |
18 | If you want to extend our theme you should consult the [official docs](https://vitepress.dev/guide/extending-default-theme) on how to best do that.
19 |
20 | ## .vitepress/config.mjs
21 |
22 | Import our `defineConfig` wrapper and pass in hte [configuration](./config/config) you want.
23 |
24 | ```js
25 | import {defineConfig} from '@lando/vitepress-theme-default-plus/config';
26 |
27 | export default defineConfig({
28 | title: 'VitePress Theme +',
29 | description: 'The VitePress default theme with some MOARPOWAH!',
30 | base: '/',
31 | lang: 'en-US',
32 | themeConfig: {
33 | ...
34 | },
35 | ...
36 | });
37 | ```
38 |
--------------------------------------------------------------------------------
/components/VPLYouTube.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
14 |
15 |
16 |
17 |
29 |
30 |
58 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | base = "./"
3 | publish = "docs/.vitepress/dist/"
4 | command = "npx mvb docs"
5 |
6 | [context.deploy-preview]
7 | command = "npm run build"
8 | # https://github.com/munter/netlify-plugin-checklinks#readme
9 | [[context.deploy-preview.plugins]]
10 | package = "netlify-plugin-checklinks"
11 | [context.deploy-preview.plugins.inputs]
12 | todoPatterns = [ "load", "CHANGELOG.html", "x.com", "twitter.com", "/v/" ]
13 | skipPatterns = [ ".rss", ".gif", ".jpg", "--vitepress-theme-default-plus.netlify.app" ]
14 | checkExternal = true
15 |
16 | # Sets our asset optimization
17 | [build.processing.css]
18 | bundle = true
19 | minify = true
20 | [build.processing.js]
21 | bundle = true
22 | minify = true
23 | [build.processing.html]
24 | pretty_urls = false
25 | [build.processing.images]
26 | compress = true
27 |
28 | # Caches our images for 1 year
29 | [[headers]]
30 | for = "/images/*"
31 | [headers.values]
32 | Cache-Control = "public, max-age=31536000"
33 |
34 | # https://github.com/netlify/netlify-plugin-lighthouse#readme
35 | [[plugins]]
36 | package = "@netlify/plugin-lighthouse"
37 | [plugins.inputs.audits]
38 | output_path = "reports/lighthouse.html"
39 |
--------------------------------------------------------------------------------
/node/normalize-legacy-frontmatter.js:
--------------------------------------------------------------------------------
1 | import Debug from 'debug';
2 |
3 | export default async function(pageData, {
4 | siteConfig,
5 | debug = Debug('@lando/normalize-legacy-frontmatter'), // eslint-disable-line
6 | } = {}) {
7 | debug = debug.extend(`${pageData.relativePath}`);
8 | const {frontmatter} = pageData;
9 |
10 | // map and remove legacy vuepress2 theme blog setting
11 | if (!frontmatter.collection && frontmatter.blog === true) {
12 | pageData.frontmatter.collection = 'post';
13 | delete pageData.frontmatter.blog;
14 | debug('mapped frontmatter.blog to frontmatter.collection === post');
15 |
16 | // ditto for guide setting
17 | } else if (!frontmatter.collection && frontmatter.guide === true) {
18 | pageData.frontmatter.collection = 'guide';
19 | delete pageData.frontmatter.guide;
20 | debug('mapped frontmatter.guide to frontmatter.collection === guide');
21 | }
22 |
23 | // ditto for updated
24 | if (!frontmatter.date && frontmatter?.updated?.timestamp) {
25 | pageData.frontmatter.date = frontmatter.updated.timestamp;
26 | delete pageData.frontmatter.updated.timestamp;
27 | debug('mapped frontmatter.updated.timestamp to frontmatter.date');
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/vite/add-layout-components-plugin.js:
--------------------------------------------------------------------------------
1 | import Debug from 'debug';
2 | import {EOL} from 'node:os';
3 |
4 | const pivot = 'export default function(app) {';
5 |
6 | export default function(layouts = [], {debug = Debug('@lando/vite-plugin')}) { // eslint-disable-line
7 | return {
8 | name: 'inject-layouts',
9 | enforce: 'pre',
10 | transform: (code, id) => {
11 | const layoutfile = 'enhance-app-with-layouts.js';
12 | if (id.includes(layoutfile) && layouts.length > 0) {
13 | // get lines and pindex
14 | const lines = code.split(EOL);
15 | // get pivot line
16 | let pindex = lines.findIndex(line => line.startsWith(pivot));
17 | // loop through and add imports
18 | for (const layout of layouts.reverse()) lines.splice(pindex, 0, layout.import);
19 | // get pivot again
20 | pindex = lines.findIndex(line => line.startsWith(pivot)) + 1;
21 | // loop through again and add components
22 | for (const layout of layouts.reverse()) lines.splice(pindex, 0, layout.add);
23 | // debug
24 | debug('autogenerated layout import file %o with content %O', layoutfile, lines);
25 | return lines.join(EOL);
26 | }
27 | },
28 | };
29 | };
30 |
--------------------------------------------------------------------------------
/docs/guides/adding-remote-content.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Loading remote content
3 | description: Learn how to add remote markdown file
4 | editLink:
5 | url: https://github.com/lando/setup-lando/edit/main/docs/windows.md
6 |
7 | tags:
8 | - url-loader
9 | url-loader:
10 | source: https://raw.githubusercontent.com/lando/setup-lando/refs/heads/main/docs/windows.md
11 | content: append
12 | frontmatter: false
13 | ---
14 |
15 | ::: tip Below content is loaded via URL
16 |
17 | The content in this page is loaded from `https://raw.githubusercontent.com/lando/setup-lando/refs/heads/main/docs/windows.md`. Below is the actual frontmatter for this page that makes this whole thing possible.
18 |
19 | **Note that the content below is the Windows installer instructions for Lando and has nothing to do with this theme. We are just using it as an example of how `url-loader` works.**
20 |
21 | ```md
22 | title: Loading remote content
23 | description: Learn how to add remote markdown file
24 | editLink:
25 | url: https://github.com/lando/setup-lando/edit/main/docs/windows.md
26 |
27 | tags:
28 | - url-loader
29 | url-loader:
30 | source: https://raw.githubusercontent.com/lando/setup-lando/refs/heads/main/docs/windows.md
31 | content: append
32 | frontmatter: false
33 | ```
34 | :::
35 |
--------------------------------------------------------------------------------
/components/VPLCollectionPageTags.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
14 |
36 |
37 |
53 |
--------------------------------------------------------------------------------
/node/add-contributors.js:
--------------------------------------------------------------------------------
1 | import Debug from 'debug';
2 |
3 | import {default as resolveGitPaths} from '../utils/resolve-git-paths.js';
4 | import {default as getContributors} from '../utils/get-contributors.js';
5 |
6 | export default async function(pageData, {
7 | debug = Debug('@lando/add-contributors'), // eslint-disable-line
8 | siteConfig,
9 | } = {}) {
10 | debug = debug.extend(`${pageData.relativePath}`);
11 | // get path
12 | const {frontmatter, relativePath} = pageData;
13 | // compute git things
14 | const gitDir = siteConfig?.userConfig?.gitRoot;
15 | const gitPaths = resolveGitPaths(relativePath, siteConfig.srcDir.replace(`${gitDir}/`, ''), frontmatter['git-include']);
16 |
17 | // get contributors
18 | const contributors = frontmatter.contributors || siteConfig?.site?.themeConfig?.contributors || false;
19 |
20 | // add contributors unless turned off
21 | if (contributors !== false) {
22 | try {
23 | pageData.contributors = await getContributors(gitDir, contributors, {debug, paths: gitPaths});
24 | debug('set contributors %o', pageData.contributors);
25 | } catch (error) {
26 | debug('could not get contributor information, considering this non-fatal but you should investigate and resolve');
27 | console.error(error);
28 | }
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/docs/components/mailchimp.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Learn about the VitePress Default Theme + global MailChimp components.
3 | ---
4 |
5 | # MailChimp
6 |
7 | ### Usage
8 |
9 | You'll need to get the form action URL for the MailChimp audience you want the user to subscribe to. If you are not sure what that is all about then [check this out](https://mailchimp.com/help/determine-webpage-signup-location/).
10 |
11 | Otherwise you can embed the below directly into a `.vue` or `.md` file.
12 |
13 | ```html
14 |
20 | ```
21 |
22 | ### Example
23 |
24 | ```html
25 |
31 | ```
32 |
33 |
39 |
--------------------------------------------------------------------------------
/docs/markdown/admonitions.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Learn about custom admonition markdown containers in VitePress Default Theme +
3 | ---
4 |
5 | # Admonition Containers
6 |
7 | Note that some of the below are actually provided by the [default theme](https://vitepress.dev/guide/markdown#custom-containers) but we've enumerated them here as well for completeness.
8 |
9 | ::: brand
10 | This is a brand block.
11 | :::
12 |
13 | ::: tip
14 | This is a tip.
15 | :::
16 |
17 | ::: success
18 | This is a success!
19 | :::
20 |
21 | ::: warning
22 | This is a warning.
23 | :::
24 |
25 | ::: danger
26 | This is a dangerous warning.
27 | :::
28 |
29 | ::: details
30 | This is a details block.
31 | :::
32 |
33 | ::: success WE CHANGED IT!
34 | All admonition containers can customize their title like this.
35 | :::
36 |
37 | The above is achieved with the following markdown:
38 |
39 | ```md
40 | ::: brand
41 | This is a brand block.
42 | :::
43 |
44 | ::: tip
45 | This is a tip.
46 | :::
47 |
48 | ::: success
49 | This is a success!
50 | :::
51 |
52 | ::: warning
53 | This is a warning.
54 | :::
55 |
56 | ::: danger
57 | This is a dangerous warning.
58 | :::
59 |
60 | ::: details
61 | This is a details block.
62 | :::
63 |
64 | ::: success WE CHANGED IT!
65 | All admonition containers can customize their title like this.
66 | :::
67 | ```
68 |
69 |
--------------------------------------------------------------------------------
/components/VPLCollectionPageTitle.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
13 |
14 |
15 |
16 |
17 |
18 |
70 |
--------------------------------------------------------------------------------
/docs/guides/guide-signup.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Adding a guide signup
3 | description: Learn how to easily add a guide newsletter signup.
4 | guide: true
5 | mailchimp:
6 | action: https://dev.us12.list-manage.com/subscribe/post?u=59874b4d6910fa65e724a4648&id=613837077f
7 | title: Want similar content?
8 | byline: Signup and we will send you a weekly blog digest of similar content to keep you satiated.
9 | button: Sign me up!
10 | tag:
11 | - tag 1
12 | - tag 2
13 | - secret tag
14 | - other tag
15 | - something else
16 | - we are really tagging a lot here
17 | ---
18 |
19 | # Adding a guide signup
20 |
21 | While you can leverage the global [MailChimp](./../components/mailchimp) component to add a newsletter signup to any page we've added a way to invoke it through `frontmatter` for convenience.
22 |
23 | **Note that this _only_ works for Guide content.**
24 |
25 | Here is how we do it for this page:
26 |
27 | ```md
28 | ---
29 | title: Adding a guide signup
30 | description: Learn how to easily add a guide newsletter signup.
31 | guide: true
32 | mailchimp:
33 | # action is required
34 | action: https://dev.us12.list-manage.com/subscribe/post?u=59874b4d6910fa65e724a4648&id=613837077f
35 | # everything else is optional
36 | title: Want similar content?
37 | byline: Signup and we will send you a weekly blog digest of similar content to keep you satiated.
38 | button: Sign me up!
39 | ---
40 | ```
41 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Apple
10 | .DS_Store
11 |
12 | # Diagnostic reports (https://nodejs.org/api/report.html)
13 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
14 |
15 | # Runtime data
16 | pids
17 | *.pid
18 | *.seed
19 | *.pid.lock
20 |
21 | # Directory for instrumented libs generated by jscoverage/JSCover
22 | lib-cov
23 |
24 | # Coverage directory used by tools like istanbul
25 | coverage
26 | *.lcov
27 |
28 | # nyc test coverage
29 | .nyc_output
30 |
31 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
32 | .grunt
33 |
34 | # Bower dependency directory (https://bower.io/)
35 | bower_components
36 |
37 | # node-waf configuration
38 | .lock-wscript
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Optional REPL history
57 | .node_repl_history
58 |
59 | # Output of 'npm pack'
60 | *.tgz
61 |
62 | # Yarn Integrity file
63 | .yarn-integrity
64 |
65 | # dotenv environment variables file
66 | .env
67 | .env.test
68 |
69 | # docs
70 | .temp
71 | .cache
72 | _site
73 | dist
74 | cache
75 | temp
76 | config.*.timestamp-*-*.*
77 | *.data.js.timestamp-*-*.*
78 |
79 | # YARN
80 | yarn.lock
81 |
--------------------------------------------------------------------------------
/docs/development.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Learn how to help develop and contribute to VitePress Default Theme Plus.
3 | ---
4 |
5 | # Development
6 |
7 | ## Requirements
8 |
9 | * [Node.js](https://nodejs.org/) version 18 or higher.
10 | * Terminal for accessing VitePress via its command line interface (CLI).
11 | * Text Editor with [Markdown](https://en.wikipedia.org/wiki/Markdown) syntax support.
12 | * [VSCode](https://code.visualstudio.com/) is recommended, along with the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar).
13 |
14 | VitePress can be used on its own, or be installed into an existing project. In both cases, you can install it with:
15 |
16 | ## Up and Running
17 |
18 | ```sh
19 | # clone repo and install deps
20 | git clone https://github.com/lando/vitepress-theme-default-plus.git &&
21 | \ cd vitepress-theme-default-plus &&
22 | \ npm install
23 |
24 | # start dev server
25 | npm run dev
26 | ```
27 |
28 | ## Testing
29 |
30 | ```sh
31 | npm run test
32 | ```
33 |
34 | ## Building
35 |
36 | ```sh
37 | # build the static site
38 | npm run build
39 |
40 | # preview the static site
41 | npm run preview
42 | ```
43 |
44 | ## Releasing
45 |
46 | An actual release to `npm` can be done by [creating a release on GitHub](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository). Pre-releases will deploy to `@edge` tag.
47 |
48 | This will also trigger our [prepare release](https://github.com/lando/prepare-release-action) and [auto-deploy](https://github.com/lando/auto-deploy-action) actions.
49 |
--------------------------------------------------------------------------------
/vite/patch-vp-use-sidebar-control.js:
--------------------------------------------------------------------------------
1 | import Debug from 'debug';
2 | import {EOL} from 'node:os';
3 |
4 | export default function({debug = Debug('@lando/vite-plugin')}) { // eslint-disable-line
5 | return {
6 | name: 'vp-use-sidebar-control',
7 | enforce: 'pre',
8 | transform: (code, id) => {
9 | const supportfile = 'dist/client/theme-default/composables/sidebar.js';
10 | if (id.includes(supportfile)) {
11 | // prepend our mvb normalizer
12 | code = `import { getItemNormalizedLink } from '@lando/vitepress-theme-default-plus';${EOL}${code}`;
13 | code = `import { normalizeItems } from '@lando/vitepress-theme-default-plus';${EOL}${code}`;
14 |
15 | // make sure we get "site" as well
16 | code = code.replace(
17 | 'const { page, hash } = useData()',
18 | 'const { site, page, hash } = useData()',
19 | );
20 |
21 | // and then use getItemNormalizedLink
22 | code = code.replace(
23 | 'isActive(page.value.relativePath, item.value.link)',
24 | 'isActive(page.value.relativePath, getItemNormalizedLink(item.value, site.value))',
25 | );
26 |
27 | // and also use normalizeItems
28 | code = code.replace(
29 | 'containsActiveLink(page.value.relativePath, item.value.items)',
30 | 'containsActiveLink(page.value.relativePath, normalizeItems(item.value.items, site.value))',
31 | );
32 |
33 | // log
34 | debug('patched %o to use getItemNormalizedLink', supportfile);
35 | return code;
36 | }
37 | },
38 | };
39 | };
40 |
--------------------------------------------------------------------------------
/components/VPLCollectionPage.vue:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
56 |
57 |
117 |
--------------------------------------------------------------------------------
/docs/blog/making-a-blog-post-2.md:
--------------------------------------------------------------------------------
1 | ---
2 | byline: Blog posts are free form articles that may or may not be techincal in nature. They differ slightly from guides primarily in their presentation and authorship.
3 | blog: true
4 | date: January 11, 2024
5 | location: The Interwebs
6 | contributors: false
7 | mailchimp:
8 | action: https://dev.us12.list-manage.com/subscribe/post?u=59874b4d6910fa65e724a4648&id=613837077f
9 | title: Want more Pirog themed content?
10 | byline: Signup and we will send you a weekly blog digest of similar content to keep you satiated.
11 | button: Sign me up!
12 | tags:
13 | - this is a test tag
14 | ---
15 |
16 | # Making a post 2
17 |
18 | Specifically, they make use of a `byline` and can only have a single, manually entered, author. They can be thought of more like "traditional" news media articles. Like guides you can create them in two ways:
19 |
20 | :::tip Mixed signals?
21 | Yes, we know that this actually should be a `Guide` instead of a blog post! However, in this weird case we think its better to use `BlogPost` so we can best illustrate the capabilities.
22 | :::
23 |
24 | ## Basics
25 |
26 | ```md
27 | ---
28 | title: "Making A Blog Post: It's sort of like a guide but it's sort of not like a guide"
29 | byline: Blog posts are free form articles that may or may not be techincal in nature. They differ slightly from guides primarily in their presentation and authorship.
30 | blog: true
31 | ---
32 | ```
33 |
34 | ::: warning You must set the title!
35 | Note that because of how the underlying components are layered and called you must set the title in the frontmatter. This will populate the `h1` on the page. You can and should then omit the `h1` in the markdown content itself.
36 | :::
37 |
38 | You can check out the full markdown file that generated this page [here](https://github.com/lando/vitepress-theme-default-plus/blob/main/docs/guides/making-a-guide-2.md). If you are interested in manually setting the `authors`, `date` and edit link then check out [Making a Guide 2](../guides/making-a-guide-2.html)
39 |
40 | ## Authorship
41 |
42 | You must at least specify a name!
43 |
44 | ```md
45 | ---
46 | author:
47 | name: Mike Pirog
48 | link: mailto:mike@lando.dev
49 | pic: https://gravatar.com/avatar/dc1322b3ddd0ef682862d7f281c821bb
50 | location: Washington, DC
51 | ---
52 | ```
53 |
54 | ## Signup
55 |
56 | ```md
57 | ---
58 | mailchimp:
59 | action: https://dev.us12.list-manage.com/subscribe/post?u=59874b4d6910fa65e724a4648&id=613837077f
60 | title: Want more Pirog themed content?
61 | byline: Signup and we will send you a weekly blog digest of similar content to keep you satiated.
62 | button: Sign me up!
63 | ---
64 | ```
65 |
--------------------------------------------------------------------------------
/docs/blog/making-a-blog-post.md:
--------------------------------------------------------------------------------
1 | ---
2 | byline: Blog posts are free form articles that may or may not be techincal in nature. They differ slightly from guides primarily in their presentation and authorship.
3 | blog: true
4 | date: January 11, 2024
5 | location: Washington, DC
6 | mailchimp:
7 | action: https://dev.us12.list-manage.com/subscribe/post?u=59874b4d6910fa65e724a4648&id=613837077f
8 | title: Want more Pirog themed content?
9 | byline: Signup and we will send you a weekly blog digest of similar content to keep you satiated.
10 | button: Sign me up!
11 | tags:
12 | - this is a test tag
13 | ---
14 |
15 | # Making a blog post and other stuff like that
16 |
17 | Specifically, they make use of a `byline` and can only have a single, manually entered, author. They can be thought of more like "traditional" news media articles. Like guides you can create them in two ways:
18 |
19 | :::tip Mixed signals?
20 | Yes, we know that this actually should be a `Guide` instead of a blog post! However, in this weird case we think its better to use `BlogPost` so we can best illustrate the capabilities.
21 | :::
22 |
23 | ## Basics
24 |
25 | ```md
26 | ---
27 | title: "Making A Blog Post: It's sort of like a guide but it's sort of not like a guide"
28 | byline: Blog posts are free form articles that may or may not be techincal in nature. They differ slightly from guides primarily in their presentation and authorship.
29 | blog: true
30 | ---
31 | ```
32 |
33 | ::: warning You must set the title!
34 | Note that because of how the underlying components are layered and called you must set the title in the frontmatter. This will populate the `h1` on the page. You can and should then omit the `h1` in the markdown content itself.
35 | :::
36 |
37 | You can check out the full markdown file that generated this page [here](https://github.com/lando/vitepress-theme-default-plus/blob/main/docs/guides/making-a-guide.md). If you are interested in manually setting the `authors`, `date` and edit link then check out [Making a Guide 2](../guides/making-a-guide-2.html)
38 |
39 | ## Authorship
40 |
41 | You must at least specify a name!
42 |
43 | ```md
44 | ---
45 | author:
46 | name: Mike Pirog
47 | link: mailto:mike@lando.dev
48 | pic: https://gravatar.com/avatar/dc1322b3ddd0ef682862d7f281c821bb
49 | location: Washington, DC
50 | ---
51 | ```
52 |
53 | ## Signup
54 |
55 | ```md
56 | ---
57 | mailchimp:
58 | action: https://dev.us12.list-manage.com/subscribe/post?u=59874b4d6910fa65e724a4648&id=613837077f
59 | title: Want more Pirog themed content?
60 | byline: Signup and we will send you a weekly blog digest of similar content to keep you satiated.
61 | button: Sign me up!
62 | ---
63 | ```
64 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # VitePress Default Theme +
2 |
3 | This extends the [default VitePress theme](https://vitepress.dev/) with some extra power and features such as:
4 |
5 |
31 |
32 |
33 |
97 |
98 |
138 |
--------------------------------------------------------------------------------
/docs/pages/collections.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Learn about the VitePress Default Theme + collections components.
3 | ---
4 |
5 | # Collections Pages
6 |
7 | You can `import` some helpful `components` from `@lando/vitepress-theme-default-plus` and compose collections pages.
8 |
9 | This is especially useful when used in tandem with [useCollection()](../composables/use-collection.md).
10 |
11 | Here is what we do to create `/guide` for this site.
12 |
13 | ```html
14 |
15 | ```
16 |
17 | You can also check out [/all](/all) and its [code](https://github.com/lando/vitepress-theme-default-plus/blob/main/docs/all.md) for an example that combines all available collections components.
18 |
19 | ## \
20 |
21 | This is more or less just a wrapper to provide structure, styling and the downstream slots so the usage is fairly straightforward:
22 |
23 | ```html
24 |
25 | ...other stuff goes here
26 |
27 | ```
28 |
29 | ## \
30 |
31 | Provide a way to filter collection items based on their [tags](../config/frontmatter#tags).
32 |
33 | ```html
34 |
35 |
36 |
37 |
40 | ```
41 |
42 | Note that you can pass one or multiple `:tag` or `:tag-id`s as a query string to select tags. This is useful for creating URL for specific "tag pages". Here are some valid paths for this docs site:
43 |
44 | ```bash
45 | /all.html?tags=we-are-really-tagging-a-lot-here,this-is-a-test-tag
46 | /all.html?tag=we%20are%20really%20tagging%20a%20lot%20here
47 | ```
48 |
49 | ## \
50 |
51 | Provide a title and lead-in for the page.
52 |
53 | ```html
54 |
55 |
56 |
57 | ALL THE THINGS!
58 |
59 |
60 | A mix of different collectons all on one page but organized in different sections!
61 |
62 |
63 |
64 | ```
65 |
66 | ## \
67 |
68 | If you'd like to provide distinct sections on a collection page. You can do something like:
69 |
70 | ```html
71 |
72 |
73 |
74 | Guides
75 |
76 |
77 | Guides are sort of like tutorial adjacent things but with a tighter vibe.
78 |
79 |
80 |
81 |
82 |
83 |
84 | ```
85 |
86 | ## \
87 |
88 | Show some collection items.
89 |
90 | ```html
91 |
97 |
98 |
104 | ```
105 |
106 | You can set the `pager` to determine the amount of items to show before the "load more" button.
107 |
108 | You can change `more` to `date` if you want to see the date of the item instead of the "Read More" link.
109 |
--------------------------------------------------------------------------------
/components/VPLAlert.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
28 |
32 |
33 |
34 |
35 |
36 |
70 |
71 |
139 |
--------------------------------------------------------------------------------
/docs/guides/tagging-shit.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Some basic information around tagging stuff
3 | tags:
4 | - obscure
5 | - this is a test tag
6 | - tag 2
7 | - secret tag
8 | ---
9 |
10 | # Tagging shit
11 |
12 | There are a few different tagging related things in these docs so this guide tries to [tie the room together](https://www.youtube.com/watch?v=_vGK008c_rA) on it.
13 |
14 | ## What can I tag?
15 |
16 | Any [collections](../config/config.md#collections) based content can be tagged via [frontmatter](../config/frontmatter.md#tags) as below:
17 |
18 | ```md
19 | ---
20 | description: Some basic information around tagging stuff
21 | tags:
22 | - obscure
23 | - this is a test tag
24 | - tag 2
25 | ---
26 | ```
27 |
28 | ## Whats tags are available?
29 |
30 | By default you can "free tag" which means there is not a centralized or finite set of acceptable tags. You can, however, [customize the appearance](../config/config.md#tags) of the tags. For example you can change the styling, add an icon or change the `tagLink` for a specific tag.
31 |
32 | Look at the TAGS section in the aside for this page. The customization of those tags is provided by the below theme config:
33 |
34 | ```js
35 | tags: {
36 | 'obscure': {
37 | color: 'var(--vp-c-purple-1)',
38 | styles: {
39 | color: 'var(--vp-c-white)',
40 | },
41 | icon: '',
42 | },
43 | 'secret tag': {
44 | color: '#C0FFEE',
45 | icon: '',
46 | link: 'https://www.youtube.com/watch?v=HU2ftCitvyQ',
47 | styles: {
48 | color: '#BA11AD',
49 | },
50 | },
51 | 'tag 2': {
52 | icon: '',
53 | },
54 | },
55 | ```
56 |
57 | ## Where do the tags link to?
58 |
59 | You can provide a URL default pattern with [tagLink](../config/config.md#tag-link). This can then be overriden on a per-tag basis using `tags[tag].link`.
60 |
61 | In the [above section](#whats-tags-are-available) the `secret tag` has been customized to link externally to this [helpful rock climbing tutorial](https://www.youtube.com/watch?v=HU2ftCitvyQ).
62 |
63 | ## Can I add tags to a page?
64 |
65 | You can add a [filter](../pages/collections.md#vplcollectionpagetags) to a [Collections Page](../pages/collections.md). You can also get a list of a given pages Tags with the below:
66 |
67 | ```html
68 |
69 |
70 |
74 | ```
75 |
76 | ## Can I set tags with a URL?
77 |
78 | Yes! Here is a way to look at all the collections content on this page with the "obscure" tag:
79 |
80 | https://vitepress-theme-default-plus.lando.dev/all?tag=obscure
81 |
--------------------------------------------------------------------------------
/vitepress-theme-default-plus.js:
--------------------------------------------------------------------------------
1 | // styles
2 | import './styles/vars.scss';
3 | import './styles/styles.scss';
4 |
5 | // client stuff
6 | import {default as enhanceAppWithLayouts} from './client/enhance-app-with-layouts.js';
7 | import {enhanceAppWithTabs} from 'vitepress-plugin-tabs/client';
8 |
9 | // layouts
10 | import DefaultTheme from 'vitepress/theme';
11 | import Layout from './components/VPLLayout.vue';
12 |
13 | // global components
14 | import VPLJobs from './components/VPLJobs.vue';
15 | import VPLMailChimp from './components/VPLMailChimp.vue';
16 | import VPLSponsors from './components/VPLSponsors.vue';
17 | import VPLYouTube from './components/VPLYouTube.vue';
18 |
19 | // composables
20 | export {default as useCollection} from './client/use-collection.js';
21 | export {default as useTags} from './client/use-tags.js';
22 | export {default as useTeam} from './client/use-team.js';
23 |
24 | // shared utils
25 | export {default as encodeTag} from './utils/encode-tag.js';
26 | export {default as getItemNormalizedLink} from './utils/get-item-nl.js';
27 | export {default as isFauxInternal} from './utils/is-faux-internal.js';
28 | export {default as isDevRelease} from './utils/is-dev-release.js';
29 | export {default as isActive} from './utils/is-active.js';
30 | export {default as normalize2base} from './utils/normalize-2base.js';
31 | export {default as normalizeItems} from './utils/normalize-items.js';
32 | export {default as normalizeMVB} from './utils/normalize-mvblink.js';
33 | export {default as normalizeRoot} from './utils/normalize-rootlink.js';
34 |
35 | // components
36 | export {default as VPLAlert} from './components/VPLAlert.vue';
37 | export {default as VPLLink} from './components/VPLLink.vue';
38 | export {default as VPLMenuGroup} from './components/VPLMenuGroup.vue';
39 | export {default as VPLMenuLink} from './components/VPLMenuLink.vue';
40 | export {default as VPLNavBarMenuGroup} from './components/VPLNavBarMenuGroup.vue';
41 | export {default as VPLVersionLink} from './components/VPLVersionLink.vue';
42 |
43 | // team page
44 | export {default as VPLTeamMembersItem} from './components/VPLTeamMembersItem.vue';
45 | export {default as VPLTeamMembers} from './components/VPLTeamMembers.vue';
46 | export {VPTeamPage as VPLTeamPage} from 'vitepress/theme';
47 | export {VPTeamPageTitle as VPLTeamPageTitle} from 'vitepress/theme';
48 | export {VPTeamPageSection as VPLTeamPageSection} from 'vitepress/theme';
49 |
50 | // collection page
51 | export {default as VPLCollectionItem} from './components/VPLCollectionItem.vue';
52 | export {default as VPLCollectionItemTags} from './components/VPLCollectionItemTags.vue';
53 | export {default as VPLCollectionItems} from './components/VPLCollectionItems.vue';
54 | export {default as VPLCollectionPage} from './components/VPLCollectionPage.vue';
55 | export {default as VPLCollectionPageTags} from './components/VPLCollectionPageTags.vue';
56 | export {default as VPLCollectionPageTitle} from './components/VPLCollectionPageTitle.vue';
57 | export {default as VPLCollectionPageSection} from './components/VPLCollectionPageSection.vue';
58 |
59 | const theme = {
60 | extends: DefaultTheme,
61 | Layout,
62 | async enhanceApp({app, router}) {
63 | // register global components
64 | app.component('Jobs', VPLJobs);
65 | app.component('MailChimp', VPLMailChimp);
66 | app.component('Sponsors', VPLSponsors);
67 | app.component('YouTube', VPLYouTube);
68 |
69 | // enhance app for tabbin
70 | enhanceAppWithTabs(app);
71 | // enhance app with layouts
72 | enhanceAppWithLayouts(app);
73 |
74 | // add query tags if we can
75 | if (!import.meta.env.SSR) {
76 | const params = new URLSearchParams(window.location.search);
77 | router.route.tags = [params.get('tag'), params.get('tags')]
78 | .filter(param => param && param !== null && typeof param === 'string')
79 | .map(param => param.split(','))
80 | .flat(Infinity);
81 | }
82 | },
83 | };
84 |
85 | export default theme;
86 |
--------------------------------------------------------------------------------
/markdown/link-override-plugin.js:
--------------------------------------------------------------------------------
1 | import Debug from 'debug';
2 | import {URL} from 'url';
3 |
4 | import {default as isFauxInternal} from '../utils/is-faux-internal.js';
5 |
6 | const indexRE = /(^|.*\/)index.md(#?.*)$/i;
7 | const EXTERNAL_URL_RE = /^(?:[a-z]+:|\/\/)/i;
8 |
9 | function isExternal(path) {
10 | return EXTERNAL_URL_RE.test(path);
11 | }
12 |
13 | function normalizeHref(hrefAttr, env) {
14 | let url = hrefAttr[1];
15 |
16 | const indexMatch = url.match(indexRE);
17 | if (indexMatch) {
18 | const [, path, hash] = indexMatch;
19 | url = path + hash;
20 | } else {
21 | let cleanUrl = url.replace(/[?#].*$/, '');
22 | // transform foo.md -> foo[.html]
23 | if (cleanUrl.endsWith('.md')) {
24 | cleanUrl = cleanUrl.replace(/\.md$/, env.cleanUrls ? '' : '.html');
25 | }
26 | // transform ./foo -> ./foo[.html]
27 | if (
28 | !env.cleanUrls &&
29 | !cleanUrl.endsWith('.html') &&
30 | !cleanUrl.endsWith('/')
31 | ) {
32 | cleanUrl += '.html';
33 | }
34 | const parsed = new URL(url, 'http://a.com');
35 | url = cleanUrl + parsed.search + parsed.hash;
36 | }
37 |
38 | // ensure leading . for relative paths
39 | if (!url.startsWith('/') && !/^\.\//.test(url)) {
40 | url = './' + url;
41 | }
42 |
43 | // export it for existence check
44 | pushLink(url.replace(/\.html$/, ''), env);
45 |
46 | // markdown-it encodes the uri
47 | hrefAttr[1] = decodeURI(url);
48 | }
49 |
50 | function pushLink(link, env) {
51 | const links = env.links || (env.links = []);
52 | links.push(link);
53 | }
54 |
55 | export default function(md, externalAttrs, base, domains, debug = Debug('@lando/markdown-plugin')) { // eslint-disable-line
56 | md.renderer.rules.link_open = (
57 | tokens,
58 | idx,
59 | options,
60 | env,
61 | self,
62 | ) => {
63 | const token = tokens[idx];
64 | const hrefIndex = token.attrIndex('href');
65 | if (hrefIndex >= 0) {
66 | const hrefAttr = token.attrs[hrefIndex];
67 | const url = hrefAttr[1];
68 | if (isExternal(url)) {
69 | // set external attributes unless faux internal
70 | if (!isFauxInternal(url, domains)) {
71 | Object.entries(externalAttrs).forEach(([key, val]) => {
72 | token.attrSet(key, val);
73 | });
74 | // we need to for _self for fauxinternals
75 | } else {
76 | token.attrSet('target', '_self');
77 | }
78 |
79 | // catch localhost links as dead link
80 | if (url.replace(EXTERNAL_URL_RE, '').startsWith('//localhost:')) {
81 | pushLink(url, env);
82 | }
83 | hrefAttr[1] = url;
84 | } else {
85 | if (
86 | // internal anchor links
87 | !url.startsWith('#') &&
88 | // mail/custom protocol links
89 | new URL(url, 'http://a.com').protocol.startsWith('http') &&
90 | // links to files (other than html/md)
91 | !/\.(?!html|md)\w+($|\?)/i.test(url)
92 | ) {
93 | normalizeHref(hrefAttr, env);
94 | } else if (url.startsWith('#')) {
95 | hrefAttr[1] = decodeURI(hrefAttr[1]);
96 | }
97 |
98 | // append base to internal (non-relative) urls
99 | if (hrefAttr[1].startsWith('/')) {
100 | hrefAttr[1] = `${base}${hrefAttr[1]}`.replace(/\/+/g, '/');
101 | }
102 | }
103 |
104 | // encode vite-specific replace strings in case they appear in URLs
105 | // this also excludes them from build-time replacements (which injects
106 | // and will break URLs)
107 | hrefAttr[1] = hrefAttr[1]
108 | .replace(/\bimport\.meta/g, 'import%2Emeta')
109 | .replace(/\bprocess\.env/g, 'process%2Eenv');
110 | }
111 | return self.renderToken(tokens, idx, options);
112 | };
113 | debug('added custom markdown %o rule with config %o', 'link_open', {base, domains});
114 | };
115 |
--------------------------------------------------------------------------------
/utils/create-content-loader.js:
--------------------------------------------------------------------------------
1 | import {join, relative, posix} from 'node:path';
2 | import {platform} from 'node:os';
3 |
4 | import {createContentLoader as ccl} from 'vitepress';
5 | import {nanoid} from 'nanoid';
6 | import {parse} from 'node-html-parser';
7 |
8 | import Debug from 'debug';
9 |
10 | import {default as addContributors} from '../node/add-contributors.js';
11 | import {default as addMetadata} from '../node/add-metadata.js';
12 | import {default as augmentAuthors} from '../node/augment-authors.js';
13 | import {default as buildCollections} from '../node/build-collections.js';
14 | import {default as getContributors} from '../utils/get-contributors.js';
15 | import {default as normalizeFrontmatter} from '../node/normalize-frontmatter.js';
16 | import {default as normalizeLegacyFrontmatter} from '../node/normalize-legacy-frontmatter.js';
17 | import {default as parseCollections} from '../node/parse-collections.js';
18 |
19 | const windowsSlashRE = /\\/g;
20 | const slash = p => p.replace(windowsSlashRE, '/');
21 | const isWindows = platform() === 'win32';
22 |
23 | const normalizePath = id => posix.normalize(isWindows ? slash(id) : id);
24 |
25 | const getRelativePath = (url, {srcDir, cleanUrls = false} = {}) => {
26 | return normalizePath(relative(srcDir, join(srcDir, url)))
27 | .replace(/(^|\/)index\.html$/, '$1')
28 | .replace(/\.html$/, cleanUrls ? '' : '.md');
29 | };
30 |
31 | export default function createContentLoader(patterns = [], {
32 | siteConfig,
33 | excerpt = false,
34 | render = false,
35 | } = {},
36 | {
37 | debug = Debug('@lando/create-content-loader'), // eslint-disable-line
38 | } = {}) {
39 | return ccl(patterns, {
40 | render: true,
41 | excerpt: true,
42 | async transform(raw) {
43 | const contributors = siteConfig?.userConfig?.themeConfig?.contributors ?? false;
44 | const root = siteConfig?.userConfig?.gitRoot;
45 | const team = contributors !== false ? await getContributors(root, contributors, {debug: debug.extend('get-contribs'), paths: []}) : [];
46 | debug('discovered full team info %o', team);
47 |
48 | const pages = await Promise.all(raw.map(async data => {
49 | // backwards compute the relativePath
50 | data.relativePath = getRelativePath(data.url, siteConfig);
51 | // make sure siteConfig.collections exists and is populated
52 | await buildCollections(siteConfig, {debug});
53 | // normalize legacy frontmatter
54 | await normalizeLegacyFrontmatter(data, {siteConfig, debug});
55 | // normalize frontmatter
56 | await normalizeFrontmatter(data, {siteConfig, debug});
57 | // add contributor information
58 | await addContributors(data, {siteConfig, debug});
59 | // add metadata information
60 | await addMetadata(data, {siteConfig, debug});
61 | // parse collections
62 | await parseCollections(data, {siteConfig, debug});
63 | // normalize authors
64 | await augmentAuthors(data, {team, debug});
65 |
66 | // get stuff
67 | const {frontmatter, html, url} = data;
68 |
69 | // ensure we have a title
70 | if (!frontmatter.title) frontmatter.title = parse(html).getElementsByTagName('h1')[0]?.text ?? frontmatter.title;
71 |
72 | // munge it all 2getha
73 | const content = Object.assign(frontmatter, {
74 | id: nanoid(),
75 | title: frontmatter.title,
76 | summary: frontmatter.summary ?? frontmatter.byline ?? frontmatter.description,
77 | authors: frontmatter.authors,
78 | date: frontmatter.date ?? data.timestamp ?? data.datetime,
79 | datetime: data.datetime,
80 | excerpt: excerpt ? data.excerpt : '',
81 | html: render ? data.html : '',
82 | relativePath: data.relativePath,
83 | tags: frontmatter.tags ?? [],
84 | timestamp: data.timestamp ?? Date.now(),
85 | type: frontmatter.collection,
86 | url,
87 | });
88 |
89 | // remove some stuff we do not need
90 | // @TODO: any other optimization here?
91 | delete content.head;
92 |
93 | // return
94 | return content;
95 | }));
96 |
97 | // sort and return
98 | return pages.sort((a, b) => b.timestamp - a.timestamp);
99 | },
100 | });
101 | };
102 |
--------------------------------------------------------------------------------
/config/defaults.js:
--------------------------------------------------------------------------------
1 | import {default as getBaseUrl} from '@lando/vitepress-theme-default-plus/get-base-url';
2 |
3 | export default function({base}) {
4 | return {
5 | base: base ?? '/',
6 | baseUrl: getBaseUrl(),
7 | collections: {},
8 | feeds: false,
9 | lang: 'en-US',
10 | markdown: {},
11 | robots: {
12 | allowAll: true,
13 | policy: [],
14 | policies: [],
15 | },
16 | sitemap: {
17 | lastmodDateOnly: false,
18 | transformItems: items => {
19 | for (const item of items) {
20 | item.url = `${base ?? '/'}${item.url}`;
21 | item.priority = 0.5;
22 | item.changefreq = 'daily';
23 | }
24 | return items;
25 | },
26 | },
27 | themeConfig: {
28 | alert: false,
29 | autometa: false,
30 | carbonAds: undefined,
31 | collections: {
32 | post: {
33 | frontmatter: {
34 | collection: 'post',
35 | contributors: false,
36 | backLink: {
37 | text: '<- Back to blog',
38 | link: '/blog',
39 | },
40 | aside: false,
41 | sidebar: false,
42 | prev: false,
43 | next: false,
44 | editLink: false,
45 | },
46 | icon: '',
47 | iconLink: '/blog',
48 | patterns: ['blog/**/*.md'],
49 | },
50 | guide: {
51 | frontmatter: {
52 | collection: 'guide',
53 | },
54 | icon: '',
55 | iconLink: '/guides',
56 | patterns: ['guides/**/*.md'],
57 | },
58 | },
59 | containers: {
60 | 'brand': {defaultTitle: 'BRAND'},
61 | 'box': {},
62 | 'box-blue': {},
63 | 'box-brand': {},
64 | 'box-green': {},
65 | 'box-red': {},
66 | 'box-yellow': {},
67 | 'caption': {},
68 | 'card': {},
69 | 'center': {},
70 | 'half': {},
71 | 'highlight': {},
72 | 'left': {},
73 | 'right': {},
74 | 'success': {defaultTitle: 'SUCCESS'},
75 | 'third': {},
76 | 'thumbnail': {},
77 | },
78 | contributors: {
79 | merge: 'name',
80 | debotify: true,
81 | exclude: [],
82 | include: [],
83 | },
84 | internalDomain: [],
85 | internalDomains: [],
86 | ga: false,
87 | hubspot: false,
88 | jobs: false,
89 | lastUpdated: {
90 | text: 'Updated',
91 | formatOptions: {
92 | dateStyle: 'timeago',
93 | },
94 | },
95 | layouts: {},
96 | multiVersionBuild: false,
97 | nav: [],
98 | sidebar: {},
99 | sidebarEnder: false,
100 | sponsors: false,
101 | tags: {},
102 | tagLink: undefined,
103 | team: [],
104 | },
105 | vite: {
106 | css: {
107 | preprocessorOptions: {
108 | sass: {api: 'modern-compiler'},
109 | scss: {api: 'modern-compiler'},
110 | },
111 | },
112 | optimizeDeps: {exclude: []},
113 | plugins: [],
114 | resolve: {alias: []},
115 | ssr: {noExternal: []},
116 | },
117 | };
118 | };
119 |
--------------------------------------------------------------------------------
/components/VPLTeamMembers.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
27 |
28 |
226 |
--------------------------------------------------------------------------------
/components/VPLMailChimp.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
{{ props.title }}
6 |
7 |
8 | {{ props.byline }}
9 |
10 |
11 |
68 |
69 |
70 |
71 |
72 |
73 |
98 |
99 |
176 |
--------------------------------------------------------------------------------
/docs/guides/advanced-markdown.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Advanced markdown
3 | description: Learn how to combine custom containers for all the magic.
4 | tags:
5 | - tag 1
6 | pirog: 5000
7 | ---
8 |
9 | # Advanced Markdown
10 |
11 | This theme provides a bunch of [custom markdown containers](./../markdown//admonitions.md) that can be used on their own. They can also be combined and wrapped together. Here is some content that demonstrates that.
12 |
13 | ## Triple cards
14 |
15 | Put three cat cards next to one another
16 |
17 | ::::third
18 | :::card Cat 1
19 | 
20 | :::
21 | ::::
22 |
23 | ::::third
24 | :::card Cat 2
25 | 
26 | :::
27 | ::::
28 |
29 | ::::third
30 | :::card Cat 3
31 | 
32 | :::
33 | ::::
34 |
35 | ### Markdown
36 |
37 | ```md
38 | ::::third
39 | :::card Cat 1
40 | 
41 | :::
42 | ::::
43 |
44 | ::::third
45 | :::card Cat 2
46 | 
47 | :::
48 | ::::
49 |
50 | ::::third
51 | :::card Cat 3
52 | 
53 | :::
54 | ::::
55 | ```
56 |
57 | ## Floaty cards
58 |
59 | ::::right
60 | :::card Cat 1
61 | 
62 | :::
63 | ::::
64 |
65 | Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.
66 |
67 | ::::left
68 | :::card Cat 2
69 | 
70 | :::
71 | ::::
72 |
73 | Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.
74 |
75 | ### Markdown
76 |
77 | ```md
78 | ::::right
79 | :::card Cat 1
80 | 
81 | :::
82 | ::::
83 |
84 | Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.
85 |
86 | ::::left
87 | :::card Cat 2
88 | 
89 | :::
90 | ::::
91 |
92 | Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.Float a cat card. Float a cat card. Float a cat card.
93 | ```
94 |
--------------------------------------------------------------------------------
/components/VPLCollectionItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
12 |
13 |