Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(theme-default): Add icons on action buttons #3795

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/index.md
Expand Up @@ -12,12 +12,19 @@ hero:
- theme: brand
text: What is VitePress?
link: /guide/what-is-vitepress
startIcon:
src: /vitepress-logo-mini.svg
width: 18
height: 18
endIcon:
- theme: alt
text: Quickstart
link: /guide/getting-started
- theme: alt
text: GitHub
link: https://github.com/vuejs/vitepress
startIcon: <span class="vpi-social-github" />
endIcon: <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="currentColor" d="m16.172 11l-5.364-5.364l1.414-1.414L20 12l-7.778 7.778l-1.414-1.414L16.172 13H4v-2z"/></svg>
image:
src: /vitepress-logo-large.webp
alt: VitePress
Expand Down
17 changes: 17 additions & 0 deletions docs/reference/default-theme-home-page.md
Expand Up @@ -75,7 +75,24 @@ interface HeroAction {

// Link rel attribute.
rel?: string

// Show the left icon on action button.
startIcon?: ActionIcon

// Show the right icon on action button.
endIcon?: ActionIcon
}

type ActionIcon =
| string
| { src: string; alt?: string; width?: string; height: string }
| {
light: string
dark: string
alt?: string
width?: string
height: string
}
```

### Customizing the name color
Expand Down
49 changes: 47 additions & 2 deletions src/client/theme-default/components/VPButton.vue
@@ -1,7 +1,9 @@
<script setup lang="ts">
import { computed } from 'vue'
import type { DefaultTheme } from 'vitepress/theme'
import { normalizeLink } from '../support/utils'
import { EXTERNAL_URL_RE } from '../../shared'
import VPImage from './VPImage.vue'

interface Props {
tag?: string
Expand All @@ -11,6 +13,8 @@ interface Props {
href?: string
target?: string;
rel?: string;
startIcon?: DefaultTheme.ActionIcon;
endIcon?: DefaultTheme.ActionIcon;
}
const props = withDefaults(defineProps<Props>(), {
size: 'medium',
Expand All @@ -35,13 +39,35 @@ const component = computed(() => {
:target="props.target ?? (isExternal ? '_blank' : undefined)"
:rel="props.rel ?? (isExternal ? 'noreferrer' : undefined)"
>
{{ text }}
<span class="start-icon" v-if="startIcon">
<VPImage
v-if="typeof startIcon === 'object'"
:image="startIcon"
:alt="startIcon.alt"
:height="startIcon.height || 32"
:width="startIcon.width || 32"
/>
<span v-else-if="startIcon" class="icon" v-html="startIcon"></span>
</span>
<span>{{ text }}</span>
<span class="end-icon" v-if="endIcon">
<VPImage
v-if="typeof endIcon === 'object'"
:image="endIcon"
:alt="endIcon.alt"
:height="endIcon.height || 32"
:width="endIcon.width || 32"
/>
<span v-else-if="endIcon" class="icon" v-html="endIcon"></span>
</span>
</component>
</template>

<style scoped>
.VPButton {
display: inline-block;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid transparent;
text-align: center;
font-weight: 600;
Expand Down Expand Up @@ -120,4 +146,23 @@ const component = computed(() => {
color: var(--vp-button-sponsor-active-text);
background-color: var(--vp-button-sponsor-active-bg);
}

.VPButton:only-child{
grid-template-columns: 1fr;
grid-gap: 0;
}

.icon{
display: flex;
justify-content: center;
align-items: center;
}

.start-icon {
margin-right: 8px;
}

.end-icon {
margin-left: 8px;
}
</style>
4 changes: 4 additions & 0 deletions src/client/theme-default/components/VPHero.vue
Expand Up @@ -10,6 +10,8 @@ export interface HeroAction {
link: string
target?: string
rel?: string
startIcon?: DefaultTheme.ActionIcon
endIcon?: DefaultTheme.ActionIcon
}

defineProps<{
Expand Down Expand Up @@ -47,6 +49,8 @@ const heroImageSlotExists = inject('hero-image-slot-exists') as Ref<boolean>
:href="action.link"
:target="action.target"
:rel="action.rel"
:start-icon="action.startIcon"
:end-icon="action.endIcon"
/>
</div>
</div>
Expand Down
16 changes: 16 additions & 0 deletions types/default-theme.d.ts
Expand Up @@ -220,6 +220,22 @@ export namespace DefaultTheme {
wrap?: boolean
}

export type ActionIcon =
| string
| {
src: string
alt?: string
width?: string
height?: string
}
| {
light: string
dark: string
alt?: string
width?: string
height?: string
}

// sidebar -------------------------------------------------------------------

export type Sidebar = SidebarItem[] | SidebarMulti
Expand Down