tfrere HF Staff commited on
Commit
80c56b4
·
1 Parent(s): fd90f3b

try pro gate pdf button feature

Browse files
Files changed (1) hide show
  1. app/src/components/Hero.astro +160 -10
app/src/components/Hero.astro CHANGED
@@ -185,20 +185,113 @@ const pdfFilename = `${slugify(pdfBase)}.pdf`;
185
  )} -->
186
  <div class="meta-container-cell meta-container-cell--pdf">
187
  <h3>PDF</h3>
188
- <p>
189
- <a
190
- class="button"
191
- href={`/${pdfFilename}`}
192
- download={pdfFilename}
193
- aria-label={`Download PDF ${pdfFilename}`}
194
- >
195
- Download PDF
196
- </a>
197
- </p>
 
 
 
 
 
 
 
198
  </div>
199
  </div>
200
  </header>
201
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  <style>
203
  /* Hero (full-width) */
204
  .hero {
@@ -308,4 +401,61 @@ const pdfFilename = `${slugify(pdfBase)}.pdf`;
308
  display: none !important;
309
  }
310
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
  </style>
 
185
  )} -->
186
  <div class="meta-container-cell meta-container-cell--pdf">
187
  <h3>PDF</h3>
188
+ <div id="pdf-download-container">
189
+ <p class="pdf-loading">Checking access...</p>
190
+ <p class="pdf-pro-only" style="display: none;">
191
+ <a
192
+ class="button"
193
+ href={`/${pdfFilename}`}
194
+ download={pdfFilename}
195
+ aria-label={`Download PDF ${pdfFilename}`}
196
+ >
197
+ Download PDF
198
+ </a>
199
+ <span class="pro-badge">PRO</span>
200
+ </p>
201
+ <p class="pdf-locked" style="display: none;">
202
+ <span class="locked-message">🔒 PDF available for Pro users only</span>
203
+ </p>
204
+ </div>
205
  </div>
206
  </div>
207
  </header>
208
 
209
+ <script>
210
+ // PDF access control for Pro users only
211
+
212
+ const FALLBACK_TIMEOUT_MS = 3000;
213
+ let userPlanChecked = false;
214
+
215
+ /**
216
+ * Check if user has Pro access
217
+ * Isolated logic for Pro user verification
218
+ * Expected plan structure: { user: "pro", org: "enterprise" }
219
+ */
220
+ function isProUser(plan: any): boolean {
221
+ if (!plan) return false;
222
+
223
+ // Check if user property is "pro"
224
+ return plan.user === "pro";
225
+ }
226
+
227
+ /**
228
+ * Update UI based on user's Pro status
229
+ */
230
+ function updatePdfAccess(isPro: boolean) {
231
+ const loadingEl = document.querySelector(".pdf-loading") as HTMLElement;
232
+ const proOnlyEl = document.querySelector(".pdf-pro-only") as HTMLElement;
233
+ const lockedEl = document.querySelector(".pdf-locked") as HTMLElement;
234
+
235
+ // Hide loading state
236
+ if (loadingEl) loadingEl.style.display = "none";
237
+
238
+ // Show appropriate state
239
+ if (isPro) {
240
+ if (proOnlyEl) proOnlyEl.style.display = "block";
241
+ } else {
242
+ if (lockedEl) lockedEl.style.display = "block";
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Handle user plan response
248
+ */
249
+ function handleUserPlan(plan: any) {
250
+ userPlanChecked = true;
251
+ const isPro = isProUser(plan);
252
+ updatePdfAccess(isPro);
253
+
254
+ // Optional: log for debugging
255
+ console.log("[PDF Access]", { plan, isPro });
256
+ }
257
+
258
+ /**
259
+ * Fallback behavior when no parent window responds
260
+ * Change this to test different scenarios locally
261
+ */
262
+ function handleFallback() {
263
+ // Default to Pro access in development/standalone mode
264
+ handleUserPlan({ user: "pro" });
265
+
266
+ // Uncomment to test locked state:
267
+ // handleUserPlan({ user: "free" });
268
+ // handleUserPlan(null);
269
+ }
270
+
271
+ // Listen for messages from parent window (Hugging Face Spaces)
272
+ window.addEventListener("message", (event) => {
273
+ if (event.data.type === "USER_PLAN") {
274
+ handleUserPlan(event.data.plan);
275
+ }
276
+ });
277
+
278
+ // Request user plan on page load
279
+ if (window.parent && window.parent !== window) {
280
+ // We're in an iframe, request user plan
281
+ window.parent.postMessage({ type: "USER_PLAN_REQUEST" }, "*");
282
+
283
+ // Fallback if no response after timeout
284
+ setTimeout(() => {
285
+ if (!userPlanChecked) {
286
+ handleFallback();
287
+ }
288
+ }, FALLBACK_TIMEOUT_MS);
289
+ } else {
290
+ // Not in iframe (local development), use fallback immediately
291
+ handleFallback();
292
+ }
293
+ </script>
294
+
295
  <style>
296
  /* Hero (full-width) */
297
  .hero {
 
401
  display: none !important;
402
  }
403
  }
404
+
405
+ /* PDF access control styles */
406
+ .pdf-loading {
407
+ color: var(--muted-color);
408
+ font-size: 0.9em;
409
+ }
410
+
411
+ .pdf-pro-only {
412
+ display: flex;
413
+ flex-direction: row;
414
+ gap: 8px;
415
+ align-items: center;
416
+ }
417
+
418
+ .pro-badge {
419
+ display: inline-block;
420
+ transform: skewX(-12deg);
421
+ border: 1px solid rgba(229, 231, 235, 0.5);
422
+ background: linear-gradient(to bottom right, #f9a8d4, #86efac, #fde047);
423
+ color: black;
424
+ padding: 4px 10px;
425
+ border-radius: 8px;
426
+ font-size: 0.875rem;
427
+ font-weight: 700;
428
+ letter-spacing: 0.025em;
429
+ text-transform: uppercase;
430
+ box-shadow: 0 10px 15px -3px rgba(34, 197, 94, 0.1),
431
+ 0 4px 6px -4px rgba(34, 197, 94, 0.1);
432
+ }
433
+
434
+ /* Dark mode pro badge */
435
+ :global(.dark) .pro-badge,
436
+ :global([data-theme="dark"]) .pro-badge {
437
+ background: linear-gradient(to bottom right, #ec4899, #22c55e, #eab308);
438
+ border-color: rgba(255, 255, 255, 0.1);
439
+ box-shadow: 0 10px 15px -3px rgba(34, 197, 94, 0.2),
440
+ 0 4px 6px -4px rgba(34, 197, 94, 0.2);
441
+ }
442
+
443
+ .pdf-locked {
444
+ display: flex;
445
+ align-items: center;
446
+ }
447
+
448
+ .locked-message {
449
+ color: var(--muted-color);
450
+ font-size: 0.85em;
451
+ display: flex;
452
+ align-items: center;
453
+ gap: 4px;
454
+ }
455
+
456
+ @media (max-width: 768px) {
457
+ .pdf-pro-only {
458
+ justify-content: flex-end;
459
+ }
460
+ }
461
  </style>