feat: simplify catch report form
This commit is contained in:
@@ -7,14 +7,20 @@ const state = Astro.url.searchParams.get("state");
|
||||
const reportId = Astro.url.searchParams.get("report_id");
|
||||
---
|
||||
<Layout title="Добавить улов — RF4 Spotter">
|
||||
<section class="form-hero"><div><span class="eyebrow"><b>+1</b> Помочь сообществу</span><h1>Добавить<br/><em>свой улов</em></h1></div><p>Полминуты — и рабочая точка появится в общей статистике после проверки модератором.</p></section>
|
||||
<section class="form-hero"><div><span class="eyebrow"><b>+1</b> Помочь сообществу</span><h1>Добавить<br/><em>свой улов</em></h1></div><p>Около минуты — и рабочая точка появится в общей статистике после проверки модератором.</p></section>
|
||||
{state === "sent" && <div class="notice success">Улов отправлен на модерацию. Спасибо!</div>}
|
||||
{state === "screenshot_sent" && <div class="notice success">Скриншот добавлен к ранее созданной заявке.</div>}
|
||||
{state === "create_error" && <div class="notice error">Заявка не создана. Проверьте поля и повторите отправку.</div>}
|
||||
{state === "create_error" && <div class="notice error" id="form-error" tabindex="-1"><strong>Заявка не создана.</strong> Проверьте поля; введённые значения сохранены.</div>}
|
||||
{state === "screenshot_error" && <div class="notice warning"><strong>Заявка сохранена без скриншота.</strong> Изображение не загрузилось; можно повторить отдельно, не отправляя улов заново.</div>}
|
||||
{state === "screenshot_error" && reportId && <form class="screenshot-retry" method="post" action="/api/report-screenshot" enctype="multipart/form-data"><input type="hidden" name="report_id" value={reportId} /><label>Повторная загрузка скриншота<input name="screenshot" type="file" accept="image/jpeg,image/png,image/webp" required /></label><button type="submit">Загрузить скриншот</button></form>}
|
||||
{unavailable ? <div class="state"><h2>Форма временно недоступна</h2></div> : <form class="report-form" method="post" action="/api/report" enctype="multipart/form-data">
|
||||
<div class="form-grid"><label>Рыба *<select name="fish_slug" required>{fishes.map(x => <option value={x.slug}>{x.name_ru}</option>)}</select></label><label>Водоём *<select name="waterbody_slug" required>{waterbodies.map(x => <option value={x.slug}>{x.name_ru}</option>)}</select></label><label>Координата X *<input name="x" type="number" min="-10000" max="10000" required /></label><label>Координата Y *<input name="y" type="number" min="-10000" max="10000" required /></label><label>Вес, граммы *<input name="weight_g" type="number" min="1" max="3000000" required /></label><label>Приманка<input name="bait_name" maxlength="200" /></label><label>Способ ловли<select name="fishing_method"><option value="">Не указан</option><option value="spinning">Спиннинг</option><option value="bottom">Донная</option><option value="float">Поплавочная</option></select></label><label>Проводка<input name="retrieve_method" maxlength="100" /></label><label>Скорость проводки<input name="retrieve_speed" type="number" min="0" max="100" /></label><label>Ник игрока<input name="player_name" maxlength="100" /></label></div>
|
||||
<label class="wide">Комментарий<textarea name="comment" maxlength="1000" rows="4"></textarea></label><label class="wide">Скриншот, JPEG/PNG/WebP до 8 МБ<input name="screenshot" type="file" accept="image/jpeg,image/png,image/webp" /></label><label class="honeypot" aria-hidden="true">Сайт<input name="website" tabindex="-1" autocomplete="off" /></label><p class="privacy">Ник и скриншот необязательны. Из изображения удаляются EXIF и прочие метаданные.</p><button type="submit">Отправить на проверку</button>
|
||||
<fieldset><legend>Главное <span>обязательно</span></legend><div class="form-grid"><label>Рыба *<select name="fish_slug" required>{fishes.map(x => <option value={x.slug}>{x.name_ru}</option>)}</select></label><label>Водоём *<select name="waterbody_slug" required>{waterbodies.map(x => <option value={x.slug}>{x.name_ru}</option>)}</select></label><label>Координата X *<input name="x" type="number" min="-10000" max="10000" placeholder="Например, 72" required /></label><label>Координата Y *<input name="y" type="number" min="-10000" max="10000" placeholder="Например, 84" required /></label><label>Вес, граммы *<input name="weight_g" type="number" min="1" max="3000000" placeholder="1250" required /></label><label>Приманка<input name="bait_name" maxlength="200" placeholder="Название в игре" /></label></div><p class="field-help">Координаты — два целых числа с карты. Вес: 1,25 кг = 1250 г.</p></fieldset>
|
||||
<details class="optional-fields"><summary>Дополнительные сведения <span>необязательно</span></summary><div class="form-grid"><label>Способ ловли<select name="fishing_method"><option value="">Не указан</option><option value="spinning">Спиннинг</option><option value="bottom">Донная</option><option value="float">Поплавочная</option></select></label><label>Проводка<input name="retrieve_method" maxlength="100" /></label><label>Скорость проводки<input name="retrieve_speed" type="number" min="0" max="100" /></label><label>Ник игрока<input name="player_name" maxlength="100" /></label></div><label class="wide">Комментарий<textarea name="comment" maxlength="1000" rows="4"></textarea></label><label class="wide">Скриншот, JPEG/PNG/WebP до 8 МБ<input name="screenshot" type="file" accept="image/jpeg,image/png,image/webp" /></label></details><label class="honeypot" aria-hidden="true">Сайт<input name="website" tabindex="-1" autocomplete="off" /></label><p class="privacy">Ник и скриншот необязательны. Из изображения удаляются EXIF и прочие метаданные.</p><button type="submit">Отправить на проверку</button>
|
||||
</form>}
|
||||
<script is:inline define:vars={{ state }}>
|
||||
const form = document.querySelector(".report-form"); const key = "rf4-report-draft";
|
||||
if (form && state === "create_error") { try { const draft = JSON.parse(sessionStorage.getItem(key) || "{}"); for (const [name, value] of Object.entries(draft)) { const field = form.elements.namedItem(name); if (field && "value" in field) field.value = value; } } catch {} document.querySelector("#form-error")?.focus(); }
|
||||
if (state === "sent") sessionStorage.removeItem(key);
|
||||
form?.addEventListener("submit", () => { const draft = {}; for (const [name, value] of new FormData(form)) if (typeof value === "string" && name !== "website") draft[name] = value; sessionStorage.setItem(key, JSON.stringify(draft)); });
|
||||
</script>
|
||||
</Layout>
|
||||
|
||||
@@ -21,3 +21,4 @@ footer{min-height:118px;background:var(--deep);color:#dbe4df;padding:28px max(32
|
||||
.float-gauge{width:122px;height:142px;position:relative;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;padding-bottom:8px;isolation:isolate}.float-gauge:before,.float-gauge:after{content:"";position:absolute;left:3px;right:3px;border:1px solid #ffffff1d;border-radius:50%}.float-gauge:before{height:28px;bottom:25px;box-shadow:0 0 0 10px #ffffff08}.float-gauge:after{height:15px;bottom:32px}.float-gauge__line{position:absolute;left:50%;top:0;width:1px;height:105px;background:linear-gradient(#ffffff55,#ffffff12);z-index:-1}.float-gauge__water{position:absolute;left:11px;right:11px;bottom:39px;height:calc(var(--level)*.62);max-height:62px;background:linear-gradient(180deg,#c9f45b08,#c9f45b36);border-top:1px solid var(--lime);clip-path:polygon(0 6px,18% 0,36% 6px,54% 0,72% 6px,90% 0,100% 4px,100% 100%,0 100%)}.float-gauge__bob{position:absolute;left:50%;bottom:calc(39px + var(--level)*.62);width:18px;height:54px;transform:translate(-50%,50%);border:1px solid #e6f8ad;border-radius:50% 50% 42% 42%;background:linear-gradient(180deg,var(--lime) 0 35%,#f4f7ed 36% 58%,#e47e3b 59%);box-shadow:0 5px 18px #c9f45b38}.float-gauge__bob i{position:absolute;left:50%;top:-24px;width:1px;height:25px;background:#dfe9dc}.float-gauge strong{position:relative;z-index:2;font:400 31px/1 Georgia,serif;text-shadow:0 2px 8px var(--deep)}.float-gauge small{position:relative;z-index:2;color:#a9b8b5;font-size:9px;text-transform:uppercase}.best-lure>div{grid-template-columns:25px 1fr auto}
|
||||
@media(max-width:720px){.float-gauge{width:100px}}
|
||||
@media(prefers-reduced-motion:no-preference){.pulse-orb span{animation:ripple-pulse 2.4s ease-out infinite}.float-gauge__bob{animation:bob 2.8s ease-in-out infinite}}@keyframes ripple-pulse{50%{box-shadow:0 0 0 15px #c9f45b08}}@keyframes bob{50%{translate:0 -3px}}
|
||||
.report-form fieldset{border:0;padding:0;margin:0}.report-form legend{width:100%;margin-bottom:18px;font:400 24px Georgia,serif}.report-form legend span,.optional-fields summary span{float:right;font:11px Inter,sans-serif;text-transform:uppercase;letter-spacing:.08em;color:#7c8c89}.field-help{color:#657572;font-size:12px}.optional-fields{margin:26px 0;border-block:1px solid #d6dfd7;padding:18px 0}.optional-fields summary{cursor:pointer;font:400 20px Georgia,serif}.optional-fields[open] summary{margin-bottom:20px}.report-form input:user-invalid,.report-form select:user-invalid{border-color:#b84c3c}
|
||||
|
||||
Reference in New Issue
Block a user