Planificacion y flashcard

This commit is contained in:
Tatiana Villa 2026-05-10 17:28:08 +02:00
parent 29f818bf56
commit 2d9f9dd292
5 changed files with 188 additions and 1 deletions

View File

@ -77,7 +77,7 @@ public class SecurityConfig {
// Panel de administración // Panel de administración
.requestMatchers("/admin/**").hasRole("ADMIN") .requestMatchers("/admin/**").hasRole("ADMIN")
// Contenido de pago // Contenido de pago
.requestMatchers("/curso", "/curso/**", "/planning", "/flashcards.html", "/flashcards/**", "/api/**").hasAnyRole("PAGADO", "ADMIN") .requestMatchers("/curso", "/curso/**", "/planning", "/esquema.html", "/flashcards.html", "/flashcards/**", "/api/**").hasAnyRole("PAGADO", "ADMIN")
// Cualquier otra ruta requiere autenticación // Cualquier otra ruta requiere autenticación
.anyRequest().authenticated() .anyRequest().authenticated()
) )

View File

@ -0,0 +1,71 @@
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: Arial, Helvetica, sans-serif; font-size: 11pt; color: #e8eaed; background: #1a1d23; min-height: 100vh; }
header {
background: #0d1117; color: #e8eaed;
padding: 14px 24px; display: flex; align-items: center; gap: 16px;
border-bottom: 1px solid #30363d;
}
header a { color: #58a6ff; font-size: 9.5pt; text-decoration: none; white-space: nowrap; }
header a:hover { color: #e8eaed; text-decoration: underline; }
header h1 { font-size: 13pt; font-weight: bold; line-height: 1.3; flex: 1; }
header .bloque-badge {
background: #1f6feb; color: #fff; font-size: 9pt;
padding: 3px 10px; border-radius: 12px; white-space: nowrap;
}
main { max-width: 680px; margin: 28px auto; padding: 0 16px; }
.nav-temas { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 20px; }
.nav-temas a {
font-size: 9pt; padding: 4px 10px; border-radius: 14px;
background: #21262d; color: #58a6ff; text-decoration: none; border: 1px solid #30363d;
}
.nav-temas a:hover, .nav-temas a.activo { background: #1f6feb; color: #fff; border-color: #1f6feb; }
.card {
background: #161b22; border-radius: 8px; box-shadow: 0 2px 12px rgba(0,0,0,.4);
overflow: hidden; border: 1px solid #30363d;
}
.card-header {
background: #0d1117; padding: 16px 20px; border-bottom: 1px solid #30363d;
}
.card-header h2 { font-size: 12pt; color: #58a6ff; margin-bottom: 4px; line-height: 1.4; }
.card-header p { font-size: 9pt; color: #8b949e; }
ul.epigrafes { list-style: none; padding: 0; }
ul.epigrafes li { border-bottom: 1px solid #21262d; }
ul.epigrafes li:last-child { border-bottom: none; }
ul.epigrafes li a {
display: block; padding: 10px 20px;
font-size: 10pt; color: #c9d1d9; text-decoration: none; line-height: 1.35;
}
ul.epigrafes li a:hover { background: #21262d; color: #f85149; padding-left: 28px; transition: padding .12s; }
.footer-btns { margin-top: 20px; display: flex; gap: 10px; flex-wrap: wrap; }
.btn {
display: inline-block; padding: 9px 18px; border-radius: 6px;
font-size: 10pt; text-decoration: none; cursor: pointer; border: none; font-family: inherit;
}
.btn-primary { background: #1f6feb; color: #fff; }
.btn-primary:hover { background: #388bfd; }
.btn-secondary { background: #21262d; color: #58a6ff; border: 1px solid #30363d; }
.btn-secondary:hover { background: #30363d; }
#no-tema { text-align: center; padding: 60px 20px; color: #8b949e; }
/* Secciones principales desplegables */
ul.epigrafes li.seccion-principal { border-bottom: 1px solid #30363d; }
ul.epigrafes li.seccion-principal details summary {
display: block; padding: 10px 20px;
font-size: 10pt; font-weight: bold; color: #58a6ff;
cursor: pointer; line-height: 1.35;
background: #0d1117; user-select: none;
}
ul.epigrafes li.seccion-principal details summary::-webkit-details-marker { display: none; }
ul.epigrafes li.seccion-principal details summary::before {
content: '▶\00a0'; font-size: 8pt; color: #388bfd;
}
ul.epigrafes li.seccion-principal details[open] summary::before { content: '▼\00a0'; }
ul.epigrafes li.seccion-principal details summary:hover { background: #21262d; color: #f85149; }
ul.epigrafes li.seccion-principal details ul { list-style: none; padding: 0; }
ul.epigrafes li.seccion-principal details ul li { border-bottom: 1px solid #21262d; }
ul.epigrafes li.seccion-principal details ul li:last-child { border-bottom: none; }
ul.epigrafes li.seccion-principal details ul li a {
display: block; padding: 8px 20px 8px 36px;
font-size: 9.5pt; color: #8b949e; text-decoration: none; line-height: 1.35;
}
ul.epigrafes li.seccion-principal details ul li a:hover { background: #21262d; color: #f85149; }

View File

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Esquema de tema · TAI</title>
<link rel="stylesheet" href="css/esquema.css">
</head>
<body>
<header>
<a href="/planning">← Planning</a>
<h1 id="header-titulo">Esquema del tema</h1>
<span class="bloque-badge" id="header-badge"></span>
</header>
<main>
<div class="nav-temas" id="nav-temas"></div>
<div class="card" id="card" style="display:none">
<div class="card-header">
<h2 id="card-titulo"></h2>
<p id="card-subtitulo"></p>
</div>
<ul class="epigrafes" id="card-lista"></ul>
</div>
<div id="no-tema">Selecciona un tema en el planning o en la navegación superior.</div>
<div class="footer-btns" id="footer-btns" style="display:none">
<a class="btn btn-primary" id="btn-md" href="#">📄 Abrir apunte completo</a>
<a class="btn btn-secondary" href="/planning">← Volver al planning</a>
</div>
</main>
<script src="js/temas-data.js"></script>
<script src="js/esquema.js"></script>
</body>
</html>

View File

@ -0,0 +1,77 @@
function render(key) {
const t = TEMAS[key];
const card = document.getElementById('card');
const noTema = document.getElementById('no-tema');
const footerBtns = document.getElementById('footer-btns');
if (!t) { card.style.display='none'; noTema.style.display=''; footerBtns.style.display='none'; return; }
document.title = key + '. ' + t.titulo.slice(0,60) + ' · TAI';
document.getElementById('header-titulo').textContent = t.titulo;
document.getElementById('header-badge').textContent = 'Bloque ' + t.bloque + ' · Tema ' + t.tema;
document.getElementById('card-titulo').textContent = key + '. ' + t.titulo;
document.getElementById('card-subtitulo').textContent = t.epigrafes.length + ' epígrafes';
const ul = document.getElementById('card-lista');
ul.innerHTML = '';
const fileParts = t.file.split('/');
const relPath = fileParts.slice(-2).join('/'); // 'bloqueN/temaN.md'
const verUrl = 'ver.html?f=' + relPath + '&tema=' + key;
let currentSubList = null;
t.epigrafes.forEach(function(h) {
const isMainSection = /^\d+\.\s/.test(h);
if (isMainSection) {
const li = document.createElement('li');
li.className = 'seccion-principal';
const details = document.createElement('details');
const summary = document.createElement('summary');
summary.textContent = h;
details.appendChild(summary);
currentSubList = document.createElement('ul');
details.appendChild(currentSubList);
li.appendChild(details);
ul.appendChild(li);
} else if (currentSubList) {
const li = document.createElement('li');
const a = document.createElement('a');
a.href = verUrl;
a.target = '_blank';
a.textContent = h;
li.appendChild(a);
currentSubList.appendChild(li);
} else {
const li = document.createElement('li');
const a = document.createElement('a');
a.href = verUrl;
a.target = '_blank';
a.textContent = h;
li.appendChild(a);
ul.appendChild(li);
}
});
document.getElementById('btn-md').href = verUrl;
card.style.display = '';
noTema.style.display = 'none';
footerBtns.style.display = '';
document.querySelectorAll('.nav-temas a').forEach(function(a) {
a.classList.toggle('activo', a.dataset.key === key);
});
}
function buildNav() {
const nav = document.getElementById('nav-temas');
[1,2,3,4].forEach(function(b) {
Object.keys(TEMAS).filter(k => TEMAS[k].bloque === b).sort().forEach(function(key) {
const a = document.createElement('a');
a.href = '?tema=' + key;
a.textContent = key;
a.dataset.key = key;
nav.appendChild(a);
});
});
}
buildNav();
const temaParam = new URLSearchParams(window.location.search).get('tema');
if (temaParam) render(temaParam);

File diff suppressed because one or more lines are too long