Redesign settings UI and log entries, add wb3 logo

- Settings: tab per star with mini-toggle + template count badge
- Templates: full-width textarea per template (not cramped columns)
- Filter mode: pill-cards instead of raw radio buttons
- Save button aligned right with border-top separator
- Log: card-based entries (rating pill, meta row, review/reply blocks)
- wb3.png logo, 160px on login, 40px in topbar with ring shadow
- Fix CSS variable names (--c-* → --line/--card/--text/--muted)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-15 21:21:12 +03:00
parent ee946f7f1f
commit 93be1e8089
7 changed files with 476 additions and 134 deletions
+308 -15
View File
@@ -129,14 +129,14 @@ a:hover { color: var(--blue-dark); text-decoration: underline; }
flex-shrink: 0;
}
.topbar__logo-img {
width: 34px;
height: 34px;
border-radius: 8px;
width: 40px;
height: 40px;
border-radius: 10px;
object-fit: contain;
flex-shrink: 0;
background: white;
padding: 3px;
box-shadow: 0 2px 8px rgba(203,17,171,0.25);
padding: 4px;
box-shadow: 0 2px 10px rgba(203,17,171,0.3), 0 0 0 2px rgba(203,17,171,0.12);
}
.topbar__name {
@@ -931,14 +931,14 @@ textarea:focus {
}
.login-promo__logo {
width: 140px;
height: 140px;
width: 160px;
height: 160px;
object-fit: contain;
border-radius: 20px;
background: white;
padding: 8px;
box-shadow: 0 8px 32px rgba(0,0,0,0.25);
margin-bottom: 28px;
border-radius: 24px;
background: #fff;
padding: 16px;
box-shadow: 0 12px 40px rgba(0,0,0,0.35), 0 0 0 4px rgba(255,255,255,0.15);
margin-bottom: 32px;
display: block;
}
@@ -1037,7 +1037,7 @@ textarea:focus {
font-size: 1.3rem;
font-weight: 700;
margin-bottom: 22px;
color: var(--c-text);
color: var(--text);
}
/* ─── Auth card ──────────────────────────────────────────────────── */
@@ -1407,9 +1407,9 @@ textarea:focus {
align-items: center;
gap: 8px;
font-size: 13px;
color: var(--c-text-muted);
color: var(--muted);
padding: 8px 0 12px;
border-bottom: 1px solid var(--c-border);
border-bottom: 1px solid var(--line);
margin-bottom: 16px;
}
@@ -1531,3 +1531,296 @@ fieldset:disabled button[type="submit"] {
.star-chip--1 { background: #FEE2E2; color: #EF4444; }
.star-chip--2 { background: #FFEDD5; color: #F97316; }
.star-chip--3 { background: #FEF9C3; color: #CA8A04; }
/* ── Filter pills ────────────────────────────────────────── */
.filter-pills {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.filter-pill {
cursor: pointer;
flex: 1 1 160px;
min-width: 140px;
}
.filter-pill input { display: none; }
.filter-pill span {
display: flex;
flex-direction: column;
gap: 3px;
padding: 12px 16px;
border-radius: var(--r);
border: 2px solid var(--line);
background: var(--card);
transition: border-color .15s, background .15s;
}
.filter-pill span strong { font-size: 13px; font-weight: 600; }
.filter-pill span small { font-size: 11px; color: var(--muted); }
.filter-pill input:checked + span {
border-color: var(--wb);
background: var(--wb-light);
}
.filter-pill input:checked + span strong { color: var(--wb); }
/* ── Star tabs ───────────────────────────────────────────── */
.star-tabs {
display: flex;
gap: 8px;
flex-wrap: wrap;
margin-bottom: 0;
}
.star-tab {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 14px;
border-radius: var(--r) var(--r) 0 0;
border: 2px solid var(--line);
border-bottom: none;
cursor: pointer;
background: var(--card);
opacity: 0.5;
transition: opacity .15s, background .15s, border-color .15s;
user-select: none;
position: relative;
bottom: -2px;
}
.star-tab.star-tab--on { opacity: 1; }
.star-tab.star-tab--active {
background: var(--bg);
opacity: 1;
z-index: 1;
}
.star-tab--1.star-tab--active { border-color: #EF4444; }
.star-tab--2.star-tab--active { border-color: #F97316; }
.star-tab--3.star-tab--active { border-color: #EAB308; }
.star-tab--4.star-tab--active { border-color: #3B82F6; }
.star-tab--5.star-tab--active { border-color: #22C55E; }
.star-tab__label { font-weight: 700; font-size: 15px; }
.star-tab--1 .star-tab__label { color: #EF4444; }
.star-tab--2 .star-tab__label { color: #F97316; }
.star-tab--3 .star-tab__label { color: #EAB308; }
.star-tab--4 .star-tab__label { color: #3B82F6; }
.star-tab--5 .star-tab__label { color: #22C55E; }
.star-tab__count {
font-size: 11px;
font-weight: 700;
min-width: 18px;
height: 18px;
line-height: 18px;
text-align: center;
border-radius: 99px;
background: var(--line);
color: var(--muted);
padding: 0 5px;
}
/* mini toggle inside tab */
.star-tab__toggle { cursor: pointer; display: flex; align-items: center; }
.star-tab__toggle input { display: none; }
.star-tab__toggle-track {
display: inline-block;
width: 28px;
height: 16px;
border-radius: 8px;
background: var(--line);
position: relative;
transition: background .15s;
}
.star-tab__toggle-track::after {
content: '';
position: absolute;
top: 2px; left: 2px;
width: 12px; height: 12px;
border-radius: 50%;
background: #fff;
transition: transform .15s;
}
.star-tab__toggle input:checked ~ .star-tab__toggle-track { background: #22C55E; }
.star-tab__toggle input:checked ~ .star-tab__toggle-track::after { transform: translateX(12px); }
/* ── Star panel ──────────────────────────────────────────── */
.star-panel {
border: 2px solid var(--line);
border-radius: 0 var(--r) var(--r) var(--r);
padding: 20px;
background: var(--bg);
}
.star-panel__header {
display: flex;
align-items: baseline;
gap: 12px;
margin-bottom: 16px;
}
.pool-panel-items {
display: flex;
flex-direction: column;
gap: 10px;
margin-bottom: 14px;
}
.pool-template-row {
display: grid;
grid-template-columns: 28px 1fr 36px;
gap: 8px;
align-items: start;
}
.pool-template-num {
width: 28px;
height: 28px;
border-radius: 50%;
background: var(--line);
color: var(--muted);
font-size: 12px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
margin-top: 8px;
}
.pool-template-input {
width: 100%;
box-sizing: border-box;
padding: 10px 14px;
border: 1.5px solid var(--line);
border-radius: var(--r);
font-size: 14px;
font-family: inherit;
resize: vertical;
background: var(--card);
color: var(--text);
transition: border-color .15s;
line-height: 1.5;
}
.pool-template-input:focus {
outline: none;
border-color: var(--wb);
}
.pool-template-del {
width: 32px;
height: 32px;
border: none;
border-radius: 6px;
background: var(--red-bg);
color: var(--red);
cursor: pointer;
font-size: 13px;
display: flex;
align-items: center;
justify-content: center;
margin-top: 8px;
transition: background .15s;
flex-shrink: 0;
}
.pool-template-del:hover { background: #fecaca; }
.btn-add-template {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 9px 16px;
border-radius: var(--r);
border: 1.5px dashed var(--line);
background: transparent;
color: var(--muted);
font-size: 13px;
cursor: pointer;
transition: border-color .15s, color .15s;
}
.btn-add-template:hover { border-color: var(--wb); color: var(--wb); }
/* ── Save button ─────────────────────────────────────────── */
.settings-footer {
display: flex;
justify-content: flex-end;
margin-top: 20px;
padding-top: 16px;
border-top: 1px solid var(--line);
}
.btn-save {
padding: 10px 28px;
background: var(--wb);
color: #fff;
border: none;
border-radius: var(--r);
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: opacity .15s;
}
.btn-save:hover { opacity: 0.85; }
fieldset:disabled .btn-save { opacity: 0.4; cursor: not-allowed; }
fieldset:disabled .pool-template-input,
fieldset:disabled .pool-template-del,
fieldset:disabled .btn-add-template,
fieldset:disabled .star-tab,
fieldset:disabled .filter-pill { pointer-events: none; opacity: 0.5; }
/* ── Log entries ─────────────────────────────────────────── */
.log-list {
display: flex;
flex-direction: column;
gap: 0;
}
.log-entry {
display: flex;
gap: 16px;
padding: 14px 0;
border-bottom: 1px solid var(--line);
align-items: flex-start;
}
.log-entry:last-child { border-bottom: none; }
.log-entry__left {
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
flex-shrink: 0;
width: 52px;
}
.log-entry__rating {
display: inline-flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 10px;
font-weight: 800;
font-size: 13px;
}
.log-entry__status { font-size: 11px; text-align: center; white-space: nowrap; }
.log-entry__body { flex: 1; min-width: 0; }
.log-entry__meta {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: baseline;
margin-bottom: 6px;
}
.log-entry__product { font-size: 13px; font-weight: 600; color: var(--text); }
.log-entry__buyer { font-size: 12px; color: var(--muted); }
.log-entry__time { font-size: 11px; color: var(--muted); margin-left: auto; }
.log-entry__review {
font-size: 13px;
color: var(--muted);
padding: 8px 12px;
background: var(--card);
border-radius: 6px;
border-left: 3px solid var(--line);
margin-bottom: 6px;
white-space: pre-wrap;
word-break: break-word;
}
.log-entry__reply {
font-size: 13px;
color: var(--text);
padding: 8px 12px;
background: var(--wb-light);
border-radius: 6px;
border-left: 3px solid var(--wb);
white-space: pre-wrap;
word-break: break-word;
}
.log-entry__reply-ico {
color: var(--wb);
font-weight: 700;
margin-right: 6px;
}
+1 -1
View File
@@ -11,7 +11,7 @@
<nav class="topbar">
<div class="topbar__inner">
<a href="{{ url_for('index') }}" class="topbar__brand">
<img src="{{ url_for('static', filename='wb2.png') }}" class="topbar__logo-img" alt="WB">
<img src="{{ url_for('static', filename='wb3.png') }}" class="topbar__logo-img" alt="WB">
<span class="topbar__name">Feedback</span>
</a>
<div class="topbar__nav">
+1 -1
View File
@@ -11,7 +11,7 @@
<nav class="topbar">
<div class="topbar__inner">
<a href="{{ url_for('index') }}" class="topbar__brand">
<img src="{{ url_for('static', filename='wb2.png') }}" class="topbar__logo-img" alt="WB">
<img src="{{ url_for('static', filename='wb3.png') }}" class="topbar__logo-img" alt="WB">
<span class="topbar__name">Feedback</span>
</a>
<div class="topbar__nav">
+157 -108
View File
@@ -11,7 +11,7 @@
<nav class="topbar">
<div class="topbar__inner">
<a href="{{ url_for('index') }}" class="topbar__brand">
<img src="{{ url_for('static', filename='wb2.png') }}" class="topbar__logo-img" alt="WB">
<img src="{{ url_for('static', filename='wb3.png') }}" class="topbar__logo-img" alt="WB">
<span class="topbar__name">Feedback</span>
</a>
<div class="topbar__nav">
@@ -67,59 +67,72 @@
<form method="post" action="{{ url_for('auto_reply_settings') }}" id="settings-form">
<fieldset {% if auto_reply_enabled %}disabled{% endif %} style="border:none;padding:0;margin:0">
<!-- Звёзды -->
<div class="settings-section">
<div class="settings-label">На какие оценки отвечать</div>
<div class="star-toggles">
{% for star in [1,2,3,4,5] %}
<label class="star-toggle star-toggle--{{ star }}">
<input type="checkbox" name="stars" value="{{ star }}"
{% if star in enabled_stars %}checked{% endif %}
onchange="updateColumns()">
<span>{{ star }}★</span>
</label>
{% endfor %}
</div>
</div>
<!-- Фильтр типа отзывов -->
<!-- Фильтр — pill-кнопки -->
<div class="settings-section">
<div class="settings-label">Отвечать на отзывы</div>
<div class="filter-options">
<label class="filter-option">
<div class="filter-pills">
<label class="filter-pill">
<input type="radio" name="filter_mode" value="no_text" {% if filter_mode == 'no_text' %}checked{% endif %}>
<span>Без основного текста <small>(достоинства/недостатки допустимы)</small></span>
<span>
<strong>Без текста</strong>
<small>достоинства/недостатки допустимы</small>
</span>
</label>
<label class="filter-option">
<label class="filter-pill">
<input type="radio" name="filter_mode" value="empty" {% if filter_mode == 'empty' %}checked{% endif %}>
<span>Полностью пустые <small>(нет текста, достоинств и недостатков)</small></span>
<span>
<strong>Полностью пустые</strong>
<small>нет ни текста, ни плюсов/минусов</small>
</span>
</label>
<label class="filter-option">
<label class="filter-pill">
<input type="radio" name="filter_mode" value="all" {% if filter_mode == 'all' %}checked{% endif %}>
<span>Все отзывы <small>(независимо от наличия текста)</small></span>
<span>
<strong>Все отзывы</strong>
<small>независимо от наличия текста</small>
</span>
</label>
</div>
</div>
<!-- Динамические колонки пулов -->
<!-- Шаблоны ответов — вкладки по звёздам -->
<div class="settings-section">
<div class="settings-label">Шаблоны ответов</div>
<div class="pool-columns" id="pool-columns">
<!-- Вкладки звёзд -->
<div class="star-tabs" id="star-tabs">
{% set star_labels = {1: 'Плохо', 2: 'Не понравилось', 3: 'Нормально', 4: 'Хорошо', 5: 'Отлично'} %}
{% for star in [1,2,3,4,5] %}
<div class="pool-col pool-col--{{ star }}" id="pool-col-{{ star }}" {% if star not in enabled_stars %}style="display:none"{% endif %}>
<div class="pool-col__header">
<span class="star-chip star-chip--{{ star }}">{{ star }}★</span>
</div>
<div class="pool-items" id="pool-items-{{ star }}"></div>
<textarea name="pool_{{ star }}_raw" id="pool-{{ star }}-hidden" hidden>{{ reply_pools[star] }}</textarea>
<button type="button" class="btn-add-item" onclick="addPoolItem('{{ star }}')">+ Добавить ответ</button>
<div class="star-tab star-tab--{{ star }} {% if star in enabled_stars %}star-tab--on{% endif %}"
data-star="{{ star }}" onclick="setActiveStar({{ star }})">
<span class="star-tab__label">{{ star }}★</span>
<span class="star-tab__count" id="tab-count-{{ star }}">0</span>
<label class="star-tab__toggle" onclick="event.stopPropagation()" title="Включить/выключить">
<input type="checkbox" name="stars" value="{{ star }}"
id="star-cb-{{ star }}"
{% if star in enabled_stars %}checked{% endif %}
onchange="onStarToggle({{ star }})">
<span class="star-tab__toggle-track"></span>
</label>
</div>
{% endfor %}
</div>
<!-- Панель редактирования активной звезды -->
<div class="star-panel" id="star-panel">
<div class="star-panel__header" id="star-panel-header"></div>
<div class="pool-panel-items" id="pool-panel-items"></div>
<button type="button" class="btn-add-template" id="btn-add-template">+ Добавить шаблон</button>
</div>
<div style="margin-top:20px">
<button type="submit">Сохранить настройки</button>
<!-- Скрытые textarea со значениями пулов для всех звёзд -->
{% for star in [1,2,3,4,5] %}
<textarea name="pool_{{ star }}_raw" id="pool-{{ star }}-hidden" hidden>{{ reply_pools[star] }}</textarea>
{% endfor %}
</div>
<div class="settings-footer">
<button type="submit" class="btn-save">Сохранить настройки</button>
</div>
</fieldset>
</form>
@@ -180,53 +193,43 @@
<div class="card">
<div class="section-header">
<h2>Журнал автоответов</h2>
<span class="badge">последние 100</span>
{% if auto_reply_logs %}
<span class="badge">{{ auto_reply_logs|length }}</span>
{% endif %}
</div>
{% if auto_reply_logs %}
<div class="logs-table-wrap">
<table class="logs-table">
<thead>
<tr>
<th>Дата лога</th>
<th>Дата оценки</th>
<th>Оценка</th>
<th>Товар</th>
<th>Покупатель</th>
<th>Текст отзыва</th>
<th>Статус</th>
<th>ID отзыва</th>
<th>Ответ</th>
</tr>
</thead>
<tbody>
<div class="log-list">
{% for log in auto_reply_logs %}
<tr>
<td>{{ log["created_at"]|format_log_datetime }}</td>
<td>{{ log["review_created_at"]|format_log_datetime if log["review_created_at"] else "—" }}</td>
<td><span class="rating rating--{{ log['rating'] }}">{{ log["rating"] }}★</span></td>
<td>
{{ log["product_name"] or "—" }}
{% if log["nm_id"] %}
<span class="tag-article">#{{ log["nm_id"] }}</span>
{% endif %}
</td>
<td>{{ log["user_name"] or "—" }}</td>
<td>{{ log["review_text"] or "—" }}</td>
<td>
{% if log["status"] == "sent" %}
<div class="log-entry log-entry--{{ log['status'] }}">
<div class="log-entry__left">
<span class="log-entry__rating rating--{{ log['rating'] }}">{{ log['rating'] }}</span>
<div class="log-entry__status">
{% if log['status'] == 'sent' %}
<span class="log-status--sent">✓ Отправлен</span>
{% elif log["status"] == "skipped" %}
{% elif log['status'] == 'skipped' %}
<span class="log-status--skip">— Пропущен</span>
{% else %}
<span class="log-status--error">✗ Ошибка</span>
{% endif %}
</td>
<td><code style="font-size:0.72rem;color:var(--c-text-muted)">{{ log["review_id"] or "—" }}</code></td>
<td>{{ log["reply_text"] or "—" }}</td>
</tr>
</div>
</div>
<div class="log-entry__body">
<div class="log-entry__meta">
<span class="log-entry__product">{{ log['product_name'] or '—' }}{% if log['nm_id'] %} <span class="tag-article">#{{ log['nm_id'] }}</span>{% endif %}</span>
<span class="log-entry__buyer">{{ log['user_name'] or '—' }}</span>
<span class="log-entry__time">{{ log['created_at']|format_log_datetime }}</span>
</div>
{% if log['review_text'] %}
<div class="log-entry__review">{{ log['review_text'] }}</div>
{% endif %}
{% if log['reply_text'] %}
<div class="log-entry__reply">
<span class="log-entry__reply-ico"></span>{{ log['reply_text'] }}
</div>
{% endif %}
</div>
</div>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="empty-state">Пока нет записей автоответа.</div>
@@ -281,51 +284,97 @@ function startCountdown(id, onZero) {
const cooldownCtrl = startCountdown('cooldown-counter');
const fetchCtrl = startCountdown('fetch-counter', () => window.location.reload());
// ── Pool editor ────────────────────────────────────────────────────
function syncHidden(star) {
const items = document.querySelectorAll(`#pool-items-${star} .pool-item-input`);
const lines = [...items].map(i => i.value.trim()).filter(Boolean);
const container = document.getElementById(`pool-items-${star}`);
container.querySelectorAll('input[name="pool_' + star + '_item"]').forEach(e => e.remove());
lines.forEach(line => {
const inp = document.createElement('input');
inp.type = 'hidden';
inp.name = `pool_${star}_item`;
inp.value = line;
container.appendChild(inp);
});
// ── Star tab pool editor ───────────────────────────────────────────
const poolData = {1:[],2:[],3:[],4:[],5:[]};
let activeStar = 5;
function esc(s) {
return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}
function addPoolItem(star, value = '') {
const container = document.getElementById(`pool-items-${star}`);
function updateTabCount(star) {
const el = document.getElementById(`tab-count-${star}`);
if (el) el.textContent = poolData[star].length;
}
function onStarToggle(star) {
const cb = document.getElementById(`star-cb-${star}`);
const tab = document.querySelector(`.star-tab[data-star="${star}"]`);
if (tab) tab.classList.toggle('star-tab--on', cb.checked);
}
function setActiveStar(star) {
activeStar = star;
document.querySelectorAll('.star-tab').forEach(t =>
t.classList.toggle('star-tab--active', +t.dataset.star === star));
renderPanel();
}
function renderPanel() {
const COLORS = {1:'#EF4444',2:'#F97316',3:'#EAB308',4:'#3B82F6',5:'#22C55E'};
const LABELS = {1:'1★ — Плохо',2:'2★ — Не понравилось',3:'3★ — Нормально',4:'4★ — Хорошо',5:'5★ — Отлично'};
const header = document.getElementById('star-panel-header');
if (header) {
header.innerHTML = `<span style="color:${COLORS[activeStar]};font-weight:700;font-size:15px">${LABELS[activeStar]}</span>
<span style="color:var(--c-text-muted);font-size:13px">${poolData[activeStar].length ? poolData[activeStar].length + ' шаблон(а/ов)' : 'нет шаблонов'}</span>`;
}
const container = document.getElementById('pool-panel-items');
container.innerHTML = '';
poolData[activeStar].forEach((text, idx) => {
const row = document.createElement('div');
row.className = 'pool-item';
row.innerHTML = `<input type="text" class="pool-item-input" value="${value.replace(/"/g,'&quot;')}" placeholder="Текст ответа…"><button type="button" class="btn-delete-item" title="Удалить">✕</button>`;
row.querySelector('.pool-item-input').addEventListener('input', () => syncHidden(star));
row.querySelector('.btn-delete-item').addEventListener('click', () => { row.remove(); syncHidden(star); });
row.className = 'pool-template-row';
row.innerHTML = `<span class="pool-template-num">${idx+1}</span>
<textarea class="pool-template-input" rows="3" placeholder="Текст ответа для ${activeStar}★…">${esc(text)}</textarea>
<button type="button" class="pool-template-del" title="Удалить">✕</button>`;
const ta = row.querySelector('textarea');
ta.addEventListener('input', () => { poolData[activeStar][idx] = ta.value; updateTabCount(activeStar); renderPanelHeader(); });
row.querySelector('.pool-template-del').addEventListener('click', () => {
poolData[activeStar].splice(idx, 1);
updateTabCount(activeStar);
renderPanel();
});
container.appendChild(row);
syncHidden(star);
}
function updateColumns() {
[1,2,3,4,5].forEach(star => {
const cb = document.querySelector(`input[name="stars"][value="${star}"]`);
const col = document.getElementById(`pool-col-${star}`);
if (col) col.style.display = cb && cb.checked ? '' : 'none';
});
}
function initPool(star) {
const hidden = document.getElementById(`pool-${star}-hidden`);
if (!hidden) return;
hidden.value.split('\n').map(l => l.trim()).filter(Boolean).forEach(line => addPoolItem(star, line));
function renderPanelHeader() {
const LABELS = {1:'1★ — Плохо',2:'2★ — Не понравилось',3:'3★ — Нормально',4:'4★ — Хорошо',5:'5★ — Отлично'};
const COLORS = {1:'#EF4444',2:'#F97316',3:'#EAB308',4:'#3B82F6',5:'#22C55E'};
const header = document.getElementById('star-panel-header');
if (header) {
header.innerHTML = `<span style="color:${COLORS[activeStar]};font-weight:700;font-size:15px">${LABELS[activeStar]}</span>
<span style="color:var(--c-text-muted);font-size:13px">${poolData[activeStar].length ? poolData[activeStar].length + ' шаблон(а/ов)' : 'нет шаблонов'}</span>`;
}
}
document.getElementById('settings-form').addEventListener('submit', () => {
[1,2,3,4,5].forEach(syncHidden);
});
function addTemplate() {
poolData[activeStar].push('');
updateTabCount(activeStar);
renderPanel();
const inputs = document.querySelectorAll('.pool-template-input');
if (inputs.length) { inputs[inputs.length-1].focus(); }
}
[1,2,3,4,5].forEach(initPool);
function serializeForSubmit() {
[1,2,3,4,5].forEach(star => {
const hidden = document.getElementById(`pool-${star}-hidden`);
if (hidden) hidden.value = poolData[star].filter(s => s.trim()).join('\n');
});
}
function initPools() {
[1,2,3,4,5].forEach(star => {
const hidden = document.getElementById(`pool-${star}-hidden`);
if (hidden) poolData[star] = hidden.value.split('\n').map(l => l.trim()).filter(Boolean);
updateTabCount(star);
});
const firstOn = [5,4,3,2,1].find(s => document.getElementById(`star-cb-${s}`)?.checked) || 5;
setActiveStar(firstOn);
}
document.getElementById('settings-form').addEventListener('submit', serializeForSubmit);
document.getElementById('btn-add-template')?.addEventListener('click', addTemplate);
initPools();
// ── API polling ────────────────────────────────────────────────────
(() => {
+2 -2
View File
@@ -12,7 +12,7 @@
<!-- Левая панель — маркетинг -->
<div class="login-promo">
<div class="login-promo__inner">
<img src="{{ url_for('static', filename='wb2.png') }}" class="login-promo__logo" alt="WB Feedback">
<img src="{{ url_for('static', filename='wb3.png') }}" class="login-promo__logo" alt="WB Feedback">
<h1 class="login-promo__title">Автоответы на отзывы<br>Wildberries — на автопилоте</h1>
<p class="login-promo__sub">Сервис сам отвечает на отзывы покупателей пока вы занимаетесь бизнесом. Никаких ручных ответов, никаких пропущенных оценок.</p>
@@ -59,7 +59,7 @@
<div class="login-form-wrap">
<section class="auth-card">
<div class="auth-kicker">
<img src="{{ url_for('static', filename='wb2.png') }}" class="auth-kicker-logo-img" alt="WB">
<img src="{{ url_for('static', filename='wb3.png') }}" class="auth-kicker-logo-img" alt="WB">
<span class="auth-kicker-text">WB Feedback</span>
</div>
<h2 class="login-form-title">Войдите в кабинет</h2>
+1 -1
View File
@@ -10,7 +10,7 @@
<div class="auth-shell">
<section class="auth-card">
<div class="auth-kicker">
<img src="{{ url_for('static', filename='wb2.png') }}" class="auth-kicker-logo-img" alt="WB">
<img src="{{ url_for('static', filename='wb3.png') }}" class="auth-kicker-logo-img" alt="WB">
<span class="auth-kicker-text">Wildberries Feedback</span>
</div>
<h1>Запрос доступа</h1>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB