wa-dev-tools/public/placeholder.html

275 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Placeholder — WA Dev Tools</title>
<link href="/vendor/tailwind.min.css" rel="stylesheet">
<script>window.WA_TOOL_ID = 'placeholder';</script>
<script src="/shared.js?v=3"></script>
<link href="/vendor/fonts.css" rel="stylesheet">
<link href="/shared.css" rel="stylesheet">
<style>
select, select option { background: var(--select-bg); color: var(--select-color); }
@keyframes fadeUp { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } }
.fade-up { animation: fadeUp 0.4s ease-out forwards; }
.fade-up-delay { animation: fadeUp 0.4s ease-out 0.1s forwards; opacity: 0; }
.preview-frame {
background: repeating-conic-gradient(rgba(128,128,128,.08) 0% 25%, transparent 0% 50%) 50%/16px 16px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
min-height: 160px;
overflow: hidden;
}
.preview-frame img { max-width: 100%; max-height: 400px; display: block; border-radius: 8px; }
.color-swatch {
width: 36px; height: 36px; border-radius: 8px; border: 2px solid var(--surface-600);
cursor: pointer; transition: transform .15s;
}
.color-swatch:hover { transform: scale(1.1); }
input[type="color"] { position: absolute; opacity: 0; width: 0; height: 0; }
</style>
</head>
<body class="noise dark:text-gray-200 text-gray-700 font-sans antialiased">
<div class="main-content">
<div class="tool-container relative z-10 max-w-2xl mx-auto">
<!-- Header -->
<div class="page-header" style="text-align:center;">
<div class="inline-flex items-center gap-2 mb-3 px-3 py-1 rounded-full border dark:border-surface-600 border-gray-300 dark:bg-surface-800/60 bg-white/60 text-xs font-mono dark:text-gray-400 text-gray-500 tracking-wide">
<span class="w-1.5 h-1.5 rounded-full bg-accent animate-pulse"></span>
PNG · JPG · WebP
</div>
<h1 class="text-3xl sm:text-4xl font-extrabold tracking-tight dark:text-white text-gray-900">
Placeholder <span class="text-accent">генератор</span>
</h1>
<p class="description mt-2 text-sm dark:text-gray-500 text-gray-400 font-mono">Изображения-заглушки любого размера, цвета и формата</p>
</div>
<!-- Controls Card -->
<div class="dark:bg-surface-800/80 bg-white/85 border dark:border-surface-600 border-gray-200 rounded-2xl p-5 sm:p-7 backdrop-blur-sm fade-up-delay shadow-sm dark:shadow-none">
<!-- Size -->
<div class="grid grid-cols-2 gap-3 mb-4">
<div>
<label class="block text-xs font-medium dark:text-gray-500 text-gray-400 mb-1.5 font-mono uppercase tracking-wider">Ширина</label>
<input type="number" id="width" value="600" min="1" max="4000" class="w-full px-3 py-2.5 dark:bg-surface-700 bg-gray-50 border dark:border-surface-600 border-gray-200 rounded-lg text-sm font-mono focus:outline-none focus:border-accent/50 transition-colors dark:text-white text-gray-800">
</div>
<div>
<label class="block text-xs font-medium dark:text-gray-500 text-gray-400 mb-1.5 font-mono uppercase tracking-wider">Высота</label>
<input type="number" id="height" value="400" min="1" max="4000" class="w-full px-3 py-2.5 dark:bg-surface-700 bg-gray-50 border dark:border-surface-600 border-gray-200 rounded-lg text-sm font-mono focus:outline-none focus:border-accent/50 transition-colors dark:text-white text-gray-800">
</div>
</div>
<!-- Colors -->
<div class="grid grid-cols-2 gap-3 mb-4">
<div>
<label class="block text-xs font-medium dark:text-gray-500 text-gray-400 mb-1.5 font-mono uppercase tracking-wider">Фон</label>
<div class="flex items-center gap-2">
<div class="relative">
<div id="bgSwatch" class="color-swatch" style="background:#3B82F6"></div>
<input type="color" id="bgPicker" value="#3B82F6">
</div>
<input type="text" id="bgColor" value="3B82F6" maxlength="20" class="flex-1 px-3 py-2.5 dark:bg-surface-700 bg-gray-50 border dark:border-surface-600 border-gray-200 rounded-lg text-sm font-mono focus:outline-none focus:border-accent/50 transition-colors dark:text-white text-gray-800">
</div>
</div>
<div>
<label class="block text-xs font-medium dark:text-gray-500 text-gray-400 mb-1.5 font-mono uppercase tracking-wider">Текст</label>
<div class="flex items-center gap-2">
<div class="relative">
<div id="fgSwatch" class="color-swatch" style="background:#FFFFFF"></div>
<input type="color" id="fgPicker" value="#FFFFFF">
</div>
<input type="text" id="fgColor" value="FFFFFF" maxlength="20" class="flex-1 px-3 py-2.5 dark:bg-surface-700 bg-gray-50 border dark:border-surface-600 border-gray-200 rounded-lg text-sm font-mono focus:outline-none focus:border-accent/50 transition-colors dark:text-white text-gray-800">
</div>
</div>
</div>
<!-- Text & Font size -->
<div class="grid grid-cols-2 gap-3 mb-4">
<div>
<label class="block text-xs font-medium dark:text-gray-500 text-gray-400 mb-1.5 font-mono uppercase tracking-wider">Надпись</label>
<input type="text" id="text" placeholder="600x400" class="w-full px-3 py-2.5 dark:bg-surface-700 bg-gray-50 border dark:border-surface-600 border-gray-200 rounded-lg text-sm font-mono focus:outline-none focus:border-accent/50 transition-colors dark:text-white text-gray-800">
</div>
<div>
<label class="block text-xs font-medium dark:text-gray-500 text-gray-400 mb-1.5 font-mono uppercase tracking-wider">Формат</label>
<select id="format" class="w-full px-3 py-2.5 dark:bg-surface-700 bg-gray-50 border dark:border-surface-600 border-gray-200 rounded-lg text-sm focus:outline-none focus:border-accent/50 transition-colors">
<option value="png">PNG</option>
<option value="jpg">JPG</option>
<option value="webp">WebP</option>
</select>
</div>
</div>
<!-- Generate URL -->
<div class="mb-4">
<label class="block text-xs font-medium dark:text-gray-500 text-gray-400 mb-1.5 font-mono uppercase tracking-wider">URL</label>
<div class="flex gap-2">
<input type="text" id="urlField" readonly class="flex-1 px-3 py-2.5 dark:bg-surface-700 bg-gray-50 border dark:border-surface-600 border-gray-200 rounded-lg text-xs font-mono focus:outline-none dark:text-gray-300 text-gray-600 truncate">
<button id="copyUrlBtn" class="px-4 py-2.5 rounded-lg text-xs font-medium dark:bg-surface-700 bg-gray-100 dark:text-gray-300 text-gray-600 hover:text-accent transition-colors border dark:border-surface-600 border-gray-200 whitespace-nowrap">
Копировать
</button>
</div>
</div>
<!-- Generate button -->
<button id="generateBtn"
class="w-full py-3 rounded-xl font-semibold text-sm tracking-wide transition-all duration-300
bg-accent text-white border border-accent cursor-pointer
hover:bg-accent-bright hover:shadow-lg hover:shadow-accent/20
active:scale-[0.98]">
Сгенерировать
</button>
</div>
<!-- Preview -->
<div id="previewCard" class="mt-5 fade-up">
<div class="dark:bg-surface-800/80 bg-white/85 border dark:border-surface-600 border-gray-200 rounded-2xl p-5 sm:p-7 backdrop-blur-sm shadow-sm dark:shadow-none">
<div class="flex items-center justify-between mb-4">
<span class="text-xs font-mono dark:text-gray-500 text-gray-400 uppercase tracking-wider">Превью</span>
<a id="downloadLink" href="#" download class="px-3 py-1.5 rounded-lg text-xs font-medium dark:bg-surface-700 bg-gray-100 dark:text-gray-300 text-gray-600 hover:text-accent transition-colors border dark:border-surface-600 border-gray-200 no-underline">
Скачать
</a>
</div>
<div class="preview-frame p-3">
<img id="previewImg" src="/placeholder-img/600x400/3B82F6/FFFFFF" alt="placeholder">
</div>
</div>
</div>
<!-- API Reference -->
<div class="mt-5 fade-up">
<div class="dark:bg-surface-800/80 bg-white/85 border dark:border-surface-600 border-gray-200 rounded-2xl p-5 sm:p-7 backdrop-blur-sm shadow-sm dark:shadow-none">
<h3 class="text-sm font-semibold dark:text-white text-gray-800 mb-3">API</h3>
<div class="space-y-2 text-xs font-mono dark:text-gray-400 text-gray-500 leading-relaxed">
<p><code class="dark:bg-surface-700 bg-gray-100 px-2 py-0.5 rounded">/placeholder-img/:WxH/:bg/:fg</code> — картинка без текста</p>
<p><code class="dark:bg-surface-700 bg-gray-100 px-2 py-0.5 rounded">/placeholder-img/:WxH/:bg/:fg?text=Hello</code>с текстом</p>
<p><code class="dark:bg-surface-700 bg-gray-100 px-2 py-0.5 rounded">?format=png|jpg|webp</code> — формат выходного файла</p>
<p><code class="dark:bg-surface-700 bg-gray-100 px-2 py-0.5 rounded">?fontsize=30</code> — размер шрифта (авто по умолчанию)</p>
<p class="dark:text-gray-500 text-gray-400 pt-1">Цвета: HEX (<code class="dark:bg-surface-700 bg-gray-100 px-1.5 py-0.5 rounded">3B82F6</code>) или имя (<code class="dark:bg-surface-700 bg-gray-100 px-1.5 py-0.5 rounded">red</code>, <code class="dark:bg-surface-700 bg-gray-100 px-1.5 py-0.5 rounded">yellow</code>)</p>
</div>
</div>
</div>
</div>
</div><!-- /main-content -->
<script>
// Elements
const widthEl = document.getElementById('width');
const heightEl = document.getElementById('height');
const bgColorEl = document.getElementById('bgColor');
const fgColorEl = document.getElementById('fgColor');
const bgPickerEl = document.getElementById('bgPicker');
const fgPickerEl = document.getElementById('fgPicker');
const bgSwatchEl = document.getElementById('bgSwatch');
const fgSwatchEl = document.getElementById('fgSwatch');
const textEl = document.getElementById('text');
const formatEl = document.getElementById('format');
const urlField = document.getElementById('urlField');
const previewImg = document.getElementById('previewImg');
const downloadLink = document.getElementById('downloadLink');
// Color picker sync
bgSwatchEl.addEventListener('click', () => bgPickerEl.click());
fgSwatchEl.addEventListener('click', () => fgPickerEl.click());
bgPickerEl.addEventListener('input', e => {
const hex = e.target.value.replace('#', '').toUpperCase();
bgColorEl.value = hex;
bgSwatchEl.style.background = e.target.value;
updateUrl();
});
fgPickerEl.addEventListener('input', e => {
const hex = e.target.value.replace('#', '').toUpperCase();
fgColorEl.value = hex;
fgSwatchEl.style.background = e.target.value;
updateUrl();
});
bgColorEl.addEventListener('input', () => {
const v = bgColorEl.value.trim();
if (/^[0-9A-Fa-f]{6}$/.test(v)) {
bgPickerEl.value = '#' + v;
bgSwatchEl.style.background = '#' + v;
} else {
bgSwatchEl.style.background = v;
}
updateUrl();
});
fgColorEl.addEventListener('input', () => {
const v = fgColorEl.value.trim();
if (/^[0-9A-Fa-f]{6}$/.test(v)) {
fgPickerEl.value = '#' + v;
fgSwatchEl.style.background = '#' + v;
} else {
fgSwatchEl.style.background = v;
}
updateUrl();
});
[widthEl, heightEl, textEl, formatEl].forEach(el => el.addEventListener('input', updateUrl));
function buildPath() {
const w = widthEl.value || 600;
const h = heightEl.value || 400;
const bg = bgColorEl.value.trim() || '3B82F6';
const fg = fgColorEl.value.trim() || 'FFFFFF';
let url = `/placeholder-img/${w}x${h}/${bg}/${fg}`;
const params = [];
const txt = textEl.value.trim();
if (txt) params.push('text=' + encodeURIComponent(txt));
const fmt = formatEl.value;
if (fmt !== 'png') params.push('format=' + fmt);
if (params.length) url += '?' + params.join('&');
return url;
}
function updateUrl() {
const p = buildPath();
urlField.value = location.origin + p;
}
function generate() {
const p = buildPath();
previewImg.src = p;
downloadLink.href = p;
updateUrl();
}
document.getElementById('generateBtn').addEventListener('click', generate);
// Copy URL
document.getElementById('copyUrlBtn').addEventListener('click', () => {
navigator.clipboard.writeText(urlField.value).then(() => {
const btn = document.getElementById('copyUrlBtn');
const orig = btn.textContent;
btn.textContent = 'Скопировано!';
btn.classList.add('text-accent');
setTimeout(() => { btn.textContent = orig; btn.classList.remove('text-accent'); }, 1500);
});
});
// Init
updateUrl();
</script>
<!-- Yandex.Metrika counter -->
<script type="text/javascript">
(function(m,e,t,r,i,k,a){
m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
m[i].l=1*new Date();
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)
})(window, document,'script','https://mc.yandex.ru/metrika/tag.js?id=108185982', 'ym');
ym(108185982, 'init', {ssr:true, webvisor:true, clickmap:true, ecommerce:"dataLayer", referrer: document.referrer, url: location.href, accurateTrackBounce:true, trackLinks:true});
</script>
<noscript><div><img src="https://mc.yandex.ru/watch/108185982" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
<!-- /Yandex.Metrika counter -->
</body>
</html>