oposiciones

This commit is contained in:
Tatiana Villa 2026-04-24 14:22:31 +02:00
parent a1f4d17c93
commit 6f562dadfc
14 changed files with 775 additions and 0 deletions

View File

@ -546,6 +546,120 @@ a:hover { text-decoration: underline; }
}
.exam-pdf-link:hover { background: color-mix(in srgb, var(--accent) 12%, transparent); border-color: var(--accent); }
/* ── Repaso de fallos ────────────────────────────────────────── */
.repaso-wrap {
margin-top: 2rem;
border-top: 1px solid var(--border);
padding-top: 1.5rem;
}
.repaso-titulo {
font-size: 1.1rem;
color: var(--warning);
margin-bottom: .5rem;
display: flex;
align-items: center;
gap: .5rem;
}
.repaso-intro {
font-size: .9rem;
color: var(--text-muted);
margin-bottom: 1.2rem;
}
.repaso-grupo {
border: 1px solid var(--border);
border-radius: 8px;
margin-bottom: .75rem;
overflow: hidden;
}
.repaso-grupo > summary {
list-style: none;
cursor: pointer;
padding: .7rem 1rem;
background: var(--bg-alt);
display: flex;
align-items: center;
justify-content: space-between;
gap: .5rem;
user-select: none;
}
.repaso-grupo > summary::-webkit-details-marker { display: none; }
.repaso-grupo[open] > summary { border-bottom: 1px solid var(--border); }
.repaso-tema-name { font-size: .9rem; font-weight: 600; color: var(--fg); display: flex; align-items: center; gap: .45rem; }
.repaso-tema-name i { color: var(--accent); }
.repaso-badge {
background: color-mix(in srgb, var(--error) 18%, transparent);
color: var(--error);
border: 1px solid color-mix(in srgb, var(--error) 35%, transparent);
border-radius: 20px;
font-size: .75rem;
font-weight: 700;
padding: .15rem .6rem;
white-space: nowrap;
}
.repaso-lista {
list-style: none;
margin: 0;
padding: 0;
}
.repaso-item {
padding: .75rem 1rem;
border-bottom: 1px solid var(--border);
}
.repaso-item:last-child { border-bottom: none; }
.repaso-q {
font-size: .85rem;
color: var(--fg);
margin-bottom: .45rem;
line-height: 1.5;
}
.repaso-answers {
display: flex;
flex-direction: column;
gap: .25rem;
}
.repaso-ans {
font-size: .8rem;
padding: .25rem .5rem;
border-radius: 4px;
display: flex;
align-items: flex-start;
gap: .4rem;
line-height: 1.4;
}
.repaso-ans.ko {
background: color-mix(in srgb, var(--error) 12%, transparent);
color: var(--error);
}
.repaso-ans.ok {
background: color-mix(in srgb, var(--success) 12%, transparent);
color: var(--success);
}
.repaso-link-tema {
display: inline-flex;
align-items: center;
gap: .4rem;
font-size: .82rem;
color: var(--accent);
text-decoration: none;
padding: .5rem 1rem;
background: color-mix(in srgb, var(--accent) 8%, transparent);
border-top: 1px solid var(--border);
width: 100%;
transition: background .15s;
}
.repaso-link-tema:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); }
.repaso-perfecto {
text-align: center;
font-size: .95rem;
color: var(--success);
padding: 1rem;
display: flex;
align-items: center;
justify-content: center;
gap: .5rem;
}
.repaso-perfecto i { color: var(--warning); font-size: 1.1rem; }
/* ── Layout ─────────────────────────────────────────────────── */
.quiz-layout {
margin-top: var(--topbar-h);
@ -701,3 +815,274 @@ a:hover { text-decoration: underline; }
.quiz-layout { padding: 1rem; }
}
/*
NOTICIAS Y CONVOCATORIAS
============================================================ */
.noticias-layout {
max-width: 860px;
margin-left: auto;
margin-right: auto;
padding: 0 1.5rem 3rem;
}
.noticias-header {
text-align: center;
margin-bottom: 2.5rem;
}
.noticias-header h1 {
font-size: 1.8rem;
color: var(--accent-2);
margin-bottom: .4rem;
}
.noticias-header p { color: var(--text-muted); font-size: .95rem; }
.noticias-section {
background: var(--bg-alt);
border: 1px solid var(--border);
border-radius: 12px;
padding: 1.5rem;
margin-bottom: 1.75rem;
}
.noticias-section-hdr {
display: flex;
align-items: center;
gap: .75rem;
margin-bottom: .5rem;
flex-wrap: wrap;
}
.noticias-section-hdr h2 {
font-size: 1.05rem;
color: var(--fg);
display: flex;
align-items: center;
gap: .5rem;
margin: 0;
flex: 1;
}
.noticias-section-hdr h2 i { color: var(--accent); }
.noticias-src-badge {
font-size: .72rem;
background: color-mix(in srgb, var(--accent) 12%, transparent);
color: var(--accent);
border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
border-radius: 20px;
padding: .15rem .6rem;
white-space: nowrap;
}
.noticias-section-desc {
font-size: .85rem;
color: var(--text-muted);
margin-bottom: 1rem;
line-height: 1.5;
}
/* ── INAP links ─────────────────────────────────────────────── */
.inap-links-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: .65rem;
margin-bottom: 1rem;
}
.inap-link-card {
display: flex;
align-items: center;
gap: .55rem;
padding: .65rem .85rem;
background: var(--bg);
border: 1px solid var(--border);
border-radius: 8px;
text-decoration: none;
color: var(--fg);
font-size: .85rem;
transition: border-color .15s, background .15s;
}
.inap-link-card:hover {
border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 8%, transparent);
color: var(--accent);
}
.inap-link-card i:first-child { color: var(--accent); width: 1rem; text-align: center; }
.inap-link-card span { flex: 1; }
.inap-ext { font-size: .7rem; color: var(--text-muted); margin-left: auto; }
.inap-link-primary {
border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 8%, transparent);
color: var(--accent);
font-weight: 600;
}
.inap-info-box {
display: flex;
gap: .75rem;
align-items: flex-start;
padding: .85rem 1rem;
background: color-mix(in srgb, var(--warning) 8%, transparent);
border: 1px solid color-mix(in srgb, var(--warning) 30%, transparent);
border-radius: 8px;
font-size: .85rem;
line-height: 1.5;
color: var(--fg);
}
.inap-info-box > i { color: var(--warning); margin-top: .15rem; flex-shrink: 0; }
.inap-info-box a { color: var(--accent); }
/* ── BOE news list ──────────────────────────────────────────── */
.news-list {
display: flex;
flex-direction: column;
gap: .4rem;
}
.news-loading, .news-empty, .news-error {
text-align: center;
padding: 1.5rem;
color: var(--text-muted);
font-size: .9rem;
display: flex;
align-items: center;
justify-content: center;
gap: .5rem;
flex-wrap: wrap;
}
.news-error {
color: var(--warning);
background: color-mix(in srgb, var(--warning) 8%, transparent);
border: 1px solid color-mix(in srgb, var(--warning) 25%, transparent);
border-radius: 8px;
flex-direction: column;
}
.news-error a { color: var(--accent); }
.news-item {
display: block;
padding: .6rem .85rem;
background: var(--bg);
border: 1px solid var(--border);
border-radius: 7px;
text-decoration: none;
color: var(--fg);
transition: border-color .13s, background .13s;
}
.news-item:hover {
border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 6%, transparent);
}
.news-item--tai {
border-color: color-mix(in srgb, var(--success) 50%, transparent);
background: color-mix(in srgb, var(--success) 6%, transparent);
}
.news-item--tai:hover {
border-color: var(--success);
background: color-mix(in srgb, var(--success) 12%, transparent);
}
.news-item-meta {
display: flex;
align-items: center;
gap: .5rem;
margin-bottom: .25rem;
flex-wrap: wrap;
}
.news-tag-tai {
font-size: .68rem;
font-weight: 700;
background: color-mix(in srgb, var(--success) 18%, transparent);
color: var(--success);
border: 1px solid color-mix(in srgb, var(--success) 35%, transparent);
border-radius: 20px;
padding: .1rem .5rem;
display: inline-flex;
align-items: center;
gap: .25rem;
}
.news-date {
font-size: .72rem;
color: var(--text-muted);
margin-left: auto;
}
.news-title {
font-size: .85rem;
line-height: 1.45;
color: var(--fg);
}
/* ── CCAA grid ──────────────────────────────────────────────── */
.ccaa-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
gap: .6rem;
}
.ccaa-card {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: .2rem;
padding: .65rem .5rem;
background: var(--bg);
border: 1px solid var(--border);
border-radius: 8px;
text-decoration: none;
text-align: center;
transition: border-color .13s, background .13s;
}
.ccaa-card:hover {
border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.ccaa-sigla {
font-size: .75rem;
font-weight: 700;
color: var(--accent);
letter-spacing: .04em;
}
.ccaa-nombre {
font-size: .8rem;
color: var(--fg);
}
@media (max-width: 600px) {
.inap-links-grid { grid-template-columns: 1fr; }
.ccaa-grid { grid-template-columns: repeat(3, 1fr); }
}
/* ── Banner de cambios INAP ─────────────────────────────────── */
.inap-cambio-banner {
position: sticky;
top: var(--topbar-h);
z-index: 90;
background: color-mix(in srgb, var(--warning) 15%, var(--bg));
border-bottom: 2px solid var(--warning);
padding: .65rem 1rem;
}
.inap-cambio-inner {
max-width: 860px;
margin: 0 auto;
display: flex;
align-items: center;
gap: .75rem;
flex-wrap: wrap;
}
.inap-cambio-banner > .inap-cambio-inner > i:first-child {
color: var(--warning);
font-size: 1.2rem;
flex-shrink: 0;
}
.inap-cambio-txt {
flex: 1;
display: flex;
flex-direction: column;
gap: .1rem;
font-size: .88rem;
}
.inap-cambio-txt strong { color: var(--warning); }
.inap-cambio-txt span { color: var(--text-muted); font-size: .8rem; }
.inap-banner-close {
background: none;
border: none;
cursor: pointer;
color: var(--text-muted);
font-size: 1rem;
padding: .25rem .4rem;
border-radius: 4px;
transition: color .15s, background .15s;
flex-shrink: 0;
}
.inap-banner-close:hover { color: var(--fg); background: color-mix(in srgb, var(--fg) 10%, transparent); }

View File

@ -17,6 +17,7 @@
<a href="../index.html">Inicio</a>
<a href="../curso.html">Temario</a>
<a href="index.html" class="active">Cuestionarios</a>
<a href="../noticias.html">Noticias</a>
</nav>
</nav>

View File

@ -22,6 +22,7 @@
<a href="index.html">Inicio</a>
<a href="curso.html" class="active">Temario</a>
<a href="cuestionarios/index.html">Cuestionarios</a>
<a href="noticias.html"><i class="fas fa-bell"></i> Noticias</a>
</nav>
<span class="topbar-progress" id="topbar-progress">1 / 33</span>
</nav>

View File

@ -17,9 +17,27 @@
<a href="index.html" class="active">Inicio</a>
<a href="curso.html">Temario</a>
<a href="cuestionarios/index.html">Cuestionarios</a>
<a href="noticias.html">Noticias</a>
</nav>
</nav>
<!-- ── Banner cambios INAP ──────────────────────────────── -->
<div id="inap-cambio-banner" class="inap-cambio-banner" style="display:none">
<div class="inap-cambio-inner">
<i class="fas fa-exclamation-circle"></i>
<div class="inap-cambio-txt">
<strong>¡La página de la convocatoria TAI ha cambiado!</strong>
<span>El INAP ha actualizado la información del proceso selectivo.</span>
</div>
<a class="inap-banner-link btn btn-primary" href="#" target="_blank" rel="noopener" style="white-space:nowrap">
<i class="fas fa-external-link-alt"></i> Ver cambios
</a>
<button class="inap-banner-close" onclick="cerrarBannerInap()" aria-label="Cerrar">
<i class="fas fa-times"></i>
</button>
</div>
</div>
<!-- ── Hero ──────────────────────────────────────────── -->
<section class="home-hero">
<h1><i class="fas fa-laptop-code"></i> Temario TAI AGE</h1>
@ -61,6 +79,7 @@
</div>
</section>
<script src="js/inap-watch.js"></script>
<script>
(function () {
const target = new Date('2026-05-23T00:00:00');

View File

@ -0,0 +1,106 @@
'use strict';
/**
* inap-watch.js
* Comprueba si la página de la convocatoria TAI del INAP ha cambiado
* desde la última visita. Si detecta cambios, muestra un banner en la
* página de inicio.
*
* Estrategia:
* 1. Descarga la página via un proxy CORS (allorigins.win)
* 2. Extrae solo el texto visible (sin scripts/estilos) y normaliza espacios
* 3. Calcula un hash djb2 del texto
* 4. Compara con el hash almacenado en localStorage
* 5. Si difiere muestra el banner y guarda el nuevo hash
* (el usuario puede silenciarlo con "Lo he visto")
*/
const INAP_URL = 'https://sede.inap.gob.es/es/procedimientos-y-servicios/seleccion/procesos-selectivos-de-cuerpos-y-escalas-generales/cuerpo-de-tecnicos-auxiliares-de-informatica-de-la-administracion-del-estado-ingreso-libre-convocatoria-2025';
const PROXY = 'https://api.allorigins.win/get?url=';
const STORE_KEY = 'inap_tai_hash';
const SEEN_KEY = 'inap_tai_hash_seen';
function djb2(str) {
let h = 5381;
for (let i = 0; i < str.length; i++) {
h = ((h << 5) + h) ^ str.charCodeAt(i);
h = h >>> 0; // mantener 32 bits sin signo
}
return h.toString(16);
}
function extraerTexto(html) {
// Eliminar scripts, estilos, comentarios y atributos dinámicos
return html
.replace(/<script[\s\S]*?<\/script>/gi, '')
.replace(/<style[\s\S]*?<\/style>/gi, '')
.replace(/<!--[\s\S]*?-->/g, '')
.replace(/<[^>]+>/g, ' ') // quitar etiquetas
.replace(/\s+/g, ' ') // normalizar espacios
.trim();
}
function mostrarBanner(urlPagina) {
const banner = document.getElementById('inap-cambio-banner');
if (!banner) return;
banner.style.display = 'flex';
banner.querySelector('.inap-banner-link').href = urlPagina;
}
function ocultarBanner() {
const banner = document.getElementById('inap-cambio-banner');
if (!banner) return;
banner.style.display = 'none';
// Marcar como visto para esta versión del hash
const hash = localStorage.getItem(STORE_KEY);
if (hash) localStorage.setItem(SEEN_KEY, hash);
}
async function comprobarCambios() {
// Si el navegador no tiene fetch o localStorage, salir silenciosamente
if (typeof fetch === 'undefined' || typeof localStorage === 'undefined') return;
const hashPrevio = localStorage.getItem(STORE_KEY);
const hashVisto = localStorage.getItem(SEEN_KEY);
// Si ya hay cambio pendiente que el usuario aún no ha marcado como visto → mostrar banner
if (hashPrevio && hashPrevio !== hashVisto) {
mostrarBanner(INAP_URL);
// Seguir para comprobar si hay cambios adicionales desde entonces
}
try {
const resp = await fetch(PROXY + encodeURIComponent(INAP_URL), { cache: 'no-store' });
if (!resp.ok) return;
const data = await resp.json();
const texto = extraerTexto(data.contents || '');
if (!texto) return;
const hashNuevo = djb2(texto);
if (!hashPrevio) {
// Primera visita: guardar referencia silenciosamente
localStorage.setItem(STORE_KEY, hashNuevo);
localStorage.setItem(SEEN_KEY, hashNuevo);
return;
}
if (hashNuevo !== hashPrevio) {
// La página cambió
localStorage.setItem(STORE_KEY, hashNuevo);
mostrarBanner(INAP_URL);
}
} catch (_) {
// Fallo de red o proxy caído: no hacer nada, sin ruido
}
}
// ── Arranque ───────────────────────────────────────────────────
// Exponer función de cierre al botón del banner
window.cerrarBannerInap = ocultarBanner;
// Ejecutar cuando la página esté lista (sin bloquear el render)
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', comprobarCambios);
} else {
comprobarCambios();
}

View File

@ -0,0 +1,84 @@
'use strict';
// ── Configuración ──────────────────────────────────────────────
// BOE Sección II-B: Oposiciones, concursos y vacantes
const BOE_RSS = 'https://www.boe.es/rss/boe_dias.php?s=2B';
// Proxy CORS gratuito que convierte RSS a JSON
const RSS2JSON = 'https://api.rss2json.com/v1/api.json?rss_url=';
// Palabras clave para resaltar entradas de interés informático/TAI
const KW_TAI = /\b(TAI|T\.A\.I|técnico[a]? (de )?administración (general |de la )?inform|inform[aá]tic|sistemas?\s+de\s+información|AGE\b)/i;
// ── Carga del feed BOE ─────────────────────────────────────────
async function cargarBOE() {
const panel = document.getElementById('boe-items');
const badge = document.getElementById('boe-fecha');
try {
const resp = await fetch(RSS2JSON + encodeURIComponent(BOE_RSS));
if (!resp.ok) throw new Error('HTTP ' + resp.status);
const data = await resp.json();
if (data.status !== 'ok') throw new Error('Feed error: ' + data.message);
const items = data.items || [];
if (items.length === 0) {
panel.innerHTML = '<p class="news-empty">No hay publicaciones recientes en esta sección.</p>';
badge.textContent = 'Sin datos';
return;
}
// Separar: primero los que coincidan con TAI/informática, luego el resto
const importantes = items.filter(it => KW_TAI.test(it.title + ' ' + (it.description || '')));
const resto = items.filter(it => !KW_TAI.test(it.title + ' ' + (it.description || '')));
const ordenados = [...importantes, ...resto].slice(0, 25);
// Fecha de la última actualización del feed
const fechaFeed = data.feed?.lastBuildDate
? new Date(data.feed.lastBuildDate).toLocaleDateString('es-ES', { day:'2-digit', month:'short', year:'numeric' })
: 'hoy';
badge.textContent = 'Act. ' + fechaFeed;
panel.innerHTML = ordenados.map(item => {
const esTAI = KW_TAI.test(item.title + ' ' + (item.description || ''));
const fecha = item.pubDate
? new Date(item.pubDate).toLocaleDateString('es-ES', { day:'2-digit', month:'short', year:'numeric' })
: '';
const titulo = escHtml(truncar(item.title || 'Sin título', 120));
return `
<a href="${escHtml(item.link || '#')}" target="_blank" rel="noopener"
class="news-item${esTAI ? ' news-item--tai' : ''}">
<div class="news-item-meta">
${esTAI
? '<span class="news-tag-tai"><i class="fas fa-star"></i> TAI / Informática</span>'
: ''}
<span class="news-date">${fecha}</span>
</div>
<div class="news-title">${titulo}</div>
</a>`;
}).join('');
} catch (err) {
console.warn('[noticias.js] Error cargando BOE:', err.message);
badge.textContent = 'Error';
panel.innerHTML = `
<div class="news-error">
<i class="fas fa-exclamation-triangle"></i>
No se pudo cargar el feed automáticamente. Consulta el BOE directamente:
<a href="https://www.boe.es/diario_boe/ultimos_dias.php" target="_blank" rel="noopener">
Últimas publicaciones BOE <i class="fas fa-external-link-alt"></i>
</a>
</div>`;
}
}
// ── Helpers ────────────────────────────────────────────────────
function escHtml(s) {
return (s || '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
}
function truncar(s, max) {
return s.length > max ? s.slice(0, max) + '…' : s;
}
// ── Arranque ───────────────────────────────────────────────────
cargarBOE();

179
oposiciones/noticias.html Normal file
View File

@ -0,0 +1,179 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TAI AGE | Noticias y Convocatorias</title>
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
</head>
<body>
<!-- ── Topbar ─────────────────────────────────────────── -->
<nav class="topbar">
<span class="topbar-brand"><i class="fas fa-graduation-cap"></i> TAI AGE</span>
<nav class="topbar-nav">
<a href="index.html">Inicio</a>
<a href="curso.html">Temario</a>
<a href="cuestionarios/index.html">Cuestionarios</a>
<a href="noticias.html" class="active">Noticias</a>
</nav>
</nav>
<div class="noticias-layout" style="margin-top:calc(var(--topbar-h) + 2rem)">
<div class="noticias-header">
<h1><i class="fas fa-bell"></i> Noticias y Convocatorias</h1>
<p>Actualiza esta página para ver los últimos avisos del INAP, novedades del BOE y nuevas convocatorias de las CCAA.</p>
</div>
<!-- ── INAP Convocatoria TAI ─────────────────────── -->
<section class="noticias-section">
<div class="noticias-section-hdr">
<h2><i class="fas fa-university"></i> INAP Convocatoria TAI en curso</h2>
<span class="noticias-src-badge">inap.es</span>
</div>
<div class="inap-links-grid">
<a href="https://sede.inap.gob.es/es/procedimientos-y-servicios/seleccion/procesos-selectivos-de-cuerpos-y-escalas-generales/cuerpo-de-tecnicos-auxiliares-de-informatica-de-la-administracion-del-estado-ingreso-libre-convocatoria-2025" target="_blank" rel="noopener" class="inap-link-card inap-link-primary">
<i class="fas fa-bullhorn"></i>
<span>Convocatoria TAI INAP</span>
<i class="fas fa-external-link-alt inap-ext"></i>
</a>
<a href="https://sede.inap.gob.es/es/procedimientos-y-servicios/seleccion/procesos-selectivos-de-cuerpos-y-escalas-generales" target="_blank" rel="noopener" class="inap-link-card">
<i class="fas fa-list-ul"></i>
<span>Procesos selectivos en curso</span>
<i class="fas fa-external-link-alt inap-ext"></i>
</a>
<a href="https://www.boe.es/buscar/doc.php?campo[0]=TITN&dato[0]=tai" target="_blank" rel="noopener" class="inap-link-card">
<i class="fas fa-search"></i>
<span>Buscar "TAI" en el BOE</span>
<i class="fas fa-external-link-alt inap-ext"></i>
</a>
<a href="https://www.boe.es/buscar/boe.php?campo[0]=TITN&dato[0]=tecnico+administracion+informatica&campo[1]=DDES&dato[1]=&field=todos&texto=&desde=&hasta=&sort_field[0]=fech&sort_order[0]=desc&accion=buscar" target="_blank" rel="noopener" class="inap-link-card">
<i class="fas fa-file-alt"></i>
<span>Resoluciones TAI en BOE</span>
<i class="fas fa-external-link-alt inap-ext"></i>
</a>
</div>
<div class="inap-info-box">
<i class="fas fa-info-circle"></i>
<p>El INAP publica actualizaciones de la convocatoria (listas provisionales, definitivas, llamamientos, fechas de examen) en su web oficial y en el BOE Sección II-B.
Revisa periódicamente la página de la convocatoria TAI o configura una alerta en el BOE para no perderte ninguna resolución.
</p>
</div>
</section>
<!-- ── BOE Oposiciones y concursos ──────────────── -->
<section class="noticias-section">
<div class="noticias-section-hdr">
<h2><i class="fas fa-newspaper"></i> BOE Oposiciones y Concursos (AGE)</h2>
<span id="boe-fecha" class="noticias-src-badge">Cargando…</span>
</div>
<p class="noticias-section-desc">Últimas publicaciones de la Sección II-B del BOE (Oposiciones, concursos y vacantes). Las entradas relacionadas con TAI / informática se marcan en verde.</p>
<div id="boe-items" class="news-list">
<div class="news-loading"><i class="fas fa-spinner fa-spin"></i> Cargando noticias del BOE…</div>
</div>
<a href="https://www.boe.es/diario_boe/ultimos_dias.php" target="_blank" rel="noopener" class="btn btn-outline" style="margin-top:1rem;font-size:.85rem">
<i class="fas fa-external-link-alt"></i> Ver BOE completo
</a>
</section>
<!-- ── Boletines CCAA ──────────────────────────────── -->
<section class="noticias-section">
<div class="noticias-section-hdr">
<h2><i class="fas fa-map-marked-alt"></i> Boletines Oficiales de las CCAA</h2>
<span class="noticias-src-badge">17 CCAA + Ceuta + Melilla</span>
</div>
<p class="noticias-section-desc">Acceso directo a los boletines oficiales autonómicos para consultar convocatorias de cuerpos de informática de cada comunidad.</p>
<div class="ccaa-grid">
<a href="https://www.juntadeandalucia.es/boja" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">BOJA</span>
<span class="ccaa-nombre">Andalucía</span>
</a>
<a href="https://www.boa.aragon.es" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">BOA</span>
<span class="ccaa-nombre">Aragón</span>
</a>
<a href="https://sede.asturias.es/bopa" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">BOPA</span>
<span class="ccaa-nombre">Asturias</span>
</a>
<a href="https://www.caib.es/boib" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">BOIB</span>
<span class="ccaa-nombre">Baleares</span>
</a>
<a href="https://www.gobiernodecanarias.org/librodigital/boc/" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">BOC</span>
<span class="ccaa-nombre">Canarias</span>
</a>
<a href="https://boc.cantabria.es" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">BOC</span>
<span class="ccaa-nombre">Cantabria</span>
</a>
<a href="https://docm.castillalamancha.es" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">DOCM</span>
<span class="ccaa-nombre">Castilla-La Mancha</span>
</a>
<a href="https://bocyl.jcyl.es" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">BOCYL</span>
<span class="ccaa-nombre">Castilla y León</span>
</a>
<a href="https://dogc.gencat.cat" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">DOGC</span>
<span class="ccaa-nombre">Cataluña</span>
</a>
<a href="https://doe.juntaex.es" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">DOE</span>
<span class="ccaa-nombre">Extremadura</span>
</a>
<a href="https://www.xunta.gal/dog" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">DOG</span>
<span class="ccaa-nombre">Galicia</span>
</a>
<a href="https://www.larioja.org/es/gobierno-rioja/boletines" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">BOR</span>
<span class="ccaa-nombre">La Rioja</span>
</a>
<a href="https://www.bocm.es" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">BOCM</span>
<span class="ccaa-nombre">Madrid</span>
</a>
<a href="https://www.borm.es" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">BORM</span>
<span class="ccaa-nombre">Murcia</span>
</a>
<a href="https://bon.navarra.es" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">BON</span>
<span class="ccaa-nombre">Navarra</span>
</a>
<a href="https://www.euskadi.eus/bopv" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">BOPV</span>
<span class="ccaa-nombre">País Vasco</span>
</a>
<a href="https://dogv.gva.es" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">DOGV</span>
<span class="ccaa-nombre">C. Valenciana</span>
</a>
<a href="https://www.ceuta.es/ceuta/index.php/boletin-oficial" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">BOCCE</span>
<span class="ccaa-nombre">Ceuta</span>
</a>
<a href="https://www.melilla.es/melillaPortal/contenedor1.jsp?seccion=s_lofb_d4_v1.jsp&contenido=17547&nivel=1400&tipo=6&codResi=1&language=es" target="_blank" rel="noopener" class="ccaa-card">
<span class="ccaa-sigla">BOME</span>
<span class="ccaa-nombre">Melilla</span>
</a>
</div>
</section>
</div>
<script src="js/noticias.js"></script>
</body>
</html>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.