alexandremoraisdarosa commited on
Commit
c1a7f7f
·
verified ·
1 Parent(s): 7173f4e

<!DOCTYPE html>

Browse files

<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Matriz de Análise de Vínculos (Layout Corrigido)</title>
<!-- Adicionado para que o estilo Tailwind CSS funcione -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
/* Estilos para o indicador de nota, botão de apagar e impressão */
.note-indicator {
position: absolute; top: 4px; right: 4px; width: 8px; height: 8px;
background-color: #0d6efd; /* Cor para o indicador */
border-radius: 50%;
display: none;
}
.has-note .note-indicator {
display: block;
}
.btn-delete {
visibility: hidden;
opacity: 0.6;
}
th:hover .btn-delete {
visibility: visible;
}


@media
print {
body { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.no-print { display: none; }
table, th, td { border-color: #999 !important; }
}
</style>
</head>
<body class="bg-gray-100 p-4 sm:p-8 font-sans">
<div class="max-w-7xl mx-auto bg-white p-6 rounded-lg shadow-md">
<h1 class="text-2xl font-bold text-center text-gray-800 mb-4">Matriz de Análise de Vínculos</h1>

<!-- Controles -->
<div class="flex flex-wrap justify-between items-center gap-4 mb-6 pb-4 border-b no-print">
<div class="flex gap-2">
<input type="text" id="newEntityInput" placeholder="Nome do Réu, Prova, Testemunha..." class="border border-gray-300 rounded px-4 py-2 w-72 focus:ring-2 focus:ring-blue-400 outline-none transition" />
<button id="addEntityBtn" class="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded transition duration-200">➕ Adicionar</button>
</div>
<div class="flex gap-2">
<button onclick="exportMatrix()" class="bg-purple-600 hover:bg-purple-700 text-white font-semibold py-2 px-4 rounded transition duration-200">📤 Exportar</button>
<button onclick="importMatrix()" class="bg-indigo-600 hover:bg-indigo-700 text-white font-semibold py-2 px-4 rounded transition duration-200">📥 Importar</button>
<button onclick="window.print()" class="bg-green-600 hover:bg-green-700 text-white font-semibold py-2 px-4 rounded transition duration-200">🖨️ Imprimir / Salvar PDF</button>
</div>
</div>

<!-- Tabela -->
<div class="overflow-x-auto">
<table id="matrix-table" class="min-w-full border-collapse"></table>
</div>
</div>

<!-- Modal de Anotações -->
<div id="note-modal" class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50">
<div class="bg-white rounded-lg shadow-lg max-w-lg w-full p-6">
<h2 class="text-xl font-bold mb-2">📝 Anotação do Vínculo</h2>
<p id="note-context" class="mb-4 text-gray-700"></p>
<textarea id="note-textarea" placeholder="Escreva aqui a fundamentação do vínculo..." class="w-full p-3 border border-gray-300 rounded-md mb-4 h-32 focus:ring-2 focus:ring-blue-400 outline-none transition"></textarea>
<div class="flex justify-end gap-2">
<button onclick="closeNoteModal()" class="px-4 py-2 bg-gray-300 hover:bg-gray-400 rounded-md transition">Cancelar</button>
<button onclick="saveNote()" class="px-4 py-2 bg-green-500 hover:bg-green-600 text-white rounded-md transition">💾 Salvar</button>
</div>
</div>
</div>

<!-- Input oculto para importação -->
<input type="file" id="importInput" accept=".json" class="hidden" />

<script>
document.addEventListener('DOMContentLoaded', () => {
const matrixTable = document.getElementById('matrix-table');
const addEntityBtn = document.getElementById('addEntityBtn');
const newEntityInput = document.getElementById('newEntityInput');
const importInput = document.getElementById('importInput');
const noteModal = document.getElementById('note-modal');
const noteTextarea = document.getElementById('note-textarea');
const noteContext = document.getElementById('note-context');
let currentNoteCell = null;

const RELATION_STATES = [
{ class: 'bg-green-100 text-green-800', symbol: '✔', tooltip: 'Vínculo Confirmado' },
{ class: 'bg-yellow-100 text-yellow-800', symbol: '∼', tooltip: 'Vínculo Possível' },
{ class: 'bg-red-100 text-red-800', symbol: '✖', tooltip: 'Vínculo Excluído' },
{ class: 'bg-gray-100 text-gray-600', symbol: '•', tooltip: 'Não Analisado' }
];

let data = { entities: [], relations: {} };

function saveData() {
localStorage.setItem('triangularMatrixData', JSON.stringify(data));
}

function loadData() {
const savedData = localStorage.getItem('triangularMatrixData');
if (savedData) {
try { data = JSON.parse(savedData); }
catch (e) { console.error("Erro ao carregar dados."); }
} else {
data = {
entities: ["Réu João", "Testemunha Maria", "Laudo A", "Réu Pedro"],
relations: { '1-0': { state: 2 }, '2-0': { state: 0, note: 'Laudo confirma digital do Réu João.' }, '3-1': { state: 1 } }
};
}
}

/**
* FUNÇÃO CORRIGIDA PARA O LAYOUT TRIANGULAR
*/
function renderMatrix() {
matrixTable.innerHTML = '';
const { entities } = data;

if (entities.length < 2) {
matrixTable.innerHTML = '<tr><td class="p-4 text-center text-gray-500">Adicione pelo menos duas entidades para iniciar a matriz.</td></tr>';
return;
}

// 1. Criar as linhas do corpo da matriz (cabeçalhos de linha + células)
for (let rowIndex = 1; rowIndex < entities.length; rowIndex++) {
const tr = document.createElement('tr');

// Cabeçalho da Linha (Eixo Y, à esquerda)
const rowTh = document.createElement('th');
rowTh.className = 'min-w-[200px] bg-gray-50 border-b border-gray-300 p-2 text-right pr-4 whitespace-nowrap relative';
rowTh.innerHTML = `<span class="mr-1">${entities[rowIndex]}</span><span class="btn-delete text-red-500 hover:text-red-700 cursor-pointer text-sm" data-index="${rowIndex}">🗑️</span>`;
tr.appendChild(rowTh);

// Células de Relação
for (let colIndex = 0; colIndex < rowIndex; colIndex++) {
const td = document.createElement('td');
td.dataset.row = rowIndex;
td.dataset.col = colIndex;

const key = `${rowIndex}-${colIndex}`;
const relation = data.relations[key] || { state: 3, note: '' };
const state = RELATION_STATES[relation.state];

td.className = `relation-cell border-b border-gray-300 text-center cursor-pointer relative text-3xl w-16 h-16 ${state.class}`;
td.setAttribute('title', state.tooltip);
td.innerHTML = `${state.symbol}<span class="note-indicator"></span>`;

if (relation.note) {
td.classList.add('has-note');
}
tr.appendChild(td);
}
matrixTable.appendChild(tr);
}

// 2. Criar a última linha com os cabeçalhos das colunas (Eixo X, no fundo)
const footerRow = document.createElement('tr');

// Canto inferior esquerdo (vazio)
footerRow.appendChild(document.createElement('th'));

// Cabeçalhos da Coluna
for (let i = 0; i < entities.length - 1; i++) {
const th = document.createElement('th');
th.className = 'bg-gray-50 border-gray-300 p-2 text-center align-top relative';
th.innerHTML = `<span class="mr-1">${entities[i]}</span><span class="btn-delete text-red-500 hover:text-red-700 cursor-pointer text-sm" data-index="${i}">🗑️</span>`;
footerRow.appendChild(th);
}
matrixTable.appendChild(footerRow);

saveData();
}

function addEntity() {
const name = newEntityInput.value.trim();
if (!name) { alert('Por favor, digite o nome da entidade.'); return; }
if (data.entities.includes(name)) { alert('Essa entidade já está na lista.'); return; }
data.entities.push(name);
newEntityInput.value = '';
renderMatrix();
}

function deleteEntity(index) {
const entityName = data.entities[index];
if (!confirm(`Tem certeza que deseja remover "${entityName}"? Todos os seus vínculos serão perdidos.`)) return;
data.entities.splice(index, 1);
const newRelations = {};
for (const key in data.relations) {
const [r, c] = key.split('-').map(Number);
if (r === index || c === index) continue;
let newR = r > index ? r - 1 : r;
let newC = c > index ? c - 1 : c;
newRelations[`${newR}-${newC}`] = data.relations[key];
}
data.relations = newRelations;
renderMatrix();
}

function getRelationKey(cell) { return `${cell.dataset.row}-${cell.dataset.col}`; }

window.openNoteModal = (cell) => {
currentNoteCell = cell;
const key = getRelationKey(cell);
const [row, col] = key.split('-').map(Number);
noteContext.innerHTML = `Anotação entre: <strong>"${data.entities[row]}"</strong> e <strong>"${data.entities[col]}"</strong>`;
noteTextarea.value = data.relations[ke

Files changed (4) hide show
  1. README.md +8 -5
  2. index.html +64 -19
  3. script.js +209 -0
  4. style.css +29 -24
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Vinculo Matrix Analyzer
3
- emoji: 👀
4
- colorFrom: pink
5
- colorTo: blue
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
  ---
2
+ title: Vinculo Matrix Analyzer 🔍
3
+ colorFrom: purple
4
+ colorTo: yellow
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://huggingface.co/deepsite).
index.html CHANGED
@@ -1,19 +1,64 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="pt-BR">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Matriz de Análise de Vínculos</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script>
9
+ tailwind.config = {
10
+ theme: {
11
+ extend: {
12
+ colors: {
13
+ primary: '#3b82f6',
14
+ secondary: '#8b5cf6',
15
+ }
16
+ }
17
+ }
18
+ }
19
+ </script>
20
+ <link rel="stylesheet" href="style.css">
21
+ </head>
22
+ <body class="bg-gray-100 p-4 sm:p-8 font-sans">
23
+ <div class="max-w-7xl mx-auto bg-white p-6 rounded-lg shadow-md">
24
+ <h1 class="text-2xl font-bold text-center text-gray-800 mb-4">Matriz de Análise de Vínculos</h1>
25
+
26
+ <!-- Controles -->
27
+ <div class="flex flex-wrap justify-between items-center gap-4 mb-6 pb-4 border-b no-print">
28
+ <div class="flex gap-2">
29
+ <input type="text" id="newEntityInput" placeholder="Nome do Réu, Prova, Testemunha..." class="border border-gray-300 rounded px-4 py-2 w-72 focus:ring-2 focus:ring-primary outline-none transition" />
30
+ <button id="addEntityBtn" class="bg-primary hover:bg-primary-dark text-white font-semibold py-2 px-4 rounded transition duration-200">➕ Adicionar</button>
31
+ </div>
32
+ <div class="flex gap-2">
33
+ <button onclick="exportMatrix()" class="bg-secondary hover:bg-secondary-dark text-white font-semibold py-2 px-4 rounded transition duration-200">📤 Exportar</button>
34
+ <button onclick="importMatrix()" class="bg-indigo-600 hover:bg-indigo-700 text-white font-semibold py-2 px-4 rounded transition duration-200">📥 Importar</button>
35
+ <button onclick="window.print()" class="bg-green-600 hover:bg-green-700 text-white font-semibold py-2 px-4 rounded transition duration-200">🖨️ Imprimir / Salvar PDF</button>
36
+ </div>
37
+ </div>
38
+
39
+ <!-- Tabela -->
40
+ <div class="overflow-x-auto">
41
+ <table id="matrix-table" class="min-w-full border-collapse"></table>
42
+ </div>
43
+ </div>
44
+
45
+ <!-- Modal de Anotações -->
46
+ <div id="note-modal" class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50">
47
+ <div class="bg-white rounded-lg shadow-lg max-w-lg w-full p-6">
48
+ <h2 class="text-xl font-bold mb-2">📝 Anotação do Vínculo</h2>
49
+ <p id="note-context" class="mb-4 text-gray-700"></p>
50
+ <textarea id="note-textarea" placeholder="Escreva aqui a fundamentação do vínculo..." class="w-full p-3 border border-gray-300 rounded-md mb-4 h-32 focus:ring-2 focus:ring-primary outline-none transition"></textarea>
51
+ <div class="flex justify-end gap-2">
52
+ <button onclick="closeNoteModal()" class="px-4 py-2 bg-gray-300 hover:bg-gray-400 rounded-md transition">Cancelar</button>
53
+ <button onclick="saveNote()" class="px-4 py-2 bg-green-500 hover:bg-green-600 text-white rounded-md transition">💾 Salvar</button>
54
+ </div>
55
+ </div>
56
+ </div>
57
+
58
+ <!-- Input oculto para importação -->
59
+ <input type="file" id="importInput" accept=".json" class="hidden" />
60
+
61
+ <script src="script.js"></script>
62
+ <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
63
+ </body>
64
+ </html>
script.js ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ document.addEventListener('DOMContentLoaded', () => {
2
+ const matrixTable = document.getElementById('matrix-table');
3
+ const addEntityBtn = document.getElementById('addEntityBtn');
4
+ const newEntityInput = document.getElementById('newEntityInput');
5
+ const importInput = document.getElementById('importInput');
6
+ const noteModal = document.getElementById('note-modal');
7
+ const noteTextarea = document.getElementById('note-textarea');
8
+ const noteContext = document.getElementById('note-context');
9
+ let currentNoteCell = null;
10
+
11
+ const RELATION_STATES = [
12
+ { class: 'bg-green-100 text-green-800', symbol: '✔', tooltip: 'Vínculo Confirmado' },
13
+ { class: 'bg-yellow-100 text-yellow-800', symbol: '∼', tooltip: 'Vínculo Possível' },
14
+ { class: 'bg-red-100 text-red-800', symbol: '✖', tooltip: 'Vínculo Excluído' },
15
+ { class: 'bg-gray-100 text-gray-600', symbol: '•', tooltip: 'Não Analisado' }
16
+ ];
17
+
18
+ let data = { entities: [], relations: {} };
19
+
20
+ function saveData() {
21
+ localStorage.setItem('triangularMatrixData', JSON.stringify(data));
22
+ }
23
+
24
+ function loadData() {
25
+ const savedData = localStorage.getItem('triangularMatrixData');
26
+ if (savedData) {
27
+ try { data = JSON.parse(savedData); }
28
+ catch (e) { console.error("Erro ao carregar dados."); }
29
+ } else {
30
+ data = {
31
+ entities: ["Réu João", "Testemunha Maria", "Laudo A", "Réu Pedro"],
32
+ relations: { '1-0': { state: 2 }, '2-0': { state: 0, note: 'Laudo confirma digital do Réu João.' }, '3-1': { state: 1 } }
33
+ };
34
+ }
35
+ }
36
+
37
+ function renderMatrix() {
38
+ matrixTable.innerHTML = '';
39
+ const { entities } = data;
40
+
41
+ if (entities.length < 2) {
42
+ matrixTable.innerHTML = '<tr><td class="p-4 text-center text-gray-500">Adicione pelo menos duas entidades para iniciar a matriz.</td></tr>';
43
+ return;
44
+ }
45
+
46
+ // 1. Criar as linhas do corpo da matriz (cabeçalhos de linha + células)
47
+ for (let rowIndex = 1; rowIndex < entities.length; rowIndex++) {
48
+ const tr = document.createElement('tr');
49
+
50
+ // Cabeçalho da Linha (Eixo Y, à esquerda)
51
+ const rowTh = document.createElement('th');
52
+ rowTh.className = 'min-w-[200px] bg-gray-50 border-b border-gray-300 p-2 text-right pr-4 whitespace-nowrap relative';
53
+ rowTh.innerHTML = `<span class="mr-1">${entities[rowIndex]}</span><span class="btn-delete text-red-500 hover:text-red-700 cursor-pointer text-sm" data-index="${rowIndex}">🗑️</span>`;
54
+ tr.appendChild(rowTh);
55
+
56
+ // Células de Relação
57
+ for (let colIndex = 0; colIndex < rowIndex; colIndex++) {
58
+ const td = document.createElement('td');
59
+ td.dataset.row = rowIndex;
60
+ td.dataset.col = colIndex;
61
+
62
+ const key = `${rowIndex}-${colIndex}`;
63
+ const relation = data.relations[key] || { state: 3, note: '' };
64
+ const state = RELATION_STATES[relation.state];
65
+
66
+ td.className = `relation-cell border-b border-gray-300 text-center cursor-pointer relative text-3xl w-16 h-16 ${state.class}`;
67
+ td.setAttribute('title', state.tooltip);
68
+ td.innerHTML = `${state.symbol}<span class="note-indicator"></span>`;
69
+
70
+ if (relation.note) {
71
+ td.classList.add('has-note');
72
+ }
73
+ tr.appendChild(td);
74
+ }
75
+ matrixTable.appendChild(tr);
76
+ }
77
+
78
+ // 2. Criar a última linha com os cabeçalhos das colunas (Eixo X, no fundo)
79
+ const footerRow = document.createElement('tr');
80
+
81
+ // Canto inferior esquerdo (vazio)
82
+ footerRow.appendChild(document.createElement('th'));
83
+
84
+ // Cabeçalhos da Coluna
85
+ for (let i = 0; i < entities.length - 1; i++) {
86
+ const th = document.createElement('th');
87
+ th.className = 'bg-gray-50 border-gray-300 p-2 text-center align-top relative';
88
+ th.innerHTML = `<span class="mr-1">${entities[i]}</span><span class="btn-delete text-red-500 hover:text-red-700 cursor-pointer text-sm" data-index="${i}">🗑️</span>`;
89
+ footerRow.appendChild(th);
90
+ }
91
+ matrixTable.appendChild(footerRow);
92
+
93
+ saveData();
94
+ }
95
+
96
+ function addEntity() {
97
+ const name = newEntityInput.value.trim();
98
+ if (!name) { alert('Por favor, digite o nome da entidade.'); return; }
99
+ if (data.entities.includes(name)) { alert('Essa entidade já está na lista.'); return; }
100
+ data.entities.push(name);
101
+ newEntityInput.value = '';
102
+ renderMatrix();
103
+ }
104
+
105
+ function deleteEntity(index) {
106
+ const entityName = data.entities[index];
107
+ if (!confirm(`Tem certeza que deseja remover "${entityName}"? Todos os seus vínculos serão perdidos.`)) return;
108
+ data.entities.splice(index, 1);
109
+ const newRelations = {};
110
+ for (const key in data.relations) {
111
+ const [r, c] = key.split('-').map(Number);
112
+ if (r === index || c === index) continue;
113
+ let newR = r > index ? r - 1 : r;
114
+ let newC = c > index ? c - 1 : c;
115
+ newRelations[`${newR}-${newC}`] = data.relations[key];
116
+ }
117
+ data.relations = newRelations;
118
+ renderMatrix();
119
+ }
120
+
121
+ function getRelationKey(cell) { return `${cell.dataset.row}-${cell.dataset.col}`; }
122
+
123
+ window.openNoteModal = (cell) => {
124
+ currentNoteCell = cell;
125
+ const key = getRelationKey(cell);
126
+ const [row, col] = key.split('-').map(Number);
127
+ noteContext.innerHTML = `Anotação entre: <strong>"${data.entities[row]}"</strong> e <strong>"${data.entities[col]}"</strong>`;
128
+ noteTextarea.value = data.relations[key]?.note || '';
129
+ noteModal.classList.remove('hidden');
130
+ noteTextarea.focus();
131
+ };
132
+
133
+ window.closeNoteModal = () => {
134
+ noteModal.classList.add('hidden');
135
+ currentNoteCell = null;
136
+ };
137
+
138
+ window.saveNote = () => {
139
+ if (!currentNoteCell) return;
140
+ const key = getRelationKey(currentNoteCell);
141
+ const note = noteTextarea.value.trim();
142
+ if (!data.relations[key]) data.relations[key] = { state: 3, note: '' };
143
+ data.relations[key].note = note;
144
+ if (note) currentNoteCell.classList.add('has-note');
145
+ else currentNoteCell.classList.remove('has-note');
146
+ saveData();
147
+ closeNoteModal();
148
+ };
149
+
150
+ window.exportMatrix = () => {
151
+ const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
152
+ const a = document.createElement('a');
153
+ a.href = URL.createObjectURL(blob);
154
+ a.download = `matriz-vinculos-${new Date().toISOString().slice(0,10)}.json`;
155
+ a.click();
156
+ URL.revokeObjectURL(a.href);
157
+ };
158
+
159
+ window.importMatrix = () => { importInput.click(); };
160
+
161
+ importInput.addEventListener('change', (e) => {
162
+ const file = e.target.files[0];
163
+ if (!file) return;
164
+ const reader = new FileReader();
165
+ reader.onload = () => {
166
+ try {
167
+ const importedData = JSON.parse(reader.result);
168
+ if (importedData.entities && importedData.relations) {
169
+ data = importedData;
170
+ renderMatrix();
171
+ alert('✅ Matriz importada com sucesso!');
172
+ } else {
173
+ alert('❌ Erro ao importar: O arquivo JSON não tem a estrutura esperada.');
174
+ }
175
+ } catch (err) { alert('❌ Erro ao importar: formato de arquivo inválido.'); }
176
+ };
177
+ reader.readAsText(file);
178
+ e.target.value = '';
179
+ });
180
+
181
+ addEntityBtn.addEventListener('click', addEntity);
182
+ newEntityInput.addEventListener('keypress', e => { if (e.key === 'Enter') addEntity(); });
183
+
184
+ matrixTable.addEventListener('click', e => {
185
+ const cell = e.target.closest('.relation-cell');
186
+ if (cell) {
187
+ const key = getRelationKey(cell);
188
+ if (!data.relations[key]) data.relations[key] = { state: 3, note: '' };
189
+ data.relations[key].state = (data.relations[key].state + 1) % RELATION_STATES.length;
190
+ renderMatrix();
191
+ return;
192
+ }
193
+ const deleteBtn = e.target.closest('.btn-delete');
194
+ if (deleteBtn) {
195
+ deleteEntity(parseInt(deleteBtn.dataset.index));
196
+ }
197
+ });
198
+
199
+ matrixTable.addEventListener('contextmenu', e => {
200
+ const cell = e.target.closest('.relation-cell');
201
+ if (cell) {
202
+ e.preventDefault();
203
+ openNoteModal(cell);
204
+ }
205
+ });
206
+
207
+ loadData();
208
+ renderMatrix();
209
+ });
style.css CHANGED
@@ -1,28 +1,33 @@
1
- body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
 
 
 
 
 
 
 
4
  }
5
-
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
9
  }
10
-
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
  }
17
-
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
24
- }
25
-
26
- .card p:last-child {
27
- margin-bottom: 0;
28
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Estilos para o indicador de nota, botão de apagar e impressão */
2
+ .note-indicator {
3
+ position: absolute;
4
+ top: 4px;
5
+ right: 4px;
6
+ width: 8px;
7
+ height: 8px;
8
+ background-color: #3b82f6;
9
+ border-radius: 50%;
10
+ display: none;
11
  }
12
+ .has-note .note-indicator {
13
+ display: block;
 
 
14
  }
15
+ .btn-delete {
16
+ visibility: hidden;
17
+ opacity: 0.6;
 
 
 
18
  }
19
+ th:hover .btn-delete {
20
+ visibility: visible;
 
 
 
 
 
 
 
 
 
21
  }
22
+ @media print {
23
+ body {
24
+ -webkit-print-color-adjust: exact;
25
+ print-color-adjust: exact;
26
+ }
27
+ .no-print {
28
+ display: none;
29
+ }
30
+ table, th, td {
31
+ border-color: #999 !important;
32
+ }
33
+ }