You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
240 lines
13 KiB
240 lines
13 KiB
{% extends "base.html" %} |
|
{% block title %}{{ content.test.title }} — редактор{% endblock %} |
|
|
|
{% block content %} |
|
<div id="editor-root" |
|
class="space-y-4 sm:space-y-5 pb-24" |
|
data-test-id="{{ test_id }}" |
|
data-initial='{{ content | tojson | safe }}'> |
|
|
|
{# ── 1. Шапка теста ─────────────────────────────────────────── #} |
|
<section class="rounded-2xl bg-white shadow-sm border border-ink-300/60 p-4 sm:p-5"> |
|
<h2 class="text-xs font-medium text-ink-500 uppercase tracking-wide">Тест</h2> |
|
|
|
<label class="mt-2 block"> |
|
<span class="sr-only">Название</span> |
|
<input id="test-title" type="text" maxlength="200" placeholder="Название теста" |
|
class="w-full rounded-lg border border-ink-300 px-3 py-3 text-lg font-semibold |
|
focus:border-brand-500 focus:ring-2 focus:ring-brand-500/20" /> |
|
</label> |
|
|
|
<label class="mt-3 block"> |
|
<span class="text-xs font-medium text-ink-500">Описание</span> |
|
<textarea id="test-description" rows="2" placeholder="Краткое описание (необязательно)" |
|
class="mt-1 w-full rounded-lg border border-ink-300 px-3 py-2 |
|
focus:border-brand-500 focus:ring-2 focus:ring-brand-500/20"></textarea> |
|
</label> |
|
|
|
<label class="mt-3 flex items-center justify-between gap-3"> |
|
<span class="text-xs font-medium text-ink-500">Проходной балл, %</span> |
|
<input id="test-threshold" type="number" min="0" max="100" step="1" |
|
inputmode="numeric" |
|
class="w-24 text-right rounded-lg border border-ink-300 px-3 py-2 |
|
focus:border-brand-500 focus:ring-2 focus:ring-brand-500/20" /> |
|
</label> |
|
</section> |
|
|
|
{# ── 2. AI-помощник ─────────────────────────────────────────── #} |
|
<section class="rounded-2xl bg-brand-50/60 border border-brand-100 p-4 sm:p-5"> |
|
<div class="flex items-center gap-2"> |
|
<span class="material-symbols-outlined text-brand-600">auto_awesome</span> |
|
<h2 class="font-semibold text-brand-700">AI-помощник</h2> |
|
</div> |
|
|
|
{# Группа A — генерация. Главные действия. На sm+ — в одну строку. #} |
|
<div class="mt-3"> |
|
<p class="text-xs font-medium text-ink-500 uppercase tracking-wide">Создать вопросы</p> |
|
<div class="mt-2 grid grid-cols-1 sm:grid-cols-2 gap-2"> |
|
<button id="ai-generate-by-title" |
|
class="inline-flex items-center justify-center gap-2 px-3 py-3 rounded-lg |
|
bg-brand-600 hover:bg-brand-700 text-white text-sm font-medium min-h-11"> |
|
<span class="material-symbols-outlined text-base">edit_note</span> |
|
По названию |
|
</button> |
|
<button id="ai-generate-test" |
|
class="inline-flex items-center justify-center gap-2 px-3 py-3 rounded-lg |
|
bg-white border border-brand-300/60 text-brand-700 hover:bg-brand-50 |
|
text-sm font-medium min-h-11"> |
|
<span class="material-symbols-outlined text-base">stars</span> |
|
По текущей сетке |
|
</button> |
|
</div> |
|
</div> |
|
|
|
{# Группа B — анализ существующего. #} |
|
<div class="mt-4"> |
|
<p class="text-xs font-medium text-ink-500 uppercase tracking-wide">Улучшить существующее</p> |
|
<div class="mt-2 grid grid-cols-2 gap-2"> |
|
<button id="ai-check" |
|
class="inline-flex items-center justify-center gap-2 px-3 py-3 rounded-lg |
|
bg-white border border-ink-300/60 hover:border-brand-300 |
|
text-sm min-h-11"> |
|
<span class="material-symbols-outlined text-base">fact_check</span> |
|
Проверить |
|
</button> |
|
<button id="ai-improve" |
|
class="inline-flex items-center justify-center gap-2 px-3 py-3 rounded-lg |
|
bg-white border border-ink-300/60 hover:border-brand-300 |
|
text-sm min-h-11"> |
|
<span class="material-symbols-outlined text-base">tune</span> |
|
Улучшить |
|
</button> |
|
</div> |
|
</div> |
|
|
|
{# Группа C — импорт. #} |
|
<div class="mt-4"> |
|
<p class="text-xs font-medium text-ink-500 uppercase tracking-wide">Импортировать</p> |
|
<label class="mt-2 inline-flex w-full items-center justify-center gap-2 px-3 py-3 |
|
rounded-lg bg-white border border-ink-300/60 hover:border-brand-300 |
|
text-sm cursor-pointer min-h-11"> |
|
<span class="material-symbols-outlined text-base text-brand-600">upload_file</span> |
|
<span>Загрузить документ (PDF, DOCX, TXT, MD)</span> |
|
<input id="ai-import-file" type="file" accept=".pdf,.docx,.txt,.md" class="hidden" /> |
|
</label> |
|
<p class="mt-1.5 text-xs text-ink-500"> |
|
До 16 МБ. AI извлечёт текст и предложит черновик теста. |
|
</p> |
|
</div> |
|
|
|
<p id="ai-status" class="mt-3 text-sm text-ink-500 min-h-[1.25rem]"></p> |
|
</section> |
|
|
|
{# ── 3. Вопросы ─────────────────────────────────────────────── #} |
|
<section> |
|
<div class="flex items-center justify-between gap-2 px-1"> |
|
<h2 class="font-semibold">Вопросы (<span id="q-count">0</span>)</h2> |
|
<button id="add-question" |
|
class="inline-flex items-center gap-1 px-3 py-2 rounded-lg |
|
bg-white border border-ink-300/60 hover:border-brand-300 text-sm min-h-10"> |
|
<span class="material-symbols-outlined text-base">add</span> |
|
<span class="hidden sm:inline">Добавить вопрос</span> |
|
<span class="sm:hidden">Добавить</span> |
|
</button> |
|
</div> |
|
<ol id="questions" class="mt-3 space-y-3"></ol> |
|
</section> |
|
</div> |
|
|
|
{# ── Sticky-footer: «Цепочка активна» + «Сохранить» ────────────── #} |
|
<div class="fixed bottom-0 inset-x-0 z-30 bg-white/95 backdrop-blur border-t border-ink-300/60 |
|
pb-[env(safe-area-inset-bottom)]"> |
|
<div class="mx-auto max-w-6xl px-4 py-3 |
|
flex items-center justify-between gap-3"> |
|
<label class="inline-flex items-center gap-2 text-sm min-w-0"> |
|
<input id="chain-active" type="checkbox" |
|
class="rounded border-ink-300 text-brand-600 focus:ring-brand-500" /> |
|
<span class="truncate">Цепочка активна</span> |
|
</label> |
|
<div class="flex items-center gap-2 shrink-0"> |
|
<a href="{{ url_for('tests.tests_list_page') }}" |
|
class="hidden sm:inline-flex px-3 py-2 rounded-lg text-ink-700 hover:bg-ink-100 text-sm"> |
|
К каталогу |
|
</a> |
|
<button id="save-draft" |
|
class="inline-flex items-center gap-2 px-4 py-2.5 rounded-lg |
|
bg-brand-600 hover:bg-brand-700 text-white font-medium min-h-11"> |
|
<span class="material-symbols-outlined text-base">save</span> |
|
Сохранить |
|
</button> |
|
</div> |
|
</div> |
|
<p id="save-status" class="mx-auto max-w-6xl px-4 pb-2 text-xs text-ink-500"></p> |
|
</div> |
|
|
|
{# ── Шаблон вопроса ─────────────────────────────────────────────── #} |
|
<template id="tpl-question"> |
|
<li class="rounded-xl bg-white border border-ink-300/60 p-3 sm:p-4 q-item"> |
|
{# Шапка карточки вопроса: номер слева, кнопки справа. #} |
|
<div class="flex items-center justify-between gap-2"> |
|
<span class="inline-flex items-center px-2 py-0.5 rounded-md |
|
bg-brand-50 text-brand-700 text-xs font-medium q-num">Вопрос #</span> |
|
<div class="flex items-center gap-0.5"> |
|
<button class="q-up p-2 rounded hover:bg-ink-100 min-w-10 min-h-10" |
|
title="Выше" aria-label="Поднять выше"> |
|
<span class="material-symbols-outlined text-base">arrow_upward</span> |
|
</button> |
|
<button class="q-down p-2 rounded hover:bg-ink-100 min-w-10 min-h-10" |
|
title="Ниже" aria-label="Опустить ниже"> |
|
<span class="material-symbols-outlined text-base">arrow_downward</span> |
|
</button> |
|
<button class="q-delete p-2 rounded hover:bg-red-50 text-red-600 min-w-10 min-h-10" |
|
title="Удалить" aria-label="Удалить вопрос"> |
|
<span class="material-symbols-outlined text-base">delete</span> |
|
</button> |
|
</div> |
|
</div> |
|
|
|
<textarea class="q-text mt-3 w-full rounded-lg border border-ink-300 px-3 py-2 |
|
focus:border-brand-500 focus:ring-2 focus:ring-brand-500/20" |
|
rows="2" placeholder="Формулировка вопроса"></textarea> |
|
|
|
{# Тип ответа + AI — две полные строки на мобиле, в строку на sm+. #} |
|
<div class="mt-3 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 text-sm"> |
|
<label class="inline-flex items-center gap-2 min-h-9"> |
|
<input type="checkbox" |
|
class="q-multi rounded border-ink-300 text-brand-600 focus:ring-brand-500" /> |
|
<span>Несколько правильных ответов</span> |
|
</label> |
|
<button class="q-ai inline-flex items-center justify-center gap-1 px-2.5 py-2 rounded-lg |
|
bg-brand-50 hover:bg-brand-100 text-brand-700 text-sm min-h-10"> |
|
<span class="material-symbols-outlined text-base">auto_awesome</span> |
|
AI: вопрос/переформулировать |
|
</button> |
|
</div> |
|
|
|
<ul class="q-options mt-3 space-y-2"></ul> |
|
<button class="q-add-option mt-2 inline-flex items-center gap-1 px-2 py-2 rounded |
|
text-sm text-brand-700 hover:bg-brand-50 min-h-10"> |
|
<span class="material-symbols-outlined text-base">add</span> |
|
Добавить вариант |
|
</button> |
|
</li> |
|
</template> |
|
|
|
{# ── Шаблон варианта ────────────────────────────────────────────── #} |
|
<template id="tpl-option"> |
|
<li class="flex items-center gap-2 opt-item"> |
|
{# Чекбокс «Правильный» — обёрнут в большой tap-target. #} |
|
<label class="inline-flex items-center justify-center w-10 h-10 shrink-0 cursor-pointer |
|
rounded hover:bg-ink-100" title="Правильный ответ"> |
|
<input type="checkbox" |
|
class="opt-correct w-5 h-5 rounded border-ink-300 text-brand-600 focus:ring-brand-500" /> |
|
</label> |
|
<input type="text" |
|
class="opt-text flex-1 min-w-0 rounded-lg border border-ink-300 px-3 py-2 |
|
focus:border-brand-500 focus:ring-2 focus:ring-brand-500/20" |
|
placeholder="Вариант ответа" /> |
|
<button class="opt-delete shrink-0 w-10 h-10 inline-flex items-center justify-center |
|
rounded hover:bg-red-50 text-red-600" |
|
title="Удалить" aria-label="Удалить вариант"> |
|
<span class="material-symbols-outlined text-base">close</span> |
|
</button> |
|
</li> |
|
</template> |
|
|
|
{# ── Модалка результата AI-проверки/улучшения (fullscreen на мобиле) ── #} |
|
<dialog id="ai-modal" |
|
class="m-0 p-0 w-full h-full sm:h-auto sm:max-w-3xl sm:w-full sm:max-h-[90vh] |
|
sm:rounded-2xl sm:m-auto bg-white backdrop:bg-black/50"> |
|
<div class="flex flex-col h-full sm:max-h-[90vh]"> |
|
<div class="flex items-center justify-between gap-3 px-4 sm:px-5 py-3 border-b border-ink-300/60"> |
|
<h3 id="ai-modal-title" class="text-lg font-semibold truncate">AI</h3> |
|
<button id="ai-modal-close" |
|
class="p-2 rounded hover:bg-ink-100 min-w-10 min-h-10" |
|
aria-label="Закрыть"> |
|
<span class="material-symbols-outlined">close</span> |
|
</button> |
|
</div> |
|
<div id="ai-modal-body" class="flex-1 overflow-y-auto px-4 sm:px-5 py-4"></div> |
|
<div id="ai-modal-actions" |
|
class="px-4 sm:px-5 py-3 border-t border-ink-300/60 |
|
flex items-center justify-end gap-2 flex-wrap |
|
pb-[max(env(safe-area-inset-bottom),0.75rem)]"></div> |
|
</div> |
|
</dialog> |
|
{% endblock %} |
|
|
|
{% block scripts %} |
|
<script src="{{ url_for('static', filename='js/editor.js') }}"></script> |
|
{% endblock %}
|
|
|