feat(files): gerenciador de arquivos/anexos com árvore de pastas, upload, preview e picker
- store/files.go: pastas (parent, anti-ciclo), FileMeta (nota opcional = avulso),
blobs com extensão neutralizada p/ tipos perigosos, sanitização de nome
- api/files.go: upload multipart (64MiB), tree, static com ETag/Range + CSP
sandbox + attachment p/ html/svg/js (stored-XSS mitigado), move/rename/delete,
CRUD de pastas
- web: overlay Ctrl+J / 📎 (modo seletor insere sintaxe md/html/txt e associa),
filtros Todos/Anexos/Avulsos/Nota atual, busca, lightbox img/video/audio/pdf/texto,
colar-e-arrastar no editor e no gerenciador, ações por card (preview/associar/
mover/renomear/excluir), mobile-first (ações sempre visíveis)
- fix: api() já serializa o body — chamadas do gerenciador passavam JSON pré-string
(dupla codificação); auth por cookie (sem Bearer manual no fetch)
- sw v10; testes store+api (traversal, ciclo, XSS headers, range); README
This commit is contained in:
1 parent
ea6b3b915d
commit
119e6cefe9
10 files changed
+1605
-4
No files matched your search
@@ -113,6 +113,36 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Gerenciador de arquivos / anexos -->
|
||||
<div id="files-overlay" class="files-overlay hidden">
|
||||
<div class="files-head">
|
||||
<span class="files-title">Arquivos</span>
|
||||
<div id="files-filters" class="files-filters"></div>
|
||||
<input id="files-search" type="search" placeholder="Buscar…" autocomplete="off">
|
||||
<button type="button" class="btn btn-primary btn-small" id="files-upload-btn">⬆ Enviar</button>
|
||||
<button type="button" class="btn btn-small" id="files-newfolder">+ Pasta</button>
|
||||
<button type="button" class="btn btn-icon btn-small" id="files-close" title="Fechar">✕</button>
|
||||
</div>
|
||||
<div class="files-body">
|
||||
<aside id="files-tree" class="files-tree"></aside>
|
||||
<section id="files-list" class="files-list dropzone">
|
||||
<div id="files-empty" class="files-empty muted">Solte arquivos aqui ou use “⬆ Enviar”.</div>
|
||||
</section>
|
||||
</div>
|
||||
<input type="file" id="files-input" multiple class="hidden">
|
||||
</div>
|
||||
|
||||
<!-- Lightbox de preview -->
|
||||
<div id="lightbox" class="overlay hidden">
|
||||
<div class="lightbox-box">
|
||||
<div id="lightbox-body" class="lightbox-body"></div>
|
||||
<div class="dialog-actions">
|
||||
<a id="lightbox-dl" class="btn btn-primary" download>Baixar</a>
|
||||
<button type="button" id="lightbox-close" class="btn">Fechar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal genérico (Sobre / confirmar) -->
|
||||
<div id="modal-overlay" class="overlay hidden">
|
||||
<div class="dialog">
|
||||
@@ -146,6 +176,7 @@
|
||||
<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 data-action="files">Gerenciador de arquivos…<span class="accel">Ctrl+J</span></li>
|
||||
<li class="menu-sep"></li>
|
||||
<li data-action="close-tab">Fechar aba<span class="accel">Alt+W</span></li>
|
||||
<li data-action="delete-note">Excluir esta nota…</li>
|
||||
@@ -192,6 +223,7 @@
|
||||
<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>
|
||||
<button type="button" class="btn btn-icon" id="btn-attach" title="Inserir anexo (📎)">📎<span class="tb-label">Anexo</span></button>
|
||||
</div>
|
||||
<span class="tb-sep"></span>
|
||||
<div class="tb-group" id="fmt-tools">
|
||||
|
||||
Reference in new issue
Block a user