@thead-vantage/react 2.1.2 → 2.2.0
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/package.json +72 -71
- package/src/components/AdBanner.tsx +13 -0
- package/src/lib/ads.ts +10 -0
- package/src/app/api/ads/route.ts +0 -174
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +0 -26
- package/src/app/layout.tsx +0 -34
- package/src/app/page.tsx +0 -103
package/package.json
CHANGED
|
@@ -1,71 +1,72 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@thead-vantage/react",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "React components and utilities for TheAd Vantage ad platform integration",
|
|
5
|
-
"main": "./src/index.ts",
|
|
6
|
-
"module": "./src/index.ts",
|
|
7
|
-
"types": "./src/index.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"import": "./src/index.ts",
|
|
11
|
-
"require": "./src/index.ts",
|
|
12
|
-
"types": "./src/index.ts"
|
|
13
|
-
},
|
|
14
|
-
"./components/AdBanner": {
|
|
15
|
-
"import": "./src/components/AdBanner.tsx",
|
|
16
|
-
"require": "./src/components/AdBanner.tsx",
|
|
17
|
-
"types": "./src/components/AdBanner.tsx"
|
|
18
|
-
},
|
|
19
|
-
"./components/AdDisplay": {
|
|
20
|
-
"import": "./src/components/AdDisplay.tsx",
|
|
21
|
-
"require": "./src/components/AdDisplay.tsx",
|
|
22
|
-
"types": "./src/components/AdDisplay.tsx"
|
|
23
|
-
},
|
|
24
|
-
"./lib/ads": {
|
|
25
|
-
"import": "./src/lib/ads.ts",
|
|
26
|
-
"require": "./src/lib/ads.ts",
|
|
27
|
-
"types": "./src/lib/ads.ts"
|
|
28
|
-
},
|
|
29
|
-
"./lib/thead-vantage-config": {
|
|
30
|
-
"import": "./src/lib/thead-vantage-config.ts",
|
|
31
|
-
"require": "./src/lib/thead-vantage-config.ts",
|
|
32
|
-
"types": "./src/lib/thead-vantage-config.ts"
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
"files": [
|
|
36
|
-
"src",
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"next": "^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"@
|
|
63
|
-
"@types/
|
|
64
|
-
"@types/react
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"react
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
|
|
71
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@thead-vantage/react",
|
|
3
|
+
"version": "2.2.0",
|
|
4
|
+
"description": "React components and utilities for TheAd Vantage ad platform integration",
|
|
5
|
+
"main": "./src/index.ts",
|
|
6
|
+
"module": "./src/index.ts",
|
|
7
|
+
"types": "./src/index.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./src/index.ts",
|
|
11
|
+
"require": "./src/index.ts",
|
|
12
|
+
"types": "./src/index.ts"
|
|
13
|
+
},
|
|
14
|
+
"./components/AdBanner": {
|
|
15
|
+
"import": "./src/components/AdBanner.tsx",
|
|
16
|
+
"require": "./src/components/AdBanner.tsx",
|
|
17
|
+
"types": "./src/components/AdBanner.tsx"
|
|
18
|
+
},
|
|
19
|
+
"./components/AdDisplay": {
|
|
20
|
+
"import": "./src/components/AdDisplay.tsx",
|
|
21
|
+
"require": "./src/components/AdDisplay.tsx",
|
|
22
|
+
"types": "./src/components/AdDisplay.tsx"
|
|
23
|
+
},
|
|
24
|
+
"./lib/ads": {
|
|
25
|
+
"import": "./src/lib/ads.ts",
|
|
26
|
+
"require": "./src/lib/ads.ts",
|
|
27
|
+
"types": "./src/lib/ads.ts"
|
|
28
|
+
},
|
|
29
|
+
"./lib/thead-vantage-config": {
|
|
30
|
+
"import": "./src/lib/thead-vantage-config.ts",
|
|
31
|
+
"require": "./src/lib/thead-vantage-config.ts",
|
|
32
|
+
"types": "./src/lib/thead-vantage-config.ts"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"src/components",
|
|
37
|
+
"src/lib",
|
|
38
|
+
"src/index.ts",
|
|
39
|
+
"README.md"
|
|
40
|
+
],
|
|
41
|
+
"keywords": [
|
|
42
|
+
"react",
|
|
43
|
+
"ads",
|
|
44
|
+
"advertising",
|
|
45
|
+
"thead-vantage",
|
|
46
|
+
"nextjs"
|
|
47
|
+
],
|
|
48
|
+
"author": "",
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"next": "^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
|
|
52
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
53
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"dev": "next dev --turbopack",
|
|
57
|
+
"build": "next build",
|
|
58
|
+
"start": "next start",
|
|
59
|
+
"lint": "next lint"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@tailwindcss/postcss": "^4",
|
|
63
|
+
"@types/node": "^20",
|
|
64
|
+
"@types/react": "^19",
|
|
65
|
+
"@types/react-dom": "^19",
|
|
66
|
+
"next": "^16.1.1",
|
|
67
|
+
"react": "^19.0.0",
|
|
68
|
+
"react-dom": "^19.0.0",
|
|
69
|
+
"tailwindcss": "^4",
|
|
70
|
+
"typescript": "^5"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -43,6 +43,13 @@ export function AdBanner({
|
|
|
43
43
|
userSegment,
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
+
console.log('[AdBanner] Processed response:', {
|
|
47
|
+
success: response.success,
|
|
48
|
+
hasAd: !!response.ad,
|
|
49
|
+
devMode: response.dev_mode,
|
|
50
|
+
message: response.message,
|
|
51
|
+
});
|
|
52
|
+
|
|
46
53
|
if (response.success && response.ad) {
|
|
47
54
|
setAd(response.ad);
|
|
48
55
|
setDevMode(response.dev_mode || false);
|
|
@@ -50,6 +57,12 @@ export function AdBanner({
|
|
|
50
57
|
// Track impression (will be skipped in dev mode)
|
|
51
58
|
trackImpression(response.ad.id);
|
|
52
59
|
} else {
|
|
60
|
+
console.warn('[AdBanner] No ad available:', {
|
|
61
|
+
success: response.success,
|
|
62
|
+
hasAd: !!response.ad,
|
|
63
|
+
message: response.message,
|
|
64
|
+
_dev_note: response._dev_note,
|
|
65
|
+
});
|
|
53
66
|
setError('No ads available');
|
|
54
67
|
}
|
|
55
68
|
} catch (err) {
|
package/src/lib/ads.ts
CHANGED
|
@@ -137,6 +137,16 @@ export async function fetchAdBanner(params: FetchAdBannerParams): Promise<AdBann
|
|
|
137
137
|
|
|
138
138
|
const data: AdsResponse = await response.json();
|
|
139
139
|
|
|
140
|
+
// Debug logging to see what we're getting from the API
|
|
141
|
+
console.log('[AdBanner] API Response:', {
|
|
142
|
+
success: data.success,
|
|
143
|
+
hasAd: !!data.ad,
|
|
144
|
+
hasAds: !!(data.ads && Array.isArray(data.ads)),
|
|
145
|
+
adsLength: Array.isArray(data.ads) ? data.ads.length : 0,
|
|
146
|
+
message: data.message,
|
|
147
|
+
dataKeys: Object.keys(data),
|
|
148
|
+
});
|
|
149
|
+
|
|
140
150
|
// Type guard to check if an object is Ad type (for arrays that might contain either)
|
|
141
151
|
const isAd = (obj: unknown): obj is Ad => {
|
|
142
152
|
if (typeof obj !== 'object' || obj === null) return false;
|
package/src/app/api/ads/route.ts
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
-
import { getApiBaseUrl, isTheadVantageDevMode, isDevelopmentMode } from '@/lib/thead-vantage-config';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* API route that proxies ads requests to TheAd Vantage Platform
|
|
6
|
-
* Supports three modes:
|
|
7
|
-
* 1. Production Mode (default) - https://thead-vantage.com/api/ads
|
|
8
|
-
* 2. Platform Developer Dev Mode - custom URL via NEXT_PUBLIC_THEAD_VANTAGE_API_URL
|
|
9
|
-
* 3. TheAd Vantage Dev Mode - localhost:3001 (NEXT_PUBLIC_THEAD_VANTAGE_DEV_MODE=true)
|
|
10
|
-
*/
|
|
11
|
-
export async function GET(request: NextRequest) {
|
|
12
|
-
try {
|
|
13
|
-
const isDevelopment = isDevelopmentMode();
|
|
14
|
-
const isTheadVantageDev = isTheadVantageDevMode();
|
|
15
|
-
|
|
16
|
-
// Get explicit API URL from query params if provided
|
|
17
|
-
const explicitApiUrl = request.nextUrl.searchParams.get('apiUrl') || undefined;
|
|
18
|
-
|
|
19
|
-
// Determine the base API URL using the three-mode system
|
|
20
|
-
const apiBaseUrl = getApiBaseUrl(explicitApiUrl);
|
|
21
|
-
|
|
22
|
-
// Get query parameters from the request (excluding apiUrl which we already used)
|
|
23
|
-
const searchParams = request.nextUrl.searchParams;
|
|
24
|
-
const params = new URLSearchParams();
|
|
25
|
-
|
|
26
|
-
// Copy all params except apiUrl
|
|
27
|
-
searchParams.forEach((value, key) => {
|
|
28
|
-
if (key !== 'apiUrl') {
|
|
29
|
-
params.append(key, value);
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// In TheAd Vantage dev mode or general development, add flags to prevent tracking
|
|
34
|
-
if (isTheadVantageDev || isDevelopment) {
|
|
35
|
-
params.set('dev_mode', 'true');
|
|
36
|
-
params.set('no_track', 'true'); // Prevent impression tracking
|
|
37
|
-
params.set('no_click_track', 'true'); // Prevent click tracking
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Build the URL for TheAd Vantage platform
|
|
41
|
-
// If apiBaseUrl already includes /api/ads, use it directly, otherwise append
|
|
42
|
-
const advantageUrl = apiBaseUrl.includes('/api/ads')
|
|
43
|
-
? `${apiBaseUrl}?${params.toString()}`
|
|
44
|
-
: `${apiBaseUrl}/api/ads?${params.toString()}`;
|
|
45
|
-
|
|
46
|
-
// Fetch from advantage platform
|
|
47
|
-
const response = await fetch(advantageUrl, {
|
|
48
|
-
method: 'GET',
|
|
49
|
-
headers: {
|
|
50
|
-
'Content-Type': 'application/json',
|
|
51
|
-
// Forward any custom headers if needed
|
|
52
|
-
...(request.headers.get('user-agent') && {
|
|
53
|
-
'User-Agent': request.headers.get('user-agent') || '',
|
|
54
|
-
}),
|
|
55
|
-
},
|
|
56
|
-
// Add cache control for development
|
|
57
|
-
cache: isDevelopment ? 'no-store' : 'default',
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
if (!response.ok) {
|
|
61
|
-
// In TheAd Vantage dev mode, return a mock response instead of failing
|
|
62
|
-
if (isTheadVantageDev) {
|
|
63
|
-
return NextResponse.json({
|
|
64
|
-
success: true,
|
|
65
|
-
dev_mode: true,
|
|
66
|
-
ad: {
|
|
67
|
-
id: 'dev-ad-1',
|
|
68
|
-
imageUrl: '/placeholder-ad.png',
|
|
69
|
-
linkUrl: '#',
|
|
70
|
-
alt: 'Development Ad - No Tracking',
|
|
71
|
-
width: 300,
|
|
72
|
-
height: 250,
|
|
73
|
-
},
|
|
74
|
-
message: 'TheAd Vantage dev mode: Using mock ad (no tracking)',
|
|
75
|
-
}, { status: 200 });
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return NextResponse.json(
|
|
79
|
-
{ error: 'Failed to fetch ads from TheAd Vantage platform' },
|
|
80
|
-
{ status: response.status }
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const data = await response.json();
|
|
85
|
-
|
|
86
|
-
// Add development mode indicator to response
|
|
87
|
-
if (isTheadVantageDev || isDevelopment) {
|
|
88
|
-
return NextResponse.json({
|
|
89
|
-
...data,
|
|
90
|
-
dev_mode: true,
|
|
91
|
-
_dev_note: 'Development mode: Impressions and clicks are not being tracked',
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return NextResponse.json(data);
|
|
96
|
-
} catch (error) {
|
|
97
|
-
// In TheAd Vantage dev mode, return mock data instead of error
|
|
98
|
-
if (isTheadVantageDevMode()) {
|
|
99
|
-
console.warn('TheAd Vantage platform connection failed, using mock ad:', error);
|
|
100
|
-
return NextResponse.json({
|
|
101
|
-
success: true,
|
|
102
|
-
dev_mode: true,
|
|
103
|
-
ad: {
|
|
104
|
-
id: 'dev-ad-1',
|
|
105
|
-
imageUrl: '/placeholder-ad.png',
|
|
106
|
-
linkUrl: '#',
|
|
107
|
-
alt: 'Development Ad - No Tracking',
|
|
108
|
-
width: 300,
|
|
109
|
-
height: 250,
|
|
110
|
-
},
|
|
111
|
-
message: 'TheAd Vantage dev mode: Using mock ad (platform unavailable)',
|
|
112
|
-
}, { status: 200 });
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
console.error('Error fetching ads:', error);
|
|
116
|
-
return NextResponse.json(
|
|
117
|
-
{ error: 'Failed to fetch ads' },
|
|
118
|
-
{ status: 500 }
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Handle impression tracking (called when ad is viewed)
|
|
125
|
-
* In TheAd Vantage dev mode, this is a no-op
|
|
126
|
-
*/
|
|
127
|
-
export async function POST(request: NextRequest) {
|
|
128
|
-
try {
|
|
129
|
-
const isTheadVantageDev = isTheadVantageDevMode();
|
|
130
|
-
const isDevelopment = isDevelopmentMode();
|
|
131
|
-
const body = await request.json();
|
|
132
|
-
const { action, adId } = body;
|
|
133
|
-
|
|
134
|
-
// In TheAd Vantage dev mode or general development, don't track impressions or clicks
|
|
135
|
-
if (isTheadVantageDev || isDevelopment) {
|
|
136
|
-
return NextResponse.json({
|
|
137
|
-
success: true,
|
|
138
|
-
dev_mode: true,
|
|
139
|
-
message: `Development mode: ${action} tracking skipped for ad ${adId}`,
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Get the API base URL to determine where to send tracking
|
|
144
|
-
const apiBaseUrl = getApiBaseUrl();
|
|
145
|
-
const trackingUrl = apiBaseUrl.includes('/api/ads')
|
|
146
|
-
? apiBaseUrl.replace('/api/ads', '/api/ads/track')
|
|
147
|
-
: `${apiBaseUrl}/api/ads/track`;
|
|
148
|
-
|
|
149
|
-
const response = await fetch(trackingUrl, {
|
|
150
|
-
method: 'POST',
|
|
151
|
-
headers: {
|
|
152
|
-
'Content-Type': 'application/json',
|
|
153
|
-
},
|
|
154
|
-
body: JSON.stringify({ action, adId }),
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
if (!response.ok) {
|
|
158
|
-
return NextResponse.json(
|
|
159
|
-
{ error: 'Failed to track ad event' },
|
|
160
|
-
{ status: response.status }
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const data = await response.json();
|
|
165
|
-
return NextResponse.json(data);
|
|
166
|
-
} catch (error) {
|
|
167
|
-
console.error('Error tracking ad:', error);
|
|
168
|
-
return NextResponse.json(
|
|
169
|
-
{ error: 'Failed to track ad' },
|
|
170
|
-
{ status: 500 }
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
package/src/app/favicon.ico
DELETED
|
Binary file
|
package/src/app/globals.css
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
@import "tailwindcss";
|
|
2
|
-
|
|
3
|
-
:root {
|
|
4
|
-
--background: #ffffff;
|
|
5
|
-
--foreground: #171717;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
@theme inline {
|
|
9
|
-
--color-background: var(--background);
|
|
10
|
-
--color-foreground: var(--foreground);
|
|
11
|
-
--font-sans: var(--font-geist-sans);
|
|
12
|
-
--font-mono: var(--font-geist-mono);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
@media (prefers-color-scheme: dark) {
|
|
16
|
-
:root {
|
|
17
|
-
--background: #0a0a0a;
|
|
18
|
-
--foreground: #ededed;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
body {
|
|
23
|
-
background: var(--background);
|
|
24
|
-
color: var(--foreground);
|
|
25
|
-
font-family: Arial, Helvetica, sans-serif;
|
|
26
|
-
}
|
package/src/app/layout.tsx
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { Metadata } from "next";
|
|
2
|
-
import { Geist, Geist_Mono } from "next/font/google";
|
|
3
|
-
import "./globals.css";
|
|
4
|
-
|
|
5
|
-
const geistSans = Geist({
|
|
6
|
-
variable: "--font-geist-sans",
|
|
7
|
-
subsets: ["latin"],
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
const geistMono = Geist_Mono({
|
|
11
|
-
variable: "--font-geist-mono",
|
|
12
|
-
subsets: ["latin"],
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
export const metadata: Metadata = {
|
|
16
|
-
title: "Create Next App",
|
|
17
|
-
description: "Generated by create next app",
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export default function RootLayout({
|
|
21
|
-
children,
|
|
22
|
-
}: Readonly<{
|
|
23
|
-
children: React.ReactNode;
|
|
24
|
-
}>) {
|
|
25
|
-
return (
|
|
26
|
-
<html lang="en">
|
|
27
|
-
<body
|
|
28
|
-
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
|
29
|
-
>
|
|
30
|
-
{children}
|
|
31
|
-
</body>
|
|
32
|
-
</html>
|
|
33
|
-
);
|
|
34
|
-
}
|
package/src/app/page.tsx
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import Image from "next/image";
|
|
2
|
-
|
|
3
|
-
export default function Home() {
|
|
4
|
-
return (
|
|
5
|
-
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
|
|
6
|
-
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
|
|
7
|
-
<Image
|
|
8
|
-
className="dark:invert"
|
|
9
|
-
src="/next.svg"
|
|
10
|
-
alt="Next.js logo"
|
|
11
|
-
width={180}
|
|
12
|
-
height={38}
|
|
13
|
-
priority
|
|
14
|
-
/>
|
|
15
|
-
<ol className="list-inside list-decimal text-sm/6 text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
|
|
16
|
-
<li className="mb-2 tracking-[-.01em]">
|
|
17
|
-
Get started by editing{" "}
|
|
18
|
-
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-[family-name:var(--font-geist-mono)] font-semibold">
|
|
19
|
-
src/app/page.tsx
|
|
20
|
-
</code>
|
|
21
|
-
.
|
|
22
|
-
</li>
|
|
23
|
-
<li className="tracking-[-.01em]">
|
|
24
|
-
Save and see your changes instantly.
|
|
25
|
-
</li>
|
|
26
|
-
</ol>
|
|
27
|
-
|
|
28
|
-
<div className="flex gap-4 items-center flex-col sm:flex-row">
|
|
29
|
-
<a
|
|
30
|
-
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:w-auto"
|
|
31
|
-
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
32
|
-
target="_blank"
|
|
33
|
-
rel="noopener noreferrer"
|
|
34
|
-
>
|
|
35
|
-
<Image
|
|
36
|
-
className="dark:invert"
|
|
37
|
-
src="/vercel.svg"
|
|
38
|
-
alt="Vercel logomark"
|
|
39
|
-
width={20}
|
|
40
|
-
height={20}
|
|
41
|
-
/>
|
|
42
|
-
Deploy now
|
|
43
|
-
</a>
|
|
44
|
-
<a
|
|
45
|
-
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 w-full sm:w-auto md:w-[158px]"
|
|
46
|
-
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
47
|
-
target="_blank"
|
|
48
|
-
rel="noopener noreferrer"
|
|
49
|
-
>
|
|
50
|
-
Read our docs
|
|
51
|
-
</a>
|
|
52
|
-
</div>
|
|
53
|
-
</main>
|
|
54
|
-
<footer className="row-start-3 flex gap-[24px] flex-wrap items-center justify-center">
|
|
55
|
-
<a
|
|
56
|
-
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
|
57
|
-
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
58
|
-
target="_blank"
|
|
59
|
-
rel="noopener noreferrer"
|
|
60
|
-
>
|
|
61
|
-
<Image
|
|
62
|
-
aria-hidden
|
|
63
|
-
src="/file.svg"
|
|
64
|
-
alt="File icon"
|
|
65
|
-
width={16}
|
|
66
|
-
height={16}
|
|
67
|
-
/>
|
|
68
|
-
Learn
|
|
69
|
-
</a>
|
|
70
|
-
<a
|
|
71
|
-
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
|
72
|
-
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
73
|
-
target="_blank"
|
|
74
|
-
rel="noopener noreferrer"
|
|
75
|
-
>
|
|
76
|
-
<Image
|
|
77
|
-
aria-hidden
|
|
78
|
-
src="/window.svg"
|
|
79
|
-
alt="Window icon"
|
|
80
|
-
width={16}
|
|
81
|
-
height={16}
|
|
82
|
-
/>
|
|
83
|
-
Examples
|
|
84
|
-
</a>
|
|
85
|
-
<a
|
|
86
|
-
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
|
87
|
-
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
88
|
-
target="_blank"
|
|
89
|
-
rel="noopener noreferrer"
|
|
90
|
-
>
|
|
91
|
-
<Image
|
|
92
|
-
aria-hidden
|
|
93
|
-
src="/globe.svg"
|
|
94
|
-
alt="Globe icon"
|
|
95
|
-
width={16}
|
|
96
|
-
height={16}
|
|
97
|
-
/>
|
|
98
|
-
Go to nextjs.org →
|
|
99
|
-
</a>
|
|
100
|
-
</footer>
|
|
101
|
-
</div>
|
|
102
|
-
);
|
|
103
|
-
}
|