feat(theme): add print options

userquin/feat-add-print-options
userquin 2 years ago
parent 46758a507c
commit dc2f98c443

@ -3,10 +3,13 @@ import icon from './documate.vue'
</script>
<template>
<div class="ad-component">
<div class="ad-component screen-only">
<a target="_blank" href="https://github.com/aircodelabs/documate">
<icon class="icon"/>
<span>Embed AI chat in your VitePress using your own content. Open-source.</span>
<icon class="icon" />
<span
>Embed AI chat in your VitePress using your own content.
Open-source.</span
>
<span class="cta">Try now </span>
</a>
</div>
@ -15,7 +18,7 @@ import icon from './documate.vue'
<style scoped>
.ad-component {
margin-bottom: 2rem;
padding: .5rem .85rem;
padding: 0.5rem 0.85rem;
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
text-decoration: none;
@ -30,8 +33,8 @@ import icon from './documate.vue'
.ad-component .icon {
display: inline-block;
width: .75rem;
height: .75rem;
width: 0.75rem;
height: 0.75rem;
margin-right: 0.3rem;
}

@ -106,4 +106,10 @@ if (carbonOptions) {
.VPCarbonAds :deep(> div:first-of-type) {
display: block;
}
@media print {
.VPCarbonAds {
display: none;
}
}
</style>

@ -5,9 +5,12 @@ import { useSidebar } from '../composables/sidebar'
import VPDoc from './VPDoc.vue'
import VPHome from './VPHome.vue'
import VPPage from './VPPage.vue'
import { useScreenOnly } from '../composables/scree-only'
const { page, frontmatter } = useData()
const { hasSidebar } = useSidebar()
const screenOnly = useScreenOnly('navbar')
const screenOnlySidebar = useScreenOnly('sidebar')
</script>
<template>
@ -16,7 +19,9 @@ const { hasSidebar } = useSidebar()
id="VPContent"
:class="{
'has-sidebar': hasSidebar,
'is-home': frontmatter.layout === 'home'
'is-home': frontmatter.layout === 'home',
'with-screen-only': screenOnly,
'no-print-sidebar': screenOnlySidebar
}"
>
<slot name="not-found" v-if="page.isNotFound"><NotFound /></slot>
@ -92,4 +97,14 @@ const { hasSidebar } = useSidebar()
padding-left: calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width));
}
}
@media print {
.VPContent.with-screen-only:not(.is-home) {
--vp-nav-height: 0;
}
.VPContent.with-screen-only.no-print-sidebar {
padding-left: 0;
width: 100%;
}
}
</style>

