my personal site
0
fork

Configure Feed

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

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

- Introduced new CSS variables for ad colors and styles to improve visual consistency.
- Refactored ad preview components to align with in-app AdView design, enhancing layout and responsiveness.
- Updated HTML structure for sponsor and copy sections to improve clarity and accessibility.
- Adjusted button styles for better user interaction and visual appeal.

+133 -91
+62 -34
gymtracker/src/admin-html.ts
··· 30 30 --font: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; 31 31 --font-mono: ui-monospace, 'Cascadia Code', 'SF Mono', Menlo, Consolas, monospace; 32 32 --cta-orange: #E87722; 33 + --ad-maroon: #861F41; 34 + --ad-cta-fill: rgba(134, 31, 65, 0.18); 33 35 --text-xs: 11px; 34 36 --text-sm: 12px; 35 37 --text-base: 14px; ··· 401 403 .id-version-row .version-input { width: 64px; min-width: 64px; flex-shrink: 0; } 402 404 .id-version-header { min-width: 0; max-width: 320px; justify-self: center; } 403 405 .id-version-header input { min-height: 36px; padding: 6px 10px; font-size: var(--text-sm); } 404 - .ad-preview { border: 1px solid var(--border); padding: 0; background: var(--surface); min-height: 8rem; overflow: hidden; } 405 - /* Matches Swift AdView + SponsorSectionHeader layout */ 406 - .preview { display: flex; flex-direction: column; align-items: flex-start; text-align: left; width: 100%; max-width: 100%; } 407 - .preview-header { 408 - display: flex; align-items: center; gap: 8px; width: 100%; 409 - padding: 0 16px 8px; border-bottom: 1px solid var(--border); margin-bottom: 0; 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 */ 408 + .preview { 409 + display: flex; flex-direction: column; align-items: stretch; text-align: left; 410 + width: 100%; max-width: 100%; 411 + border: 1px solid rgba(255, 255, 255, 0.1); 412 + border-radius: 0; 413 + overflow: hidden; 414 + background: rgba(20, 20, 20, 0.75); 415 + backdrop-filter: blur(40px) saturate(150%); 416 + -webkit-backdrop-filter: blur(40px) saturate(150%); 417 + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04); 410 418 } 411 - .preview-header-logo { width: 20px; height: 20px; object-fit: contain; border-radius: 4px; flex-shrink: 0; } 412 - .preview-header-sponsor { font-size: var(--text-sm); font-weight: 500; color: var(--text); flex: 1; } 413 - .preview-header-sponsored { font-size: var(--text-xs); color: var(--muted); } 414 - .preview.preview-text { padding: 16px; gap: 12px; } 415 - .preview.preview-text .preview-header { padding: 0 0 8px; margin-bottom: 4px; } 416 - .preview.preview-banner .preview-copy-block, 417 - .preview.preview-feature .preview-copy-block { padding: 14px 16px; display: flex; flex-direction: column; gap: 12px; width: 100%; } 418 - .preview.preview-banner .preview-header, 419 - .preview.preview-feature .preview-header { padding: 12px 16px 8px; } 420 - .preview-copy { display: flex; flex-direction: column; gap: 10px; width: 100%; } 421 - .preview-headline { font-size: var(--text-lg); font-weight: 600; line-height: 1.3; color: var(--text); } 422 - .preview-subline { font-size: var(--text-sm); color: var(--muted); line-height: 1.4; } 419 + .preview-text-inner { 420 + display: flex; flex-direction: column; gap: 12px; 421 + padding: 18px 16px; width: 100%; 422 + } 423 + .preview-body { 424 + display: flex; flex-direction: column; gap: 12px; 425 + padding: 12px 16px 18px; width: 100%; 426 + } 427 + .preview-copy-stack { 428 + display: flex; flex-direction: column; align-items: flex-start; width: 100%; 429 + } 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 + .preview-headline { 441 + font-size: var(--text-xl); font-weight: 700; line-height: 1.25; color: var(--text); 442 + margin-top: 8px; 443 + } 444 + .preview-subline { 445 + font-size: var(--text-sm); font-weight: 500; color: var(--muted); line-height: 1.4; margin-top: 6px; 446 + } 423 447 .preview-cta-wrap { 424 448 display: flex; align-items: center; justify-content: center; gap: 6px; 425 449 width: 100%; padding: 10px; 426 - color: var(--cta-orange); background: rgba(232, 119, 34, 0.12); 427 - font-size: var(--text-sm); font-weight: 500; cursor: default; border: none; 428 - border-radius: 8px; box-sizing: border-box; 450 + color: var(--ad-maroon); background: var(--ad-cta-fill); 451 + font-size: var(--text-sm); font-weight: 600; cursor: default; 452 + border-radius: 0; box-sizing: border-box; 429 453 } 430 - .preview-cta-arrow { font-size: 12px; opacity: 0.9; } 454 + .preview-cta-arrow { font-size: 12px; opacity: 0.95; line-height: 1; } 455 + .preview-img-divider { height: 1px; width: 100%; background: var(--border); flex-shrink: 0; } 431 456 .preview-img-wrap { width: 100%; overflow: hidden; position: relative; background: var(--border); } 432 457 .preview-img { width: 100%; height: 100%; object-fit: cover; display: block; } 433 458 .preview-img-wrap.preview-img-error { background: var(--border); } 434 459 .preview-img-wrap.preview-img-error .preview-img { display: none; } 435 - .preview-img-placeholder { width: 100%; background: var(--border); display: flex; align-items: center; justify-content: center; font-size: var(--text-sm); color: var(--muted); } 460 + .preview-img-placeholder { 461 + width: 100%; background: var(--border); display: flex; align-items: center; justify-content: center; 462 + font-size: var(--text-sm); color: var(--muted); 463 + } 436 464 437 465 ::-webkit-scrollbar { width: 4px; height: 4px; } 438 466 ::-webkit-scrollbar-thumb { background: var(--border); } ··· 1351 1379 function updatePreview() { 1352 1380 const d = getFormData(); 1353 1381 const tier = d.tier || 'banner'; 1354 - const sponsor = d.sponsor || getPlaceholder('sponsor'); 1382 + const sponsorRaw = d.sponsor || getPlaceholder('sponsor'); 1383 + const sponsor = sponsorRaw.toUpperCase(); 1355 1384 const headline = d.headline || getPlaceholder('headline'); 1356 1385 const subline = d.subline || getPlaceholder('subline'); 1357 1386 const cta = d.cta || getPlaceholder('cta'); 1358 1387 const image_url = d.image_url || null; 1359 1388 const logo_url = d.logo_url || null; 1360 1389 const usesImageLayout = tier !== 'text'; 1361 - const sponsorHeader = '<div class="preview-header">' + 1362 - (logo_url ? '<img src="' + escapeHtml(logo_url) + '" alt="" class="preview-header-logo" onerror="this.style.display=\\'none\\'">' : '') + 1363 - '<span class="preview-header-sponsor">' + escapeHtml(sponsor) + '</span>' + 1364 - '<span class="preview-header-sponsored">Sponsored</span></div>'; 1365 - const copyContent = '<div class="preview-copy">' + 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 + 1366 1394 '<strong class="preview-headline">' + escapeHtml(headline) + '</strong>' + 1367 1395 (subline ? '<span class="preview-subline">' + escapeHtml(subline) + '</span>' : '') + 1368 1396 '</div>'; 1369 1397 const ctaBtn = '<div class="preview-cta-wrap"><span class="preview-cta-text">' + escapeHtml(cta) + '</span><span class="preview-cta-arrow">↗</span></div>'; 1370 - let html = '<div class="preview preview-' + tier + '">'; 1371 - html += sponsorHeader; 1398 + let html; 1372 1399 if (usesImageLayout) { 1373 1400 const imgHeight = tier === 'feature' ? 220 : 140; 1401 + html = '<div class="preview preview-' + tier + '">'; 1374 1402 if (image_url) { 1375 1403 html += '<div class="preview-img-wrap" style="height:' + imgHeight + 'px">'; 1376 1404 html += '<img src="' + escapeHtml(image_url) + '" alt="" class="preview-img" onerror="this.parentElement.classList.add(\\'preview-img-error\\')">'; ··· 1378 1406 } else { 1379 1407 html += '<div class="preview-img-placeholder" style="height:' + imgHeight + 'px">Image</div>'; 1380 1408 } 1381 - html += '<div class="preview-copy-block">' + copyContent + ctaBtn + '</div>'; 1409 + html += '<div class="preview-img-divider"></div>'; 1410 + html += '<div class="preview-body">' + copyStack + ctaBtn + '</div></div>'; 1382 1411 } else { 1383 - html += copyContent + ctaBtn; 1412 + html = '<div class="preview preview-text"><div class="preview-text-inner">' + copyStack + ctaBtn + '</div></div>'; 1384 1413 } 1385 - html += '</div>'; 1386 1414 adPreview.innerHTML = html; 1387 1415 } 1388 1416
+71 -57
gymtracker/src/ads-landing-html.ts
··· 27 27 --text: #1a1614; 28 28 --text-mid: #4a4240; 29 29 --muted: #7a7270; 30 + --ad-cta-fill: rgba(134, 31, 65, 0.072); 30 31 --font: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; 31 32 --font-display: var(--font); 32 33 --font-body: var(--font); ··· 742 743 .tier-btn:hover { color: var(--text); } 743 744 .tier-btn.active { background: rgba(134,31,65,0.12); color: var(--maroon); font-weight: 600; } 744 745 745 - /* ── Preview Pane (matches admin) ─────────────────────── */ 746 + /* ── Preview Pane (matches in-app AdView) ─────────────────────── */ 746 747 .preview-pane { position: sticky; top: 84px; min-width: 0; } 747 - .ad-preview { padding: 0; background: transparent; min-height: 8rem; overflow: hidden; } 748 + .ad-preview { padding: 0; background: transparent; min-height: 8rem; overflow: visible; } 748 749 .preview { 749 750 display: flex; 750 751 flex-direction: column; 751 - align-items: flex-start; 752 + align-items: stretch; 752 753 text-align: left; 753 754 width: 100%; 754 755 max-width: 100%; 755 - background: var(--surface); 756 + background: rgba(255, 255, 255, 0.82); 756 757 border: 1px solid var(--border); 757 758 border-radius: 0; 758 759 overflow: hidden; 760 + backdrop-filter: blur(24px) saturate(160%); 761 + -webkit-backdrop-filter: blur(24px) saturate(160%); 762 + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9); 759 763 } 760 - .preview-header { 764 + .preview-text-inner { 761 765 display: flex; 762 - align-items: center; 763 - gap: 8px; 766 + flex-direction: column; 767 + gap: 12px; 768 + padding: 18px 16px; 764 769 width: 100%; 765 - padding: 0 16px 8px; 766 - border-bottom: 1px solid var(--border); 767 - margin-bottom: 0; 768 770 } 769 - .preview.preview-text { padding: 16px; gap: 12px; } 770 - .preview.preview-text .preview-header { padding: 0 0 8px; margin-bottom: 4px; } 771 - .preview.preview-banner .preview-header, 772 - .preview.preview-feature .preview-header { padding: 12px 16px 8px; } 773 - .preview.preview-banner .preview-copy-block, 774 - .preview.preview-feature .preview-copy-block { 775 - padding: 14px 16px; 771 + .preview-body { 776 772 display: flex; 777 773 flex-direction: column; 778 774 gap: 12px; 775 + padding: 12px 16px 18px; 779 776 width: 100%; 780 777 } 781 - .preview-header-logo { 782 - width: 20px; 783 - height: 20px; 778 + .preview-copy-stack { 779 + display: flex; 780 + flex-direction: column; 781 + align-items: flex-start; 782 + width: 100%; 783 + } 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; 784 794 border-radius: 0; 785 - object-fit: contain; 786 795 flex-shrink: 0; 787 796 } 788 - .preview-header-sponsor { 797 + .preview-sponsor-name { 789 798 font-size: 0.875rem; 790 - font-weight: 500; 791 - color: var(--text); 792 - flex: 1; 793 - } 794 - .preview-header-sponsored { 795 - font-size: 0.75rem; 799 + font-weight: 600; 800 + letter-spacing: 0.065em; 801 + text-transform: uppercase; 796 802 color: var(--muted); 797 - } 798 - .preview-copy { 799 - display: flex; 800 - flex-direction: column; 801 - gap: 10px; 802 - width: 100%; 803 + line-height: 1.3; 804 + flex: 1; 805 + min-width: 0; 803 806 } 804 807 .preview-headline { 805 - font-size: 1rem; 806 - font-weight: 600; 808 + font-size: 1.0625rem; 809 + font-weight: 700; 807 810 color: var(--text); 808 - line-height: 1.3; 809 - margin: 0; 811 + line-height: 1.25; 812 + margin-top: 8px; 810 813 } 811 814 .preview-subline { 812 815 font-size: 0.875rem; 816 + font-weight: 500; 813 817 color: var(--muted); 814 818 line-height: 1.4; 815 - margin: 0; 819 + margin-top: 6px; 820 + } 821 + .preview-img-divider { 822 + height: 1px; 823 + width: 100%; 824 + background: var(--border); 825 + flex-shrink: 0; 816 826 } 817 827 .preview-img-wrap { 818 828 width: 100%; ··· 844 854 gap: 6px; 845 855 width: 100%; 846 856 padding: 10px; 847 - color: var(--orange); 848 - background: rgba(232, 119, 34, 0.12); 857 + color: var(--maroon); 858 + background: var(--ad-cta-fill); 849 859 font-size: 0.875rem; 850 - font-weight: 500; 851 - border-radius: 8px; 860 + font-weight: 600; 861 + border-radius: 0; 852 862 box-sizing: border-box; 853 863 } 854 - .preview-cta-arrow { font-size: 12px; opacity: 0.9; } 864 + .preview-cta-arrow { font-size: 12px; opacity: 0.95; line-height: 1; } 855 865 .preview-label { 856 866 font-size: 0.75rem; 857 867 color: var(--muted); ··· 1359 1369 1360 1370 <aside class="preview-pane"> 1361 1371 <div id="adPreview" class="ad-preview"><div class="preview preview-banner"> 1362 - <div class="preview-header"><span class="preview-header-sponsor">Benny&rsquo;s Coffee</span><span class="preview-header-sponsored">Sponsored</span></div> 1363 1372 <div class="preview-img-placeholder" style="height:140px">Image</div> 1364 - <div class="preview-copy-block"> 1365 - <div class="preview-copy"><strong class="preview-headline">Fuel your workout</strong><span class="preview-subline">310 N Main St &middot; Open 7am&ndash;9pm</span></div> 1373 + <div class="preview-img-divider"></div> 1374 + <div class="preview-body"> 1375 + <div class="preview-copy-stack"> 1376 + <div class="preview-sponsor-row"><span class="preview-sponsor-name">BENNY&rsquo;S COFFEE</span></div> 1377 + <strong class="preview-headline">Fuel your workout</strong> 1378 + <span class="preview-subline">310 N Main St &middot; Open 7am&ndash;9pm</span> 1379 + </div> 1366 1380 <div class="preview-cta-wrap"><span class="preview-cta-text">View menu</span><span class="preview-cta-arrow">↗</span></div> 1367 1381 </div> 1368 1382 </div></div> ··· 1489 1503 function updatePreview() { 1490 1504 var d = getFormData(); 1491 1505 var tier = d.tier || 'banner'; 1492 - var sponsor = d.sponsor || getPlaceholder('sponsor'); 1506 + var sponsor = (d.sponsor || getPlaceholder('sponsor')).toUpperCase(); 1493 1507 var headline = d.headline || getPlaceholder('headline'); 1494 1508 var subline = d.subline || getPlaceholder('subline'); 1495 1509 var cta = d.cta || getPlaceholder('cta'); 1496 1510 var image_src = d.image_src || null; 1497 1511 var logo_src = d.logo_src || null; 1498 1512 var usesImageLayout = tier !== 'text'; 1499 - var sponsorHeader = '<div class="preview-header">' + 1500 - (logo_src ? '<img src="' + escapeHtml(logo_src) + '" alt="" class="preview-header-logo" onerror="this.style.display=\\'none\\'">' : '') + 1501 - '<span class="preview-header-sponsor">' + escapeHtml(sponsor) + '</span>' + 1502 - '<span class="preview-header-sponsored">Sponsored</span></div>'; 1503 - var copyContent = '<div class="preview-copy">' + 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 + 1504 1517 '<strong class="preview-headline">' + escapeHtml(headline) + '</strong>' + 1505 1518 (subline ? '<span class="preview-subline">' + escapeHtml(subline) + '</span>' : '') + 1506 1519 '</div>'; 1507 1520 var ctaBtn = '<div class="preview-cta-wrap"><span class="preview-cta-text">' + escapeHtml(cta) + '</span><span class="preview-cta-arrow">↗</span></div>'; 1508 - var html = '<div class="preview preview-' + tier + '">' + sponsorHeader; 1521 + var html; 1509 1522 if (usesImageLayout) { 1510 1523 var imgHeight = tier === 'feature' ? 220 : 140; 1524 + html = '<div class="preview preview-' + tier + '">'; 1511 1525 if (image_src) { 1512 1526 html += '<div class="preview-img-wrap" style="height:' + imgHeight + 'px">'; 1513 1527 html += '<img src="' + escapeHtml(image_src) + '" alt="" class="preview-img" onerror="this.parentElement.classList.add(\\'preview-img-error\\')">'; ··· 1515 1529 } else { 1516 1530 html += '<div class="preview-img-placeholder" style="height:' + imgHeight + 'px">Image</div>'; 1517 1531 } 1518 - html += '<div class="preview-copy-block">' + copyContent + ctaBtn + '</div>'; 1532 + html += '<div class="preview-img-divider"></div>'; 1533 + html += '<div class="preview-body">' + copyStack + ctaBtn + '</div></div>'; 1519 1534 } else { 1520 - html += copyContent + ctaBtn; 1535 + html = '<div class="preview preview-text"><div class="preview-text-inner">' + copyStack + ctaBtn + '</div></div>'; 1521 1536 } 1522 - html += '</div>'; 1523 1537 adPreview.innerHTML = html; 1524 1538 } 1525 1539