ty-produktovyy-dizayner-i-se/index.html

264 lines
17 KiB
HTML
Raw Permalink 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>
<!-- no-design-system -->
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>HR Candidate Matcher</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="app">
<header class="app-header" role="banner">
<div class="container app-header-inner">
<div class="app-logo">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
<circle cx="9" cy="7" r="4"/>
<path d="M22 21v-2a4 4 0 0 0-3-3.87"/>
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
</svg>
<span class="app-logo-text">HR Candidate Matcher</span>
</div>
<nav class="app-nav" id="app-nav" role="navigation" aria-label="Основная навигация" hidden>
<ol class="steps" id="steps-indicator">
<li class="step" data-step="input"><span class="step-num">1</span> Ввод</li>
<li class="step" data-step="criteria"><span class="step-num">2</span> Критерии</li>
<li class="step" data-step="match"><span class="step-num">3</span> Сопоставление</li>
<li class="step" data-step="interview"><span class="step-num">4</span> Интервью</li>
</ol>
</nav>
<button class="btn btn-ghost btn-sm" id="btn-clear-all" type="button" aria-label="Очистить все данные" hidden>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
Очистить всё
</button>
</div>
</header>
<main id="main-content" class="main-content" role="main">
<section id="screen-welcome" class="screen" aria-label="Добро пожаловать">
<div class="container">
<div class="welcome-hero">
<h1 class="welcome-title">HR Candidate Matcher</h1>
<p class="welcome-desc">Сопоставьте резюме с требованиями вакансии по прозрачным критериям. Подготовьте вопросы для интервью. Все данные остаются в вашем браузере.</p>
<div class="welcome-actions">
<button class="btn btn-primary btn-lg" id="btn-start-empty" type="button">Начать с нуля</button>
<button class="btn btn-outline btn-lg" id="btn-start-demo" type="button">Попробовать пример</button>
</div>
<p class="welcome-privacy">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
Персональные данные не сохраняются без явного согласия и не покидают браузер.
</p>
</div>
</div>
</section>
<section id="screen-input" class="screen" hidden aria-label="Ввод данных">
<div class="container">
<div class="screen-header">
<button class="btn btn-ghost btn-sm btn-back" id="btn-back-from-input" type="button" aria-label="Назад">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>
Назад
</button>
<h2 class="screen-title">Ввод данных</h2>
</div>
<p class="screen-subtitle">Вставьте текст вакансии и обезличенное резюме. Данные обрабатываются локально.</p>
<form id="form-input" novalidate>
<div class="input-grid">
<div class="input-col">
<div class="field" id="field-vacancy">
<label for="input-vacancy" class="field-label">Текст вакансии <span class="field-required" aria-label="обязательное поле">*</span></label>
<textarea id="input-vacancy" class="textarea" rows="16" placeholder="Вставьте описание вакансии…" aria-describedby="vacancy-error" aria-required="true"></textarea>
<div class="field-error" id="vacancy-error" role="alert" aria-live="polite" hidden></div>
</div>
</div>
<div class="input-col">
<div class="field" id="field-resume">
<label for="input-resume" class="field-label">Текст резюме <span class="field-required" aria-label="обязательное поле">*</span></label>
<textarea id="input-resume" class="textarea" rows="16" placeholder="Вставьте обезличенное резюме…" aria-describedby="resume-error" aria-required="true"></textarea>
<div class="field-error" id="resume-error" role="alert" aria-live="polite" hidden></div>
</div>
</div>
</div>
<div class="input-actions">
<button class="btn btn-primary btn-lg" id="btn-extract" type="submit">Извлечь требования</button>
</div>
</form>
</div>
</section>
<section id="screen-criteria" class="screen" hidden aria-label="Критерии">
<div class="container">
<div class="screen-header">
<button class="btn btn-ghost btn-sm btn-back" id="btn-back-from-criteria" type="button" aria-label="Назад к вводу">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>
Назад
</button>
<h2 class="screen-title">Критерии</h2>
</div>
<p class="screen-subtitle">Проверьте и отредактируйте извлечённые требования. Укажите важность каждого.</p>
<div class="criteria-table-wrap" role="region" aria-label="Список критериев" tabindex="0">
<table class="criteria-table" id="criteria-table">
<thead>
<tr>
<th scope="col" class="col-label">Требование</th>
<th scope="col" class="col-type">Тип</th>
<th scope="col" class="col-weight">Вес</th>
<th scope="col" class="col-synonyms">Синонимы</th>
<th scope="col" class="col-actions"><span class="sr-only">Действия</span></th>
</tr>
</thead>
<tbody id="criteria-tbody"></tbody>
</table>
</div>
<div class="criteria-empty" id="criteria-empty" hidden>
<p>Критерии не добавлены. Добавьте требования вручную или вернитесь к вводу данных.</p>
</div>
<div class="criteria-actions">
<button class="btn btn-outline" id="btn-add-criterion" type="button">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
Добавить требование
</button>
<button class="btn btn-primary btn-lg" id="btn-to-match" type="button">Перейти к сопоставлению</button>
</div>
</div>
</section>
<section id="screen-match" class="screen" hidden aria-label="Сопоставление">
<div class="container">
<div class="screen-header">
<button class="btn btn-ghost btn-sm btn-back" id="btn-back-from-match" type="button" aria-label="Назад к критериям">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>
Назад
</button>
<h2 class="screen-title">Сопоставление</h2>
</div>
<p class="screen-subtitle">Результаты сопоставления требований с фрагментами резюме.</p>
<div class="match-filter-bar" id="match-filter-bar">
<button class="chip chip-active" data-filter="all" type="button">Все</button>
<button class="chip" data-filter="confirmed" type="button">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg>
Подтверждено
</button>
<button class="chip" data-filter="not_found" type="button">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>
Не найдено
</button>
<button class="chip" data-filter="unclear" type="button">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
Уточнить
</button>
</div>
<div class="match-table-wrap" role="region" aria-label="Таблица сопоставления" tabindex="0">
<table class="match-table" id="match-table">
<thead>
<tr>
<th scope="col" class="col-criterion">Требование</th>
<th scope="col" class="col-evidence">Найденные фрагменты</th>
<th scope="col" class="col-status">Статус</th>
<th scope="col" class="col-note">Примечание</th>
</tr>
</thead>
<tbody id="match-tbody"></tbody>
</table>
</div>
<div class="match-empty" id="match-empty" hidden>
<p>Нет результатов по выбранному фильтру.</p>
<button class="btn btn-outline btn-sm" id="btn-reset-filter" type="button">Сбросить фильтр</button>
</div>
<div class="match-coverage" id="match-coverage">
<div class="coverage-label">Покрытие указанных требований</div>
<div class="coverage-bar-track">
<div class="coverage-bar-fill" id="coverage-bar-fill" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" aria-label="Покрытие требований"></div>
</div>
<div class="coverage-value" id="coverage-value">0%</div>
</div>
<div class="match-actions">
<button class="btn btn-outline" id="btn-view-source" type="button">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
Исходные тексты
</button>
<button class="btn btn-primary btn-lg" id="btn-to-interview" type="button">Вопросы для интервью</button>
</div>
</div>
</section>
<div class="modal-overlay" id="modal-source" hidden role="dialog" aria-modal="true" aria-label="Исходные тексты">
<div class="modal-panel">
<div class="modal-header">
<h3>Исходные тексты</h3>
<button class="btn btn-ghost btn-sm" id="btn-close-source" type="button" aria-label="Закрыть">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
</button>
</div>
<div class="modal-body">
<div class="source-grid">
<div class="source-col">
<h4>Вакансия</h4>
<pre class="source-text" id="source-vacancy"></pre>
</div>
<div class="source-col">
<h4>Резюме</h4>
<pre class="source-text" id="source-resume"></pre>
</div>
</div>
</div>
</div>
</div>
<section id="screen-interview" class="screen" hidden aria-label="Интервью">
<div class="container">
<div class="screen-header">
<button class="btn btn-ghost btn-sm btn-back" id="btn-back-from-interview" type="button" aria-label="Назад к сопоставлению">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>
Назад
</button>
<h2 class="screen-title">Вопросы для интервью</h2>
</div>
<p class="screen-subtitle">Вопросы по неподтверждённым и требующим уточнения пунктам.</p>
<div class="demo-badge" role="status">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
Демо-режим: вопросы сгенерированы по шаблонам
</div>
<div id="interview-questions"></div>
<div class="interview-empty" id="interview-empty" hidden>
<p>Все требования подтверждены — вопросы для интервью не требуются.</p>
</div>
<div class="interview-actions">
<button class="btn btn-outline" id="btn-copy-questions" type="button">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
Копировать все вопросы
</button>
<button class="btn btn-outline" id="btn-export-summary" type="button">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Экспорт сводки
</button>
<button class="btn btn-outline" id="btn-start-over" type="button">Начать заново</button>
</div>
</div>
</section>
</main>
<div class="toast-container" id="toast-container" aria-live="polite" aria-atomic="true"></div>
<div class="modal-overlay" id="modal-confirm" hidden role="alertdialog" aria-modal="true" aria-labelledby="confirm-title" aria-describedby="confirm-desc">
<div class="modal-panel modal-sm">
<h3 id="confirm-title">Подтверждение</h3>
<p id="confirm-desc"></p>
<div class="modal-actions">
<button class="btn btn-ghost" id="btn-confirm-cancel" type="button">Отмена</button>
<button class="btn btn-danger" id="btn-confirm-ok" type="button">Подтвердить</button>
</div>
</div>
</div>
</div>
<script src="js/data.js"></script>
<script src="js/storage.js"></script>
<script src="js/aiAdapter.js"></script>
<script src="js/logic.js"></script>
<script src="js/ui.js"></script>
<script src="js/app.js"></script>
</body>
</html>