Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c5df497a5 | ||
|
|
3946adda09 | ||
|
|
f0a5f43c77 | ||
|
|
05340bd8d2 | ||
|
|
0a9622fb96 | ||
|
|
9c09f5dd8a | ||
|
|
82c1fb6c8f | ||
|
|
13bf00030d | ||
|
|
9d67890b68 | ||
|
|
f8fa5f79d5 |
No files matched your search
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Antes de cada push: a verificação rápida. Ignore com `git push --no-verify` (use com parcimônia).
|
||||||
|
exec "$(git rev-parse --show-toplevel)/scripts/verificar.sh"
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
name: CI
|
name: CI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
# Mudança só de documentação não precisa de 6 jobs em 3 sistemas.
|
||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
|
paths-ignore: ['**.md', 'docs/**', 'LICENSE*', '.gitignore', '.githooks/**']
|
||||||
pull_request:
|
pull_request:
|
||||||
|
paths-ignore: ['**.md', 'docs/**', 'LICENSE*', '.gitignore', '.githooks/**']
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ci-${{ github.ref }}
|
group: ci-${{ github.ref }}
|
||||||
|
|||||||
@@ -4,6 +4,17 @@
|
|||||||
|
|
||||||
Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow SemVer.
|
Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow SemVer.
|
||||||
|
|
||||||
|
## [1.3.1] - 2026-10-23
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- **New official logo:** the maned wolf (guará) inside the orange ring, drawn by the project's author, with a transparent background so the same art works in the light and dark themes. It replaces the old track-disc logo in the app (sidebar, top bar and home screen), the favicon, the desktop app icons and the README.
|
||||||
|
- `guara ui` serves the new `guara.png` and `guara-s.png`; `scripts/gerar-logo.py` derives the small logo and the app icon from the official art.
|
||||||
|
- Development: `scripts/verificar.sh` runs locally what the CI runs, with an optional pre-push hook (`scripts/instalar-hooks.sh`), and the CI no longer runs on documentation-only changes.
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
- No change to scanning, recovery, signing or any other behavior. This is the first release after the in-app updater: an app on 1.3.0 should offer **Update now**.
|
||||||
|
- The screenshots in `docs/img/` still show the old logo and will be redone.
|
||||||
|
|
||||||
## [1.3.0] - 2026-10-23
|
## [1.3.0] - 2026-10-23
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -4,6 +4,17 @@
|
|||||||
|
|
||||||
Formato baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/); versões seguem SemVer.
|
Formato baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/); versões seguem SemVer.
|
||||||
|
|
||||||
|
## [1.3.1] - 2026-10-23
|
||||||
|
|
||||||
|
### Alterado
|
||||||
|
- **Logo oficial nova:** o guará dentro do anel laranja, desenhado pelo autor do projeto, com fundo transparente para a mesma arte servir aos temas claro e escuro. Ela substitui a logo antiga das trilhas de disco no app (barra lateral, topo e tela inicial), no favicon, nos ícones do app desktop e no README.
|
||||||
|
- O `guara ui` serve os novos `guara.png` e `guara-s.png`; o `scripts/gerar-logo.py` deriva a logo pequena e o ícone do app da arte oficial.
|
||||||
|
- Desenvolvimento: o `scripts/verificar.sh` roda localmente o que o CI roda, com um hook opcional de pre-push (`scripts/instalar-hooks.sh`), e o CI deixa de rodar em mudanças só de documentação.
|
||||||
|
|
||||||
|
### Notas
|
||||||
|
- Nenhuma mudança na varredura, na recuperação, na assinatura ou em qualquer outro comportamento. É a primeira versão depois do atualizador do app: um app na 1.3.0 deve oferecer **Atualizar agora**.
|
||||||
|
- Os screenshots em `docs/img/` ainda mostram a logo antiga e serão refeitos.
|
||||||
|
|
||||||
## [1.3.0] - 2026-10-23
|
## [1.3.0] - 2026-10-23
|
||||||
|
|
||||||
### Adicionado
|
### Adicionado
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ Thanks for helping! Golden rules:
|
|||||||
## Workflow
|
## Workflow
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo fmt --all
|
scripts/instalar-hooks.sh # uma vez: roda a verificação rápida antes de cada push
|
||||||
cargo clippy --workspace --all-targets
|
scripts/verificar.sh # rápido (segundos): fmt, clippy como no CI, tradução, scripts, workflows
|
||||||
cargo test --workspace
|
scripts/verificar.sh --completo # inclui cargo test --workspace e cargo audit
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The CI takes 5 to 30 minutes on three systems, so run the check before pushing: almost everything that makes the CI fail shows up locally in seconds. Documentation-only changes (`*.md`, `docs/`) skip the CI.
|
||||||
|
|
||||||
On Linux the tests build images with `mtools`, `ntfs-3g`, `e2fsprogs`, `exfatprogs`, `imagemagick`, `zip` and `python3`. Without these tools the image tests are skipped (set `GUARA_REQUIRE_FIXTURES=1` to make them fail).
|
On Linux the tests build images with `mtools`, `ntfs-3g`, `e2fsprogs`, `exfatprogs`, `imagemagick`, `zip` and `python3`. Without these tools the image tests are skipped (set `GUARA_REQUIRE_FIXTURES=1` to make them fail).
|
||||||
|
|
||||||
For the external reference images (BitLocker, FileVault 2, dfvfs, AFF4), run `scripts/fetch-testdata.sh`; without them those tests are skipped. The BitLocker test takes about 75 s.
|
For the external reference images (BitLocker, FileVault 2, dfvfs, AFF4), run `scripts/fetch-testdata.sh`; without them those tests are skipped. The BitLocker test takes about 75 s.
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ Obrigado por ajudar! Regras de ouro:
|
|||||||
## Fluxo
|
## Fluxo
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo fmt --all
|
scripts/instalar-hooks.sh # uma vez: roda a verificação rápida antes de cada push
|
||||||
cargo clippy --workspace --all-targets
|
scripts/verificar.sh # rápido (segundos): fmt, clippy como no CI, tradução, scripts, workflows
|
||||||
cargo test --workspace
|
scripts/verificar.sh --completo # inclui cargo test --workspace e cargo audit
|
||||||
```
|
```
|
||||||
|
|
||||||
|
O CI leva de 5 a 30 minutos em três sistemas, então rode a verificação antes do push: quase tudo que faz o CI falhar aparece aqui em segundos. Mudanças só de documentação (`*.md`, `docs/`) pulam o CI.
|
||||||
|
|
||||||
No Linux os testes geram imagens com `mtools`, `ntfs-3g`, `e2fsprogs`, `exfatprogs`, `imagemagick`, `zip` e `python3`. Sem essas ferramentas os testes com imagem são ignorados (defina `GUARA_REQUIRE_FIXTURES=1` para falhar).
|
No Linux os testes geram imagens com `mtools`, `ntfs-3g`, `e2fsprogs`, `exfatprogs`, `imagemagick`, `zip` e `python3`. Sem essas ferramentas os testes com imagem são ignorados (defina `GUARA_REQUIRE_FIXTURES=1` para falhar).
|
||||||
|
|
||||||
Para as imagens de referência externas (BitLocker, FileVault 2, dfvfs, AFF4), rode `scripts/fetch-testdata.sh`; sem elas esses testes são pulados. O teste de BitLocker leva cerca de 75 s.
|
Para as imagens de referência externas (BitLocker, FileVault 2, dfvfs, AFF4), rode `scripts/fetch-testdata.sh`; sem elas esses testes são pulados. O teste de BitLocker leva cerca de 75 s.
|
||||||
|
|||||||
@@ -416,7 +416,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "guara-cli"
|
name = "guara-cli"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"ctrlc",
|
"ctrlc",
|
||||||
@@ -429,7 +429,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "guara-core"
|
name = "guara-core"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"argon2",
|
"argon2",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ resolver = "2"
|
|||||||
members = ["crates/guara-core", "crates/guara-cli"]
|
members = ["crates/guara-core", "crates/guara-cli"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://github.com/lucasrguerra/guara"
|
repository = "https://github.com/lucasrguerra/guara"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<p align="center"><img src="apps/gui/ui/guara-logo.svg" width="360" alt="Guará"></p>
|
<p align="center"><img src="apps/gui/ui/guara.png" width="300" alt="Guará"></p>
|
||||||
<h1 align="center">Guará</h1>
|
<h1 align="center">Guará</h1>
|
||||||
<p align="center">Free file recovery for hard drives, SSDs and USB sticks.<br>Terminal and graphical interface · Windows, Linux and macOS · read-only on the source.</p>
|
<p align="center">Free file recovery for hard drives, SSDs and USB sticks.<br>Terminal and graphical interface · Windows, Linux and macOS · read-only on the source.</p>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<p align="center"><img src="apps/gui/ui/guara-logo.svg" width="360" alt="Guará"></p>
|
<p align="center"><img src="apps/gui/ui/guara.png" width="300" alt="Guará"></p>
|
||||||
<h1 align="center">Guará</h1>
|
<h1 align="center">Guará</h1>
|
||||||
<p align="center">Recuperação de arquivos livre e gratuita para HD, SSD e pendrive.<br>Terminal e interface gráfica · Windows, Linux e macOS · somente leitura na origem.</p>
|
<p align="center">Recuperação de arquivos livre e gratuita para HD, SSD e pendrive.<br>Terminal e interface gráfica · Windows, Linux e macOS · somente leitura na origem.</p>
|
||||||
|
|
||||||
|
|||||||
@@ -28,10 +28,11 @@ Legend: ✅ done · 🟡 partial · 🔜 planned · 🔭 long-term idea · ⛔ o
|
|||||||
| 1.1.0 | 2026-10-20 | Core messages and dates in English, automated translation check, RustCrypto on digest 0.11, verified Docker device access and Superset workspaces |
|
| 1.1.0 | 2026-10-20 | Core messages and dates in English, automated translation check, RustCrypto on digest 0.11, verified Docker device access and Superset workspaces |
|
||||||
| 1.2.0 | 2026-10-22 | QCOW2, VMDK, VHD, VHDX and DMG virtual disks, hash-chained audit trail, PDF report, APFS free-space map |
|
| 1.2.0 | 2026-10-22 | QCOW2, VMDK, VHD, VHDX and DMG virtual disks, hash-chained audit trail, PDF report, APFS free-space map |
|
||||||
| 1.3.0 | 2026-10-23 | Update from inside the app, Ed25519 signatures, differencing QCOW2/VMDK and LZFSE DMG, reference images tested on Linux, macOS and Windows, XFS real-deletion test |
|
| 1.3.0 | 2026-10-23 | Update from inside the app, Ed25519 signatures, differencing QCOW2/VMDK and LZFSE DMG, reference images tested on Linux, macOS and Windows, XFS real-deletion test |
|
||||||
|
| 1.3.1 | 2026-10-23 | New official logo |
|
||||||
|
|
||||||
Details of each version in the [CHANGELOG](CHANGELOG.md).
|
Details of each version in the [CHANGELOG](CHANGELOG.md).
|
||||||
|
|
||||||
## Current status (1.3.0) against what is expected from a forensic suite
|
## Current status (1.3.1) against what is expected from a forensic suite
|
||||||
|
|
||||||
### 1. File systems with metadata
|
### 1. File systems with metadata
|
||||||
|
|
||||||
|
|||||||
@@ -28,10 +28,11 @@ Legenda: ✅ feito · 🟡 parcial · 🔜 planejado · 🔭 ideia a longo prazo
|
|||||||
| 1.1.0 | 2026-10-20 | Mensagens do núcleo e datas em inglês, verificação automática da tradução, RustCrypto em digest 0.11, acesso a dispositivo no Docker e workspaces do Superset verificados |
|
| 1.1.0 | 2026-10-20 | Mensagens do núcleo e datas em inglês, verificação automática da tradução, RustCrypto em digest 0.11, acesso a dispositivo no Docker e workspaces do Superset verificados |
|
||||||
| 1.2.0 | 2026-10-22 | Discos virtuais QCOW2, VMDK, VHD, VHDX e DMG, trilha de auditoria encadeada por hash, relatório em PDF, mapa de espaço livre do APFS |
|
| 1.2.0 | 2026-10-22 | Discos virtuais QCOW2, VMDK, VHD, VHDX e DMG, trilha de auditoria encadeada por hash, relatório em PDF, mapa de espaço livre do APFS |
|
||||||
| 1.3.0 | 2026-10-23 | Atualização pelo próprio app, assinaturas Ed25519, QCOW2/VMDK diferenciais e DMG com LZFSE, imagens de referência testadas em Linux, macOS e Windows, teste de exclusão real do XFS |
|
| 1.3.0 | 2026-10-23 | Atualização pelo próprio app, assinaturas Ed25519, QCOW2/VMDK diferenciais e DMG com LZFSE, imagens de referência testadas em Linux, macOS e Windows, teste de exclusão real do XFS |
|
||||||
|
| 1.3.1 | 2026-10-23 | Nova logo oficial |
|
||||||
|
|
||||||
Detalhes de cada versão no [CHANGELOG](CHANGELOG.pt-BR.md).
|
Detalhes de cada versão no [CHANGELOG](CHANGELOG.pt-BR.md).
|
||||||
|
|
||||||
## Situação atual (1.3.0) contra o que se espera de uma suíte forense
|
## Situação atual (1.3.1) contra o que se espera de uma suíte forense
|
||||||
|
|
||||||
### 1. Sistemas de arquivos com metadados
|
### 1. Sistemas de arquivos com metadados
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "guara-gui"
|
name = "guara-gui"
|
||||||
description = "Guará: interface gráfica de recuperação de arquivos"
|
description = "Guará: interface gráfica de recuperação de arquivos"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://github.com/lucasrguerra/guara"
|
repository = "https://github.com/lucasrguerra/guara"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 145 KiB |
|
Before Width: | Height: | Size: 835 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 419 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 406 KiB |
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "Guara",
|
"productName": "Guara",
|
||||||
"version": "1.3.0",
|
"version": "1.3.1",
|
||||||
"identifier": "dev.guara.app",
|
"identifier": "dev.guara.app",
|
||||||
"build": {
|
"build": {
|
||||||
"frontendDist": "../ui"
|
"frontendDist": "../ui"
|
||||||
|
|||||||
@@ -332,7 +332,7 @@ dialog.lightbox[open] { display: grid; }
|
|||||||
.lb-head .ttl { flex: 1; min-width: 0; } .lb-head .ttl b { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .lb-head .ttl small { color: var(--text-2); }
|
.lb-head .ttl { flex: 1; min-width: 0; } .lb-head .ttl b { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .lb-head .ttl small { color: var(--text-2); }
|
||||||
.lb-body { padding: 12px; min-height: 0; }
|
.lb-body { padding: 12px; min-height: 0; }
|
||||||
|
|
||||||
.hero-logo { width: min(440px, 80%); height: auto; display: block; margin: 0 0 22px -4px; }
|
.hero-logo { width: min(340px, 70%); height: auto; margin: 0 0 14px -6px; }
|
||||||
.pill.accent { background: var(--accent-soft); color: var(--accent); }
|
.pill.accent { background: var(--accent-soft); color: var(--accent); }
|
||||||
|
|
||||||
/* ------------------------------------------------------------ explorador de arquivos */
|
/* ------------------------------------------------------------ explorador de arquivos */
|
||||||
@@ -516,8 +516,8 @@ dialog.lightbox[open] { display: grid; }
|
|||||||
.h-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; background: var(--ok); }
|
.h-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; background: var(--ok); }
|
||||||
.h-dot.warning { background: var(--warn); } .h-dot.failing { background: var(--bad); }
|
.h-dot.warning { background: var(--warn); } .h-dot.failing { background: var(--bad); }
|
||||||
|
|
||||||
/* logo inline: segue o tema escolhido no app, não o do sistema */
|
/* logo: uma arte só (laranja sobre transparente) serve aos temas claro e escuro */
|
||||||
.logo .a { stroke: var(--accent); } .logo .b { stroke: var(--accent-2); } .logo .t { fill: var(--text); }
|
.logo-img { display: block; flex: none; }
|
||||||
|
|
||||||
/* atualização do app */
|
/* atualização do app */
|
||||||
.update-card { position: fixed; right: 18px; bottom: 18px; z-index: 60; width: min(400px, calc(100vw - 36px)); display: grid; gap: 10px; padding: 16px 18px; border-radius: 18px; background: var(--surface); box-shadow: var(--shadow); border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent); }
|
.update-card { position: fixed; right: 18px; bottom: 18px; z-index: 60; width: min(400px, calc(100vw - 36px)); display: grid; gap: 10px; padding: 16px 18px; border-radius: 18px; background: var(--surface); box-shadow: var(--shadow); border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent); }
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ function renderHome() {
|
|||||||
S.device = null; S.job = null;
|
S.device = null; S.job = null;
|
||||||
renderSide();
|
renderSide();
|
||||||
main.innerHTML = `<div class="page">
|
main.innerHTML = `<div class="page">
|
||||||
<section class="hero"><img class="hero-logo" src="guara-logo.svg" alt="Guará"><h1>Encontre o que você achou que tinha perdido.</h1>
|
<section class="hero"><img class="logo-img hero-logo" src="guara.png" alt="Guará"><h1>Encontre o que você achou que tinha perdido.</h1>
|
||||||
<p>Escolha um disco, SSD ou pendrive ao lado. O Guará lê tudo: arquivos apagados, partições perdidas e espaço não particionado, sem escrever nada no disco de origem.</p></section>
|
<p>Escolha um disco, SSD ou pendrive ao lado. O Guará lê tudo: arquivos apagados, partições perdidas e espaço não particionado, sem escrever nada no disco de origem.</p></section>
|
||||||
<div class="cards">
|
<div class="cards">
|
||||||
<div class="card"><h3>Uma varredura, tudo junto</h3><p>Metadados do sistema de arquivos e busca por assinatura na mesma passada, sem duplicatas.</p></div>
|
<div class="card"><h3>Uma varredura, tudo junto</h3><p>Metadados do sistema de arquivos e busca por assinatura na mesma passada, sem duplicatas.</p></div>
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" role="img" aria-label="Guará"><style>.a{stroke:#0f766e}.b{stroke:#14b8a6}.t{fill:#1d1d1f}@media (prefers-color-scheme:dark){.a{stroke:#2dd4bf}.b{stroke:#5eead4}.t{fill:#f5f5f7}}</style><defs><clipPath id="g-head"><path d="M50 95 C46 88 43 80 40 74 C33 70 25 64 22 56 L14 6 L36 30 C40 28 45 27 50 27 C55 27 60 28 64 30 L86 6 L78 56 C75 64 67 70 60 74 C57 80 54 88 50 95 Z"/></clipPath></defs><g clip-path="url(#g-head)" fill="none" stroke-width="4.2"><path class="a" d="M50 93A7 7 0 0 1 50 107"/><path class="b" d="M50 93A7 7 0 0 0 50 107" stroke-dasharray="3 3" stroke-dashoffset="0"/><path class="a" d="M50 86A14 14 0 0 1 50 114"/><path class="b" d="M50 86A14 14 0 0 0 50 114" stroke-dasharray="6 4" stroke-dashoffset="3"/><path class="a" d="M50 79A21 21 0 0 1 50 121"/><path class="b" d="M50 79A21 21 0 0 0 50 121" stroke-dasharray="9 5" stroke-dashoffset="6"/><path class="a" d="M50 72A28 28 0 0 1 50 128"/><path class="b" d="M50 72A28 28 0 0 0 50 128" stroke-dasharray="3 6" stroke-dashoffset="9"/><path class="a" d="M50 65A35 35 0 0 1 50 135"/><path class="b" d="M50 65A35 35 0 0 0 50 135" stroke-dasharray="6 3" stroke-dashoffset="12"/><path class="a" d="M50 58A42 42 0 0 1 50 142"/><path class="b" d="M50 58A42 42 0 0 0 50 142" stroke-dasharray="9 4" stroke-dashoffset="15"/><path class="a" d="M50 51A49 49 0 0 1 50 149"/><path class="b" d="M50 51A49 49 0 0 0 50 149" stroke-dasharray="3 5" stroke-dashoffset="18"/><path class="a" d="M50 44A56 56 0 0 1 50 156"/><path class="b" d="M50 44A56 56 0 0 0 50 156" stroke-dasharray="6 6" stroke-dashoffset="21"/><path class="a" d="M50 37A63 63 0 0 1 50 163"/><path class="b" d="M50 37A63 63 0 0 0 50 163" stroke-dasharray="9 3" stroke-dashoffset="24"/><path class="a" d="M50 30A70 70 0 0 1 50 170"/><path class="b" d="M50 30A70 70 0 0 0 50 170" stroke-dasharray="3 4" stroke-dashoffset="27"/><path class="a" d="M50 23A77 77 0 0 1 50 177"/><path class="b" d="M50 23A77 77 0 0 0 50 177" stroke-dasharray="6 5" stroke-dashoffset="30"/><path class="a" d="M50 16A84 84 0 0 1 50 184"/><path class="b" d="M50 16A84 84 0 0 0 50 184" stroke-dasharray="9 6" stroke-dashoffset="33"/><path class="a" d="M50 9A91 91 0 0 1 50 191"/><path class="b" d="M50 9A91 91 0 0 0 50 191" stroke-dasharray="3 3" stroke-dashoffset="36"/><path class="a" d="M50 2A98 98 0 0 1 50 198"/><path class="b" d="M50 2A98 98 0 0 0 50 198" stroke-dasharray="6 4" stroke-dashoffset="39"/><rect class="t" stroke="none" x="0" y="74" width="100" height="30"/></g><path class="t" d="M37 50Q42 47 46 52Q41 53 37 50ZM63 50Q58 47 54 52Q59 53 63 50Z"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 870 KiB |
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" role="img" aria-label="Guará"><style>.a{stroke:#0f766e}.b{stroke:#14b8a6}.t{fill:#1d1d1f}@media (prefers-color-scheme:dark){.a{stroke:#2dd4bf}.b{stroke:#5eead4}.t{fill:#f5f5f7}}</style><defs><clipPath id="g-head"><path d="M50 95 C46 88 43 80 40 74 C33 70 25 64 22 56 L14 6 L36 30 C40 28 45 27 50 27 C55 27 60 28 64 30 L86 6 L78 56 C75 64 67 70 60 74 C57 80 54 88 50 95 Z"/></clipPath></defs><g clip-path="url(#g-head)" fill="none" stroke-width="4.2"><path class="a" d="M50 93A7 7 0 0 1 50 107"/><path class="b" d="M50 93A7 7 0 0 0 50 107" stroke-dasharray="3 3" stroke-dashoffset="0"/><path class="a" d="M50 86A14 14 0 0 1 50 114"/><path class="b" d="M50 86A14 14 0 0 0 50 114" stroke-dasharray="6 4" stroke-dashoffset="3"/><path class="a" d="M50 79A21 21 0 0 1 50 121"/><path class="b" d="M50 79A21 21 0 0 0 50 121" stroke-dasharray="9 5" stroke-dashoffset="6"/><path class="a" d="M50 72A28 28 0 0 1 50 128"/><path class="b" d="M50 72A28 28 0 0 0 50 128" stroke-dasharray="3 6" stroke-dashoffset="9"/><path class="a" d="M50 65A35 35 0 0 1 50 135"/><path class="b" d="M50 65A35 35 0 0 0 50 135" stroke-dasharray="6 3" stroke-dashoffset="12"/><path class="a" d="M50 58A42 42 0 0 1 50 142"/><path class="b" d="M50 58A42 42 0 0 0 50 142" stroke-dasharray="9 4" stroke-dashoffset="15"/><path class="a" d="M50 51A49 49 0 0 1 50 149"/><path class="b" d="M50 51A49 49 0 0 0 50 149" stroke-dasharray="3 5" stroke-dashoffset="18"/><path class="a" d="M50 44A56 56 0 0 1 50 156"/><path class="b" d="M50 44A56 56 0 0 0 50 156" stroke-dasharray="6 6" stroke-dashoffset="21"/><path class="a" d="M50 37A63 63 0 0 1 50 163"/><path class="b" d="M50 37A63 63 0 0 0 50 163" stroke-dasharray="9 3" stroke-dashoffset="24"/><path class="a" d="M50 30A70 70 0 0 1 50 170"/><path class="b" d="M50 30A70 70 0 0 0 50 170" stroke-dasharray="3 4" stroke-dashoffset="27"/><path class="a" d="M50 23A77 77 0 0 1 50 177"/><path class="b" d="M50 23A77 77 0 0 0 50 177" stroke-dasharray="6 5" stroke-dashoffset="30"/><path class="a" d="M50 16A84 84 0 0 1 50 184"/><path class="b" d="M50 16A84 84 0 0 0 50 184" stroke-dasharray="9 6" stroke-dashoffset="33"/><path class="a" d="M50 9A91 91 0 0 1 50 191"/><path class="b" d="M50 9A91 91 0 0 0 50 191" stroke-dasharray="3 3" stroke-dashoffset="36"/><path class="a" d="M50 2A98 98 0 0 1 50 198"/><path class="b" d="M50 2A98 98 0 0 0 50 198" stroke-dasharray="6 4" stroke-dashoffset="39"/><rect class="t" stroke="none" x="0" y="74" width="100" height="30"/></g><path class="t" d="M37 50Q42 47 46 52Q41 53 37 50ZM63 50Q58 47 54 52Q59 53 63 50Z"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 2.6 KiB |
@@ -5,7 +5,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||||
<meta name="color-scheme" content="light dark">
|
<meta name="color-scheme" content="light dark">
|
||||||
<title>Guará</title>
|
<title>Guará</title>
|
||||||
<link rel="icon" href="guara.svg" type="image/svg+xml">
|
<link rel="icon" href="guara-s.png" type="image/png">
|
||||||
<link rel="stylesheet" href="app.css">
|
<link rel="stylesheet" href="app.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -14,10 +14,10 @@
|
|||||||
<button class="icon-btn" id="menuBtn" aria-label="Abrir menu" aria-expanded="false">
|
<button class="icon-btn" id="menuBtn" aria-label="Abrir menu" aria-expanded="false">
|
||||||
<svg viewBox="0 0 24 24" width="22" height="22"><path d="M4 7h16M4 12h16M4 17h16" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none"/></svg>
|
<svg viewBox="0 0 24 24" width="22" height="22"><path d="M4 7h16M4 12h16M4 17h16" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none"/></svg>
|
||||||
</button>
|
</button>
|
||||||
<svg class="logo" width="24" height="24" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><clipPath id="g-head-top"><path d="M50 95 C46 88 43 80 40 74 C33 70 25 64 22 56 L14 6 L36 30 C40 28 45 27 50 27 C55 27 60 28 64 30 L86 6 L78 56 C75 64 67 70 60 74 C57 80 54 88 50 95 Z"/></clipPath></defs><g clip-path="url(#g-head-top)" fill="none" stroke-width="4.2"><path class="a" d="M50 93A7 7 0 0 1 50 107"/><path class="b" d="M50 93A7 7 0 0 0 50 107" stroke-dasharray="3 3" stroke-dashoffset="0"/><path class="a" d="M50 86A14 14 0 0 1 50 114"/><path class="b" d="M50 86A14 14 0 0 0 50 114" stroke-dasharray="6 4" stroke-dashoffset="3"/><path class="a" d="M50 79A21 21 0 0 1 50 121"/><path class="b" d="M50 79A21 21 0 0 0 50 121" stroke-dasharray="9 5" stroke-dashoffset="6"/><path class="a" d="M50 72A28 28 0 0 1 50 128"/><path class="b" d="M50 72A28 28 0 0 0 50 128" stroke-dasharray="3 6" stroke-dashoffset="9"/><path class="a" d="M50 65A35 35 0 0 1 50 135"/><path class="b" d="M50 65A35 35 0 0 0 50 135" stroke-dasharray="6 3" stroke-dashoffset="12"/><path class="a" d="M50 58A42 42 0 0 1 50 142"/><path class="b" d="M50 58A42 42 0 0 0 50 142" stroke-dasharray="9 4" stroke-dashoffset="15"/><path class="a" d="M50 51A49 49 0 0 1 50 149"/><path class="b" d="M50 51A49 49 0 0 0 50 149" stroke-dasharray="3 5" stroke-dashoffset="18"/><path class="a" d="M50 44A56 56 0 0 1 50 156"/><path class="b" d="M50 44A56 56 0 0 0 50 156" stroke-dasharray="6 6" stroke-dashoffset="21"/><path class="a" d="M50 37A63 63 0 0 1 50 163"/><path class="b" d="M50 37A63 63 0 0 0 50 163" stroke-dasharray="9 3" stroke-dashoffset="24"/><path class="a" d="M50 30A70 70 0 0 1 50 170"/><path class="b" d="M50 30A70 70 0 0 0 50 170" stroke-dasharray="3 4" stroke-dashoffset="27"/><path class="a" d="M50 23A77 77 0 0 1 50 177"/><path class="b" d="M50 23A77 77 0 0 0 50 177" stroke-dasharray="6 5" stroke-dashoffset="30"/><path class="a" d="M50 16A84 84 0 0 1 50 184"/><path class="b" d="M50 16A84 84 0 0 0 50 184" stroke-dasharray="9 6" stroke-dashoffset="33"/><path class="a" d="M50 9A91 91 0 0 1 50 191"/><path class="b" d="M50 9A91 91 0 0 0 50 191" stroke-dasharray="3 3" stroke-dashoffset="36"/><path class="a" d="M50 2A98 98 0 0 1 50 198"/><path class="b" d="M50 2A98 98 0 0 0 50 198" stroke-dasharray="6 4" stroke-dashoffset="39"/><rect class="t" stroke="none" x="0" y="74" width="100" height="30"/></g><path class="t" d="M37 50Q42 47 46 52Q41 53 37 50ZM63 50Q58 47 54 52Q59 53 63 50Z"/></svg><strong>Guará</strong>
|
<img class="logo-img" src="guara-s.png" width="24" height="24" alt=""><strong>Guará</strong>
|
||||||
</header>
|
</header>
|
||||||
<aside class="sidebar" id="sidebar" aria-label="Dispositivos e sessões">
|
<aside class="sidebar" id="sidebar" aria-label="Dispositivos e sessões">
|
||||||
<div class="brand"><svg class="logo" width="30" height="30" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><clipPath id="g-head-side"><path d="M50 95 C46 88 43 80 40 74 C33 70 25 64 22 56 L14 6 L36 30 C40 28 45 27 50 27 C55 27 60 28 64 30 L86 6 L78 56 C75 64 67 70 60 74 C57 80 54 88 50 95 Z"/></clipPath></defs><g clip-path="url(#g-head-side)" fill="none" stroke-width="4.2"><path class="a" d="M50 93A7 7 0 0 1 50 107"/><path class="b" d="M50 93A7 7 0 0 0 50 107" stroke-dasharray="3 3" stroke-dashoffset="0"/><path class="a" d="M50 86A14 14 0 0 1 50 114"/><path class="b" d="M50 86A14 14 0 0 0 50 114" stroke-dasharray="6 4" stroke-dashoffset="3"/><path class="a" d="M50 79A21 21 0 0 1 50 121"/><path class="b" d="M50 79A21 21 0 0 0 50 121" stroke-dasharray="9 5" stroke-dashoffset="6"/><path class="a" d="M50 72A28 28 0 0 1 50 128"/><path class="b" d="M50 72A28 28 0 0 0 50 128" stroke-dasharray="3 6" stroke-dashoffset="9"/><path class="a" d="M50 65A35 35 0 0 1 50 135"/><path class="b" d="M50 65A35 35 0 0 0 50 135" stroke-dasharray="6 3" stroke-dashoffset="12"/><path class="a" d="M50 58A42 42 0 0 1 50 142"/><path class="b" d="M50 58A42 42 0 0 0 50 142" stroke-dasharray="9 4" stroke-dashoffset="15"/><path class="a" d="M50 51A49 49 0 0 1 50 149"/><path class="b" d="M50 51A49 49 0 0 0 50 149" stroke-dasharray="3 5" stroke-dashoffset="18"/><path class="a" d="M50 44A56 56 0 0 1 50 156"/><path class="b" d="M50 44A56 56 0 0 0 50 156" stroke-dasharray="6 6" stroke-dashoffset="21"/><path class="a" d="M50 37A63 63 0 0 1 50 163"/><path class="b" d="M50 37A63 63 0 0 0 50 163" stroke-dasharray="9 3" stroke-dashoffset="24"/><path class="a" d="M50 30A70 70 0 0 1 50 170"/><path class="b" d="M50 30A70 70 0 0 0 50 170" stroke-dasharray="3 4" stroke-dashoffset="27"/><path class="a" d="M50 23A77 77 0 0 1 50 177"/><path class="b" d="M50 23A77 77 0 0 0 50 177" stroke-dasharray="6 5" stroke-dashoffset="30"/><path class="a" d="M50 16A84 84 0 0 1 50 184"/><path class="b" d="M50 16A84 84 0 0 0 50 184" stroke-dasharray="9 6" stroke-dashoffset="33"/><path class="a" d="M50 9A91 91 0 0 1 50 191"/><path class="b" d="M50 9A91 91 0 0 0 50 191" stroke-dasharray="3 3" stroke-dashoffset="36"/><path class="a" d="M50 2A98 98 0 0 1 50 198"/><path class="b" d="M50 2A98 98 0 0 0 50 198" stroke-dasharray="6 4" stroke-dashoffset="39"/><rect class="t" stroke="none" x="0" y="74" width="100" height="30"/></g><path class="t" d="M37 50Q42 47 46 52Q41 53 37 50ZM63 50Q58 47 54 52Q59 53 63 50Z"/></svg><div><strong>Guará</strong><small>Recuperação de arquivos</small></div></div>
|
<div class="brand"><img class="logo-img" src="guara-s.png" width="30" height="30" alt=""><div><strong>Guará</strong><small>Recuperação de arquivos</small></div></div>
|
||||||
<nav>
|
<nav>
|
||||||
<div class="side-title">Dispositivos <button class="icon-btn small" id="refreshBtn" title="Atualizar lista" aria-label="Atualizar lista"><svg viewBox="0 0 24 24" width="16" height="16"><path d="M20 12a8 8 0 1 1-2.5-5.8M20 4v5h-5" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg></button></div>
|
<div class="side-title">Dispositivos <button class="icon-btn small" id="refreshBtn" title="Atualizar lista" aria-label="Atualizar lista"><svg viewBox="0 0 24 24" width="16" height="16"><path d="M20 12a8 8 0 1 1-2.5-5.8M20 4v5h-5" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg></button></div>
|
||||||
<ul id="deviceList" class="list"></ul>
|
<ul id="deviceList" class="list"></ul>
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ const JS: &str = include_str!("../../../apps/gui/ui/app.js");
|
|||||||
const PREVIEW_JS: &str = include_str!("../../../apps/gui/ui/preview.js");
|
const PREVIEW_JS: &str = include_str!("../../../apps/gui/ui/preview.js");
|
||||||
const I18N_JS: &str = include_str!("../../../apps/gui/ui/i18n.js");
|
const I18N_JS: &str = include_str!("../../../apps/gui/ui/i18n.js");
|
||||||
const I18N_EN_JS: &str = include_str!("../../../apps/gui/ui/i18n-en.js");
|
const I18N_EN_JS: &str = include_str!("../../../apps/gui/ui/i18n-en.js");
|
||||||
const LOGO: &str = include_str!("../../../apps/gui/ui/guara-logo.svg");
|
|
||||||
const EXPLORER_JS: &str = include_str!("../../../apps/gui/ui/explorer.js");
|
const EXPLORER_JS: &str = include_str!("../../../apps/gui/ui/explorer.js");
|
||||||
const ICON: &str = include_str!("../../../apps/gui/ui/guara.svg");
|
const LOGO: &[u8] = include_bytes!("../../../apps/gui/ui/guara.png");
|
||||||
|
const LOGO_S: &[u8] = include_bytes!("../../../apps/gui/ui/guara-s.png");
|
||||||
const PDF_JS: &str = include_str!("../../../apps/gui/ui/vendor/pdf.min.mjs");
|
const PDF_JS: &str = include_str!("../../../apps/gui/ui/vendor/pdf.min.mjs");
|
||||||
const PDF_WORKER: &str = include_str!("../../../apps/gui/ui/vendor/pdf.worker.min.mjs");
|
const PDF_WORKER: &str = include_str!("../../../apps/gui/ui/vendor/pdf.worker.min.mjs");
|
||||||
|
|
||||||
@@ -98,8 +98,11 @@ fn handle(req: Request, eng: &Engine, token: &str, hosts: &[String]) {
|
|||||||
Response::from_string(I18N_EN_JS).with_header(ct("text/javascript; charset=utf-8")),
|
Response::from_string(I18N_EN_JS).with_header(ct("text/javascript; charset=utf-8")),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
(Method::Get, "/guara-logo.svg") => {
|
(Method::Get, "/guara.png") => {
|
||||||
let _ = req.respond(Response::from_string(LOGO).with_header(ct("image/svg+xml")));
|
let _ = req.respond(Response::from_data(LOGO).with_header(ct("image/png")));
|
||||||
|
}
|
||||||
|
(Method::Get, "/guara-s.png") => {
|
||||||
|
let _ = req.respond(Response::from_data(LOGO_S).with_header(ct("image/png")));
|
||||||
}
|
}
|
||||||
(Method::Get, "/explorer.js") => {
|
(Method::Get, "/explorer.js") => {
|
||||||
let _ = req.respond(
|
let _ = req.respond(
|
||||||
@@ -107,9 +110,6 @@ fn handle(req: Request, eng: &Engine, token: &str, hosts: &[String]) {
|
|||||||
.with_header(ct("text/javascript; charset=utf-8")),
|
.with_header(ct("text/javascript; charset=utf-8")),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
(Method::Get, "/guara.svg") => {
|
|
||||||
let _ = req.respond(Response::from_string(ICON).with_header(ct("image/svg+xml")));
|
|
||||||
}
|
|
||||||
(Method::Get, "/vendor/pdf.min.mjs") => {
|
(Method::Get, "/vendor/pdf.min.mjs") => {
|
||||||
let _ = req.respond(
|
let _ = req.respond(
|
||||||
Response::from_string(PDF_JS).with_header(ct("text/javascript; charset=utf-8")),
|
Response::from_string(PDF_JS).with_header(ct("text/javascript; charset=utf-8")),
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ set -euo pipefail
|
|||||||
cache="$1"; shift
|
cache="$1"; shift
|
||||||
pkgs=("$@")
|
pkgs=("$@")
|
||||||
mkdir -p "$cache/partial"
|
mkdir -p "$cache/partial"
|
||||||
|
# O apt roda como root e deixa arquivos (lock, .deb) que o usuário do runner não lê; sem devolver a
|
||||||
|
# posse, o actions/cache falha ao empacotar a pasta ("tar failed with exit code 2") e nunca grava.
|
||||||
|
trap 'sudo chown -R "$(id -u):$(id -g)" "$cache" 2>/dev/null || true; rm -f "$cache/lock"' EXIT
|
||||||
opts=(-o "Dir::Cache::archives=$cache" -y)
|
opts=(-o "Dir::Cache::archives=$cache" -y)
|
||||||
|
|
||||||
# 1) com .deb em cache: instala direto, sem nem atualizar o índice do apt
|
# 1) com .deb em cache: instala direto, sem nem atualizar o índice do apt
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Gera, a partir da logo oficial, os arquivos derivados usados no app e nos ícones.
|
||||||
|
|
||||||
|
A logo oficial é apps/gui/ui/guara.png (RGBA, fundo transparente, serve aos temas claro e escuro).
|
||||||
|
Ela não é alterada aqui. Saída:
|
||||||
|
apps/gui/ui/guara-s.png 128 px, recortada e quadrada (barra lateral e favicon)
|
||||||
|
apps/gui/src-tauri/icons/source.png 1024 px, a arte sobre o fundo escuro com cantos arredondados;
|
||||||
|
o CI e `npx @tauri-apps/cli icon` geram o resto dos ícones.
|
||||||
|
|
||||||
|
Uso: python3 scripts/gerar-logo.py
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
RAIZ = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")
|
||||||
|
UI = os.path.join(RAIZ, "apps/gui/ui")
|
||||||
|
ICONES = os.path.join(RAIZ, "apps/gui/src-tauri/icons")
|
||||||
|
FUNDO_ICONE = (10, 16, 28) # o azul-noite do fundo da arte original
|
||||||
|
|
||||||
|
|
||||||
|
def recortar_quadrado(im, margem=0.04):
|
||||||
|
"""Recorta no que é visível (opacidade > 16, ignora resquícios) e centraliza num quadrado."""
|
||||||
|
box = im.getchannel("A").point(lambda v: 255 if v > 16 else 0).getbbox()
|
||||||
|
im = im.crop(box)
|
||||||
|
w, h = im.size
|
||||||
|
lado = round(max(w, h) * (1 + 2 * margem))
|
||||||
|
quadro = Image.new("RGBA", (lado, lado), (0, 0, 0, 0))
|
||||||
|
quadro.paste(im, ((lado - w) // 2, (lado - h) // 2), im)
|
||||||
|
return quadro
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
logo = recortar_quadrado(Image.open(os.path.join(UI, "guara.png")).convert("RGBA"))
|
||||||
|
logo.resize((128, 128), Image.LANCZOS).save(os.path.join(UI, "guara-s.png"), optimize=True)
|
||||||
|
print("guara-s.png")
|
||||||
|
|
||||||
|
lado = 1024
|
||||||
|
fundo = Image.new("RGBA", (lado, lado), FUNDO_ICONE + (255,))
|
||||||
|
arte = logo.resize((round(lado * 0.82),) * 2, Image.LANCZOS)
|
||||||
|
fundo.paste(arte, ((lado - arte.width) // 2, (lado - arte.height) // 2), arte)
|
||||||
|
mascara = Image.new("L", (lado, lado), 0)
|
||||||
|
ImageDraw.Draw(mascara).rounded_rectangle((0, 0, lado - 1, lado - 1), radius=round(lado * 0.2237), fill=255)
|
||||||
|
icone = Image.new("RGBA", (lado, lado), (0, 0, 0, 0))
|
||||||
|
icone.paste(fundo, (0, 0), mascara)
|
||||||
|
icone.save(os.path.join(ICONES, "source.png"), optimize=True)
|
||||||
|
print("icons/source.png")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Liga o hook de pre-push do repositório (roda scripts/verificar.sh antes de cada push).
|
||||||
|
set -euo pipefail
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
git config core.hooksPath .githooks
|
||||||
|
echo "hook ligado: git push passa a rodar scripts/verificar.sh (desligue com: git config --unset core.hooksPath)"
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""Gera a logo do Guará: a cabeça do lobo-guará, de frente, recortada das
|
|
||||||
trilhas de um disco.
|
|
||||||
|
|
||||||
As trilhas são arcos concêntricos com centro abaixo do focinho. Na metade
|
|
||||||
direita estão inteiras (dados recuperados) e na esquerda quebradas em
|
|
||||||
fragmentos (dados perdidos). Focinho e olhos usam a cor do texto. As cores
|
|
||||||
são as do app (apps/gui/ui/app.css): --accent e --accent-2 no tema claro e
|
|
||||||
seus equivalentes no escuro, trocados por prefers-color-scheme.
|
|
||||||
|
|
||||||
Uso: python3 scripts/make-logo.py [pasta] (padrão: apps/gui/ui)
|
|
||||||
Grava guara-logo.svg e guara.svg (mesma arte; o segundo é o ícone).
|
|
||||||
O PNG para os ícones do app (src-tauri/icons/source.png) sai desta arte
|
|
||||||
renderizada em 1024x1024.
|
|
||||||
"""
|
|
||||||
import os, sys
|
|
||||||
|
|
||||||
HEAD = ("M50 95 C46 88 43 80 40 74 C33 70 25 64 22 56 L14 6 L36 30 "
|
|
||||||
"C40 28 45 27 50 27 C55 27 60 28 64 30 L86 6 L78 56 "
|
|
||||||
"C75 64 67 70 60 74 C57 80 54 88 50 95 Z")
|
|
||||||
STYLE = (".a{stroke:#0f766e}.b{stroke:#14b8a6}.t{fill:#1d1d1f}"
|
|
||||||
"@media (prefers-color-scheme:dark){.a{stroke:#2dd4bf}.b{stroke:#5eead4}.t{fill:#f5f5f7}}")
|
|
||||||
|
|
||||||
|
|
||||||
def tracks():
|
|
||||||
out = []
|
|
||||||
for i, r in enumerate(range(7, 104, 7)):
|
|
||||||
top, bot = 100 - r, 100 + r
|
|
||||||
out.append(f'<path class="a" d="M50 {top}A{r} {r} 0 0 1 50 {bot}"/>')
|
|
||||||
dash = f"{3 + i % 3 * 3} {3 + (i * 5) % 4}"
|
|
||||||
out.append(f'<path class="b" d="M50 {top}A{r} {r} 0 0 0 50 {bot}" '
|
|
||||||
f'stroke-dasharray="{dash}" stroke-dashoffset="{i * 3}"/>')
|
|
||||||
return "".join(out)
|
|
||||||
|
|
||||||
|
|
||||||
def svg():
|
|
||||||
return (
|
|
||||||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" role="img" aria-label="Guará">'
|
|
||||||
f'<style>{STYLE}</style>'
|
|
||||||
f'<defs><clipPath id="g-head"><path d="{HEAD}"/></clipPath></defs>'
|
|
||||||
f'<g clip-path="url(#g-head)" fill="none" stroke-width="4.2">{tracks()}'
|
|
||||||
# o focinho é a ponta da própria cabeça (recortada pelo mesmo contorno),
|
|
||||||
# então nenhuma trilha escapa pelas laterais
|
|
||||||
'<rect class="t" stroke="none" x="0" y="74" width="100" height="30"/></g>'
|
|
||||||
'<path class="t" d="M37 50Q42 47 46 52Q41 53 37 50ZM63 50Q58 47 54 52Q59 53 63 50Z"/>'
|
|
||||||
'</svg>\n'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
out = sys.argv[1] if len(sys.argv) > 1 else "apps/gui/ui"
|
|
||||||
for name in ("guara-logo.svg", "guara.svg"):
|
|
||||||
with open(os.path.join(out, name), "w") as f:
|
|
||||||
f.write(svg())
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Verificação local: roda o mesmo que o CI roda, antes de você dar push.
|
||||||
|
#
|
||||||
|
# scripts/verificar.sh rápido (~1 min): formatação, clippy, tradução, scripts, workflows
|
||||||
|
# scripts/verificar.sh --completo inclui os testes do workspace e o cargo audit
|
||||||
|
#
|
||||||
|
# O CI leva de 5 a 30 minutos por execução e roda em 3 sistemas; quase tudo que o faz falhar
|
||||||
|
# aparece aqui em segundos. Se isto passa, o CI só deve revelar o que é próprio dele (Windows,
|
||||||
|
# macOS, imagens baixadas, apt do runner).
|
||||||
|
set -uo pipefail
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
completo=0
|
||||||
|
[ "${1:-}" = "--completo" ] && completo=1
|
||||||
|
falhas=()
|
||||||
|
passo() { # passo "nome" comando...
|
||||||
|
local nome="$1"; shift
|
||||||
|
printf '\n\033[1m== %s\033[0m\n' "$nome"
|
||||||
|
if "$@"; then printf '\033[32mok\033[0m %s\n' "$nome"; else printf '\033[31mFALHOU\033[0m %s\n' "$nome"; falhas+=("$nome"); fi
|
||||||
|
}
|
||||||
|
|
||||||
|
passo "formatação (cargo fmt)" cargo fmt --all -- --check
|
||||||
|
# as mesmas flags do CI: avisos viram erro, inclusive nos testes
|
||||||
|
passo "clippy (workspace, todos os alvos)" env RUSTFLAGS="-D warnings" cargo clippy --workspace --all-targets
|
||||||
|
passo "cobertura da tradução da interface" node scripts/check-ui-i18n.mjs
|
||||||
|
passo "teste do latest.json" python3 -B scripts/test_make_latest_json.py
|
||||||
|
passo "sintaxe dos scripts bash" bash -c 'for f in scripts/*.sh .githooks/*; do bash -n "$f" || exit 1; done'
|
||||||
|
passo "workflows (YAML válido)" python3 -c "
|
||||||
|
import glob, yaml
|
||||||
|
for f in glob.glob('.github/workflows/*.yml'):
|
||||||
|
yaml.safe_load(open(f))
|
||||||
|
"
|
||||||
|
if [ -f apps/gui/src-tauri/Cargo.toml ] && pkg-config --exists webkit2gtk-4.1 2>/dev/null; then
|
||||||
|
passo "app desktop (cargo check)" env RUSTFLAGS="" cargo check --manifest-path apps/gui/src-tauri/Cargo.toml
|
||||||
|
else
|
||||||
|
printf '\n(app desktop: pulado, faltam as bibliotecas do WebKitGTK; o CI compila)\n'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$completo" = 1 ]; then
|
||||||
|
passo "testes (cargo test --workspace)" cargo test --workspace
|
||||||
|
passo "auditoria de dependências (cargo audit)" cargo audit
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '\n'
|
||||||
|
if [ ${#falhas[@]} -eq 0 ]; then
|
||||||
|
printf '\033[32mtudo certo\033[0m: pode dar push.\n'
|
||||||
|
else
|
||||||
|
printf '\033[31mfalhou:\033[0m %s\n' "${falhas[*]}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||