my personal site
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(gymtracker): enhance ad preview structure and styling in admin and landing pages

- Added new section header styles for ad previews to improve layout and visual hierarchy.
- Refactored HTML structure for sponsor and copy sections to align with updated design specifications.
- Adjusted padding and margins for better spacing and consistency across ad components.

+159 -59
+46 -18
gymtracker/src/admin-html.ts
··· 404 404 .id-version-header { min-width: 0; max-width: 320px; justify-self: center; } 405 405 .id-version-header input { min-height: 36px; padding: 6px 10px; font-size: var(--text-sm); } 406 406 .ad-preview { border: none; padding: 0; background: transparent; min-height: 8rem; overflow: visible; } 407 - /* Matches in-app AdView: frosted card, image → divider → sponsor row + copy + maroon CTA */ 407 + /* Section header inside frosted preview card (logo + sponsor | Sponsored) */ 408 + .preview-section-header { 409 + display: flex; 410 + align-items: center; 411 + gap: 10px; 412 + width: 100%; 413 + padding: 14px 16px 10px; 414 + box-sizing: border-box; 415 + border-bottom: 1px solid var(--border); 416 + flex-shrink: 0; 417 + } 418 + .preview-section-header-logo { 419 + width: 26px; 420 + height: 26px; 421 + object-fit: contain; 422 + border-radius: 2px; 423 + flex-shrink: 0; 424 + } 425 + .preview-section-header-title { 426 + font-size: var(--text-sm); 427 + font-weight: 700; 428 + letter-spacing: 0.09em; 429 + text-transform: uppercase; 430 + color: var(--text); 431 + line-height: 1.2; 432 + flex: 1; 433 + min-width: 0; 434 + } 435 + .preview-section-sponsored { 436 + font-size: var(--text-sm); 437 + font-weight: 500; 438 + color: var(--muted); 439 + flex-shrink: 0; 440 + line-height: 1.2; 441 + } 408 442 .preview { 409 443 display: flex; flex-direction: column; align-items: stretch; text-align: left; 410 444 width: 100%; max-width: 100%; ··· 419 453 .preview-text-inner { 420 454 display: flex; flex-direction: column; gap: 12px; 421 455 padding: 18px 16px; width: 100%; 456 + } 457 + .preview-section-header + .preview-text-inner { 458 + padding-top: 14px; 422 459 } 423 460 .preview-body { 424 461 display: flex; flex-direction: column; gap: 12px; ··· 427 464 .preview-copy-stack { 428 465 display: flex; flex-direction: column; align-items: flex-start; width: 100%; 429 466 } 430 - .preview-sponsor-row { 431 - display: flex; align-items: center; gap: 10px; width: 100%; 432 - } 433 - .preview-sponsor-logo { 434 - width: 32px; height: 32px; object-fit: contain; border-radius: 0; flex-shrink: 0; 435 - } 436 - .preview-sponsor-name { 437 - font-size: var(--text-sm); font-weight: 600; letter-spacing: 0.065em; text-transform: uppercase; 438 - color: var(--muted); line-height: 1.3; flex: 1; min-width: 0; 439 - } 440 467 .preview-headline { 441 468 font-size: var(--text-xl); font-weight: 700; line-height: 1.25; color: var(--text); 442 - margin-top: 8px; 469 + margin-top: 0; 443 470 } 444 471 .preview-subline { 445 472 font-size: var(--text-sm); font-weight: 500; color: var(--muted); line-height: 1.4; margin-top: 6px; ··· 1387 1414 const image_url = d.image_url || null; 1388 1415 const logo_url = d.logo_url || null; 1389 1416 const usesImageLayout = tier !== 'text'; 1390 - const sponsorRow = '<div class="preview-sponsor-row">' + 1391 - (logo_url ? '<img src="' + escapeHtml(logo_url) + '" alt="" class="preview-sponsor-logo" onerror="this.style.display=\\'none\\'">' : '') + 1392 - '<span class="preview-sponsor-name">' + escapeHtml(sponsor) + '</span></div>'; 1393 - const copyStack = '<div class="preview-copy-stack">' + sponsorRow + 1417 + const sectionHeader = '<div class="preview-section-header">' + 1418 + (logo_url ? '<img src="' + escapeHtml(logo_url) + '" alt="" class="preview-section-header-logo" onerror="this.style.display=\\'none\\'">' : '') + 1419 + '<span class="preview-section-header-title">' + escapeHtml(sponsor) + '</span>' + 1420 + '<span class="preview-section-sponsored">Sponsored</span></div>'; 1421 + const copyStack = '<div class="preview-copy-stack">' + 1394 1422 '<strong class="preview-headline">' + escapeHtml(headline) + '</strong>' + 1395 1423 (subline ? '<span class="preview-subline">' + escapeHtml(subline) + '</span>' : '') + 1396 1424 '</div>'; ··· 1398 1426 let html; 1399 1427 if (usesImageLayout) { 1400 1428 const imgHeight = tier === 'feature' ? 220 : 140; 1401 - html = '<div class="preview preview-' + tier + '">'; 1429 + html = '<div class="preview preview-' + tier + '">' + sectionHeader; 1402 1430 if (image_url) { 1403 1431 html += '<div class="preview-img-wrap" style="height:' + imgHeight + 'px">'; 1404 1432 html += '<img src="' + escapeHtml(image_url) + '" alt="" class="preview-img" onerror="this.parentElement.classList.add(\\'preview-img-error\\')">'; ··· 1409 1437 html += '<div class="preview-img-divider"></div>'; 1410 1438 html += '<div class="preview-body">' + copyStack + ctaBtn + '</div></div>'; 1411 1439 } else { 1412 - html = '<div class="preview preview-text"><div class="preview-text-inner">' + copyStack + ctaBtn + '</div></div>'; 1440 + html = '<div class="preview preview-text">' + sectionHeader + '<div class="preview-text-inner">' + copyStack + ctaBtn + '</div></div>'; 1413 1441 } 1414 1442 adPreview.innerHTML = html; 1415 1443 }
+113 -41
gymtracker/src/ads-landing-html.ts
··· 314 314 display: flex; 315 315 flex-direction: column; 316 316 justify-content: center; 317 - gap: 6px; 318 - padding: 12px; 317 + gap: 0; 318 + padding: 0; 319 319 border-radius: 0; 320 320 border: 1px solid var(--border); 321 321 background: var(--bg); 322 + } 323 + .format-preview-text-lines { 324 + display: flex; 325 + flex-direction: column; 326 + gap: 6px; 327 + padding: 12px; 322 328 } 323 329 .format-preview-banner { 324 330 width: 100%; ··· 338 344 justify-content: center; 339 345 } 340 346 .format-preview-img span { font-size: 11px; color: var(--muted); font-weight: 500; } 347 + .format-preview-section-row { 348 + display: flex; 349 + align-items: center; 350 + gap: 6px; 351 + padding: 6px 10px 5px; 352 + border-bottom: 1px solid var(--border); 353 + } 354 + .format-preview-section-logo { 355 + width: 14px; 356 + height: 14px; 357 + border-radius: 2px; 358 + background: var(--border-strong); 359 + flex-shrink: 0; 360 + } 361 + .format-preview-section-title { 362 + flex: 1; 363 + min-width: 0; 364 + height: 5px; 365 + max-width: 58%; 366 + background: var(--text); 367 + opacity: 0.88; 368 + border-radius: 0; 369 + } 370 + .format-preview-section-sponsored { 371 + font-size: 9px; 372 + font-weight: 500; 373 + color: var(--muted); 374 + flex-shrink: 0; 375 + letter-spacing: 0.02em; 376 + } 341 377 .format-preview-body { padding: 10px 12px; display: flex; flex-direction: column; gap: 4px; } 342 378 .fph { width: 60%; height: 8px; background: var(--border-strong); border-radius: 0; } 343 379 .fps { width: 45%; height: 6px; background: var(--border); border-radius: 0; } ··· 743 779 .tier-btn:hover { color: var(--text); } 744 780 .tier-btn.active { background: rgba(134,31,65,0.12); color: var(--maroon); font-weight: 600; } 745 781 746 - /* ── Preview Pane (matches in-app AdView) ─────────────────────── */ 782 + /* ── Preview Pane (section header + Ad copy inside one frosted card) ─ */ 747 783 .preview-pane { position: sticky; top: 84px; min-width: 0; } 748 784 .ad-preview { padding: 0; background: transparent; min-height: 8rem; overflow: visible; } 785 + .preview-section-header { 786 + display: flex; 787 + align-items: center; 788 + gap: 10px; 789 + width: 100%; 790 + padding: 14px 16px 10px; 791 + box-sizing: border-box; 792 + border-bottom: 1px solid var(--border); 793 + flex-shrink: 0; 794 + } 795 + .preview-section-header-logo { 796 + width: 26px; 797 + height: 26px; 798 + object-fit: contain; 799 + border-radius: 2px; 800 + flex-shrink: 0; 801 + } 802 + .preview-section-header-title { 803 + font-size: 0.875rem; 804 + font-weight: 700; 805 + letter-spacing: 0.09em; 806 + text-transform: uppercase; 807 + color: var(--text); 808 + line-height: 1.2; 809 + flex: 1; 810 + min-width: 0; 811 + } 812 + .preview-section-sponsored { 813 + font-size: 0.875rem; 814 + font-weight: 500; 815 + color: var(--muted); 816 + flex-shrink: 0; 817 + line-height: 1.2; 818 + } 749 819 .preview { 750 820 display: flex; 751 821 flex-direction: column; ··· 768 838 padding: 18px 16px; 769 839 width: 100%; 770 840 } 841 + .preview-section-header + .preview-text-inner { 842 + padding-top: 14px; 843 + } 771 844 .preview-body { 772 845 display: flex; 773 846 flex-direction: column; ··· 781 854 align-items: flex-start; 782 855 width: 100%; 783 856 } 784 - .preview-sponsor-row { 785 - display: flex; 786 - align-items: center; 787 - gap: 10px; 788 - width: 100%; 789 - } 790 - .preview-sponsor-logo { 791 - width: 32px; 792 - height: 32px; 793 - object-fit: contain; 794 - border-radius: 0; 795 - flex-shrink: 0; 796 - } 797 - .preview-sponsor-name { 798 - font-size: 0.875rem; 799 - font-weight: 600; 800 - letter-spacing: 0.065em; 801 - text-transform: uppercase; 802 - color: var(--muted); 803 - line-height: 1.3; 804 - flex: 1; 805 - min-width: 0; 806 - } 807 857 .preview-headline { 808 858 font-size: 1.0625rem; 809 859 font-weight: 700; 810 860 color: var(--text); 811 861 line-height: 1.25; 812 - margin-top: 8px; 862 + margin-top: 0; 813 863 } 814 864 .preview-subline { 815 865 font-size: 0.875rem; ··· 1256 1306 <div class="format-card"> 1257 1307 <div class="format-card-preview"> 1258 1308 <div class="format-preview-text"> 1259 - <div class="fph"></div> 1260 - <div class="fps"></div> 1261 - <div class="fpc"></div> 1309 + <div class="format-preview-section-row"> 1310 + <span class="format-preview-section-logo" aria-hidden="true"></span> 1311 + <span class="format-preview-section-title" aria-hidden="true"></span> 1312 + <span class="format-preview-section-sponsored">Sponsored</span> 1313 + </div> 1314 + <div class="format-preview-text-lines"> 1315 + <div class="fph"></div> 1316 + <div class="fps"></div> 1317 + <div class="fpc"></div> 1318 + </div> 1262 1319 </div> 1263 1320 </div> 1264 1321 <div class="format-card-info"> ··· 1266 1323 <div class="format-card-desc">Sponsor name, headline, subline, and a CTA. No image needed.</div> 1267 1324 <dl class="format-specs"> 1268 1325 <dt>Assets</dt> 1269 - <dd>Sponsor name, headline, subline (optional), CTA. Optional logo (20×20px).</dd> 1326 + <dd>Sponsor name, headline, subline (optional), CTA. Optional logo in the section header.</dd> 1270 1327 <dt>Image</dt> 1271 1328 <dd>None required.</dd> 1272 1329 </dl> ··· 1275 1332 <div class="format-card"> 1276 1333 <div class="format-card-preview"> 1277 1334 <div class="format-preview-banner"> 1335 + <div class="format-preview-section-row"> 1336 + <span class="format-preview-section-logo" aria-hidden="true"></span> 1337 + <span class="format-preview-section-title" aria-hidden="true"></span> 1338 + <span class="format-preview-section-sponsored">Sponsored</span> 1339 + </div> 1278 1340 <div class="format-preview-img"><span>Banner image</span></div> 1279 1341 <div class="format-preview-body"> 1280 1342 <div class="fph"></div> ··· 1290 1352 <dt>Banner image</dt> 1291 1353 <dd>1200×628px (landscape). JPG or PNG, max 2MB.</dd> 1292 1354 <dt>Copy</dt> 1293 - <dd>Headline, subline (optional), CTA. Optional logo (20×20px).</dd> 1355 + <dd>Headline, subline (optional), CTA. Optional logo in the section header.</dd> 1294 1356 </dl> 1295 1357 </div> 1296 1358 </div> 1297 1359 <div class="format-card"> 1298 1360 <div class="format-card-preview"> 1299 1361 <div class="format-preview-banner format-preview-feature"> 1362 + <div class="format-preview-section-row"> 1363 + <span class="format-preview-section-logo" aria-hidden="true"></span> 1364 + <span class="format-preview-section-title" aria-hidden="true"></span> 1365 + <span class="format-preview-section-sponsored">Sponsored</span> 1366 + </div> 1300 1367 <div class="format-preview-img"><span>Feature image</span></div> 1301 1368 <div class="format-preview-body"> 1302 1369 <div class="fph"></div> ··· 1312 1379 <dt>Feature image</dt> 1313 1380 <dd>1080×1350px (4:5 portrait). JPG or PNG, max 2MB.</dd> 1314 1381 <dt>Copy</dt> 1315 - <dd>Headline, subline (optional), CTA. Optional logo (20×20px). More room for subline.</dd> 1382 + <dd>Headline, subline (optional), CTA. Optional logo in the section header. More room for subline.</dd> 1316 1383 </dl> 1317 1384 </div> 1318 1385 </div> ··· 1368 1435 </form> 1369 1436 1370 1437 <aside class="preview-pane"> 1371 - <div id="adPreview" class="ad-preview"><div class="preview preview-banner"> 1438 + <div id="adPreview" class="ad-preview"> 1439 + <div class="preview preview-banner"> 1440 + <div class="preview-section-header"> 1441 + <span class="preview-section-header-title">BENNY&rsquo;S COFFEE</span> 1442 + <span class="preview-section-sponsored">Sponsored</span> 1443 + </div> 1372 1444 <div class="preview-img-placeholder" style="height:140px">Image</div> 1373 1445 <div class="preview-img-divider"></div> 1374 1446 <div class="preview-body"> 1375 1447 <div class="preview-copy-stack"> 1376 - <div class="preview-sponsor-row"><span class="preview-sponsor-name">BENNY&rsquo;S COFFEE</span></div> 1377 1448 <strong class="preview-headline">Fuel your workout</strong> 1378 1449 <span class="preview-subline">310 N Main St &middot; Open 7am&ndash;9pm</span> 1379 1450 </div> ··· 1510 1581 var image_src = d.image_src || null; 1511 1582 var logo_src = d.logo_src || null; 1512 1583 var usesImageLayout = tier !== 'text'; 1513 - var sponsorRow = '<div class="preview-sponsor-row">' + 1514 - (logo_src ? '<img src="' + escapeHtml(logo_src) + '" alt="" class="preview-sponsor-logo" onerror="this.style.display=\\'none\\'">' : '') + 1515 - '<span class="preview-sponsor-name">' + escapeHtml(sponsor) + '</span></div>'; 1516 - var copyStack = '<div class="preview-copy-stack">' + sponsorRow + 1584 + var sectionHeader = '<div class="preview-section-header">' + 1585 + (logo_src ? '<img src="' + escapeHtml(logo_src) + '" alt="" class="preview-section-header-logo" onerror="this.style.display=\\'none\\'">' : '') + 1586 + '<span class="preview-section-header-title">' + escapeHtml(sponsor) + '</span>' + 1587 + '<span class="preview-section-sponsored">Sponsored</span></div>'; 1588 + var copyStack = '<div class="preview-copy-stack">' + 1517 1589 '<strong class="preview-headline">' + escapeHtml(headline) + '</strong>' + 1518 1590 (subline ? '<span class="preview-subline">' + escapeHtml(subline) + '</span>' : '') + 1519 1591 '</div>'; ··· 1521 1593 var html; 1522 1594 if (usesImageLayout) { 1523 1595 var imgHeight = tier === 'feature' ? 220 : 140; 1524 - html = '<div class="preview preview-' + tier + '">'; 1596 + html = '<div class="preview preview-' + tier + '">' + sectionHeader; 1525 1597 if (image_src) { 1526 1598 html += '<div class="preview-img-wrap" style="height:' + imgHeight + 'px">'; 1527 1599 html += '<img src="' + escapeHtml(image_src) + '" alt="" class="preview-img" onerror="this.parentElement.classList.add(\\'preview-img-error\\')">'; ··· 1532 1604 html += '<div class="preview-img-divider"></div>'; 1533 1605 html += '<div class="preview-body">' + copyStack + ctaBtn + '</div></div>'; 1534 1606 } else { 1535 - html = '<div class="preview preview-text"><div class="preview-text-inner">' + copyStack + ctaBtn + '</div></div>'; 1607 + html = '<div class="preview preview-text">' + sectionHeader + '<div class="preview-text-inner">' + copyStack + ctaBtn + '</div></div>'; 1536 1608 } 1537 1609 adPreview.innerHTML = html; 1538 1610 }