@launch77-shared/plugin-marketing-ui 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/dist/generator.js +260 -0
- package/package.json +46 -0
- package/plugin.json +9 -0
- package/templates/src/.gitkeep +0 -0
- package/templates/src/app/marketing-ui-examples/page.tsx +283 -0
- package/templates/src/modules/marketing-ui/README.md +400 -0
- package/templates/src/modules/marketing-ui/index.ts +2 -0
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# MarketingUi Plugin
|
|
2
|
+
|
|
3
|
+
Marketing UI component library plugin with conversion-optimized components
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
launch77 plugin:install marketing-ui
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
After installation, the plugin will:
|
|
14
|
+
|
|
15
|
+
- TODO: Describe what the plugin does
|
|
16
|
+
- TODO: List any files created or modified
|
|
17
|
+
- TODO: Explain configuration options
|
|
18
|
+
|
|
19
|
+
## Development
|
|
20
|
+
|
|
21
|
+
### Building
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm run build
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Testing
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm run typecheck
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Template Files
|
|
34
|
+
|
|
35
|
+
The `templates/` directory contains files that will be copied to the target application when this plugin is installed. Add any template files your plugin needs here.
|
|
36
|
+
|
|
37
|
+
## License
|
|
38
|
+
|
|
39
|
+
UNLICENSED
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/generator.ts
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import { StandardGenerator } from "@launch77/plugin-runtime";
|
|
7
|
+
|
|
8
|
+
// src/utils/config-modifier.ts
|
|
9
|
+
import fs from "fs/promises";
|
|
10
|
+
async function addTailwindContent(filePath, contentPath) {
|
|
11
|
+
try {
|
|
12
|
+
const fileExists = await fs.access(filePath).then(() => true).catch(() => false);
|
|
13
|
+
if (!fileExists) {
|
|
14
|
+
return {
|
|
15
|
+
success: false,
|
|
16
|
+
error: `File not found: ${filePath}`
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
20
|
+
if (content.includes(contentPath)) {
|
|
21
|
+
return {
|
|
22
|
+
success: true,
|
|
23
|
+
alreadyExists: true
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const lines = content.split("\n");
|
|
27
|
+
let contentArrayStartIndex = -1;
|
|
28
|
+
let contentArrayEndIndex = -1;
|
|
29
|
+
for (let i = 0; i < lines.length; i++) {
|
|
30
|
+
const line = lines[i];
|
|
31
|
+
if (line.includes("content:") && line.includes("[")) {
|
|
32
|
+
contentArrayStartIndex = i;
|
|
33
|
+
if (line.includes("]")) {
|
|
34
|
+
contentArrayEndIndex = i;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
38
|
+
if (lines[j].includes("]")) {
|
|
39
|
+
contentArrayEndIndex = j;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (contentArrayStartIndex === -1) {
|
|
47
|
+
return {
|
|
48
|
+
success: false,
|
|
49
|
+
error: "Could not find content array in Tailwind config"
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
let indentation = " ";
|
|
53
|
+
for (let i = contentArrayStartIndex + 1; i < contentArrayEndIndex; i++) {
|
|
54
|
+
const match = lines[i].match(/^(\s+)['"]/);
|
|
55
|
+
if (match) {
|
|
56
|
+
indentation = match[1];
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const newLine = `${indentation}'${contentPath}',`;
|
|
61
|
+
lines.splice(contentArrayEndIndex, 0, newLine);
|
|
62
|
+
const newContent = lines.join("\n");
|
|
63
|
+
await fs.writeFile(filePath, newContent, "utf-8");
|
|
64
|
+
return {
|
|
65
|
+
success: true
|
|
66
|
+
};
|
|
67
|
+
} catch (error) {
|
|
68
|
+
return {
|
|
69
|
+
success: false,
|
|
70
|
+
error: error instanceof Error ? error.message : String(error)
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/utils/next-config-modifier.ts
|
|
76
|
+
import * as fs2 from "fs/promises";
|
|
77
|
+
async function addNextImageRemotePattern(filePath, hostname) {
|
|
78
|
+
try {
|
|
79
|
+
const fileExists = await fs2.access(filePath).then(
|
|
80
|
+
() => true,
|
|
81
|
+
() => false
|
|
82
|
+
);
|
|
83
|
+
if (!fileExists) {
|
|
84
|
+
return {
|
|
85
|
+
success: false,
|
|
86
|
+
error: `Config file not found at ${filePath}`
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
const content = await fs2.readFile(filePath, "utf-8");
|
|
90
|
+
if (content.includes(`hostname: '${hostname}'`) || content.includes(`hostname: "${hostname}"`)) {
|
|
91
|
+
return {
|
|
92
|
+
success: true,
|
|
93
|
+
alreadyExists: true
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const patternToAdd = ` {
|
|
97
|
+
protocol: 'https',
|
|
98
|
+
hostname: '${hostname}',
|
|
99
|
+
port: '',
|
|
100
|
+
pathname: '/**',
|
|
101
|
+
},`;
|
|
102
|
+
const lines = content.split("\n");
|
|
103
|
+
let newContent;
|
|
104
|
+
const hasRemotePatterns = content.includes("remotePatterns");
|
|
105
|
+
if (hasRemotePatterns) {
|
|
106
|
+
const remotePatternsIndex = lines.findIndex((line) => line.includes("remotePatterns"));
|
|
107
|
+
if (remotePatternsIndex === -1) {
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
error: "Could not find remotePatterns in config"
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
let arrayStartIndex = remotePatternsIndex;
|
|
114
|
+
for (let i = remotePatternsIndex; i < lines.length; i++) {
|
|
115
|
+
if (lines[i].includes("[")) {
|
|
116
|
+
arrayStartIndex = i;
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
lines.splice(arrayStartIndex + 1, 0, patternToAdd);
|
|
121
|
+
newContent = lines.join("\n");
|
|
122
|
+
} else {
|
|
123
|
+
const hasImages = content.includes("images:");
|
|
124
|
+
if (hasImages) {
|
|
125
|
+
const imagesIndex = lines.findIndex((line) => line.includes("images:"));
|
|
126
|
+
if (imagesIndex === -1) {
|
|
127
|
+
return {
|
|
128
|
+
success: false,
|
|
129
|
+
error: "Could not find images configuration"
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
let objectStartIndex = imagesIndex;
|
|
133
|
+
for (let i = imagesIndex; i < lines.length; i++) {
|
|
134
|
+
if (lines[i].includes("{")) {
|
|
135
|
+
objectStartIndex = i;
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const remotePatternsProp = ` remotePatterns: [
|
|
140
|
+
${patternToAdd}
|
|
141
|
+
],`;
|
|
142
|
+
lines.splice(objectStartIndex + 1, 0, remotePatternsProp);
|
|
143
|
+
newContent = lines.join("\n");
|
|
144
|
+
} else {
|
|
145
|
+
const configIndex = lines.findIndex((line) => line.includes("const config") || line.includes("module.exports") || line.includes("export default"));
|
|
146
|
+
if (configIndex === -1) {
|
|
147
|
+
return {
|
|
148
|
+
success: false,
|
|
149
|
+
error: "Could not find Next.js config object"
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
let objectStartIndex = configIndex;
|
|
153
|
+
for (let i = configIndex; i < lines.length; i++) {
|
|
154
|
+
if (lines[i].includes("{")) {
|
|
155
|
+
objectStartIndex = i;
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const imagesProp = ` images: {
|
|
160
|
+
remotePatterns: [
|
|
161
|
+
${patternToAdd}
|
|
162
|
+
],
|
|
163
|
+
},`;
|
|
164
|
+
lines.splice(objectStartIndex + 1, 0, imagesProp);
|
|
165
|
+
newContent = lines.join("\n");
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
await fs2.writeFile(filePath, newContent, "utf-8");
|
|
169
|
+
return {
|
|
170
|
+
success: true
|
|
171
|
+
};
|
|
172
|
+
} catch (error) {
|
|
173
|
+
return {
|
|
174
|
+
success: false,
|
|
175
|
+
error: error instanceof Error ? error.message : String(error)
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// src/generator.ts
|
|
181
|
+
var MarketingUiGenerator = class extends StandardGenerator {
|
|
182
|
+
constructor(context) {
|
|
183
|
+
super(context);
|
|
184
|
+
}
|
|
185
|
+
async injectCode() {
|
|
186
|
+
console.log(chalk.cyan("\u{1F527} Setting up Marketing UI library...\n"));
|
|
187
|
+
await this.updateTailwindConfig();
|
|
188
|
+
await this.updateNextConfig();
|
|
189
|
+
}
|
|
190
|
+
async updateTailwindConfig() {
|
|
191
|
+
const tailwindConfigPath = path.join(this.context.appPath, "tailwind.config.ts");
|
|
192
|
+
const result1 = await addTailwindContent(tailwindConfigPath, "node_modules/@launch77-shared/lib-marketing-ui/dist/**/*.js");
|
|
193
|
+
const result2 = await addTailwindContent(tailwindConfigPath, "../../node_modules/@launch77-shared/lib-marketing-ui/dist/**/*.js");
|
|
194
|
+
if (result1.success || result2.success) {
|
|
195
|
+
if (result1.alreadyExists && result2.alreadyExists) {
|
|
196
|
+
console.log(chalk.gray(" \u2713 Marketing UI library already configured in tailwind.config.ts"));
|
|
197
|
+
} else {
|
|
198
|
+
console.log(chalk.green(" \u2713 Added Marketing UI library to Tailwind content paths"));
|
|
199
|
+
}
|
|
200
|
+
} else {
|
|
201
|
+
console.log(chalk.yellow(` \u26A0\uFE0F Could not auto-configure tailwind.config.ts: ${result1.error}`));
|
|
202
|
+
console.log(chalk.gray(" You will need to add the content paths manually:"));
|
|
203
|
+
console.log(chalk.gray(" 'node_modules/@launch77-shared/lib-marketing-ui/dist/**/*.js'"));
|
|
204
|
+
console.log(chalk.gray(" '../../node_modules/@launch77-shared/lib-marketing-ui/dist/**/*.js'"));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async updateNextConfig() {
|
|
208
|
+
const nextConfigJsPath = path.join(this.context.appPath, "next.config.js");
|
|
209
|
+
const nextConfigTsPath = path.join(this.context.appPath, "next.config.ts");
|
|
210
|
+
const resultJs = await addNextImageRemotePattern(nextConfigJsPath, "images.unsplash.com");
|
|
211
|
+
const resultTs = await addNextImageRemotePattern(nextConfigTsPath, "images.unsplash.com");
|
|
212
|
+
if (resultJs.success || resultTs.success) {
|
|
213
|
+
if (resultJs.alreadyExists || resultTs.alreadyExists) {
|
|
214
|
+
console.log(chalk.gray(" \u2713 Unsplash images already configured in next.config"));
|
|
215
|
+
} else {
|
|
216
|
+
console.log(chalk.green(" \u2713 Added Unsplash to Next.js image remotePatterns"));
|
|
217
|
+
}
|
|
218
|
+
} else {
|
|
219
|
+
console.log(chalk.yellow(` \u26A0\uFE0F Could not auto-configure next.config: ${resultJs.error || resultTs.error}`));
|
|
220
|
+
console.log(chalk.gray(" You will need to add image configuration manually"));
|
|
221
|
+
console.log(chalk.gray(" See src/modules/marketing-ui/README.md for details"));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
showNextSteps() {
|
|
225
|
+
console.log(chalk.bold.green("\n\u2705 Plugin installed successfully!\n"));
|
|
226
|
+
console.log(chalk.bold("Next Steps:\n"));
|
|
227
|
+
console.log("1. Explore components:");
|
|
228
|
+
console.log(chalk.cyan(" Visit http://localhost:3000/marketing-ui-examples\n"));
|
|
229
|
+
console.log("2. Import components in your code:");
|
|
230
|
+
console.log(chalk.cyan(" import { HeroCentered, CTAButton } from '@launch77-shared/lib-marketing-ui'\n"));
|
|
231
|
+
console.log("3. View documentation:");
|
|
232
|
+
console.log(chalk.cyan(" See src/modules/marketing-ui/README.md\n"));
|
|
233
|
+
console.log(chalk.gray("Note: Unsplash images are pre-configured. To add other image hosts,"));
|
|
234
|
+
console.log(chalk.gray("see the External Images section in README.md\n"));
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
async function main() {
|
|
238
|
+
const args = process.argv.slice(2);
|
|
239
|
+
const appPath = args.find((arg) => arg.startsWith("--appPath="))?.split("=")[1];
|
|
240
|
+
const appName = args.find((arg) => arg.startsWith("--appName="))?.split("=")[1];
|
|
241
|
+
const workspaceName = args.find((arg) => arg.startsWith("--workspaceName="))?.split("=")[1];
|
|
242
|
+
const pluginPath = args.find((arg) => arg.startsWith("--pluginPath="))?.split("=")[1];
|
|
243
|
+
if (!appPath || !appName || !workspaceName || !pluginPath) {
|
|
244
|
+
console.error(chalk.red("Error: Missing required arguments"));
|
|
245
|
+
console.error(chalk.gray("Usage: --appPath=<path> --appName=<name> --workspaceName=<name> --pluginPath=<path>"));
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
const generator = new MarketingUiGenerator({ appPath, appName, workspaceName, pluginPath });
|
|
249
|
+
await generator.run();
|
|
250
|
+
}
|
|
251
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
252
|
+
main().catch((error) => {
|
|
253
|
+
console.error(chalk.red("\n\u274C Error during plugin setup:"));
|
|
254
|
+
console.error(error);
|
|
255
|
+
process.exit(1);
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
export {
|
|
259
|
+
MarketingUiGenerator
|
|
260
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@launch77-shared/plugin-marketing-ui",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Marketing UI component library plugin with conversion-optimized components",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/generator.js",
|
|
8
|
+
"bin": {
|
|
9
|
+
"generate": "./dist/generator.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist/",
|
|
13
|
+
"templates/",
|
|
14
|
+
"plugin.json"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsup",
|
|
18
|
+
"dev": "tsup --watch",
|
|
19
|
+
"typecheck": "tsc --noEmit",
|
|
20
|
+
"lint": "eslint src/**/*.ts",
|
|
21
|
+
"release:connect": "launch77-release-connect",
|
|
22
|
+
"release:verify": "launch77-release-verify"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@launch77/plugin-runtime": "^0.1.0",
|
|
26
|
+
"chalk": "^5.3.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^20.10.0",
|
|
30
|
+
"tsup": "^8.0.0",
|
|
31
|
+
"typescript": "^5.3.0"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"launch77": {
|
|
37
|
+
"installedPlugins": {
|
|
38
|
+
"release": {
|
|
39
|
+
"package": "release",
|
|
40
|
+
"version": "1.0.1",
|
|
41
|
+
"installedAt": "2026-01-26T01:08:50.461Z",
|
|
42
|
+
"source": "local"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
package/plugin.json
ADDED
|
File without changes
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
import { HeroCentered, HeroSplit, ContentSection, MarketingCard, CardGrid, CTAButton, CookieConsent } from '@launch77-shared/lib-marketing-ui'
|
|
5
|
+
import { Button, Badge } from '@launch77-shared/lib-ui'
|
|
6
|
+
import { Zap, Shield, Check, Rocket, Target, Lock } from 'lucide-react'
|
|
7
|
+
|
|
8
|
+
export default function MarketingUiExamplesPage() {
|
|
9
|
+
const [showCookieConsent, setShowCookieConsent] = useState(false)
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<div className="min-h-screen bg-background">
|
|
13
|
+
<div className="container mx-auto px-4 py-12 space-y-24">
|
|
14
|
+
{/* Page Header */}
|
|
15
|
+
<div className="space-y-4">
|
|
16
|
+
<h1 className="text-4xl font-bold">Marketing UI Components</h1>
|
|
17
|
+
<p className="text-lg text-muted-foreground">Pre-built marketing components from @launch77-shared/lib-marketing-ui for building landing pages and marketing sites.</p>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
{/* Hero Sections */}
|
|
21
|
+
<section className="space-y-12">
|
|
22
|
+
<div>
|
|
23
|
+
<h2 className="text-3xl font-bold mb-2">Hero Sections</h2>
|
|
24
|
+
<p className="text-muted-foreground">Centered and split hero layouts for impactful first impressions</p>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
{/* HeroCentered */}
|
|
28
|
+
<div className="space-y-4">
|
|
29
|
+
<h3 className="text-2xl font-semibold">HeroCentered</h3>
|
|
30
|
+
<div className="border rounded-lg overflow-hidden">
|
|
31
|
+
<HeroCentered
|
|
32
|
+
badge={
|
|
33
|
+
<Badge variant="secondary" className="text-sm">
|
|
34
|
+
🚀 New Release
|
|
35
|
+
</Badge>
|
|
36
|
+
}
|
|
37
|
+
headline="Build Your Next SaaS in Days, Not Months"
|
|
38
|
+
subheadline="The AI-first platform that turns your idea into a production-ready app with pre-built components, auth, payments, and more."
|
|
39
|
+
primaryCTA={<Button size="lg">Start Building Free</Button>}
|
|
40
|
+
secondaryCTA={
|
|
41
|
+
<Button variant="outline" size="lg">
|
|
42
|
+
View Demo
|
|
43
|
+
</Button>
|
|
44
|
+
}
|
|
45
|
+
/>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
{/* HeroSplit */}
|
|
50
|
+
<div className="space-y-4">
|
|
51
|
+
<h3 className="text-2xl font-semibold">HeroSplit</h3>
|
|
52
|
+
<div className="border rounded-lg overflow-hidden">
|
|
53
|
+
<HeroSplit
|
|
54
|
+
imageUrl="https://images.unsplash.com/photo-1551434678-e076c223a692?w=800&h=600&fit=crop"
|
|
55
|
+
imageAlt="Team collaboration"
|
|
56
|
+
imageSide="right"
|
|
57
|
+
decorativeBlob={true}
|
|
58
|
+
blobGradient="from-purple-400 to-blue-400"
|
|
59
|
+
content={
|
|
60
|
+
<div className="space-y-6">
|
|
61
|
+
<Badge variant="outline">Product Update</Badge>
|
|
62
|
+
<h1 className="text-4xl lg:text-5xl font-bold">Ship Faster with Launch77</h1>
|
|
63
|
+
<p className="text-lg text-muted-foreground">Join thousands of developers using our AI-powered platform to build and deploy web apps at lightning speed.</p>
|
|
64
|
+
<div className="flex gap-4">
|
|
65
|
+
<Button size="lg">Get Started</Button>
|
|
66
|
+
<Button variant="link" size="lg">
|
|
67
|
+
Learn More →
|
|
68
|
+
</Button>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
}
|
|
72
|
+
/>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</section>
|
|
76
|
+
|
|
77
|
+
{/* Content Sections */}
|
|
78
|
+
<section className="space-y-12">
|
|
79
|
+
<div>
|
|
80
|
+
<h2 className="text-3xl font-bold mb-2">Content Sections</h2>
|
|
81
|
+
<p className="text-muted-foreground">Flexible content layouts for features, benefits, and more</p>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
{/* ContentSection - Features */}
|
|
85
|
+
<div className="space-y-4">
|
|
86
|
+
<h3 className="text-2xl font-semibold">Features Grid</h3>
|
|
87
|
+
<ContentSection headline="Built for Modern Development">
|
|
88
|
+
<div className="space-y-4">
|
|
89
|
+
<Badge>Why Choose Launch77</Badge>
|
|
90
|
+
<p className="text-lg text-muted-foreground">Everything you need to build, deploy, and scale your applications</p>
|
|
91
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mt-8">
|
|
92
|
+
<div className="flex gap-4">
|
|
93
|
+
<div className="text-2xl">🚀</div>
|
|
94
|
+
<div>
|
|
95
|
+
<h3 className="font-semibold mb-1">Ship 10x Faster</h3>
|
|
96
|
+
<p className="text-sm text-muted-foreground">Go from idea to production in days, not months</p>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
<div className="flex gap-4">
|
|
100
|
+
<div className="text-2xl">💰</div>
|
|
101
|
+
<div>
|
|
102
|
+
<h3 className="font-semibold mb-1">Save Money</h3>
|
|
103
|
+
<p className="text-sm text-muted-foreground">Reduce development costs by up to 70%</p>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
<div className="flex gap-4">
|
|
107
|
+
<div className="text-2xl">🛡️</div>
|
|
108
|
+
<div>
|
|
109
|
+
<h3 className="font-semibold mb-1">Enterprise Security</h3>
|
|
110
|
+
<p className="text-sm text-muted-foreground">SOC 2 compliant with end-to-end encryption</p>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
<div className="flex gap-4">
|
|
114
|
+
<div className="text-2xl">📈</div>
|
|
115
|
+
<div>
|
|
116
|
+
<h3 className="font-semibold mb-1">Scale Effortlessly</h3>
|
|
117
|
+
<p className="text-sm text-muted-foreground">Handle millions of users without breaking a sweat</p>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</ContentSection>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
{/* ContentSection - Centered */}
|
|
126
|
+
<div className="space-y-4">
|
|
127
|
+
<h3 className="text-2xl font-semibold">Centered Content</h3>
|
|
128
|
+
<ContentSection headline="How It Works" textAlign="center">
|
|
129
|
+
<div className="space-y-4">
|
|
130
|
+
<p className="text-lg text-muted-foreground">Get from idea to production in three simple steps</p>
|
|
131
|
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 mt-12">
|
|
132
|
+
<div className="text-center">
|
|
133
|
+
<div className="text-4xl mb-4">1️⃣</div>
|
|
134
|
+
<h3 className="font-semibold mb-2">Describe Your App</h3>
|
|
135
|
+
<p className="text-sm text-muted-foreground">Tell our AI what you want to build</p>
|
|
136
|
+
</div>
|
|
137
|
+
<div className="text-center">
|
|
138
|
+
<div className="text-4xl mb-4">2️⃣</div>
|
|
139
|
+
<h3 className="font-semibold mb-2">Customize & Review</h3>
|
|
140
|
+
<p className="text-sm text-muted-foreground">Fine-tune the generated code to your needs</p>
|
|
141
|
+
</div>
|
|
142
|
+
<div className="text-center">
|
|
143
|
+
<div className="text-4xl mb-4">3️⃣</div>
|
|
144
|
+
<h3 className="font-semibold mb-2">Deploy & Scale</h3>
|
|
145
|
+
<p className="text-sm text-muted-foreground">Go live with one click and scale effortlessly</p>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
</ContentSection>
|
|
150
|
+
</div>
|
|
151
|
+
</section>
|
|
152
|
+
|
|
153
|
+
{/* Cards */}
|
|
154
|
+
<section className="space-y-12">
|
|
155
|
+
<div>
|
|
156
|
+
<h2 className="text-3xl font-bold mb-2">Cards</h2>
|
|
157
|
+
<p className="text-muted-foreground">Marketing cards for features, testimonials, and pricing</p>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
{/* MarketingCard */}
|
|
161
|
+
<div className="space-y-4">
|
|
162
|
+
<h3 className="text-2xl font-semibold">MarketingCard</h3>
|
|
163
|
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
164
|
+
<MarketingCard icon={Zap} title="Beautiful Design" description="Pre-built components that look great out of the box" variant="feature" />
|
|
165
|
+
<MarketingCard icon={Rocket} title="Lightning Fast" description="Optimized for performance and Core Web Vitals" variant="feature" />
|
|
166
|
+
<MarketingCard icon={Check} title="Fully Customizable" description="Extend and modify components to match your brand" variant="feature" />
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
{/* CardGrid */}
|
|
171
|
+
<div className="space-y-4">
|
|
172
|
+
<h3 className="text-2xl font-semibold">CardGrid</h3>
|
|
173
|
+
<CardGrid columns={3} gap="md">
|
|
174
|
+
<MarketingCard icon={Rocket} title="Fast Development" description="Build and ship features at unprecedented speed" variant="feature" />
|
|
175
|
+
<MarketingCard icon={Shield} title="Premium Quality" description="Enterprise-grade code that scales with your business" variant="solution" />
|
|
176
|
+
<MarketingCard icon={Target} title="Focus on Users" description="Spend more time on what matters - your customers" variant="feature" />
|
|
177
|
+
<MarketingCard icon={Lock} title="Secure by Default" description="Built-in security best practices and compliance" variant="solution" />
|
|
178
|
+
</CardGrid>
|
|
179
|
+
</div>
|
|
180
|
+
</section>
|
|
181
|
+
|
|
182
|
+
{/* CTA Components */}
|
|
183
|
+
<section className="space-y-12">
|
|
184
|
+
<div>
|
|
185
|
+
<h2 className="text-3xl font-bold mb-2">Call-to-Action</h2>
|
|
186
|
+
<p className="text-muted-foreground">Conversion-optimized CTA buttons and sections</p>
|
|
187
|
+
</div>
|
|
188
|
+
|
|
189
|
+
{/* CTAButton */}
|
|
190
|
+
<div className="space-y-4">
|
|
191
|
+
<h3 className="text-2xl font-semibold">CTAButton</h3>
|
|
192
|
+
<div className="flex gap-4 flex-wrap">
|
|
193
|
+
<CTAButton
|
|
194
|
+
href="/signup"
|
|
195
|
+
size="lg"
|
|
196
|
+
trackingData={{
|
|
197
|
+
location: 'examples-page',
|
|
198
|
+
text: 'Get Started Free',
|
|
199
|
+
destination: '/signup',
|
|
200
|
+
}}
|
|
201
|
+
>
|
|
202
|
+
Get Started Free
|
|
203
|
+
</CTAButton>
|
|
204
|
+
<CTAButton
|
|
205
|
+
href="/learn-more"
|
|
206
|
+
variant="secondary"
|
|
207
|
+
trackingData={{
|
|
208
|
+
location: 'examples-page',
|
|
209
|
+
text: 'Learn More',
|
|
210
|
+
destination: '/learn-more',
|
|
211
|
+
}}
|
|
212
|
+
>
|
|
213
|
+
Learn More
|
|
214
|
+
</CTAButton>
|
|
215
|
+
<CTAButton
|
|
216
|
+
href="/trial"
|
|
217
|
+
size="lg"
|
|
218
|
+
external={false}
|
|
219
|
+
trackingData={{
|
|
220
|
+
location: 'examples-page',
|
|
221
|
+
text: 'Start Your Trial',
|
|
222
|
+
destination: '/trial',
|
|
223
|
+
}}
|
|
224
|
+
>
|
|
225
|
+
Start Your Trial
|
|
226
|
+
</CTAButton>
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
|
|
230
|
+
{/* CTA Section */}
|
|
231
|
+
<div className="space-y-4">
|
|
232
|
+
<h3 className="text-2xl font-semibold">CTA Section</h3>
|
|
233
|
+
<ContentSection headline="Ready to Get Started?" textAlign="center" className="bg-gradient-to-br from-blue-50 to-purple-50 rounded-2xl p-12">
|
|
234
|
+
<div className="space-y-4">
|
|
235
|
+
<p className="text-lg text-muted-foreground">Join thousands of developers building with Launch77</p>
|
|
236
|
+
<div className="flex gap-4 justify-center mt-8">
|
|
237
|
+
<Button size="lg">Start Free Trial</Button>
|
|
238
|
+
<Button variant="outline" size="lg">
|
|
239
|
+
Book a Demo
|
|
240
|
+
</Button>
|
|
241
|
+
</div>
|
|
242
|
+
<p className="text-sm text-muted-foreground mt-4">No credit card required • 14-day free trial</p>
|
|
243
|
+
</div>
|
|
244
|
+
</ContentSection>
|
|
245
|
+
</div>
|
|
246
|
+
</section>
|
|
247
|
+
|
|
248
|
+
{/* Utilities */}
|
|
249
|
+
<section className="space-y-12">
|
|
250
|
+
<div>
|
|
251
|
+
<h2 className="text-3xl font-bold mb-2">Utilities</h2>
|
|
252
|
+
<p className="text-muted-foreground">Additional marketing utilities for analytics and consent management</p>
|
|
253
|
+
</div>
|
|
254
|
+
|
|
255
|
+
{/* CookieConsent */}
|
|
256
|
+
<div className="space-y-4">
|
|
257
|
+
<h3 className="text-2xl font-semibold">CookieConsent</h3>
|
|
258
|
+
<div className="p-4 bg-blue-50 rounded-lg space-y-4">
|
|
259
|
+
<p className="text-sm text-blue-800">
|
|
260
|
+
<strong>Note:</strong> The CookieConsent component manages its own state and appears automatically on first visit. Click the button below to preview the banner.
|
|
261
|
+
</p>
|
|
262
|
+
<Button onClick={() => setShowCookieConsent(true)} variant="outline">
|
|
263
|
+
Show Cookie Consent Preview
|
|
264
|
+
</Button>
|
|
265
|
+
</div>
|
|
266
|
+
{showCookieConsent && <CookieConsent debug={true} />}
|
|
267
|
+
</div>
|
|
268
|
+
</section>
|
|
269
|
+
|
|
270
|
+
{/* Documentation Link */}
|
|
271
|
+
<section className="border-t pt-12">
|
|
272
|
+
<div className="text-center space-y-4">
|
|
273
|
+
<h2 className="text-2xl font-bold">Need More Help?</h2>
|
|
274
|
+
<p className="text-muted-foreground">Check out the full documentation for detailed usage examples and API reference.</p>
|
|
275
|
+
<Button variant="outline" asChild>
|
|
276
|
+
<a href="/modules/marketing-ui">View Documentation</a>
|
|
277
|
+
</Button>
|
|
278
|
+
</div>
|
|
279
|
+
</section>
|
|
280
|
+
</div>
|
|
281
|
+
</div>
|
|
282
|
+
)
|
|
283
|
+
}
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
# Marketing UI Component Library
|
|
2
|
+
|
|
3
|
+
This module provides access to the Launch77 Marketing UI component library - a collection of pre-built marketing components designed for landing pages, promotional sites, and marketing campaigns.
|
|
4
|
+
|
|
5
|
+
## Available Components
|
|
6
|
+
|
|
7
|
+
### Hero Sections
|
|
8
|
+
|
|
9
|
+
- **HeroCentered** - Centered hero layout with headline, subheadline, badge, and CTAs
|
|
10
|
+
- **HeroSplit** - Split-screen hero with content on one side and image/media on the other
|
|
11
|
+
|
|
12
|
+
### Content Sections
|
|
13
|
+
|
|
14
|
+
- **ContentSection** - Flexible content container with headline and customizable alignment
|
|
15
|
+
- **SectionContainer** - Wrapper component for consistent section spacing and layout
|
|
16
|
+
|
|
17
|
+
### Cards & Grids
|
|
18
|
+
|
|
19
|
+
- **MarketingCard** - Marketing-focused card with icon, title, and description
|
|
20
|
+
- **CardGrid** - Grid layout for displaying multiple marketing cards
|
|
21
|
+
|
|
22
|
+
### Call-to-Action
|
|
23
|
+
|
|
24
|
+
- **CTAButton** - Conversion-optimized call-to-action link button
|
|
25
|
+
|
|
26
|
+
### Utilities
|
|
27
|
+
|
|
28
|
+
- **CookieConsent** - GDPR-compliant cookie consent banner
|
|
29
|
+
- **AnalyticsWrapper** - Wrapper for consent-based analytics tracking
|
|
30
|
+
|
|
31
|
+
### Typography
|
|
32
|
+
|
|
33
|
+
- **FluidHeading** - Responsive heading with fluid typography
|
|
34
|
+
- **FluidText** - Responsive text with fluid sizing
|
|
35
|
+
|
|
36
|
+
## Usage Examples
|
|
37
|
+
|
|
38
|
+
### Basic Hero Section
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { HeroCentered } from '@launch77-shared/lib-marketing-ui'
|
|
42
|
+
import { Button, Badge } from '@launch77-shared/lib-ui'
|
|
43
|
+
|
|
44
|
+
export default function HomePage() {
|
|
45
|
+
return (
|
|
46
|
+
<HeroCentered
|
|
47
|
+
badge={<Badge variant="secondary">New Release</Badge>}
|
|
48
|
+
headline="Build Your Next SaaS in Days, Not Months"
|
|
49
|
+
subheadline="The AI-first platform that turns your idea into a production-ready app with pre-built components, auth, payments, and more."
|
|
50
|
+
primaryCTA={<Button size="lg">Start Building Free</Button>}
|
|
51
|
+
secondaryCTA={
|
|
52
|
+
<Button variant="outline" size="lg">
|
|
53
|
+
View Demo
|
|
54
|
+
</Button>
|
|
55
|
+
}
|
|
56
|
+
/>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Split Hero with Image
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import { HeroSplit } from '@launch77-shared/lib-marketing-ui'
|
|
65
|
+
import { Button, Badge } from '@launch77-shared/lib-ui'
|
|
66
|
+
|
|
67
|
+
export default function AboutPage() {
|
|
68
|
+
return (
|
|
69
|
+
<HeroSplit
|
|
70
|
+
imageUrl="/images/hero-illustration.png"
|
|
71
|
+
imageAlt="Platform illustration"
|
|
72
|
+
imageSide="right"
|
|
73
|
+
decorativeBlob={true}
|
|
74
|
+
blobGradient="from-purple-400 to-blue-400"
|
|
75
|
+
content={
|
|
76
|
+
<div className="space-y-6">
|
|
77
|
+
<Badge variant="outline">Product Update</Badge>
|
|
78
|
+
<h1 className="text-4xl lg:text-5xl font-bold">Ship Faster with Launch77</h1>
|
|
79
|
+
<p className="text-lg text-muted-foreground">Join thousands of developers using our AI-powered platform to build and deploy web apps at lightning speed.</p>
|
|
80
|
+
<div className="flex gap-4">
|
|
81
|
+
<Button size="lg">Get Started</Button>
|
|
82
|
+
<Button variant="link" size="lg">
|
|
83
|
+
Learn More →
|
|
84
|
+
</Button>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
}
|
|
88
|
+
/>
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Content Section with Features
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
import { ContentSection } from '@launch77-shared/lib-marketing-ui'
|
|
97
|
+
import { Badge } from '@launch77-shared/lib-ui'
|
|
98
|
+
|
|
99
|
+
export default function FeaturesSection() {
|
|
100
|
+
return (
|
|
101
|
+
<ContentSection headline="Built for Modern Development">
|
|
102
|
+
<div className="space-y-4">
|
|
103
|
+
<Badge>Why Choose Launch77</Badge>
|
|
104
|
+
<p className="text-lg text-muted-foreground">Everything you need to build, deploy, and scale your applications</p>
|
|
105
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mt-8">
|
|
106
|
+
<div className="flex gap-4">
|
|
107
|
+
<div className="text-2xl">🚀</div>
|
|
108
|
+
<div>
|
|
109
|
+
<h3 className="font-semibold mb-1">Ship 10x Faster</h3>
|
|
110
|
+
<p className="text-sm text-muted-foreground">Go from idea to production in days, not months</p>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
<div className="flex gap-4">
|
|
114
|
+
<div className="text-2xl">💰</div>
|
|
115
|
+
<div>
|
|
116
|
+
<h3 className="font-semibold mb-1">Save Money</h3>
|
|
117
|
+
<p className="text-sm text-muted-foreground">Reduce development costs by up to 70%</p>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</ContentSection>
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Marketing Cards Grid
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
import { CardGrid, MarketingCard } from '@launch77-shared/lib-marketing-ui'
|
|
131
|
+
import { Rocket, Shield, Target } from 'lucide-react'
|
|
132
|
+
|
|
133
|
+
export default function BenefitsSection() {
|
|
134
|
+
return (
|
|
135
|
+
<CardGrid columns={3} gap="md">
|
|
136
|
+
<MarketingCard icon={Rocket} title="Fast Development" description="Build and ship features at unprecedented speed" variant="feature" />
|
|
137
|
+
<MarketingCard icon={Shield} title="Premium Quality" description="Enterprise-grade code that scales with your business" variant="solution" />
|
|
138
|
+
<MarketingCard icon={Target} title="Focus on Users" description="Spend more time on what matters - your customers" variant="feature" />
|
|
139
|
+
</CardGrid>
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Individual Marketing Card
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
import { MarketingCard } from '@launch77-shared/lib-marketing-ui'
|
|
148
|
+
import { Zap } from 'lucide-react'
|
|
149
|
+
|
|
150
|
+
export default function FeatureCard() {
|
|
151
|
+
return <MarketingCard icon={Zap} title="Beautiful Design" description="Pre-built components that look great out of the box" variant="feature" />
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Call-to-Action Button
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
import { CTAButton } from '@launch77-shared/lib-marketing-ui'
|
|
159
|
+
|
|
160
|
+
export default function CTASection() {
|
|
161
|
+
return (
|
|
162
|
+
<CTAButton
|
|
163
|
+
href="/signup"
|
|
164
|
+
size="lg"
|
|
165
|
+
trackingData={{
|
|
166
|
+
location: 'hero-section',
|
|
167
|
+
text: 'Start Free Trial',
|
|
168
|
+
destination: '/signup',
|
|
169
|
+
}}
|
|
170
|
+
>
|
|
171
|
+
Start Free Trial
|
|
172
|
+
</CTAButton>
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Cookie Consent Banner
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
import { CookieConsent } from '@launch77-shared/lib-marketing-ui'
|
|
181
|
+
|
|
182
|
+
// Add to your root layout
|
|
183
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
184
|
+
return (
|
|
185
|
+
<html lang="en">
|
|
186
|
+
<body>
|
|
187
|
+
{children}
|
|
188
|
+
<CookieConsent privacyPolicyUrl="/privacy" />
|
|
189
|
+
</body>
|
|
190
|
+
</html>
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Analytics Wrapper
|
|
196
|
+
|
|
197
|
+
```tsx
|
|
198
|
+
import { AnalyticsWrapper } from '@launch77-shared/lib-marketing-ui'
|
|
199
|
+
|
|
200
|
+
// Wrap your app to enable consent-based analytics
|
|
201
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
202
|
+
return (
|
|
203
|
+
<html lang="en">
|
|
204
|
+
<body>
|
|
205
|
+
<AnalyticsWrapper>{children}</AnalyticsWrapper>
|
|
206
|
+
</body>
|
|
207
|
+
</html>
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Fluid Typography
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
import { FluidHeading, FluidText } from '@launch77-shared/lib-marketing-ui'
|
|
216
|
+
|
|
217
|
+
export default function ResponsiveContent() {
|
|
218
|
+
return (
|
|
219
|
+
<div>
|
|
220
|
+
<FluidHeading level={1} minSize={32} maxSize={64}>
|
|
221
|
+
Responsive Heading
|
|
222
|
+
</FluidHeading>
|
|
223
|
+
<FluidText minSize={16} maxSize={20}>
|
|
224
|
+
This text scales fluidly between viewport sizes for optimal readability.
|
|
225
|
+
</FluidText>
|
|
226
|
+
</div>
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Component Props
|
|
232
|
+
|
|
233
|
+
### HeroCentered
|
|
234
|
+
|
|
235
|
+
- `headline` (string, required) - Main headline text
|
|
236
|
+
- `subheadline` (string, optional) - Subheadline/tagline
|
|
237
|
+
- `badge` (ReactNode, optional) - Badge element to display above headline
|
|
238
|
+
- `primaryCTA` (ReactNode, optional) - Primary call-to-action button
|
|
239
|
+
- `secondaryCTA` (ReactNode, optional) - Secondary call-to-action button
|
|
240
|
+
- `background` (string, optional) - Background CSS classes (default: 'bg-white')
|
|
241
|
+
- `className` (string, optional) - Additional CSS classes
|
|
242
|
+
- `id` (string, optional) - HTML id attribute (default: 'hero')
|
|
243
|
+
|
|
244
|
+
### HeroSplit
|
|
245
|
+
|
|
246
|
+
- `imageUrl` (string, required) - Image source URL
|
|
247
|
+
- `imageAlt` (string, required) - Image alt text for accessibility
|
|
248
|
+
- `imageSide` ('left' | 'right', optional) - Image position (default: 'right')
|
|
249
|
+
- `content` (ReactNode, required) - Hero content (headline, text, buttons, etc.)
|
|
250
|
+
- `decorativeBlob` (boolean, optional) - Show decorative background blob (default: false)
|
|
251
|
+
- `blobGradient` (string, optional) - Tailwind gradient classes for blob
|
|
252
|
+
- `background` (string, optional) - Background CSS classes (default: 'bg-white')
|
|
253
|
+
- `className` (string, optional) - Additional CSS classes
|
|
254
|
+
- `id` (string, optional) - HTML id attribute (default: 'hero')
|
|
255
|
+
- `imageSizes` (string, optional) - Next.js Image sizes attribute
|
|
256
|
+
- `imagePriority` (boolean, optional) - Next.js Image priority loading (default: true)
|
|
257
|
+
|
|
258
|
+
### ContentSection
|
|
259
|
+
|
|
260
|
+
- `headline` (string, optional) - Section headline
|
|
261
|
+
- `children` (ReactNode, required) - Section content
|
|
262
|
+
- `maxWidth` ('narrow' | 'medium' | 'wide', optional) - Max width constraint (default: 'medium')
|
|
263
|
+
- `textAlign` ('left' | 'center' | 'right', optional) - Text alignment (default: 'center')
|
|
264
|
+
- `background` (string, optional) - Background CSS classes (default: 'bg-white')
|
|
265
|
+
- `className` (string, optional) - Additional CSS classes
|
|
266
|
+
- `id` (string, optional) - HTML id attribute
|
|
267
|
+
|
|
268
|
+
### MarketingCard
|
|
269
|
+
|
|
270
|
+
- `icon` (LucideIcon, optional) - Lucide icon component (not string)
|
|
271
|
+
- `title` (string, required) - Card title
|
|
272
|
+
- `description` (string, required) - Card description
|
|
273
|
+
- `variant` ('feature' | 'problem' | 'solution', optional) - Visual variant (default: 'feature')
|
|
274
|
+
- `iconBadgeColor` (string, optional) - Override badge background color
|
|
275
|
+
- `iconColor` (string, optional) - Override icon color
|
|
276
|
+
- `className` (string, optional) - Additional CSS classes
|
|
277
|
+
- `children` (ReactNode, optional) - Additional content below description
|
|
278
|
+
|
|
279
|
+
### CardGrid
|
|
280
|
+
|
|
281
|
+
- `columns` (2 | 3 | 4, optional) - Number of columns (default: 3)
|
|
282
|
+
- `gap` ('sm' | 'md' | 'lg' | 'xl', optional) - Grid gap size (default: 'md')
|
|
283
|
+
- `className` (string, optional) - Additional CSS classes
|
|
284
|
+
- `children` (ReactNode, required) - Grid items (typically MarketingCard components)
|
|
285
|
+
|
|
286
|
+
### CTAButton
|
|
287
|
+
|
|
288
|
+
- `href` (string, required) - Link destination URL
|
|
289
|
+
- `children` (ReactNode, required) - Button text
|
|
290
|
+
- `external` (boolean, optional) - Open in new tab (default: true)
|
|
291
|
+
- `trackingData` (object, optional) - Analytics tracking data with `location`, `text`, and `destination`
|
|
292
|
+
- `variant` ('default' | 'outline' | 'secondary' | 'ghost' | 'link', optional) - Button style variant
|
|
293
|
+
- `size` ('sm' | 'md' | 'lg', optional) - Button size
|
|
294
|
+
- `className` (string, optional) - Additional CSS classes
|
|
295
|
+
- `onClick` (function, optional) - Click handler
|
|
296
|
+
|
|
297
|
+
### CookieConsent
|
|
298
|
+
|
|
299
|
+
- `privacyPolicyUrl` (string, optional) - Privacy policy page URL (default: '/privacy')
|
|
300
|
+
- `debug` (boolean, optional) - Enable debug mode to always show banner (default: false)
|
|
301
|
+
|
|
302
|
+
## Styling
|
|
303
|
+
|
|
304
|
+
All marketing components use Tailwind CSS and the Launch77 design system tokens. You can customize their appearance using:
|
|
305
|
+
|
|
306
|
+
- **Tailwind classes** - Apply utility classes via `className` prop
|
|
307
|
+
- **Design tokens** - Use CSS variables from the design system
|
|
308
|
+
- **Brand customization** - Edit `src/modules/design-system/config/brand.css`
|
|
309
|
+
|
|
310
|
+
## Live Examples
|
|
311
|
+
|
|
312
|
+
Visit [http://localhost:3000/marketing-ui-examples](http://localhost:3000/marketing-ui-examples) to see all components in action.
|
|
313
|
+
|
|
314
|
+
## Design Principles
|
|
315
|
+
|
|
316
|
+
The Marketing UI library follows these principles:
|
|
317
|
+
|
|
318
|
+
1. **Conversion-focused** - Components are optimized for marketing and conversion goals
|
|
319
|
+
2. **Accessible** - WCAG 2.1 AA compliant with keyboard navigation and screen reader support
|
|
320
|
+
3. **Responsive** - Mobile-first design that works on all screen sizes
|
|
321
|
+
4. **Performance** - Optimized for Core Web Vitals and fast page loads
|
|
322
|
+
5. **Customizable** - Easy to adapt to your brand while maintaining consistency
|
|
323
|
+
|
|
324
|
+
## Integration with UI Library
|
|
325
|
+
|
|
326
|
+
Marketing UI components work seamlessly with the base UI library components:
|
|
327
|
+
|
|
328
|
+
```tsx
|
|
329
|
+
import { HeroCentered } from '@launch77-shared/lib-marketing-ui'
|
|
330
|
+
import { Button, Badge } from '@launch77-shared/lib-ui'
|
|
331
|
+
|
|
332
|
+
// Mix marketing and UI components
|
|
333
|
+
;<HeroCentered
|
|
334
|
+
badge={<Badge>New</Badge>} // UI library component
|
|
335
|
+
headline="Welcome"
|
|
336
|
+
primaryCTA={<Button>Get Started</Button>} // UI library component
|
|
337
|
+
/>
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
## Utility Functions
|
|
341
|
+
|
|
342
|
+
The library also exports utility functions:
|
|
343
|
+
|
|
344
|
+
```tsx
|
|
345
|
+
import { cn } from '@launch77-shared/lib-marketing-ui'
|
|
346
|
+
|
|
347
|
+
// Merge Tailwind classes
|
|
348
|
+
const className = cn('base-class', condition && 'conditional-class', 'another-class')
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## Important Notes
|
|
352
|
+
|
|
353
|
+
- **Icons**: MarketingCard accepts Lucide icon components (from `lucide-react`), not strings or emojis
|
|
354
|
+
- **HeroSplit**: Uses a `content` prop for the hero content, not individual headline/CTA props
|
|
355
|
+
- **CTAButton**: Renders as an anchor tag with tracking - requires `href` prop
|
|
356
|
+
- **CardGrid**: Uses children pattern - pass MarketingCard components as children, not a `cards` array prop
|
|
357
|
+
|
|
358
|
+
## External Images Configuration
|
|
359
|
+
|
|
360
|
+
The HeroSplit component uses Next.js's `<Image>` component for optimized image loading. If you use external image URLs (like CDNs or services like Unsplash), you need to configure them in `next.config.js`:
|
|
361
|
+
|
|
362
|
+
```js
|
|
363
|
+
// next.config.js
|
|
364
|
+
module.exports = {
|
|
365
|
+
images: {
|
|
366
|
+
remotePatterns: [
|
|
367
|
+
{
|
|
368
|
+
protocol: 'https',
|
|
369
|
+
hostname: 'images.unsplash.com',
|
|
370
|
+
port: '',
|
|
371
|
+
pathname: '/**',
|
|
372
|
+
},
|
|
373
|
+
// Add other image hosts as needed
|
|
374
|
+
{
|
|
375
|
+
protocol: 'https',
|
|
376
|
+
hostname: 'your-cdn.com',
|
|
377
|
+
port: '',
|
|
378
|
+
pathname: '/**',
|
|
379
|
+
},
|
|
380
|
+
],
|
|
381
|
+
},
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
**Why is this needed?**
|
|
386
|
+
Next.js blocks external images by default for security reasons. This configuration tells Next.js which domains are safe to optimize images from.
|
|
387
|
+
|
|
388
|
+
**Common image hosts to add:**
|
|
389
|
+
|
|
390
|
+
- Unsplash: `images.unsplash.com`
|
|
391
|
+
- Your CDN: e.g., `cdn.yoursite.com`
|
|
392
|
+
- Cloud storage: e.g., `storage.googleapis.com`, `s3.amazonaws.com`
|
|
393
|
+
|
|
394
|
+
**Error message if not configured:**
|
|
395
|
+
|
|
396
|
+
```
|
|
397
|
+
Error: Invalid src prop (...) on `next/image`, hostname "..." is not configured under images in your `next.config.js`
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
See the [Next.js Image Optimization docs](https://nextjs.org/docs/app/api-reference/components/image#remotepatterns) for more details.
|