Skip to content

Commit b09e64a

Browse files
committed
Merge branch 'main' of github.com:nuxt/scripts
2 parents 08027ed + d637151 commit b09e64a

File tree

8 files changed

+400
-10
lines changed

8 files changed

+400
-10
lines changed
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
---
2+
title: Carbon Ads
3+
description: Show carbon ads in your Nuxt app using a Vue component.
4+
links:
5+
- label: "<ScriptCarbonAds>"
6+
icon: i-simple-icons-github
7+
to: https://github.com/nuxt/scripts/blob/main/src/runtime/components/ScriptCarbonAds.vue
8+
size: xs
9+
---
10+
11+
[Carbon Ads](https://www.carbonads.net/) is an ad service that provides a performance friendly way to show ads on your site.
12+
13+
Nuxt Scripts provides a headless `ScriptCarbonAds` component to embed Carbon Ads in your Nuxt app.
14+
15+
## ScriptCarbonAds
16+
17+
The `ScriptCarbonAds` component works differently to other Nuxt Scripts component and does not rely on `useScript`, instead it simply
18+
inserts a script tag into the div of the component on mount.
19+
20+
By default, the component uses CarbonAds best practices which is to load immediately on mount. You can make use of [Element Event Triggers](/docs/guides/script-triggers#element-event-triggers) if you
21+
want to load the ads on a specific event.
22+
23+
```vue
24+
<template>
25+
<ScriptCarbonAds
26+
serve="..."
27+
placement="..."
28+
/>
29+
</template>
30+
```
31+
32+
### Handling Ad-blockers
33+
34+
You can use these hooks to add a fallback when CarbonAds is blocked.
35+
36+
```vue
37+
<template>
38+
<ScriptCarbonAds
39+
serve="..."
40+
placement="..."
41+
>
42+
<template #error>
43+
<!-- Fallback ad -->
44+
Please support us by disabling your ad blocker.
45+
</template>
46+
</ScriptCarbonAds>
47+
</template>
48+
```
49+
50+
### Adding UI
51+
52+
The component renders as headless, meaning there is no inherit styles. If you'd like to customize the look of the ad, you can
53+
use this example from nuxt.com.
54+
55+
```vue
56+
<template>
57+
<ScriptCarbonAds
58+
class="Carbon border border-gray-200 dark:border-gray-800 rounded-lg bg-white dark:bg-white/5"
59+
serve="..."
60+
placement="..."
61+
/>
62+
</template>
63+
64+
<style lang="postcss">
65+
/* Credits to nuxt.com */
66+
.dark .Carbon {
67+
min-height: 220px;
68+
.carbon-text {
69+
@apply text-gray-400;
70+
71+
&:hover {
72+
@apply text-gray-200;
73+
}
74+
}
75+
}
76+
77+
.light .Carbon {
78+
.carbon-text {
79+
@apply text-gray-600;
80+
81+
&:hover {
82+
@apply text-gray-800;
83+
}
84+
}
85+
}
86+
87+
.Carbon {
88+
@apply p-3 flex flex-col max-w-full;
89+
90+
@screen sm {
91+
@apply max-w-xs;
92+
}
93+
94+
@screen lg {
95+
@apply mt-0;
96+
}
97+
98+
#carbonads span {
99+
@apply flex flex-col justify-between;
100+
101+
.carbon-wrap {
102+
@apply flex flex-col;
103+
104+
flex: 1;
105+
106+
@media (min-width: 320px) {
107+
@apply flex-row;
108+
}
109+
110+
@screen lg {
111+
@apply flex-col;
112+
}
113+
114+
.carbon-img {
115+
@apply flex items-start justify-center mb-4;
116+
117+
@media (min-width: 320px) {
118+
@apply mb-0;
119+
}
120+
121+
@screen lg {
122+
@apply mb-4;
123+
}
124+
}
125+
126+
.carbon-text {
127+
@apply flex-1 text-sm w-full m-0 text-left block;
128+
129+
&:hover {
130+
@apply no-underline;
131+
}
132+
133+
@media (min-width: 320px) {
134+
@apply ml-4;
135+
}
136+
137+
@screen lg {
138+
@apply ml-0;
139+
}
140+
}
141+
}
142+
}
143+
144+
img {
145+
@apply w-full;
146+
}
147+
148+
& .carbon-poweredby {
149+
@apply ml-2 text-xs text-right text-gray-400 block pt-2;
150+
151+
&:hover {
152+
@apply no-underline text-gray-500;
153+
}
154+
}
155+
}
156+
</style>
157+
```
158+
159+
### Props
160+
161+
The `ScriptCarbonAds` component accepts the following props:
162+
163+
- `serve`: The serve URL provided by Carbon Ads.
164+
- `placement`: The placement ID provided by Carbon Ads.
165+
- `trigger`: The trigger event to load the script. Default is `undefined`. See [Element Event Triggers](/docs/guides/script-triggers#element-event-triggers) for more information.
166+
167+
### Events
168+
169+
The component emits the script events.
170+
171+
```ts
172+
const emits = defineEmits<{
173+
error: [e: string | Event]
174+
load: []
175+
}>()
176+
```
177+
178+
### Slots
179+
180+
There are a number of slots mapped to the script status that you can use to customize the ad experience.
181+
182+
- **error**:
183+
The slot is used to display content when the ad fails to load.
184+
185+
- **awaitingLoad**
186+
The slot is used to display content before the ad script is loaded.
187+
188+
- **loaded**
189+
The slot is used to display content after the ad script is loaded.
190+
191+
- **loading**
192+
The slot is used to display content while the ad script is loading.
193+
194+
```vue
195+
<template>
196+
<ScriptCarbonAds
197+
serve="..."
198+
placement="..."
199+
>
200+
<template #awaitingLoad>
201+
Loading ads...
202+
</template>
203+
</ScriptCarbonAds>
204+
</template>
205+
```
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<template>
2+
<ScriptCarbonAds
3+
class="Carbon border border-gray-200 dark:border-gray-800 rounded-lg bg-white dark:bg-white/5"
4+
serve="CW7DTKJL"
5+
placement="unlighthousedev"
6+
>
7+
<template #awaitingLoad>
8+
<div>waiting for carbon</div>
9+
</template>
10+
<template #error>
11+
<div>Please enable ads</div>
12+
</template>
13+
</ScriptCarbonAds>
14+
</template>
15+
16+
<style lang="postcss">
17+
/* Credits to nuxt.com */
18+
.dark .Carbon {
19+
min-height: 220px;
20+
.carbon-text {
21+
@apply text-gray-400;
22+
23+
&:hover {
24+
@apply text-gray-200;
25+
}
26+
}
27+
}
28+
29+
.light .Carbon {
30+
.carbon-text {
31+
@apply text-gray-600;
32+
33+
&:hover {
34+
@apply text-gray-800;
35+
}
36+
}
37+
}
38+
39+
.Carbon {
40+
@apply p-3 flex flex-col max-w-full;
41+
42+
@screen sm {
43+
@apply max-w-xs;
44+
}
45+
46+
@screen lg {
47+
@apply mt-0;
48+
}
49+
50+
#carbonads span {
51+
@apply flex flex-col justify-between;
52+
53+
.carbon-wrap {
54+
@apply flex flex-col;
55+
56+
flex: 1;
57+
58+
@media (min-width: 320px) {
59+
@apply flex-row;
60+
}
61+
62+
@screen lg {
63+
@apply flex-col;
64+
}
65+
66+
.carbon-img {
67+
@apply flex items-start justify-center mb-4;
68+
69+
@media (min-width: 320px) {
70+
@apply mb-0;
71+
}
72+
73+
@screen lg {
74+
@apply mb-4;
75+
}
76+
}
77+
78+
.carbon-text {
79+
@apply flex-1 text-sm w-full m-0 text-left block;
80+
81+
&:hover {
82+
@apply no-underline;
83+
}
84+
85+
@media (min-width: 320px) {
86+
@apply ml-4;
87+
}
88+
89+
@screen lg {
90+
@apply ml-0;
91+
}
92+
}
93+
}
94+
}
95+
96+
img {
97+
@apply w-full;
98+
}
99+
100+
& .carbon-poweredby {
101+
@apply ml-2 text-xs text-right text-gray-400 block pt-2;
102+
103+
&:hover {
104+
@apply no-underline text-gray-500;
105+
}
106+
}
107+
}
108+
</style>

src/module.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import type {
2222
NuxtConfigScriptRegistry,
2323
NuxtUseScriptInput,
2424
NuxtUseScriptOptions,
25+
RegistryScript,
2526
RegistryScripts,
2627
} from './runtime/types'
2728

@@ -128,15 +129,16 @@ export default defineNuxtModule<ModuleOptions>({
128129
const registryScripts = [...scripts]
129130
// @ts-expect-error runtime
130131
await nuxt.hooks.callHook('scripts:registry', registryScripts)
131-
addImports(registryScripts.map((i) => {
132+
const withComposables = registryScripts.filter(i => !!i.import?.name) as Required<RegistryScript>[]
133+
addImports(withComposables.map((i) => {
132134
return {
133135
priority: -1,
134136
...i.import,
135137
}
136138
}))
137139

138140
// compare the registryScripts to the original registry to find new scripts
139-
const newScripts = registryScripts.filter(i => !scripts.some(r => r.import.name === i.import.name))
141+
const newScripts = withComposables.filter(i => !scripts.some(r => r.import?.name === i.import.name))
140142

141143
// augment types to support the integrations registry
142144
extendTypes(name!, async ({ typesPath }) => {
@@ -156,9 +158,9 @@ declare module '#nuxt-scripts' {
156158
type NuxtUseScriptOptions = Omit<import('${typesPath}').NuxtUseScriptOptions, 'use' | 'beforeInit'>
157159
interface ScriptRegistry {
158160
${newScripts.map((i) => {
159-
const key = i.import.name.replace('useScript', '')
161+
const key = i.import?.name.replace('useScript', '')
160162
const keyLcFirst = key.substring(0, 1).toLowerCase() + key.substring(1)
161-
return ` ${keyLcFirst}?: import('${i.import.from}').${key}Input | [import('${i.import.from}').${key}Input, NuxtUseScriptOptions]`
163+
return ` ${keyLcFirst}?: import('${i.import?.from}').${key}Input | [import('${i.import?.from}').${key}Input, NuxtUseScriptOptions]`
162164
}).join('\n')}
163165
}
164166
}`
@@ -176,7 +178,7 @@ ${newScripts.map((i) => {
176178
const inits = []
177179
// for global scripts, we can initialise them script away
178180
for (const [k, c] of Object.entries(config.registry || {})) {
179-
const importDefinition = registryScripts.find(i => i.import.name === `useScript${k.substring(0, 1).toUpperCase() + k.substring(1)}`)
181+
const importDefinition = withComposables.find(i => i.import.name === `useScript${k.substring(0, 1).toUpperCase() + k.substring(1)}`)
180182
if (importDefinition) {
181183
// title case
182184
imports.unshift(importDefinition.import.name)
@@ -206,7 +208,7 @@ ${(config.globals || []).map(g => !Array.isArray(g)
206208

207209
const moduleInstallPromises: Map<string, () => Promise<boolean> | undefined> = new Map()
208210
addBuildPlugin(NuxtScriptBundleTransformer({
209-
scripts,
211+
scripts: withComposables,
210212
defaultBundle: config.defaultScriptOptions?.bundle,
211213
moduleDetected(module) {
212214
if (nuxt.options.dev && module !== '@nuxt/scripts' && !moduleInstallPromises.has(module) && !hasNuxtModule(module))

src/plugins/transform.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import type { Node } from 'estree-walker'
77
import { walk } from 'estree-walker'
88
import type { Literal, ObjectExpression, Property, SimpleCallExpression } from 'estree'
99
import type { Input } from 'valibot'
10-
import type { RegistryScripts } from '#nuxt-scripts'
10+
import type { RegistryScript } from '#nuxt-scripts'
1111

1212
export interface AssetBundlerTransformerOptions {
1313
resolveScript: (src: string) => string
1414
moduleDetected?: (module: string) => void
1515
defaultBundle?: boolean
16-
scripts?: RegistryScripts
16+
scripts?: Required<RegistryScript>[]
1717
}
1818

1919
export function NuxtScriptBundleTransformer(options: AssetBundlerTransformerOptions) {

src/registry.ts

Lines changed: 6 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)