@@ -3,52 +3,90 @@ import { createHeaderSearchBar } from './headerSearchBar';
3
3
4
4
export default async function generatePluginHTML ( pluginData , env ) {
5
5
const secureHtmlService = createSecureHtmlService ( ) ;
6
- // Sanitize the input data
7
6
const safePlugin = secureHtmlService . sanitizePluginData ( pluginData ) ;
8
- console . log ( "datertots" , JSON . stringify ( pluginData ) ) ;
7
+
9
8
if ( ! safePlugin ) {
10
9
return new Response ( 'Invalid plugin data' , { status : 400 } ) ;
11
10
}
12
11
13
- // Fetch the current download count
14
12
const downloadKey = `downloads:${ safePlugin . author } :${ safePlugin . slug } ` ;
15
13
const downloadCount = parseInt ( await env . DOWNLOAD_COUNTS . get ( downloadKey ) ) || 0 ;
16
14
const activeInstalls = safePlugin . active_installs ;
15
+
17
16
const html = `
18
- <!DOCTYPE html>
19
- <html lang="en">
20
- <head>
21
- <title>${ safePlugin . name } - Plugin Details</title>
22
- <link
23
- href="https://cdn.jsdelivr.net/npm/[email protected] /dist/tailwind.min.css"
24
- rel="stylesheet"
25
- crossorigin="anonymous"
26
- >
27
- <style>
28
- body { background-color: #191919; color: white; }
29
- .asset-card-container-home { background: linear-gradient(to bottom right, #131313, #181818); }
30
- </style>
31
- </head>
32
- <body>
33
- <div class="min-h-screen bg-[#191919] text-white">
34
- ${ createHeaderSearchBar ( ) }
35
- <div class="bg-gradient-to-r from-green-500 to-purple-600 pt-16">
36
- <div class="container mx-auto px-2 max-h-[620px]">
37
- <div class="relative max-w-[1300px] mx-auto shadow-lg rounded-t-2xl overflow-hidden">
38
- <img src="${ safePlugin . banners . high } " alt="${ safePlugin . name } banner" class="h-auto max-h-[620px] justify-center object-cover w-full">
39
- </div>
40
- </div>
41
- </div>
42
- <div class="container mx-auto px-4 py-16">
43
- <div class="grid grid-cols-1 md:grid-cols-3 gap-12">
44
- <div class="md:col-span-2 bg-gradient-to-br rounded-3xl asset-card-container-home shadow-2xl p-8 transform min-h-[200px]">
45
- <div class='px-4 py-6 bg-[#191919] rounded-3xl mb-2 flex items-center'>
46
- <img src="${ safePlugin . icons [ '1x' ] } " alt="${ safePlugin . name } " class="w-24 h-24 mr-4 rounded-lg">
47
- <div>
48
- <h1 class="text-2xl font-bold mb-1">${ safePlugin . name } </h1>
49
- <p class="text-md w-90">${ safePlugin . short_description } </p>
50
- </div>
51
- </div>
17
+ <!DOCTYPE html>
18
+ <html lang="en">
19
+ <head>
20
+ <title>${ safePlugin . name } - Plugin Details</title>
21
+ <link
22
+ href="https://cdn.jsdelivr.net/npm/[email protected] /dist/tailwind.min.css"
23
+ rel="stylesheet"
24
+ crossorigin="anonymous"
25
+ >
26
+ <style>
27
+ body { background-color: #191919; color: white; }
28
+ .asset-card-container-home { background: linear-gradient(to bottom right, #131313, #181818); }
29
+ /* Add only the modal styles we need */
30
+ #playgroundModal {
31
+ display: none;
32
+ position: fixed;
33
+ top: 0;
34
+ left: 0;
35
+ width: 100%;
36
+ height: 100%;
37
+ background: rgba(0, 0, 0, 0.8);
38
+ z-index: 1000;
39
+ }
40
+ #playgroundModal.active {
41
+ display: flex;
42
+ align-items: center;
43
+ justify-content: center;
44
+ }
45
+ .modal-content {
46
+ width: 90%;
47
+ height: 90%;
48
+ background: white;
49
+ border-radius: 8px;
50
+ padding: 20px;
51
+ position: relative;
52
+ }
53
+ #closePlayground {
54
+ position: absolute;
55
+ right: 10px;
56
+ top: 10px;
57
+ font-size: 24px;
58
+ cursor: pointer;
59
+ color: #666;
60
+ }
61
+ #playground-iframe {
62
+ width: 100%;
63
+ height: 100%;
64
+ border: none;
65
+ }
66
+ </style>
67
+ </head>
68
+ <body>
69
+ <div class="min-h-screen bg-[#191919] text-white">
70
+ ${ createHeaderSearchBar ( ) }
71
+ <div class="bg-gradient-to-r from-green-500 to-purple-600 pt-16">
72
+ <div class="container mx-auto px-2 max-h-[620px]">
73
+ <div class="relative max-w-[1300px] mx-auto shadow-lg rounded-t-2xl overflow-hidden">
74
+ <img src="${ safePlugin . banners . high } " alt="${ safePlugin . name } banner" class="h-auto max-h-[620px] justify-center object-cover w-full">
75
+ </div>
76
+ </div>
77
+ </div>
78
+ <div class="container mx-auto px-4 py-16">
79
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-12">
80
+ <!-- Left content column -->
81
+ <div class="md:col-span-2 bg-gradient-to-br rounded-3xl asset-card-container-home shadow-2xl p-8 transform min-h-[200px]">
82
+ <!-- Existing left column content -->
83
+ <div class='px-4 py-6 bg-[#191919] rounded-3xl mb-2 flex items-center'>
84
+ <img src="${ safePlugin . icons [ '1x' ] } " alt="${ safePlugin . name } " class="w-24 h-24 mr-4 rounded-lg">
85
+ <div>
86
+ <h1 class="text-2xl font-bold mb-1">${ safePlugin . name } </h1>
87
+ <p class="text-md w-90">${ safePlugin . short_description } </p>
88
+ </div>
89
+ </div>
52
90
<div class="bg-[#191919] rounded-3xl p-2 mb-2">
53
91
<div class="text-md leading-8">${ safePlugin . sections ?. description } </div>
54
92
</div>
@@ -65,6 +103,7 @@ export default async function generatePluginHTML(pluginData, env) {
65
103
</div>
66
104
` : '' }
67
105
</div>
106
+ <!-- Right sidebar -->
68
107
<div>
69
108
<div class="bg-gradient-to-br rounded-3xl asset-card-container-home shadow-2xl rounded-lg p-6 mb-8">
70
109
<div class="flex items-center mb-4">
@@ -74,26 +113,36 @@ export default async function generatePluginHTML(pluginData, env) {
74
113
<p class="text-gray-200 text-md">by ${ safePlugin . author } </p>
75
114
</div>
76
115
</div>
77
- <div class="flex items-center justify-between mb-4">
116
+ <div class="flex items-center mb-4">
78
117
<div class="flex items-center">
79
- ${ safePlugin . rating && safePlugin . rating > 0 ? `
80
- <span class="text-yellow-400 mr-1">★</span>
81
- <span>${ safePlugin . rating } /5</span>
82
- ` : '' }
118
+ ${ safePlugin . rating && safePlugin . rating > 0 ? `
119
+ <span class="text-yellow-400 mr-1">★</span>
120
+ <span>${ safePlugin . rating } /5</span>
121
+ ` : '' }
83
122
</div>
123
+ <div class="flex items-center flex-col gap-2">
84
124
<div class="flex items-center">
85
- <span class="mr-2 text-purple-600">↓</span>
86
- <span class="text-s" id="download-count">${ downloadCount . toLocaleString ( ) } + downloads</span>
125
+ <span class="mr-2 text-purple-600">↓</span>
126
+ <span class="text-s" id="download-count">${ downloadCount . toLocaleString ( ) } + downloads</span>
87
127
</div>
88
128
<div class="flex items-center">
89
- <span class="mr-2 text-purple-600">🔌</span>
129
+ <span class="mr-2 text-purple-600">🔌</span>
90
130
<span class="text-s" id="active-installs">${ activeInstalls . toLocaleString ( ) } + activations</span>
91
131
</div>
132
+ </div>
92
133
</div>
93
- <a href="/download?author=${ encodeURIComponent ( safePlugin . author ) } &slug=${ encodeURIComponent ( safePlugin . slug ) } "
94
- class="w-full bg-purple-600 hover:bg-purple-700 text-white font-bold py-2 px-4 rounded-3xl mb-4 flex items-center justify-center">
95
- Download v${ safePlugin . version }
96
- </a>
134
+ <!-- Download and Playground buttons -->
135
+ <div class="flex flex-col gap-6 mb-4">
136
+ <button id="tryInPlayground"
137
+ class="flex-2 bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-3xl">
138
+ Try in Playground
139
+ </button>
140
+ <a href="/download?author=${ encodeURIComponent ( safePlugin . author ) } &slug=${ encodeURIComponent ( safePlugin . slug ) } "
141
+ class="flex-1 bg-purple-600 hover:bg-purple-700 text-white font-bold py-2 px-4 rounded-3xl text-center">
142
+ Download v${ safePlugin . version }
143
+ </a>
144
+ </div>
145
+ <!-- Plugin details -->
97
146
<div class="text-sm text-gray-200">
98
147
<p>Last updated: ${ safePlugin . last_updated } </p>
99
148
<p>Version: ${ safePlugin . version } </p>
@@ -102,6 +151,7 @@ export default async function generatePluginHTML(pluginData, env) {
102
151
<p>Requires PHP: ${ safePlugin . requires_php } </p>
103
152
</div>
104
153
</div>
154
+
105
155
${ safePlugin . authorData ? `
106
156
<div class="bg-gradient-to-br rounded-3xl asset-card-container-home shadow-2xl p-6">
107
157
<h3 class="text-xl font-bold mb-4">Author</h3>
@@ -120,17 +170,78 @@ export default async function generatePluginHTML(pluginData, env) {
120
170
</div>
121
171
</div>
122
172
</div>
123
- <div class="bg-black py-8">
124
- <div class="container mx-auto px-4 text-center text-gray-200">
125
- <p>© ${ new Date ( ) . getFullYear ( ) } ${ new Date ( ) . toLocaleTimeString ( ) } Your Footer Text.</p>
126
- <a href="/terms" class="text-purple-400 hover:underline">Terms of Service</a> |
127
- <a href="/privacy" class="text-purple-400 hover:underline">Privacy Policy</a> |
128
- <a href="https://github.com/xpportal/Micro-Plugin-Publisher" class="text-purple-400 hover:underline">
129
- Source Code
130
- </a>
173
+
174
+ <!-- Playground Modal -->
175
+ <div id="playgroundModal">
176
+ <div class="modal-content">
177
+ <span id="closePlayground">×</span>
178
+ <iframe id="playground-iframe"
179
+ sandbox="allow-same-origin allow-scripts allow-popups allow-forms"
180
+ title="WordPress Playground">
181
+ </iframe>
182
+ </div>
131
183
</div>
184
+
185
+ <!-- Footer -->
186
+ <div class="bg-black py-8">
187
+ <div class="container mx-auto px-4 text-center text-gray-200">
188
+ <p>© ${ new Date ( ) . getFullYear ( ) } ${ new Date ( ) . toLocaleTimeString ( ) } Your Footer Text.</p>
189
+ <a href="/terms" class="text-purple-400 hover:underline">Terms of Service</a> |
190
+ <a href="/privacy" class="text-purple-400 hover:underline">Privacy Policy</a> |
191
+ <a href="https://github.com/xpportal/Micro-Plugin-Publisher" class="text-purple-400 hover:underline">
192
+ Source Code
193
+ </a>
194
+ </div>
132
195
</div>
133
196
</div>
197
+
198
+ <!-- Playground initialization script -->
199
+ <script type="module">
200
+ import { startPlaygroundWeb } from 'https://playground.xr.foundation/client/index.js';
201
+
202
+ document.getElementById('tryInPlayground').addEventListener('click', async () => {
203
+ const modal = document.getElementById('playgroundModal');
204
+ const iframe = document.getElementById('playground-iframe');
205
+ modal.classList.add('active');
206
+
207
+ try {
208
+ const client = await startPlaygroundWeb({
209
+ iframe: iframe,
210
+ remoteUrl: 'https://playground.xr.foundation/remote.html',
211
+ blueprint: {
212
+ landingPage: '/wp-admin/',
213
+ preferredVersions: {
214
+ php: '8.0',
215
+ wp: 'latest'
216
+ },
217
+ steps: [
218
+ {
219
+ step: 'login',
220
+ username: 'admin',
221
+ password: 'password'
222
+ },
223
+ {
224
+ step: 'installPlugin',
225
+ pluginData: {
226
+ resource: 'url',
227
+ url: '/download?author=${ encodeURIComponent ( safePlugin . author ) } &slug=${ encodeURIComponent ( safePlugin . slug ) } track=false'
228
+ }
229
+ }
230
+ ]
231
+ }
232
+ });
233
+ } catch (error) {
234
+ console.error('Playground initialization failed:', error);
235
+ }
236
+ });
237
+
238
+ document.getElementById('closePlayground').addEventListener('click', () => {
239
+ const modal = document.getElementById('playgroundModal');
240
+ const iframe = document.getElementById('playground-iframe');
241
+ modal.classList.remove('active');
242
+ iframe.src = 'about:blank';
243
+ });
244
+ </script>
134
245
</body>
135
246
</html>
136
247
` ;
0 commit comments