@ -6,11 +6,14 @@ import { useSidebar } from '../composables/sidebar'
import VPDocAside from './VPDocAside.vue'
import VPDocFooter from './VPDocFooter.vue'
import VPDocOutlineDropdown from './VPDocOutlineDropdown.vue'
import { useScreenOnly } from '../composables/scree-only'
const { theme } = useData()
const route = useRoute()
const { hasSidebar, hasAside, leftAside } = useSidebar()
const screenOnly = useScreenOnly('navbar')
const screenOnlyOutline = useScreenOnly('outline')
const pageName = computed(() =>
route.path.replace(/[./]+/g, '_').replace(/_html$/, '')
@ -20,11 +23,11 @@ const pageName = computed(() =>
<template>
<div
class="VPDoc"
:class="{ 'has-sidebar': hasSidebar, 'has-aside': hasAside }"
:class="{ 'has-sidebar': hasSidebar, 'has-aside': hasAside, 'with-screen-only': screenOnly }"
>
<slot name="doc-top" />
<div class="container">
<div v-if="hasAside" class="aside" :class="{'left-aside': leftAside}">
<div v-if="hasAside" class="aside" :class="{'left-aside': leftAside,'screen-only': screenOnlyOutline}">
<div class="aside-curtain" />
<div class="aside-container">
<div class="aside-content">
@ -207,4 +210,11 @@ const pageName = computed(() =>
content: '';
color: currentColor;
}
@media print {
/* will be moved to the left? */
.VPDoc.with-screen-only {
padding-top: 24px !important;
}
}
</style>

@ -5,8 +5,11 @@ import { getHeaders, resolveTitle, type MenuItem } from '../composables/outline'
import VPDocOutlineItem from './VPDocOutlineItem.vue'
import { onContentUpdated } from 'vitepress'
import VPIconChevronRight from './icons/VPIconChevronRight.vue'
import { useScreenOnly } from '../composables/scree-only'
const { frontmatter, theme } = useData()
const screenOnly = useScreenOnly('navbar')
const open = ref(false)
onContentUpdated(() => {
@ -14,7 +17,6 @@ onContentUpdated(() => {
})
const headers = shallowRef<MenuItem[]>([])
onContentUpdated(() => {
headers.value = getHeaders(
frontmatter.value.outline ?? theme.value.outline
@ -23,7 +25,7 @@ onContentUpdated(() => {
</script>
<template>
<div v-if="headers.length > 0" class="VPDocOutlineDropdown" :class="{ 'screen-only': frontmatter.navbar === false }">
<div v-if="headers.length > 0" class="VPDocOutlineDropdown" :class="{ 'screen-only': screenOnly }">
<button @click="open = !open" :class="{ open }">
{{ resolveTitle(theme) }}
<VPIconChevronRight class="icon" />

@ -1,13 +1,19 @@
<script setup lang="ts">
import { useData } from '../composables/data'
import { useSidebar } from '../composables/sidebar'
import { useScreenOnly } from '../composables/scree-only'
const { theme, frontmatter } = useData()
const { hasSidebar } = useSidebar()
const screenOnly = useScreenOnly('footer')
</script>
<template>
<footer v-if="theme.footer && frontmatter.footer !== false" class="VPFooter" :class="{ 'has-sidebar': hasSidebar }">
<footer
v-if="theme.footer && frontmatter.footer !== false"
class="VPFooter"
:class="{ 'has-sidebar': hasSidebar, 'screen-only': screenOnly }"
>
<div class="container">
<p v-if="theme.footer.message" class="message" v-html="theme.footer.message"></p>
<p v-if="theme.footer.copyright" class="copyright" v-html="theme.footer.copyright"></p>

@ -7,6 +7,7 @@ import { getHeaders, type MenuItem } from '../composables/outline'
import { useSidebar } from '../composables/sidebar'
import VPLocalNavOutlineDropdown from './VPLocalNavOutlineDropdown.vue'
import VPIconAlignLeft from './icons/VPIconAlignLeft.vue'
import { useScreenOnly } from '../composables/scree-only'
defineProps<{
open: boolean
@ -40,12 +41,14 @@ const empty = computed(() => {
return headers.value.length === 0 && !hasSidebar.value
})
const screenOnly = useScreenOnly('navbar')
const classes = computed(() => {
return {
VPLocalNav: true,
fixed: empty.value,
'reached-top': y.value >= navHeight.value,
'screen-only': frontmatter.value.navbar === false
'screen-only': screenOnly.value
}
})
</script>

@ -5,9 +5,11 @@ import { useData } from '../composables/data'
import { useNav } from '../composables/nav'
import VPNavBar from './VPNavBar.vue'
import VPNavScreen from './VPNavScreen.vue'
import {useScreenOnly} from "../composables/scree-only";
const { isScreenOpen, closeScreen, toggleScreen } = useNav()
const { frontmatter } = useData()
const screenOnly = useScreenOnly('navbar')
const hasNavbar = computed(() => {
return frontmatter.value.navbar !== false
@ -23,7 +25,7 @@ watchEffect(() => {
</script>
<template>
<header v-if="hasNavbar" class="VPNav">
<header v-if="hasNavbar" class="VPNav" :class="{ 'screen-only': screenOnly }">
<VPNavBar :is-screen-open="isScreenOpen" @toggle-screen="toggleScreen">
<template #nav-bar-title-before><slot name="nav-bar-title-before" /></template>
<template #nav-bar-title-after><slot name="nav-bar-title-after" /></template>

@ -4,8 +4,10 @@ import { inBrowser } from 'vitepress'
import { ref, watch } from 'vue'
import { useSidebar } from '../composables/sidebar'
import VPSidebarItem from './VPSidebarItem.vue'
import { useScreenOnly } from '../composables/scree-only'
const { sidebarGroups, hasSidebar } = useSidebar()
const screenOnly = useScreenOnly('sidebar')
const props = defineProps<{
open: boolean
@ -31,7 +33,7 @@ watch(
<aside
v-if="hasSidebar"
class="VPSidebar"
:class="{ open }"
:class="{ open, 'screen-only': screenOnly }"
ref="navEl"
@click.stop
>

@ -0,0 +1,15 @@
import { useData } from './data'
import type { DefaultTheme } from 'vitepress/theme'
import { computed } from 'vue'
export function useScreenOnly(entry: keyof DefaultTheme.PrintOptions) {
const { theme, frontmatter } = useData()
return computed(
() =>
frontmatter.value[entry] === false ||
theme.value.print === false ||
(typeof theme.value.print === 'object' &&
theme.value.print[entry] === false)
)
}

@ -223,6 +223,24 @@ export async function resolveSiteData(
): Promise<SiteData> {
userConfig = userConfig || (await resolveUserConfig(root, command, mode))[0]
const themeConfig = userConfig.themeConfig || {}
if (typeof themeConfig.print === 'boolean') {
themeConfig.print = {
outline: themeConfig.print,
navbar: themeConfig.print,
sidebar: themeConfig.print,
footer: themeConfig.print
}
}
else {
themeConfig.print ??= {}
themeConfig.print.outline ??= false
themeConfig.print.navbar ??= false
themeConfig.print.sidebar ??= false
themeConfig.print.footer ??= true
}
return {
lang: userConfig.lang || 'en-US',
dir: userConfig.dir || 'ltr',
@ -232,7 +250,7 @@ export async function resolveSiteData(
base: userConfig.base ? userConfig.base.replace(/([^/])$/, '$1/') : '/',
head: resolveSiteDataHead(userConfig),
appearance: userConfig.appearance ?? true,
themeConfig: userConfig.themeConfig || {},
themeConfig,
locales: userConfig.locales || {},
scrollOffset: userConfig.scrollOffset ?? 90,
cleanUrls: !!userConfig.cleanUrls,

@ -145,6 +145,19 @@ export namespace DefaultTheme {
* Customize text of 404 page.
*/
notFound?: NotFoundOptions
/**
* Customize how pages will be printed.
*
* To exclude `outline`, `navbar`, `sidebar` and `footer` from being printed, configure `print: false`.
*
* To print all of them, configure `print: true`.
*
* Frontmatter configuration will override the global configuration, for example, a page containing `navbar: false`, the navbar will not be printed.
*
* @default { outline: false, navbar: false, sidebar: false, footer: true }
*/
print?: boolean | PrintOptions
}
// nav -----------------------------------------------------------------------
@ -474,4 +487,33 @@ export namespace DefaultTheme {
*/
code?: string
}
// print options -----------------------------------------------------------------
export interface PrintOptions {
/**
* Should the outline be printed?
*
* @default false
*/
outline?: boolean
/**
* Should the navbar be printed?
*
* @default false
*/
navbar?: boolean
/**
* Should the sidebar be printed?
*
* @default false
*/
sidebar?: boolean
/**
* Should the sidebar be printed?
*
* @default true
*/
footer?: boolean
}
}

Loading…
Cancel
Save