feat: add carbon ads feature (#647)

close #647
pull/654/head
Kia King Ishii 3 years ago
parent 439f370355
commit 36a67bd67d

@ -33,6 +33,11 @@ export default defineConfig({
appId: '8J64VVRP8K', appId: '8J64VVRP8K',
apiKey: 'a18e2f4cc5665f6602c5631fd868adfd', apiKey: 'a18e2f4cc5665f6602c5631fd868adfd',
indexName: 'vitepress' indexName: 'vitepress'
},
carbonAds: {
code: 'CEBDT27Y',
placement: 'vuejsorg'
} }
} }
}) })
@ -66,7 +71,10 @@ function sidebarGuide() {
}, },
{ {
text: 'Theme', text: 'Theme',
items: [{ text: 'Introduction', link: '/guide/theme-introduction' }] items: [
{ text: 'Introduction', link: '/guide/theme-introduction' },
{ text: 'Carbon Ads', link: '/guide/theme-carbon-ads' }
]
}, },
{ {
text: 'Migrations', text: 'Migrations',

@ -56,3 +56,29 @@ export interface Footer {
copyright?: string copyright?: string
} }
``` ```
## carbonAds
- Type: `CarbonAds`
A option to display [Carbon Ads](https://www.carbonads.net/).
```ts
export default {
themeConfig: {
carbonAds: {
code: 'your-carbon-code',
placement: 'your-carbon-placement'
}
}
}
```
```ts
export interface CarbonAds {
code: string,
placement: string
}
```
Learn more in [Theme: Carbon Ads](../guide/theme-carbon-ads)

@ -0,0 +1,22 @@
# Carbon Ads
VitePress has built in native support for [Carbon Ads](https://www.carbonads.net/). By defining the Carbon Ads credentials in config, VitePress will display ads on the page.
```js
export default {
themeConfig: {
carbonAds: {
code: 'your-carbon-code',
placement: 'your-carbon-placement'
}
}
}
```
These values are used to call carbon CDN script as shown below.
```js
`//cdn.carbonads.com/carbon.js?serve=${code}&placement=${placement}`
```
To learn more about Carbon Ads configuration, please visit [Carbon Ads website](https://www.carbonads.net/).

@ -1,7 +1,6 @@
declare const __VP_HASH_MAP__: Record<string, string> declare const __VP_HASH_MAP__: Record<string, string>
declare const __ALGOLIA__: boolean declare const __ALGOLIA__: boolean
declare const __CARBON__: boolean declare const __CARBON__: boolean
declare const __BSA__: boolean
declare module '*.vue' { declare module '*.vue' {
import { ComponentOptions } from 'vue' import { ComponentOptions } from 'vue'

@ -0,0 +1,93 @@
<script setup lang="ts">
import { ref, watch, onMounted } from 'vue'
import { useData } from 'vitepress'
import { useAside } from '../composables/aside'
const { theme } = useData()
const carbonOptions = theme.value.carbonAds
const { isAsideEnabled } = useAside()
const container = ref()
let hasInitalized = false
function init() {
if (!hasInitalized) {
hasInitalized = true
const s = document.createElement('script')
s.id = '_carbonads_js'
s.src = `//cdn.carbonads.com/carbon.js?serve=${carbonOptions.code}&placement=${carbonOptions.placement}`
s.async = true
container.value.appendChild(s)
}
}
// no need to account for option changes during dev, we can just
// refresh the page
if (carbonOptions) {
onMounted(() => {
// if the page is loaded when aside is active, load carbon directly.
// otherwise, only load it if the page resizes to wide enough. this avoids
// loading carbon at all on mobile where it's never shown
if (isAsideEnabled.value) {
init()
} else {
watch(isAsideEnabled, (wide) => wide && init())
}
})
}
</script>
<template>
<div class="VPCarbonAds" ref="container" />
</template>
<style>
.VPCarbonAds {
padding: 24px 24px 20px;
border-radius: 8px;
min-height: 240px;
text-align: center;
line-height: 18px;
font-size: 12px;
font-weight: 500;
background-color: var(--vp-c-bg-alt);
transition: color 0.5s, background-color 0.5s;
}
@media (min-width: 1440px) {
.VPCarbonAds {
padding: 32px 32px 28px;
}
}
.VPCarbonAds img {
margin: 0 auto;
border-radius: 6px;
}
.VPCarbonAds .carbon-text {
display: block;
margin: 0 auto;
padding-top: 12px;
color: var(--vp-c-text-1);
transition: color 0.25s;
}
.VPCarbonAds .carbon-text:hover {
color: var(--vp-c-brand);
}
.VPCarbonAds .carbon-poweredby {
display: block;
padding-top: 6px;
font-size: 11px;
font-weight: 500;
color: var(--vp-c-text-2);
text-transform: uppercase;
transition: color 0.25s;
}
.VPCarbonAds .carbon-poweredby:hover {
color: var(--vp-c-text-1);
}
</style>

@ -2,7 +2,7 @@
import { computed } from 'vue' import { computed } from 'vue'
import { useData } from 'vitepress' import { useData } from 'vitepress'
import { useSidebar } from '../composables/sidebar' import { useSidebar } from '../composables/sidebar'
import VPDocOutline from './VPDocOutline.vue' import VPDocAside from './VPDocAside.vue'
import VPDocFooter from './VPDocFooter.vue' import VPDocFooter from './VPDocFooter.vue'
const { page } = useData() const { page } = useData()
@ -20,7 +20,7 @@ const pageName = computed(() => {
<div class="aside-curtain" /> <div class="aside-curtain" />
<div class="aside-container"> <div class="aside-container">
<div class="aside-content"> <div class="aside-content">
<VPDocOutline v-if="page.headers" /> <VPDocAside />
</div> </div>
</div> </div>
</div> </div>

@ -0,0 +1,20 @@
<script setup lang="ts">
import { useData } from 'vitepress'
import VPDocAsideOutline from './VPDocAsideOutline.vue'
import VPDocAsideCarbonAds from './VPDocAsideCarbonAds.vue'
const { page, theme } = useData()
</script>
<template>
<div class="VPDocAside">
<VPDocAsideOutline v-if="page.headers.length" />
<VPDocAsideCarbonAds v-if="theme.carbonAds" />
</div>
</template>
<style scoped>
.VPDocAside :deep(.VPDocAsideOutline + .VPDocAsideCarbonAds) {
margin-top: 24px;
}
</style>

@ -0,0 +1,13 @@
<script setup lang="ts">
import { defineAsyncComponent } from 'vue'
const VPCarbonAds = __ALGOLIA__
? defineAsyncComponent(() => import('./VPCarbonAds.vue'))
: () => null
</script>
<template>
<div class="VPDocAsideCarbonAds">
<VPCarbonAds />
</div>
</template>

@ -28,7 +28,7 @@ function handleClick({ target: el }: Event) {
</script> </script>
<template> <template>
<div class="VPDocOutline" :class="{ 'has-outline': hasOutline }" ref="container"> <div class="VPDocAsideOutline" :class="{ 'has-outline': hasOutline }" ref="container">
<div class="outline-marker" ref="marker" /> <div class="outline-marker" ref="marker" />
<div class="outline-title">On this page</div> <div class="outline-title">On this page</div>
@ -60,7 +60,7 @@ function handleClick({ target: el }: Event) {
</template> </template>
<style scoped> <style scoped>
.VPDocOutline { .VPDocAsideOutline {
position: relative; position: relative;
display: none; display: none;
border-left: 1px solid var(--vp-c-divider-light); border-left: 1px solid var(--vp-c-divider-light);
@ -69,7 +69,7 @@ function handleClick({ target: el }: Event) {
font-weight: 500; font-weight: 500;
} }
.VPDocOutline.has-outline { .VPDocAsideOutline.has-outline {
display: block; display: block;
} }

@ -1,11 +1,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import '@docsearch/css' import '@docsearch/css'
import { useData } from 'vitepress'
import { defineAsyncComponent, ref, onMounted, onUnmounted } from 'vue' import { defineAsyncComponent, ref, onMounted, onUnmounted } from 'vue'
import { useData } from 'vitepress'
const VPAlgoliaSearchBox = defineAsyncComponent(() => { const VPAlgoliaSearchBox = __ALGOLIA__
return import('./VPAlgoliaSearchBox.vue') ? defineAsyncComponent(() => import('./VPAlgoliaSearchBox.vue'))
}) : () => null
const { theme } = useData() const { theme } = useData()

@ -0,0 +1,21 @@
import { computed } from 'vue'
import { useMediaQuery } from '@vueuse/core'
import { useSidebar } from './sidebar'
export function useAside() {
const { hasSidebar } = useSidebar()
const is960 = useMediaQuery('(min-width: 960px)')
const is1280 = useMediaQuery('(min-width: 1280px)')
const isAsideEnabled = computed(() => {
if (!is1280.value && !is960.value) {
return false
}
return hasSidebar.value ? is1280.value : is960.value
})
return {
isAsideEnabled
}
}

@ -1,7 +1,6 @@
import { Ref, computed, onMounted, onUpdated, onUnmounted } from 'vue' import { Ref, computed, onMounted, onUpdated, onUnmounted } from 'vue'
import { Header, useData } from 'vitepress' import { Header, useData } from 'vitepress'
import { useMediaQuery } from '@vueuse/core' import { useAside } from '../composables/aside'
import { useSidebar } from '../composables/sidebar'
import { throttleAndDebounce } from '../support/utils' import { throttleAndDebounce } from '../support/utils'
interface HeaderWithChildren extends Header { interface HeaderWithChildren extends Header {
@ -66,13 +65,7 @@ export function useActiveAnchor(
container: Ref<HTMLElement>, container: Ref<HTMLElement>,
marker: Ref<HTMLElement> marker: Ref<HTMLElement>
) { ) {
const { hasSidebar } = useSidebar() const { isAsideEnabled } = useAside()
const is960 = useMediaQuery('(min-width: 960px)')
const is1280 = useMediaQuery('(min-width: 1280px)')
const isOutlineEnabled = computed(() => {
return hasSidebar.value ? is1280.value : is960.value
})
const onScroll = throttleAndDebounce(setActiveLink, 100) const onScroll = throttleAndDebounce(setActiveLink, 100)
@ -93,7 +86,7 @@ export function useActiveAnchor(
}) })
function setActiveLink() { function setActiveLink() {
if (!isOutlineEnabled.value) { if (!isAsideEnabled.value) {
return return
} }

@ -77,11 +77,13 @@
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
:root { :root {
/* TODO: Clean these styles up */
--vp-c-bg: var(--vp-c-white); --vp-c-bg: var(--vp-c-white);
--vp-c-bg-soft: var(--vp-c-white-soft); --vp-c-bg-soft: var(--vp-c-white-soft);
--vp-c-bg-mute: var(--vp-c-white-mute); --vp-c-bg-mute: var(--vp-c-white-mute);
--vp-c-bg-content: var(--vp-c-white); --vp-c-bg-content: var(--vp-c-white);
--vp-c-bg-sidebar: var(--vp-c-white-soft); --vp-c-bg-sidebar: var(--vp-c-white-soft);
--vp-c-bg-alt: var(--vp-c-white-soft);
--vp-c-divider: var(--vp-c-divider-light-1); --vp-c-divider: var(--vp-c-divider-light-1);
--vp-c-divider-light: var(--vp-c-divider-light-2); --vp-c-divider-light: var(--vp-c-divider-light-2);
@ -111,11 +113,13 @@
} }
.dark { .dark {
/* TODO: Clean these styles up */
--vp-c-bg: var(--vp-c-black); --vp-c-bg: var(--vp-c-black);
--vp-c-bg-soft: var(--vp-c-black-soft); --vp-c-bg-soft: var(--vp-c-black-soft);
--vp-c-bg-mute: var(--vp-c-black-mute); --vp-c-bg-mute: var(--vp-c-black-mute);
--vp-c-bg-content: var(--vp-c-bg-soft); --vp-c-bg-content: var(--vp-c-black-soft);
--vp-c-bg-sidebar: var(--vp-c-bg); --vp-c-bg-sidebar: var(--vp-c-black);
--vp-c-bg-alt: var(--vp-c-black);
--vp-c-divider: var(--vp-c-divider-dark-1); --vp-c-divider: var(--vp-c-divider-dark-1);
--vp-c-divider-light: var(--vp-c-divider-dark-2); --vp-c-divider-light: var(--vp-c-divider-dark-2);

@ -89,9 +89,8 @@ export function createVitePressPlugin(
alias alias
}, },
define: { define: {
__CARBON__: !!site.themeConfig.carbonAds?.carbon, __ALGOLIA__: !!site.themeConfig.algolia,
__BSA__: !!site.themeConfig.carbonAds?.custom, __CARBON__: !!site.themeConfig.carbonAds
__ALGOLIA__: !!site.themeConfig.algolia
}, },
optimizeDeps: { optimizeDeps: {
// force include vue to avoid duplicated copies when linked + optimized // force include vue to avoid duplicated copies when linked + optimized

@ -176,8 +176,7 @@ export namespace DefaultTheme {
// carbon ads ---------------------------------------------------------------- // carbon ads ----------------------------------------------------------------
export interface CarbonAdsOptions { export interface CarbonAdsOptions {
carbon: string code: string
custom?: string
placement: string placement: string
} }
} }

Loading…
Cancel
Save