design: Nubes style for DrHider, fix favicon + logo
Deploy contracts-flask / validate (push) Successful in 0s
Deploy contracts-flask / validate (push) Successful in 0s
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||||
|
<rect width="32" height="32" rx="4" fill="#001C34"/>
|
||||||
|
<text x="16" y="24" text-anchor="middle" font-size="22" font-weight="bold" fill="white" font-family="sans-serif">N</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 246 B |
Executable
+25
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Creator: CorelDRAW -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="82.3711mm" height="18.2443mm" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
|
||||||
|
viewBox="0 0 8221.93 1821.07"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:xodm="http://www.corel.com/coreldraw/odm/2003">
|
||||||
|
<defs>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
.fil0 {fill:#001C34}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g id="Слой_x0020_1">
|
||||||
|
<metadata id="CorelCorpID_0Corel-Layer"/>
|
||||||
|
<g id="_2283355517888">
|
||||||
|
<path class="fil0" d="M477.49 479.69l-413.51 0 -63.98 276.48 178.44 0 1.17 1028.71 0 26.75 0.03 0 276.39 0 0 -871.72c0,-101.28 82.43,-183.69 183.75,-183.69l589.25 3.44c101.34,0 183.76,82.46 183.76,183.74l0 871.72 276.44 0 0 -871.72c0,-253.77 -206.46,-460.15 -460.05,-460.15l-589.52 -3.53 -162.17 0.45 0 -0.48z"/>
|
||||||
|
<path class="fil0" d="M6664.65 1813.37l1181.04 0c212.14,0 376.24,-175.01 376.24,-387.08 0,-212.13 -172.55,-384.68 -384.69,-384.68l-653.66 0c-60.22,0 -109.16,-48.94 -109.16,-109.18l0 -66.18c0,-60.19 48.94,-109.14 109.16,-109.14l695.76 0 63.74 -275.49 -759.5 0c-212.13,0 -384.66,172.53 -384.66,384.63l0 66.18c0,212.13 172.53,384.67 384.66,384.67l653.66 0c60.2,0 109.2,49 109.2,109.19 0,60.13 -49,116.1 -109.2,116.1l-1118.9 0 -53.68 270.98z"/>
|
||||||
|
<path class="fil0" d="M6200.79 483.5l-723.21 0c-215.88,0 -391.47,175.6 -391.47,391.51l0 485.5c0,248.38 202.05,450.4 450.4,450.4l989.38 0 62.13 -268.51 -1051.51 0c-96.41,0 -174.95,-85.37 -174.95,-181.88l-1.5 -39.46 923.62 0 308.51 -1.84 0 -237.95 0 -206.26c0,-215.91 -175.59,-391.51 -391.41,-391.51zm115.96 560.28l-955.19 0 0 -168.77c0,-63.96 52.07,-116.05 116.02,-116.05l723.21 0c63.91,0 115.96,52.08 115.96,116.05l0 168.77z"/>
|
||||||
|
<path class="fil0" d="M4683.49 1194.24l0 168.28c0,100.92 -81.7,178.37 -182.67,178.37l-589.87 1.23c-93.18,0 -170.28,-69.96 -181.63,-160.09l0 -458.13c11.36,-90.1 88.46,-160.07 181.63,-160.07l589.44 3.5c100.97,0 183.1,82.18 183.1,183.1l0 30.42 0 213.4zm-1230.2 -345.53l-0.89 -795.03 276.91 -53.68 0 526.07c55.74,-24.16 117.03,-37.74 181.5,-37.74l589.71 3.5c252.69,0 458.42,205.72 458.42,458.59l0 30.42 0 213.4 0 168.28c0,252.86 -205.73,458.54 -458.42,458.54l-589.71 -3.5c-252.7,0 -458.41,-205.67 -458.41,-458.56l0 -171.61 0 -240.48 0.89 -98.2z"/>
|
||||||
|
<path class="fil0" d="M3041.25 1150.84l0 204.28c0,100.93 -82.15,183.05 -183.11,183.05l-582.11 -3.46c-100.96,0 -183.11,-82.16 -183.11,-183.08l0 -67.42 1.48 0.24 0 -862.65 -276.91 53.68 0.12 103.41 -0.12 0.04 0 772.69c0,252.87 205.72,458.54 458.39,458.54l582.4 3.5c252.67,0 458.4,-205.68 458.4,-458.55l0 -70.79 0.71 0.12 0 -862.65 -276.91 53.68 0.76 675.35z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.8 KiB |
+76
-80
@@ -4,79 +4,96 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>DrHider — обфускация документов</title>
|
<title>DrHider — обфускация документов</title>
|
||||||
|
<link rel="icon" href="/static/favicon.svg" type="image/svg+xml">
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--bg: #0d1117; --fg: #c9d1d9; --muted: #8b949e;
|
--brand: #2563eb; --brand-dark: #1d4ed8;
|
||||||
--accent: #58a6ff; --green: #3fb950; --red: #f85149; --border: #30363d;
|
--bg: #f8fafc; --card: #fff; --fg: #1e293b; --muted: #64748b;
|
||||||
--card-bg: #161b22; --orange: #d2991d;
|
--border: #e2e8f0; --red: #ef4444; --green: #22c55e;
|
||||||
|
--grey-light: #f3f4f6; --radius: 8px;
|
||||||
}
|
}
|
||||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
body { font: 15px/1.5 -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: var(--bg); color: var(--fg); max-width: 700px; margin: 0 auto; padding: 32px 20px 60px; }
|
body { font: 14px/1.6 -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: var(--bg); color: var(--fg); }
|
||||||
h1 { font-size: 22px; margin-bottom: 4px; }
|
.header { background: var(--card); border-bottom: 1px solid var(--border); padding: 12px 24px; display: flex; align-items: center; gap: 12px; }
|
||||||
|
.header img { height: 24px; }
|
||||||
|
.header .sep { color: var(--muted); }
|
||||||
|
.header a { color: var(--brand); text-decoration: none; font-size: 13px; }
|
||||||
|
.header a:hover { color: var(--brand-dark); }
|
||||||
|
main { max-width: 700px; margin: 0 auto; padding: 40px 20px 60px; }
|
||||||
|
h1 { font-size: 22px; font-weight: 600; margin-bottom: 4px; }
|
||||||
.sub { color: var(--muted); font-size: 14px; margin-bottom: 24px; }
|
.sub { color: var(--muted); font-size: 14px; margin-bottom: 24px; }
|
||||||
.nav { margin-bottom: 20px; }
|
|
||||||
.nav a { color: var(--accent); text-decoration: none; font-size: 13px; }
|
.card { background: var(--card); border: 1px solid var(--border); border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,.04); }
|
||||||
.nav a:hover { text-decoration: underline; }
|
.card-header { background: var(--grey-light); padding: 12px 16px; border-radius: 12px 12px 0 0; font-size: 14px; font-weight: 600; border-bottom: 1px solid var(--border); }
|
||||||
|
.card-body { padding: 16px; }
|
||||||
|
|
||||||
#dropZone {
|
#dropZone {
|
||||||
border: 2px dashed var(--border); border-radius: 12px; padding: 40px 20px;
|
border: 2px dashed var(--border); border-radius: 12px; padding: 36px 20px;
|
||||||
text-align: center; cursor: pointer; transition: all .2s;
|
text-align: center; cursor: pointer; transition: all .2s;
|
||||||
background: var(--card-bg); margin-bottom: 16px;
|
background: var(--grey-light); margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
#dropZone:hover, #dropZone.active { border-color: var(--accent); background: #0d1a28; }
|
#dropZone:hover, #dropZone.active { border-color: var(--brand); background: #eff6ff; }
|
||||||
#dropZone p { color: var(--muted); margin: 4px 0; font-size: 14px; }
|
#dropZone p { color: var(--muted); margin: 4px 0; font-size: 14px; }
|
||||||
#dropZone .big { font-size: 36px; }
|
#dropZone .icon { font-size: 32px; margin-bottom: 8px; }
|
||||||
|
|
||||||
#fileList { display: none; margin: 16px 0; }
|
#fileList { display: none; }
|
||||||
#fileList.show { display: block; }
|
#fileList.show { display: block; }
|
||||||
.file-row { display: flex; align-items: center; gap: 10px; padding: 8px 12px; background: var(--card-bg); border: 1px solid var(--border); border-radius: 6px; margin-bottom: 6px; font-size: 13px; }
|
.file-row { display: flex; align-items: center; gap: 10px; padding: 8px 12px; background: var(--grey-light); border-radius: 6px; margin-bottom: 4px; font-size: 13px; }
|
||||||
.file-row .name { flex: 1; }
|
.file-row .name { flex: 1; }
|
||||||
.file-row .size { color: var(--muted); }
|
.file-row .size { color: var(--muted); }
|
||||||
.file-row .remove { cursor: pointer; color: var(--red); font-weight: bold; }
|
.file-row .remove { cursor: pointer; color: var(--red); font-weight: bold; font-size: 16px; }
|
||||||
|
|
||||||
#status { display: none; margin: 16px 0; padding: 12px; border-radius: 8px; font-size: 13px; }
|
#status { display: none; margin-top: 12px; padding: 12px 16px; border-radius: 8px; font-size: 13px; }
|
||||||
#status.show { display: block; }
|
#status.show { display: block; }
|
||||||
#status.progress { background: #1a2a3a; border: 1px solid var(--accent); color: var(--accent); }
|
#status.progress { background: #eff6ff; border: 1px solid var(--brand); color: var(--brand); }
|
||||||
#status.done { background: #1a2a1a; border: 1px solid var(--green); color: var(--green); }
|
#status.done { background: #f0fdf4; border: 1px solid var(--green); color: #16a34a; }
|
||||||
#status.error { background: #2a1a1a; border: 1px solid var(--red); color: var(--red); }
|
#status.error { background: #fef2f2; border: 1px solid var(--red); color: var(--red); }
|
||||||
|
|
||||||
button {
|
.btn { display: inline-flex; align-items: center; justify-content: center; height: 36px; padding: 0 16px; border-radius: 6px; font-size: 14px; font-weight: 500; cursor: pointer; border: 1px solid var(--border); background: var(--card); transition: all .15s; }
|
||||||
padding: 10px 24px; border: none; border-radius: 8px; cursor: pointer;
|
.btn:hover { background: var(--grey-light); }
|
||||||
font-size: 14px; font-weight: 600; transition: all .2s;
|
.btn-primary { background: var(--brand); color: #fff; border-color: var(--brand); width: 100%; margin-top: 8px; }
|
||||||
}
|
.btn-primary:hover { background: var(--brand-dark); }
|
||||||
.btn-go { background: var(--green); color: #000; width: 100%; margin-top: 12px; }
|
.btn-primary:disabled { opacity: .5; cursor: not-allowed; }
|
||||||
.btn-go:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
||||||
.btn-go:hover:not(:disabled) { background: #4cd964; }
|
|
||||||
|
|
||||||
.note { margin-top: 24px; padding: 12px 16px; background: var(--card-bg); border: 1px solid var(--border); border-radius: 8px; font-size: 12px; color: var(--muted); }
|
|
||||||
.note strong { color: var(--orange); }
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="nav"><a href="/">← Основной сервис</a></div>
|
<header class="header">
|
||||||
|
<img src="/static/logo.svg" alt="Nubes">
|
||||||
|
<span class="sep">|</span>
|
||||||
|
<a href="/">Сверка договоров</a>
|
||||||
|
<span class="sep">|</span>
|
||||||
|
<strong>DrHider</strong>
|
||||||
|
</header>
|
||||||
|
|
||||||
<h1>🛡️ DrHider — обфускация документов</h1>
|
<main>
|
||||||
<p class="sub">Загрузите документы — получите ZIP с обезличенными копиями и таблицей соответствия. Без сохранения на сервере.</p>
|
<h1>🛡️ DrHider — обфускация документов</h1>
|
||||||
|
<p class="sub">Загрузите документы — получите ZIP с обезличенными копиями и таблицей соответствия. Без сохранения на сервере.</p>
|
||||||
|
|
||||||
<div id="dropZone">
|
<div class="card">
|
||||||
<div class="big">📁</div>
|
<div class="card-header">📁 Загрузка файлов</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div id="dropZone">
|
||||||
|
<div class="icon">📄</div>
|
||||||
<p>Выберите файлы или перетащите сюда</p>
|
<p>Выберите файлы или перетащите сюда</p>
|
||||||
<p style="font-size:12px;">.docx .pdf .doc .zip</p>
|
<p style="font-size:12px;">.docx .pdf .doc .zip</p>
|
||||||
<input type="file" id="fileInput" multiple accept=".docx,.pdf,.doc,.zip" style="display:none">
|
<input type="file" id="fileInput" multiple accept=".docx,.pdf,.doc,.zip" style="display:none">
|
||||||
</div>
|
</div>
|
||||||
|
<div id="fileList"></div>
|
||||||
|
<button class="btn btn-primary" id="btnGo" disabled>Обфусцировать</button>
|
||||||
|
<div id="status"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="fileList"></div>
|
<div class="card" style="margin-top:16px;">
|
||||||
|
<div class="card-header">ℹ️ Как это работает</div>
|
||||||
<button class="btn-go" id="btnGo" disabled>Обфусцировать</button>
|
<div class="card-body" style="font-size:13px;color:var(--muted);">
|
||||||
|
<p><strong>⚡ Всё в памяти.</strong> Файлы не сохраняются на сервер. После обработки данные удаляются.</p>
|
||||||
<div id="status"></div>
|
<p><strong>📋 mapping.csv</strong> — таблица «оригинал → замена» внутри ZIP.</p>
|
||||||
|
<p><strong>🔒 Результат</strong> — обезличенные файлы можно загружать в основной сервис сверки.</p>
|
||||||
<div class="note">
|
</div>
|
||||||
<strong>⚡ Всё в памяти.</strong> Файлы не сохраняются на сервер. После обработки данные удаляются.<br>
|
</div>
|
||||||
<strong>📋 mapping.csv</strong> — таблица «оригинал → замена» внутри ZIP.<br>
|
</main>
|
||||||
<strong>🔒 Результат</strong> — обезличенные файлы можно загружать в основной сервис сверки.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const DZ = document.getElementById('dropZone');
|
const DZ = document.getElementById('dropZone');
|
||||||
@@ -88,59 +105,38 @@ let files = [];
|
|||||||
|
|
||||||
DZ.onclick = () => INPUT.click();
|
DZ.onclick = () => INPUT.click();
|
||||||
INPUT.onchange = () => { addFiles(INPUT.files); INPUT.value = ''; };
|
INPUT.onchange = () => { addFiles(INPUT.files); INPUT.value = ''; };
|
||||||
|
|
||||||
DZ.ondragover = e => { e.preventDefault(); DZ.classList.add('active'); };
|
DZ.ondragover = e => { e.preventDefault(); DZ.classList.add('active'); };
|
||||||
DZ.ondragleave = () => DZ.classList.remove('active');
|
DZ.ondragleave = () => DZ.classList.remove('active');
|
||||||
DZ.ondrop = e => { e.preventDefault(); DZ.classList.remove('active'); addFiles(e.dataTransfer.files); };
|
DZ.ondrop = e => { e.preventDefault(); DZ.classList.remove('active'); addFiles(e.dataTransfer.files); };
|
||||||
|
|
||||||
function addFiles(fl) {
|
function addFiles(fl) { for (let f of fl) { if (files.find(x => x.name===f.name && x.size===f.size)) continue; files.push(f); } render(); }
|
||||||
for (let f of fl) {
|
|
||||||
if (files.find(x => x.name === f.name && x.size === f.size)) continue;
|
|
||||||
files.push(f);
|
|
||||||
}
|
|
||||||
render();
|
|
||||||
}
|
|
||||||
|
|
||||||
function remove(i) { files.splice(i, 1); render(); }
|
function remove(i) { files.splice(i, 1); render(); }
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
LIST.innerHTML = files.map((f, i) =>
|
LIST.innerHTML = files.map((f,i) => `<div class="file-row"><span class="name">${esc(f.name)}</span><span class="size">${fmt(f.size)}</span><span class="remove" onclick="remove(${i})">×</span></div>`).join('');
|
||||||
`<div class="file-row"><span class="name">${esc(f.name)}</span><span class="size">${fmt(f.size)}</span><span class="remove" onclick="remove(${i})">✕</span></div>`
|
|
||||||
).join('');
|
|
||||||
LIST.className = files.length ? 'show' : '';
|
LIST.className = files.length ? 'show' : '';
|
||||||
BTN.disabled = files.length === 0;
|
BTN.disabled = !files.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
BTN.onclick = async () => {
|
BTN.onclick = async () => {
|
||||||
if (!files.length) return;
|
if (!files.length) return;
|
||||||
BTN.disabled = true;
|
BTN.disabled = true;
|
||||||
setStatus('progress', '⏳ Обработка...');
|
setStatus('progress', '⏳ Обработка...');
|
||||||
|
const fd = new FormData(); files.forEach(f => fd.append('files', f));
|
||||||
const fd = new FormData();
|
|
||||||
files.forEach(f => fd.append('files', f));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const resp = await fetch('/api/drhider', { method: 'POST', body: fd });
|
const r = await fetch('/api/drhider', { method:'POST', body:fd });
|
||||||
if (!resp.ok) throw new Error(await resp.text());
|
if (!r.ok) throw new Error(await r.text());
|
||||||
|
const blob = await r.blob();
|
||||||
const blob = await resp.blob();
|
const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'drhider_output.zip'; a.click();
|
||||||
const url = URL.createObjectURL(blob);
|
setStatus('done', '✅ Готово! ZIP скачан.');
|
||||||
const a = document.createElement('a');
|
} catch(e) {
|
||||||
a.href = url;
|
setStatus('error', '❌ ' + e.message);
|
||||||
a.download = 'drhider_output.zip';
|
|
||||||
a.click();
|
|
||||||
URL.revokeObjectURL(url);
|
|
||||||
|
|
||||||
setStatus('done', '✅ Готово! ZIP скачан. Файлы обезличены, mapping.csv внутри.');
|
|
||||||
} catch (e) {
|
|
||||||
setStatus('error', '❌ Ошибка: ' + e.message);
|
|
||||||
}
|
}
|
||||||
BTN.disabled = false;
|
BTN.disabled = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
function setStatus(cls, msg) { STATUS.className = 'show ' + cls; STATUS.textContent = msg; }
|
function setStatus(c,m) { STATUS.className = 'show '+c; STATUS.textContent = m; }
|
||||||
function esc(s) { return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); }
|
function esc(s) { return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); }
|
||||||
function fmt(n) { return n > 1e6 ? (n/1e6).toFixed(1)+' MB' : n > 1e3 ? (n/1e3).toFixed(0)+' KB' : n+' B'; }
|
function fmt(n) { return n>1e6 ? (n/1e6).toFixed(1)+' MB' : n>1e3 ? (n/1e3).toFixed(0)+' KB' : n+' B'; }
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Сверка договоров — LLM</title>
|
<title>Сверка договоров — LLM</title>
|
||||||
<link rel="icon" type="image/png" href="/favicon.png">
|
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
|
||||||
<script src="https://unpkg.com/lucide@latest"></script>
|
<script src="https://unpkg.com/lucide@latest"></script>
|
||||||
<style>
|
<style>
|
||||||
:root { --brand-primary: #2563eb; --brand-primary-dark: #1d4ed8; --brand-gray: #d1d5db; --brand-grey-light: #f3f4f6; --background: #ffffff; --foreground: #1a1a1a; --muted: #6b7280; --destructive: #ef4444; --green: #22c55e; }
|
:root { --brand-primary: #2563eb; --brand-primary-dark: #1d4ed8; --brand-gray: #d1d5db; --brand-grey-light: #f3f4f6; --background: #ffffff; --foreground: #1a1a1a; --muted: #6b7280; --destructive: #ef4444; --green: #22c55e; }
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="topbar">
|
<div class="topbar">
|
||||||
<img src="/nubes-logo.svg" alt="Nubes">
|
<img src="/static/logo.svg" alt="Nubes">
|
||||||
<span class="title">Сверка договоров — LLM AI-driven Event Sourcing <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.0.184-flask</span></span>
|
<span class="title">Сверка договоров — LLM AI-driven Event Sourcing <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.0.184-flask</span></span>
|
||||||
<div id="pipelineStepper" style="display:flex;gap:8px;font-size:11px;align-items:center;color:var(--muted);">
|
<div id="pipelineStepper" style="display:flex;gap:8px;font-size:11px;align-items:center;color:var(--muted);">
|
||||||
<span id="stepUpload">○ Загрузка</span><span>→</span>
|
<span id="stepUpload">○ Загрузка</span><span>→</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user