added on WebSTLs (webstls.com) at 2026-07-01 22:27:01
| 1 | <!-- ===================================================================== | |
| 2 | Per-model marketplace export view. All listing fields in one place | |
| 3 | with copy-to-clipboard buttons and direct download links. Works | |
| 4 | for every marketplace today, even before API adapters ship. | |
| 5 | ===================================================================== --> | |
| 6 | ||
| 7 | <style> | |
| 8 | .ex-grid { display: grid; grid-template-columns: 1.4fr 1fr; gap: 20px; align-items: flex-start; } | |
| 9 | @media (max-width: 1000px) { .ex-grid { grid-template-columns: 1fr; } } | |
| 10 | .ex-field { background: var(--col-surface-1); border: 1px solid var(--col-border); border-radius: 10px; padding: 16px 18px; margin-bottom: 14px; } | |
| 11 | .ex-field h3 { margin: 0 0 8px; font-size: 13px; letter-spacing: 1.5px; text-transform: uppercase; color: var(--col-text-3); font-weight: 700; display: flex; align-items: center; justify-content: space-between; } | |
| 12 | .ex-field .ex-value { background: var(--col-bg-2); border: 1px solid var(--col-border); border-radius: 6px; padding: 12px 14px; font-size: 14px; color: var(--col-text); line-height: 1.6; min-height: 24px; } | |
| 13 | .ex-field .ex-value.mono { font-family: var(--font-mono, ui-monospace, monospace); font-size: 13px; } | |
| 14 | .ex-field .ex-value.long { white-space: pre-wrap; max-height: 320px; overflow-y: auto; } | |
| 15 | .ex-copy { background: var(--col-surface-2); border: 1px solid var(--col-border); color: var(--col-text-2); padding: 4px 10px; border-radius: 5px; cursor: pointer; font-size: 11px; letter-spacing: 1px; text-transform: uppercase; font-family: var(--font-mono, monospace); transition: all 0.15s; } | |
| 16 | .ex-copy:hover { background: var(--col-accent); color: #fff; border-color: var(--col-accent); } | |
| 17 | .ex-copy.copied { background: #10b981; color: #fff; border-color: #10b981; } | |
| 18 | ||
| 19 | .ex-platform { background: var(--col-surface-1); border: 1px solid var(--col-border); border-radius: 8px; padding: 12px 14px; margin-bottom: 8px; display: flex; align-items: center; gap: 10px; } | |
| 20 | .ex-platform .name { font-weight: 600; color: var(--col-text); flex: 1; } | |
| 21 | .ex-platform .meta { font-family: var(--font-mono, monospace); font-size: 10px; letter-spacing: 1px; text-transform: uppercase; color: var(--col-text-3); } | |
| 22 | ||
| 23 | .ex-hero { width: 100%; aspect-ratio: 16/10; background-size: cover; background-position: center; border-radius: 10px; border: 1px solid var(--col-border); margin-bottom: 14px; } | |
| 24 | </style> | |
| 25 | ||
| 26 | <div class="page-head"> | |
| 27 | <div> | |
| 28 | <span class="page-eyebrow"><a href="/marketplaces.cgi" class="text-brand">← Marketplaces</a></span> | |
| 29 | <h1 class="page-title">Export "$model_title"</h1> | |
| 30 | <p class="page-subtitle">Copy any field into the marketplace of your choice. Once API adapters ship for a platform, the Push button becomes one-click.</p> | |
| 31 | </div> | |
| 32 | </div> | |
| 33 | ||
| 34 | <div class="ex-grid"> | |
| 35 | ||
| 36 | <!-- ===== Left: the listing fields ===== --> | |
| 37 | <div> | |
| 38 | ||
| 39 | <div class="ex-hero" style="background-image:url('$hero_image')"></div> | |
| 40 | ||
| 41 | <div class="ex-field"> | |
| 42 | <h3>Title <button type="button" class="ex-copy" data-copy="title">Copy</button></h3> | |
| 43 | <div class="ex-value mono" id="ex-title">$model_title</div> | |
| 44 | </div> | |
| 45 | ||
| 46 | <div class="ex-field"> | |
| 47 | <h3>Description <button type="button" class="ex-copy" data-copy="desc">Copy</button></h3> | |
| 48 | <div class="ex-value long" id="ex-desc">$model_desc</div> | |
| 49 | </div> | |
| 50 | ||
| 51 | <div class="ex-field"> | |
| 52 | <h3>Price <button type="button" class="ex-copy" data-copy="price">Copy</button></h3> | |
| 53 | <div class="ex-value mono" id="ex-price">$model_price $model_currency</div> | |
| 54 | </div> | |
| 55 | ||
| 56 | <div class="ex-field"> | |
| 57 | <h3>Tags / category <button type="button" class="ex-copy" data-copy="tags">Copy</button></h3> | |
| 58 | <div class="ex-value mono" id="ex-tags">$model_tags</div> | |
| 59 | </div> | |
| 60 | ||
| 61 | <div class="ex-field"> | |
| 62 | <h3>Default license blurb <button type="button" class="ex-copy" data-copy="license">Copy</button></h3> | |
| 63 | <div class="ex-value long" id="ex-license">$model_license</div> | |
| 64 | </div> | |
| 65 | ||
| 66 | <div class="ex-field"> | |
| 67 | <h3>Hero image <a href="$hero_image" download class="ex-copy">Download</a></h3> | |
| 68 | <div class="ex-value mono" id="ex-image-url">$hero_image</div> | |
| 69 | </div> | |
| 70 | ||
| 71 | </div> | |
| 72 | ||
| 73 | <!-- ===== Right: per-platform readiness + push buttons ===== --> | |
| 74 | <div> | |
| 75 | <div class="ex-field"> | |
| 76 | <h3>Per-platform readiness</h3> | |
| 77 | <p class="text-xs text-secondary" style="margin:0 0 10px;line-height:1.5"> | |
| 78 | Title/description character limits vary. Yellow warnings mean the field is too long for that platform — trim before pasting. | |
| 79 | </p> | |
| 80 | ||
| 81 | [loop:@platforms] | |
| 82 | <div class="ex-platform"> | |
| 83 | <div class="brand-mark" style="background:linear-gradient(130deg,var(--col-accent),var(--col-accent-bright));width:28px;height:28px;font-size:11px;flex-shrink:0">$loop1.slug</div> | |
| 84 | <div style="flex:1;min-width:0"> | |
| 85 | <div class="name">$loop1.name</div> | |
| 86 | <div class="meta">title $loop1.title_chars/$loop1.title_limit · tags max $loop1.tags_max</div> | |
| 87 | </div> | |
| 88 | $loop1.title_status | |
| 89 | [if:$loop1.is_planned] | |
| 90 | <span class="pill" style="background:rgba(124,58,237,0.15);color:#a78bfa;border:1px solid rgba(124,58,237,0.35)">Manual</span> | |
| 91 | [/if] | |
| 92 | [if:!$loop1.is_planned] | |
| 93 | <button type="button" class="btn btn-primary btn-sm">Push</button> | |
| 94 | [/if] | |
| 95 | </div> | |
| 96 | [/loop] | |
| 97 | </div> | |
| 98 | ||
| 99 | <div class="banner info"> | |
| 100 | <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/></svg> | |
| 101 | <div class="text-xs" style="line-height:1.55"> | |
| 102 | <strong>Tip:</strong> for marketplaces with strict character limits (Etsy 140-char titles, Amazon 200), copy first then trim. The "Push" button replaces the manual flow once that platform's adapter ships. | |
| 103 | </div> | |
| 104 | </div> | |
| 105 | </div> | |
| 106 | ||
| 107 | </div> | |
| 108 | ||
| 109 | ||
| 110 | <script> | |
| 111 | /* | |
| 112 | * Copy-to-clipboard for each field. Falls back to a textarea select | |
| 113 | * trick if the modern Clipboard API isn't available. | |
| 114 | */ | |
| 115 | (function() { | |
| 116 | document.querySelectorAll('.ex-copy[data-copy]').forEach(function(btn) { | |
| 117 | btn.addEventListener('click', function() { | |
| 118 | var key = btn.dataset.copy; | |
| 119 | var src = document.getElementById('ex-' + key); | |
| 120 | if (!src) return; | |
| 121 | var text = src.innerText || src.textContent || ''; | |
| 122 | copyText(text, btn); | |
| 123 | }); | |
| 124 | }); | |
| 125 | ||
| 126 | function copyText(text, btn) { | |
| 127 | if (navigator.clipboard && navigator.clipboard.writeText) { | |
| 128 | navigator.clipboard.writeText(text).then(function() { flash(btn); }, function() { fallback(text, btn); }); | |
| 129 | } else { | |
| 130 | fallback(text, btn); | |
| 131 | } | |
| 132 | } | |
| 133 | function fallback(text, btn) { | |
| 134 | var ta = document.createElement('textarea'); | |
| 135 | ta.value = text; | |
| 136 | ta.style.position = 'fixed'; | |
| 137 | ta.style.opacity = '0'; | |
| 138 | document.body.appendChild(ta); | |
| 139 | ta.select(); | |
| 140 | try { document.execCommand('copy'); flash(btn); } catch (e) {} | |
| 141 | document.body.removeChild(ta); | |
| 142 | } | |
| 143 | function flash(btn) { | |
| 144 | var orig = btn.textContent; | |
| 145 | btn.textContent = 'Copied'; | |
| 146 | btn.classList.add('copied'); | |
| 147 | setTimeout(function() { btn.textContent = orig; btn.classList.remove('copied'); }, 1400); | |
| 148 | } | |
| 149 | })(); | |
| 150 | </script> |