- Backend Go: API REST, auth por token (Bearer + cookie HttpOnly), storage em disco com revisões content-addressed (estilo Git: hash, autor, data, diff, restauração) - Editor txt/md/html com preview, tags #tag, categorias, painel de histórico - Preferências: números de linha, marcador de coluna (padrão 80), quebra de linha, fonte/tamanho, 4 temas e colorização de sintaxe (overlay no textarea) - Frontend vanilla embutido via go:embed; Dockerfile multi-stage + docker-compose
255 lines
12 KiB
HTML
255 lines
12 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="pt-BR">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="color-scheme" content="light">
|
|
<title>Notas — editor estilo Mousepad</title>
|
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><rect width='16' height='16' rx='2' fill='%233584e4'/><path d='M3 4h10M3 7h10M3 10h7' stroke='white' stroke-width='1.5' stroke-linecap='round'/></svg>">
|
|
<link rel="stylesheet" href="/css/app.css">
|
|
</head>
|
|
<body>
|
|
|
|
<!-- Diálogo de login (token) -->
|
|
<div id="login-overlay" class="overlay hidden">
|
|
<form id="login-form" class="dialog" autocomplete="off">
|
|
<h1>Notas</h1>
|
|
<p class="dialog-hint">Digite o token de acesso (variável <code>NOTES_TOKEN</code> do servidor).</p>
|
|
<input id="login-token" type="password" placeholder="token de acesso" autofocus required>
|
|
<p id="login-error" class="dialog-error hidden"></p>
|
|
<div class="dialog-actions">
|
|
<button type="submit" id="login-submit" class="btn btn-primary">Entrar</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Diálogo de Preferências do editor -->
|
|
<div id="prefs-overlay" class="overlay hidden">
|
|
<form id="prefs-form" class="dialog dialog-wide" autocomplete="off">
|
|
<h1>Preferências do editor</h1>
|
|
<fieldset>
|
|
<legend>Exibição</legend>
|
|
<label class="row"><input type="checkbox" id="pf-gutter"> Mostrar números de linha</label>
|
|
<label class="row"><input type="checkbox" id="pf-wrap"> Quebrar linha automaticamente</label>
|
|
<label class="row"><input type="checkbox" id="pf-colmark"> Marcar coluna
|
|
<input type="number" id="pf-col" min="20" max="320" step="1" class="num"> (padrão 80)</label>
|
|
<label class="row"><input type="checkbox" id="pf-hl"> Colorir sintaxe (Markdown e HTML)</label>
|
|
</fieldset>
|
|
<fieldset>
|
|
<legend>Fonte e tema</legend>
|
|
<label class="row">Fonte
|
|
<select id="pf-font">
|
|
<option value="mono">DejaVu Sans Mono (padrão)</option>
|
|
<option value="ubuntu">Ubuntu Mono</option>
|
|
<option value="cascadia">Cascadia Code</option>
|
|
<option value="liberation">Liberation Mono</option>
|
|
<option value="courier">Courier New</option>
|
|
<option value="system">Monoespaçada do sistema</option>
|
|
</select>
|
|
</label>
|
|
<label class="row">Tamanho <input type="number" id="pf-size" min="10" max="32" step="1" class="num"> px</label>
|
|
<label class="row">Esquema de cores
|
|
<select id="pf-theme">
|
|
<option value="claro">Claro (Greybird — padrão)</option>
|
|
<option value="escuro">Escuro (Adwaita)</option>
|
|
<option value="solar-claro">Solarizado claro</option>
|
|
<option value="solar-escuro">Solarizado escuro</option>
|
|
</select>
|
|
</label>
|
|
</fieldset>
|
|
<div class="dialog-actions">
|
|
<button type="button" id="pf-reset" class="btn">Restaurar padrões</button>
|
|
<span class="st-grow"></span>
|
|
<button type="button" id="pf-cancel" class="btn">Cancelar</button>
|
|
<button type="submit" class="btn btn-primary">Aplicar</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Modal genérico (Sobre / confirmar) -->
|
|
<div id="modal-overlay" class="overlay hidden">
|
|
<div class="dialog">
|
|
<h1 id="modal-title"></h1>
|
|
<div id="modal-body"></div>
|
|
<div class="dialog-actions">
|
|
<button type="button" id="modal-ok" class="btn btn-primary">OK</button>
|
|
<button type="button" id="modal-cancel" class="btn hidden">Cancelar</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="app">
|
|
|
|
<!-- Barra de menus (estilo Mousepad) -->
|
|
<header id="menubar" role="menubar">
|
|
<div class="menu-brand">
|
|
<button type="button" class="menu-btn" id="btn-sidebar" title="Mostrar/ocultar barra lateral">☰</button>
|
|
<span class="brand-title">Notas</span>
|
|
</div>
|
|
<div class="menu" data-menu="arquivo">
|
|
<button type="button" class="menu-btn">Arquivo</button>
|
|
<ul class="menu-dropdown">
|
|
<li data-action="new-note">Nova nota<span class="accel">Ctrl+N</span></li>
|
|
<li data-action="save">Salvar<span class="accel">Ctrl+S</span></li>
|
|
<li data-action="export">Baixar arquivo (.txt/.md/.html)…</li>
|
|
<li class="menu-sep"></li>
|
|
<li data-action="delete-note">Excluir esta nota…</li>
|
|
</ul>
|
|
</div>
|
|
<div class="menu" data-menu="editar">
|
|
<button type="button" class="menu-btn">Editar</button>
|
|
<ul class="menu-dropdown">
|
|
<li data-action="undo">Desfazer<span class="accel">Ctrl+Z</span></li>
|
|
<li data-action="redo">Refazer<span class="accel">Ctrl+Y</span></li>
|
|
<li class="menu-sep"></li>
|
|
<li data-action="select-all">Selecionar tudo<span class="accel">Ctrl+A</span></li>
|
|
<li class="menu-sep"></li>
|
|
<li data-action="prefs">Preferências…<span class="accel">Ctrl+,</span></li>
|
|
</ul>
|
|
</div>
|
|
<div class="menu" data-menu="exibir">
|
|
<button type="button" class="menu-btn">Exibir</button>
|
|
<ul class="menu-dropdown">
|
|
<li data-action="toggle-sidebar">Barra lateral<span class="accel">F9</span></li>
|
|
<li data-action="toggle-gutter">Números de linha</li>
|
|
<li data-action="toggle-wrap">Quebrar linha</li>
|
|
<li class="menu-sep"></li>
|
|
<li data-action="toggle-edit">Modo edição<span class="accel">Ctrl+E</span></li>
|
|
<li data-action="toggle-preview">Modo visualização<span class="accel">Ctrl+R</span></li>
|
|
<li class="menu-sep"></li>
|
|
<li data-action="toggle-versions">Painel de versões<span class="accel">Ctrl+H</span></li>
|
|
</ul>
|
|
</div>
|
|
<div class="menu" data-menu="ajuda">
|
|
<button type="button" class="menu-btn">Ajuda</button>
|
|
<ul class="menu-dropdown">
|
|
<li data-action="about">Sobre o Notas</li>
|
|
<li data-action="logout">Sair (esquecer token)</li>
|
|
</ul>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Barra de ferramentas -->
|
|
<div id="toolbar">
|
|
<div class="tb-group">
|
|
<button type="button" class="btn btn-icon" id="btn-new" title="Nova nota (Ctrl+N)">✚<span class="tb-label">Nova</span></button>
|
|
<button type="button" class="btn btn-icon" id="btn-save" title="Salvar (Ctrl+S)">💾<span class="tb-label">Salvar</span></button>
|
|
<button type="button" class="btn btn-icon" id="btn-export" title="Baixar arquivo">⬇<span class="tb-label">Baixar</span></button>
|
|
</div>
|
|
<span class="tb-sep"></span>
|
|
<div class="tb-group" id="fmt-tools">
|
|
<button type="button" class="btn btn-icon fmt" data-fmt="bold" title="Negrito (Ctrl+B)"><b>B</b></button>
|
|
<button type="button" class="btn btn-icon fmt" data-fmt="italic" title="Itálico (Ctrl+I)"><i>I</i></button>
|
|
<button type="button" class="btn btn-icon fmt" data-fmt="strike" title="Tachado"><s>S</s></button>
|
|
<button type="button" class="btn btn-icon fmt" data-fmt="h1" title="Título 1">H1</button>
|
|
<button type="button" class="btn btn-icon fmt" data-fmt="h2" title="Título 2">H2</button>
|
|
<button type="button" class="btn btn-icon fmt" data-fmt="list-ul" title="Lista com marcadores">≡•</button>
|
|
<button type="button" class="btn btn-icon fmt" data-fmt="list-ol" title="Lista numerada">≡1</button>
|
|
<button type="button" class="btn btn-icon fmt" data-fmt="quote" title="Citação">❝</button>
|
|
<button type="button" class="btn btn-icon fmt" data-fmt="link" title="Link (Ctrl+K)">🔗</button>
|
|
<button type="button" class="btn btn-icon fmt" data-fmt="code" title="Código `inline`"></></button>
|
|
<button type="button" class="btn btn-icon fmt" data-fmt="block" title="Bloco de código">{ }</button>
|
|
</div>
|
|
<span class="tb-sep"></span>
|
|
<div class="tb-group">
|
|
<label class="tb-caption" for="format-select">Formato</label>
|
|
<select id="format-select" title="Formato da nota">
|
|
<option value="txt">Texto puro .txt</option>
|
|
<option value="md" selected>Markdown .md</option>
|
|
<option value="html">HTML .html</option>
|
|
</select>
|
|
</div>
|
|
<span class="tb-grow"></span>
|
|
<div class="tb-group">
|
|
<div class="segmented" id="mode-toggle">
|
|
<button type="button" class="seg active" data-mode="edit" title="Editar (Ctrl+E)">Editar</button>
|
|
<button type="button" class="seg" data-mode="preview" title="Visualizar (Ctrl+R)">Preview</button>
|
|
</div>
|
|
<button type="button" class="btn btn-icon" id="btn-versions" title="Painel de versões (Ctrl+H)">🕘<span class="tb-label">Versões</span></button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Corpo: sidebar + editor + painel de versões -->
|
|
<main id="layout">
|
|
|
|
<aside id="sidebar">
|
|
<div class="side-section">
|
|
<input id="search-input" type="search" placeholder="Buscar notas…" autocomplete="off">
|
|
</div>
|
|
<div class="side-section">
|
|
<label class="side-label" for="category-select">Categoria</label>
|
|
<select id="category-select">
|
|
<option value="*">Todas as categorias</option>
|
|
<option value="">Sem categoria</option>
|
|
</select>
|
|
</div>
|
|
<div class="side-section">
|
|
<span class="side-label">Tags</span>
|
|
<div id="tag-cloud"><span class="muted">nenhuma tag ainda</span></div>
|
|
</div>
|
|
<div class="side-section side-notes">
|
|
<div class="side-listhead">
|
|
<span class="side-label">Notas</span>
|
|
<span id="notes-count" class="muted"></span>
|
|
</div>
|
|
<ul id="notes-list"></ul>
|
|
</div>
|
|
</aside>
|
|
|
|
<section id="editor-pane">
|
|
<div id="note-meta">
|
|
<input id="note-title" type="text" placeholder="Título da nota" maxlength="200" autocomplete="off">
|
|
<input id="note-category" type="text" placeholder="categoria (opcional)" maxlength="100" autocomplete="off" class="meta-cat">
|
|
</div>
|
|
<div id="editor-host">
|
|
<div id="editor-wrap">
|
|
<div id="gutter" aria-hidden="true"><div id="gutter-inner"></div></div>
|
|
<div id="code-area">
|
|
<div id="hl" aria-hidden="true"></div>
|
|
<div id="col-marker" class="hidden" aria-hidden="true"></div>
|
|
<textarea id="editor" spellcheck="false" placeholder="Comece a escrever… use #tags para organizar (ex.: #linux #devops)"></textarea>
|
|
</div>
|
|
</div>
|
|
<div id="preview" class="hidden"></div>
|
|
<iframe id="preview-frame" class="hidden" sandbox="allow-scripts" title="Pré-visualização HTML"></iframe>
|
|
</div>
|
|
</section>
|
|
|
|
<aside id="versions-panel" class="hidden">
|
|
<div class="panel-head">
|
|
<span class="side-label">Histórico de revisões</span>
|
|
<button type="button" class="btn btn-icon" id="btn-close-versions" title="Fechar painel">✕</button>
|
|
</div>
|
|
<ul id="revisions-list"></ul>
|
|
<div id="version-detail" class="hidden">
|
|
<div class="diff-head">
|
|
<span id="version-info"></span>
|
|
<button type="button" class="btn btn-primary btn-small" id="btn-restore">Restaurar</button>
|
|
</div>
|
|
<pre id="version-diff"></pre>
|
|
</div>
|
|
<div class="panel-foot">
|
|
<input id="rev-message" type="text" placeholder="Mensagem da próxima revisão (opcional)" maxlength="500" autocomplete="off">
|
|
<input id="author-input" type="text" placeholder="autor (ex.: lg)" maxlength="80" autocomplete="off">
|
|
</div>
|
|
</aside>
|
|
|
|
</main>
|
|
|
|
<!-- Barra de status (estilo Mousepad) -->
|
|
<footer id="statusbar">
|
|
<span id="st-file" class="st-item">sem nota aberta</span>
|
|
<span id="st-format" class="st-item">.txt</span>
|
|
<span id="st-pos" class="st-item">Ln 1, Col 1</span>
|
|
<span class="st-grow"></span>
|
|
<span id="st-stats" class="st-item">0 caracteres</span>
|
|
<span id="st-saved" class="st-item">—</span>
|
|
</footer>
|
|
|
|
<div id="toast" class="hidden"></div>
|
|
</div>
|
|
|
|
<script src="/js/app.js"></script>
|
|
</body>
|
|
</html>
|