feat(theme): support themeable images for logo and hero (#745)

Co-authored-by: Divyansh Singh <40380293+brc-dd@users.noreply.github.com>
pull/803/head
Anthony Fu 2 years ago committed by GitHub
parent 35772ca8d0
commit 42813ce936
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import type { DefaultTheme } from 'vitepress/theme'
import VPButton from './VPButton.vue' import VPButton from './VPButton.vue'
import VPImage from './VPImage.vue'
export interface HeroAction { export interface HeroAction {
theme?: 'brand' | 'alt' theme?: 'brand' | 'alt'
@ -7,16 +9,11 @@ export interface HeroAction {
link: string link: string
} }
export interface Image {
src: string
alt?: string
}
defineProps<{ defineProps<{
name?: string name?: string
text: string text: string
tagline?: string tagline?: string
image?: Image image?: DefaultTheme.ThemeableImage
actions?: HeroAction[] actions?: HeroAction[]
}>() }>()
</script> </script>
@ -25,7 +22,9 @@ defineProps<{
<div class="VPHero" :class="{ 'has-image': image }"> <div class="VPHero" :class="{ 'has-image': image }">
<div class="container"> <div class="container">
<div class="main"> <div class="main">
<h1 v-if="name" class="name"><span class="clip">{{ name }}</span></h1> <h1 v-if="name" class="name">
<span class="clip">{{ name }}</span>
</h1>
<p v-if="text" class="text">{{ text }}</p> <p v-if="text" class="text">{{ text }}</p>
<p v-if="tagline" class="tagline">{{ tagline }}</p> <p v-if="tagline" class="tagline">{{ tagline }}</p>
@ -45,7 +44,7 @@ defineProps<{
<div v-if="image" class="image"> <div v-if="image" class="image">
<div class="image-container"> <div class="image-container">
<div class="image-bg" /> <div class="image-bg" />
<img class="image-src" :src="image.src" :alt="image.alt"> <VPImage class="image-src" :image="image" />
</div> </div>
</div> </div>
</div> </div>
@ -293,7 +292,7 @@ defineProps<{
} }
} }
.image-src { :deep(.image-src) {
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;

@ -0,0 +1,38 @@
<script setup lang="ts">
import { withBase } from 'vitepress'
import type { DefaultTheme } from 'vitepress/theme'
defineProps<{
image: DefaultTheme.ThemeableImage
}>()
</script>
<script lang="ts">
export default {
inheritAttrs: false
}
</script>
<template>
<template v-if="image">
<img
v-if="typeof image === 'string' || 'src' in image"
class="VPImage"
v-bind="typeof image === 'string' ? $attrs : { ...image, ...$attrs }"
:src="withBase(typeof image === 'string' ? image : image.src)"
/>
<template v-else>
<VPImage class="dark" :image="image.dark" v-bind="$attrs" />
<VPImage class="light" :image="image.light" v-bind="$attrs" />
</template>
</template>
</template>
<style scoped>
html:not(.dark) .VPImage.dark {
display: none;
}
.dark .VPImage.light {
display: none;
}
</style>

@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useData } from 'vitepress' import { useData } from 'vitepress'
import { useSidebar } from '../composables/sidebar' import { useSidebar } from '../composables/sidebar'
import VPImage from './VPImage.vue'
const { site, theme } = useData() const { site, theme } = useData()
const { hasSidebar } = useSidebar() const { hasSidebar } = useSidebar()
@ -9,7 +10,7 @@ const { hasSidebar } = useSidebar()
<template> <template>
<div class="VPNavBarTitle" :class="{ 'has-sidebar': hasSidebar }"> <div class="VPNavBarTitle" :class="{ 'has-sidebar': hasSidebar }">
<a class="title" :href="site.base"> <a class="title" :href="site.base">
<img v-if="theme.logo" class="logo" :src="theme.logo"> <VPImage class="logo" :image="theme.logo" />
<template v-if="theme.siteTitle">{{ theme.siteTitle }}</template> <template v-if="theme.siteTitle">{{ theme.siteTitle }}</template>
<template v-else-if="theme.siteTitle === undefined">{{ site.title }}</template> <template v-else-if="theme.siteTitle === undefined">{{ site.title }}</template>
</a> </a>
@ -52,7 +53,7 @@ const { hasSidebar } = useSidebar()
} }
} }
.logo { :deep(.logo) {
margin-right: 8px; margin-right: 8px;
height: 24px; height: 24px;
} }

@ -12,7 +12,8 @@
"types": ["vite/client"], "types": ["vite/client"],
"paths": { "paths": {
"/@theme/*": ["theme-default/*"], "/@theme/*": ["theme-default/*"],
"vitepress": ["index.ts"] "vitepress": ["index.ts"],
"vitepress/theme": ["../../types/default-theme.d"]
} }
}, },
"include": ["."] "include": ["."]

@ -5,7 +5,7 @@ export namespace DefaultTheme {
* *
* @example '/logo.svg' * @example '/logo.svg'
*/ */
logo?: string logo?: ThemeableImage
/** /**
* Custom site title in navbar. If the value is undefined, * Custom site title in navbar. If the value is undefined,
@ -96,6 +96,11 @@ export namespace DefaultTheme {
items: (NavItemChildren | NavItemWithLink)[] items: (NavItemChildren | NavItemWithLink)[]
} }
// image -----------------------------------------------------------------------
export type ThemeableImage = Image | { light: Image; dark: Image }
export type Image = string | { src: string; alt?: string }
// sidebar ------------------------------------------------------------------- // sidebar -------------------------------------------------------------------
export type Sidebar = SidebarGroup[] | SidebarMulti export type Sidebar = SidebarGroup[] | SidebarMulti

Loading…
Cancel
Save