Saltar al contenido principal

Marco de secciones del curso

Ficha técnica

Propósito​

Restyle de las secciones del curso (/course/view.php) para que cada una se presente como un acordeón de borde redondeado con cabecera sombreada, siguiendo el nodo de Figma Table_acordeon (19723-2794), reutilizado seis veces en la vista de curso 19723-2726. Extiende también a la vista de una sola sección (coursedisplay = mostrar una sección por página, Figma 19756-3011): tarjeta "héroe" de sección (carátula, progreso) y navegación anterior/siguiente sección, con datos reales de course_stats.

Alcance​

  • Aplica dentro de id="page-content" — el límite acordado para todo el "contenido interno de curso" (ver también Marco del contenido de actividad, que extiende el mismo lenguaje a mod/*/view.php). No alcanza al cajón de bloques (side-pre), la fila de hero de curso, el banner ni la miga de pan, que ya tienen su propio restyle (ver Fila "Contenido del curso" + insignias, Banner "Tu desempeño académico", Drawer "Índice de curso").
  • Alcanza a los formatos que apilan secciones con el contrato de marcado de core_courseformat: topics, weeks, grid (hereda ese contrato vía {{< core_courseformat/local/content/section }}) y secciones delegadas (core_courseformat/local/content/delegatedsection.mustache).
  • No alcanza a format_onetopic: sus secciones se navegan como pestañas, no como acordeones apilados, y su plantilla no emite .section-item. Ya tiene su propio restyle en Pestañas de secciones del curso (format_onetopic).
  • Profundidad del acordeón de listado: marco, cabecera sombreada y chevron de plegado. Quedan fuera el chip de ícono junto al título y la etiqueta "X de Y actividades" por fila del Figma, así como el rediseño de las filas de actividad (columna de descripción y botón Completado/Continuar/Pendiente). La etiqueta "N de M actividades" y el ícono decorativo sí están resueltos en la tarjeta "héroe" de la vista de una sola sección (ver abajo), que reutiliza course_stats::get_user_module_progress() para ese dato.

Desviaciones conscientes​

  • Chevron rotatorio en vez de fijo: el Figma dibuja el chevron apuntando siempre hacia arriba (dibuja el estado expandido). Aquí rota entre expandido (arriba) y plegado (abajo), reutilizando el mismo mecanismo .icons-collapse-expand / .collapsed que ya usa el drawer de índice de curso (scss/courseindex.scss).
  • Cabecera completa clicable: el Figma la dibuja como un <button>. Se añade un overlay sobre el toggler nativo (a.icons-collapse-expand::after), activo solo fuera de modo edición: en edición el área debe quedar libre para el arrastre de secciones/actividades, el checkbox de selección múltiple y el menú de acciones de sección.
  • format_onetopic fuera de alcance, y con él, el curso piloto (id 3) y el de la biblioteca escolar (id 5): sus secciones siguen siendo pestañas.
  • Formato con una sección por página (coursedisplay = mostrar una sección por página, p. ej. el curso de evaluación en modo grid): el marco y la cabecera sombreada de la tabla de actividades se aplican igual, pero sin chevron ni plegado — en ese modo Moodle no emite el toggler y el cuerpo no es colapsable; la cabecera vacía se oculta por completo (ver "Detalles técnicos").
  • Navegación anterior/siguiente sección con leyenda de dos líneas: a diferencia de la navegación de actividad (ver Marco del contenido de actividad), aquí SÍ se construye "Módulo anterior"/"Siguiente módulo" + nombre en dos líneas, porque es una plantilla enteramente propia del tema (theme_cdigital/section_navigation_row), no una sobrescritura de la plantilla de core_courseformat — no acarrea el mismo riesgo de resincronización en upgrade.
  • La carátula de la tarjeta "héroe" reutiliza la imagen del curso, no una imagen propia de la sección: Moodle no tiene ese concepto en su modelo de datos, y las imágenes por sección que administra format_grid para sus mosaicos viven en almacenamiento propio del plugin sin API pública — depender de eso para un detalle cosmético quedó fuera de alcance.

Arquitectura​

El marcado del acordeón de listado lo emite core_courseformat y es estable en el contrato entre plantillas (.section-item, .course-section-header, data-for="section_title" / "sectiontoggler"), no clases puramente presentacionales de Bootstrap. Por eso, igual que en Pestañas de secciones (format_onetopic) y la miga de pan (ADR-005), no se sobrescribe ninguna plantilla: las de core_courseformat cambian entre versiones de Moodle y obligarían a resincronizar en cada upgrade.

#region-main
└─ .course-content
└─ ul.section-list
└─ li.course-section.main
└─ div.section-item ← marco (borde 1px, radio 16)
├─ div.course-section-header ← cabecera sombreada (#f3f5fd)
│ └─ a.icons-collapse-expand + h.sectionname
└─ div.content.collapse ← cuerpo

La tarjeta "héroe" y la navegación de sección, en cambio, son plantillas propias del tema (mismo patrón que course_hero_row.mustache/continue_card.mustache), inyectadas desde core_renderer::full_header() y core_renderer::course_content_footer() cuando single_section_num() detecta coursedisplay == COURSE_DISPLAY_MULTIPAGE — sin depender del estado interno cacheado del course_format (lee el parámetro section de la URL directamente, ya que el orden de renderizado no garantiza que set_sectionnum() ya se haya llamado). El resumen de la tarjeta y la navegación reutilizan las clases estables de core (core_courseformat\output\local\content\section\summary, core_courseformat\output\local\content\sectionnavigation) en vez de recalcular esos datos — get_output_classname() resuelve automáticamente a la versión de format_grid cuando aplica, sin que el tema necesite distinguir el formato.

Detalles técnicos​

  • Cabecera vacía en vista de una sola sección: core_courseformat/local/content/section/header.mustache no emite título ni chevron cuando displayonesection es verdadero (ambas ramas quedan detrás de {{^displayonesection}}), pero data-region="sectionbadges" sí se sigue emitiendo siempre, así que .course-section-header no queda realmente vacío como para usar :empty. Se detecta con :not(:has(.sectionname)) y se colapsa por height/padding/border/overflow en vez de display: none — verificado en vivo que un display: none !important no ganaba la pelea contra el display: flex !important de la utilidad Bootstrap .d-flex en este archivo compilado concreto, mientras que las propiedades que .d-flex no toca sí se aplican sin necesitar !important.
  • :has() no admite anidarse dentro de otro :has(), ni siquiera a través de :not() (lo prohíbe la especificación de Selectors Level 4; un selector así es inválido y el navegador descarta la regla completa). El resumen duplicado del cuerpo de la sección ([data-for="sectioninfo"], que de otro modo repetiría el mismo texto que ya muestra la tarjeta "héroe") se oculta con un combinador de hermanos (.course-section-header:not(:has(.sectionname)) + .content [data-for="sectioninfo"]) en vez de envolver .section-item en un :has() que contuviera esa misma condición.

Archivos del tema involucrados​

ArchivoFunción
scss/mixins.scss@mixin cdigital-chevron-toggle() — mecanismo de chevron plegable compartido con scss/courseindex.scss y scss/activitypage.scss; se concatena primero
scss/coursesections.scssMarco y cabecera del acordeón de listado; cabecera vacía en vista de una sola sección; tarjeta "héroe" (.cdigital-sectionhero*) y navegación de sección (.cdigital-sectionnav*)
templates/section_hero_row.mustacheTarjeta "héroe" (carátula, nombre, progreso) + tarjeta de resumen
templates/section_navigation_row.mustacheNavegación "Módulo anterior"/"Siguiente módulo"
classes/output/core_renderer.phpsingle_section_num(), section_hero_row_context(), section_navigation_context(); override de full_header() y course_content_footer()
lib.phptheme_cdigital_get_main_scss_content() — registra scss/mixins.scss primero y scss/coursesections.scss después de scss/coursetabs.scss

Build y despliegue​

Solo SCSS: no requiere build de AMD (grunt). Basta con purgar cachés tras el despliegue — ver Procedimiento de despliegue.

Historial de cambios​

Ver CHANGELOG.md en la raíz del sitio de documentación.