diff --git a/public/index.html b/public/index.html index 567b566..e8d1b27 100755 --- a/public/index.html +++ b/public/index.html @@ -10,6 +10,9 @@ + + + diff --git a/src/App.tsx b/src/App.tsx index 9374cfc..3dae758 100755 --- a/src/App.tsx +++ b/src/App.tsx @@ -9,7 +9,7 @@ import { Creditos } from "./Creditos" function App() { /// @ts-ignore const soportaBackdropFilter = document.body.style.backdropFilter !== undefined - const mostrarMensajeBackdropFilterRaw = localStorage.getItem("mensaje-backdrop-filter-oculto") !== undefined + const mostrarMensajeBackdropFilterRaw = localStorage.getItem("mensaje-backdrop-filter-oculto") === undefined const [mostrarMensajeBackdropFilter, setMostrarMensaje] = createSignal(mostrarMensajeBackdropFilterRaw) diff --git a/src/BarraSuperior.tsx b/src/BarraSuperior.tsx index 221c5ac..864ee13 100755 --- a/src/BarraSuperior.tsx +++ b/src/BarraSuperior.tsx @@ -2,7 +2,7 @@ import { estilosGlobales } from "./Estilos" import { StyleSheet, css } from "aphrodite" import { numWallpaper, setNumWallpaper } from "./Store" -const totalWallpapers = 5 +const ultimoIndiceWallpaper = 5 const e = StyleSheet.create({ contCambiador: { @@ -36,14 +36,14 @@ const retrocederWallpaper = () => { setNumWallpaper(num - 1) localStorage.setItem("num-img", (num - 1).toString()) } else { - setNumWallpaper(totalWallpapers) - localStorage.setItem("num-img", (totalWallpapers).toString()) + setNumWallpaper(ultimoIndiceWallpaper) + localStorage.setItem("num-img", (ultimoIndiceWallpaper).toString()) } } const avanzarWallpaper = () => { const num = numWallpaper() - if (num < totalWallpapers) { + if (num < ultimoIndiceWallpaper) { setNumWallpaper(num + 1) localStorage.setItem("num-img", (num + 1).toString()) } else { diff --git a/src/ContenedorHorarios/CursosElem.tsx b/src/ContenedorHorarios/CursosElem.tsx index 6b4b629..7d15be7 100755 --- a/src/ContenedorHorarios/CursosElem.tsx +++ b/src/ContenedorHorarios/CursosElem.tsx @@ -1,7 +1,8 @@ -import { Cursos, CursoRaw, DatosGrupo, ListaCursosUsuario, Curso } from "../types/DatosHorario" -import { createEffect, createMemo, For, SetStateFunction } from "solid-js" +import { Cursos, DatosGrupo, ListaCursosUsuario, Curso } from "../types/DatosHorario" +import { createMemo, For, SetStateFunction } from "solid-js" import { StyleSheet, css } from "aphrodite" import { estilosGlobales } from "../Estilos" +import { TablaObserver } from "./TablaObserver" const e = StyleSheet.create({ inline: { @@ -29,14 +30,14 @@ const e = StyleSheet.create({ }) interface Props { + version: number, dataAnio: Cursos, anioActual: () => string, fnAgregarCurso: (c: Curso) => void, listaCursosUsuario: ListaCursosUsuario, - idHover: () => string, - setIdHover: (v: string) => string, esCursoMiHorario: boolean, - setCursosUsuarios: SetStateFunction + setCursosUsuarios: SetStateFunction, + tablaObserver: TablaObserver, } type FnSetCursosUsuarios = SetStateFunction; @@ -45,7 +46,7 @@ interface PropsIndicadorGrupo { nombre: string, esLab: boolean, idParcial: string, - setIdHover: (v: string) => string, + tablaObserver: TablaObserver, onClick: () => void } @@ -54,8 +55,8 @@ function IndicadorGrupo(props: PropsIndicadorGrupo) { return ( props.setIdHover(id)} - onMouseLeave={() => props.setIdHover("")} + onMouseEnter={() => props.tablaObserver.resaltar(id)} + onMouseLeave={() => props.tablaObserver.quitarResaltado()} onClick={props.onClick} > {props.esLab ? "L" : ""}{props.nombre} @@ -114,7 +115,7 @@ export function CursosElem(props: Props) { {([indiceCurso, datosCurso]) => { - const idCurso = `${anio()}_${datosCurso.abreviado}` + const idCurso = `${props.version}_${anio()}_${datosCurso.abreviado}` const cursoAgregadoMemo = createMemo( () => props.listaCursosUsuario.cursos.find((x) => x.nombre === datosCurso.nombre && !x.oculto) !== undefined, @@ -152,8 +153,8 @@ export function CursosElem(props: Props) {
props.setIdHover(idCurso)} - onMouseLeave={() => props.setIdHover("")} + onMouseEnter={() => props.tablaObserver.resaltar(idCurso)} + onMouseLeave={() => props.tablaObserver.quitarResaltado()} > {datosCurso.abreviado} - {datosCurso.nombre}
@@ -168,10 +169,11 @@ export function CursosElem(props: Props) { {([x, fnOnClick]) => ( - ) @@ -190,10 +192,11 @@ export function CursosElem(props: Props) { {([x, fnOnClick]) => ( - ) diff --git a/src/ContenedorHorarios/Horarios.tsx b/src/ContenedorHorarios/Horarios.tsx index 048b593..383d5b6 100755 --- a/src/ContenedorHorarios/Horarios.tsx +++ b/src/ContenedorHorarios/Horarios.tsx @@ -7,6 +7,7 @@ import { CursosElem } from "./CursosElem" import { EstadoLayout } from "./ContenedorHorarios" import { BotonMaxMin } from "./BotonMaxMin" import { useListaCursos } from "./useListaCursos" +import { TablaObserver } from "./TablaObserver" interface HorariosProps { data: DatosHorario, @@ -25,8 +26,8 @@ const { export function Horarios(props: HorariosProps) { const [anioActual, setAnioActual] = createSignal("1er año") - // ID que indica cuales celdas resaltar. - const [idHover, setIdHover] = createSignal("") + + const tablaObserver = new TablaObserver() const elAnios = ( @@ -102,21 +103,20 @@ export function Horarios(props: HorariosProps) { data={dataTabla()} version={props.data.version} anio={anioActual()} - idHover={idHover} - setIdHover={setIdHover} setCursosUsuarios={setListaCursos} + tablaObserver={tablaObserver} />
diff --git a/src/ContenedorHorarios/MiHorario.tsx b/src/ContenedorHorarios/MiHorario.tsx index 7909a68..a409dae 100755 --- a/src/ContenedorHorarios/MiHorario.tsx +++ b/src/ContenedorHorarios/MiHorario.tsx @@ -1,13 +1,13 @@ import { estilosGlobales } from "../Estilos" import { StyleSheet, css } from "aphrodite" import { Tabla } from "./Tabla" -import { mostrarDescansos } from "../Store" import { EstadoLayout } from "./ContenedorHorarios" -import { Switch, Match, For, createMemo, createSignal, SetStateFunction } from "solid-js" +import { Switch, Match, createMemo, SetStateFunction } from "solid-js" import { BotonMaxMin } from "./BotonMaxMin" import { BotonIcono } from "./BotonIcono" import { Curso, Cursos, ListaCursosUsuario } from "../types/DatosHorario" import { CursosElem } from "./CursosElem" +import { TablaObserver } from "./TablaObserver" interface MiHorarioProps { estadoLayout: EstadoLayout, @@ -31,7 +31,7 @@ const e = StyleSheet.create({ }) export function MiHorario(props: MiHorarioProps) { - const [idHover, setIdHover] = createSignal("") + const tablaObserver = new TablaObserver() const datosMiHorario = createMemo(() => { const obj: Cursos = {} @@ -48,7 +48,7 @@ export function MiHorario(props: MiHorarioProps) { /* TODO: En barra superior colocar todos los horarios. En barra inferior el horario actual. Al hacer click en un horario de la barra superior, llevarlo al inicio de la lista. - */ + */ return (
@@ -110,21 +110,20 @@ export function MiHorario(props: MiHorarioProps) { data={datosMiHorario()} anio={"Mi horario"} version={1} - idHover={idHover} - setIdHover={setIdHover} setCursosUsuarios={props.setCursosUsuarios} + tablaObserver={tablaObserver} />
"Mi horario"} dataAnio={datosMiHorario()} fnAgregarCurso={props.fnAgregarCurso} listaCursosUsuario={props.cursosUsuario} - idHover={idHover} - setIdHover={setIdHover} esCursoMiHorario setCursosUsuarios={props.setCursosUsuarios} + tablaObserver={tablaObserver} /> diff --git a/src/ContenedorHorarios/Tabla.tsx b/src/ContenedorHorarios/Tabla.tsx index 1182a63..ffa7b2d 100755 --- a/src/ContenedorHorarios/Tabla.tsx +++ b/src/ContenedorHorarios/Tabla.tsx @@ -4,6 +4,7 @@ import { estilosGlobales } from "../Estilos" import { Cursos, ListaCursosUsuario, DataProcesada } from "../types/DatosHorario" import { Dia, dias, horas } from "../Store" import { FilaTabla } from "./Tabla/FilaTabla" +import { TablaObserver } from "./TablaObserver" export const coloresBorde = Object.freeze([ "rgba(33,150,243,1)", @@ -160,16 +161,13 @@ interface Props { data: Cursos, anio: string, version: number, - idHover: () => string, - setIdHover: (v: string) => string, - setCursosUsuarios: SetStateFunction + setCursosUsuarios: SetStateFunction, + tablaObserver: TablaObserver, } export function Tabla(props: Props) { const anio = () => props.anio.substring(0, props.anio.indexOf(" ")) const data = createMemo(() => procesarAnio(props.data, anio(), props.version, props.setCursosUsuarios)) - const idHover = props.idHover - const setIdHover = props.setIdHover const celdas = createMemo(() => { // Hace reaccionar a la reactividad de Solid @@ -180,8 +178,7 @@ export function Tabla(props: Props) { )}
diff --git a/src/ContenedorHorarios/Tabla/CeldaFila.tsx b/src/ContenedorHorarios/Tabla/CeldaFila.tsx index e195422..921cacb 100755 --- a/src/ContenedorHorarios/Tabla/CeldaFila.tsx +++ b/src/ContenedorHorarios/Tabla/CeldaFila.tsx @@ -1,8 +1,9 @@ import { StyleSheet, css } from "aphrodite" import { estilosGlobales } from "../../Estilos" -import { For, createSignal, createMemo, createEffect, SetStateFunction } from "solid-js" +import { For, createSignal, createMemo } from "solid-js" import { Dia } from "../../Store" -import { DatosGrupo, ListaCursosUsuario } from "../../types/DatosHorario" +import { DatosGrupo } from "../../types/DatosHorario" +import { TablaObserver } from "../TablaObserver" const e = StyleSheet.create({ celdaComun: { @@ -19,7 +20,7 @@ const e = StyleSheet.create({ borderRadius: "5px", // transition: "background-color 100ms, color 100ms" }, - celdaCursoActiva: { + celdaResaltado: { // color: "#151515" }, celdaCursoTeoria: { @@ -28,7 +29,7 @@ const e = StyleSheet.create({ celdaCursoLab: { fontStyle: "italic", }, - celdaSeleccionada: { + celdaSeleccionado: { textDecoration: "underline", }, }) @@ -78,22 +79,16 @@ interface Props { datosGrupo: DatosGrupo, fnSeleccionar: () => void }[], - idHover: () => string, - setIdHover: (v: string) => string, fnResaltarFila: () => void, fnDesresaltarFila: () => void, dia: Dia, + tablaObserver: TablaObserver, } -const claseSeldaSeleccionada = css(e.celdaSeleccionada) +const claseSeldaSeleccionada = css(e.celdaSeleccionado) export function CeldaFila(props: Props) { const datos = props.datos - const idHover = props.idHover - const setIdHover = props.setIdHover - - const fnOnMouseEnter = (id: string) => setIdHover(id) - const fnOnMouseLeave = () => setIdHover("") return (
@@ -104,6 +99,8 @@ export function CeldaFila(props: Props) { const esLab = datos.esLab const fnSeleccionar = datos.fnSeleccionar + const estadoCeldaMemo = props.tablaObserver.registrarConId(id) + const [estabaResaltado, setEstabaResaltado] = createSignal(false) const estaSeleccionado = createMemo(() => datos.datosGrupo.seleccionado) @@ -113,20 +110,59 @@ export function CeldaFila(props: Props) { const clases = [ e.celdaCurso, esLab ? e.celdaCursoLab : e.celdaCursoTeoria, - estaSeleccionado() && e.celdaSeleccionada, + estaSeleccionado() && e.celdaSeleccionado, ] let adicional = "" - const idHoverS = idHover() - if (idHoverS !== "" && id.search(idHoverS) !== -1) { - props.fnResaltarFila() - clases.push(e.celdaCursoActiva) - adicional = clasesColores[props.dia] - setEstabaResaltado(true) - } else if (estabaResaltado()) { - props.fnDesresaltarFila() - setEstabaResaltado(false) + const estadoCelda = estadoCeldaMemo() + + switch (estadoCelda) { + case "Normal": { + if (estabaResaltado()) { + props.fnDesresaltarFila() + setEstabaResaltado(false) + } + + break + } + case "Oculto": { + if (estabaResaltado()) { + props.fnDesresaltarFila() + setEstabaResaltado(false) + } + + // TODO + break + } + case "Resaltado": { + props.fnResaltarFila() + setEstabaResaltado(true) + clases.push(e.celdaResaltado) + adicional = clasesColores[props.dia] + break + } + case "Seleccionado": { + if (estabaResaltado()) { + props.fnDesresaltarFila() + setEstabaResaltado(false) + } + + break + } + case "ResaltadoOculto": { + props.fnResaltarFila() + setEstabaResaltado(true) + + break + } + case "ResaltadoSeleccionado": { + props.fnResaltarFila() + setEstabaResaltado(true) + + break + } } + return `${css(...clases)} ${adicional}` }, undefined, @@ -135,9 +171,13 @@ export function CeldaFila(props: Props) { return ( fnOnMouseEnter(id)} - onMouseLeave={fnOnMouseLeave} - onClick={fnSeleccionar} + onMouseEnter={() => { + props.tablaObserver.resaltar(id) + }} + onMouseLeave={() => { + props.tablaObserver.quitarResaltado() + }} + onClick={fnSeleccionar} > {txt} diff --git a/src/ContenedorHorarios/Tabla/FilaTabla.tsx b/src/ContenedorHorarios/Tabla/FilaTabla.tsx index 1ef7f75..fc248a1 100755 --- a/src/ContenedorHorarios/Tabla/FilaTabla.tsx +++ b/src/ContenedorHorarios/Tabla/FilaTabla.tsx @@ -1,10 +1,11 @@ import { StyleSheet, css } from "aphrodite" import { estilosGlobales } from "../../Estilos" -import { For, createSignal, createMemo, createState, createEffect, State, SetStateFunction } from "solid-js" +import { For, createMemo, createState, State } from "solid-js" import { Dia, dias } from "../../Store" import { CeldaFila } from "./CeldaFila" -import { DataProcesada, ListaCursosUsuario } from "../../types/DatosHorario" +import { DataProcesada } from "../../types/DatosHorario" import { coloresBorde, diaANum } from "../Tabla" +import { TablaObserver } from "../TablaObserver" const e = StyleSheet.create({ celdaHora: { @@ -61,8 +62,7 @@ const [diasResaltados, setDiasResaltados] = createState({ interface Props { hora: string, data: DataProcesada, - idHover: () => string, - setIdHover: (v: string) => string + tablaObserver: TablaObserver, } const diasFilter = createMemo(() => Object.entries(diasResaltados) @@ -140,16 +140,15 @@ export function FilaTabla(props: Props) { return ( fnResaltar(dia)} fnDesresaltarFila={() => fnDesresaltar(dia)} dia={dia} + tablaObserver={props.tablaObserver} /> ) }} -
+
) diff --git a/src/ContenedorHorarios/TablaObserver.ts b/src/ContenedorHorarios/TablaObserver.ts index b732d30..e023e56 100644 --- a/src/ContenedorHorarios/TablaObserver.ts +++ b/src/ContenedorHorarios/TablaObserver.ts @@ -1,18 +1,18 @@ +import { createMemo, createState, SetStateFunction, State } from "solid-js" + /** * - Normal * - Oculto - Otro grupo seleccionado - * - Seleccionado - Cursor ensima - * - Resaltado - Grupo seleccionado - * - ResaltadoSeleccionado - Grupo seleccionado y cursor encima - * - ResaltadoOculto - Otro grupo seleccionado y cursor encima + * - Resaltado - Cursor encima + * - Seleccionado - Grupo escogido + * - ResaltadoSeleccionado - Grupo escogido y cursor encima + * - ResaltadoOculto - Otro grupo escogido y cursor encima */ -import { createMemo, createState, SetStateFunction, State } from "solid-js"; - type EstadoCelda = | "Normal" | "Oculto" - | "Seleccionado" | "Resaltado" + | "Seleccionado" | "ResaltadoSeleccionado" | "ResaltadoOculto" @@ -20,7 +20,7 @@ interface Datos { anio?: string, curso?: string, esLab?: boolean, - grupo?: string + grupo?: string, } export class TablaObserver { @@ -28,35 +28,93 @@ export class TablaObserver { private readonly resaltado: State private readonly setResaltado: SetStateFunction private gruposSeleccionados = {} + private memos: {[id: string]: () => EstadoCelda} = {}; constructor() { const [resaltado, setResaltado] = createState({ anio: undefined, curso: undefined, esLab: undefined, - grupo: undefined - }); - this.resaltado = resaltado; - this.setResaltado = setResaltado; + grupo: undefined, + }) + this.resaltado = resaltado + this.setResaltado = setResaltado } - // Cada celda se registra dando estos datos - // Devuelve un memo con un valor de EstadoCelda, - // el cual cada celda sabra como manejar - registrar(anio: string, cursoAbreviado: string, esLab: boolean, grupo: string) { - const fn = () => { - - }; - - const memo = createMemo( - fn, + /** + * Crea un memo que indica el estado de la celda + * @param anio El año + * @param curso Curso abreviado + * @param esLab Si es laboratorio + * @param grupo Una única letra + */ + private registrar(anio: string, curso: string, esLab: boolean, grupo: string): () => EstadoCelda { + const resaltado = this.resaltado + const resaltadoMemo = createMemo( + () => { + if (resaltado.anio === anio && resaltado.curso === curso) { + if (resaltado.esLab === undefined) { + return true + } else if (resaltado.esLab !== esLab) { + return false + } else { + if (resaltado.grupo === undefined) { + return true + } else return resaltado.grupo === grupo; + } + } else { + return false + } + }, undefined, - (x, y) => x === y - ); + (x, y) => x === y, + ) + + return createMemo( + (): EstadoCelda => { + if (resaltadoMemo()) { + return "Resaltado" + } else { + return "Normal" + } + }, + undefined, + (x, y) => x === y, + ) } - resaltar(id: string) { + /** + * Crea un memo que indica el estado de la celda a partir de un id + * @param id Id a registrar - YYYYMMDD_Año_Curso[\_Lab[_Grupo]] + */ + registrarConId(id: string): () => EstadoCelda { + if (this.memos[id]) { + return this.memos[id] + } + const [, anio, curso, lab, grupo] = id.split("_") + const memo = this.registrar(anio, curso, lab === "L", grupo) + this.memos[id] = memo; + return memo; + } + + /** + * Parsea el id y hace que las celdas registradas se actualizen adecuadamente + * @param id Id a resaltar - YYYYMMDD_Año_Curso[\_Lab[_Grupo]] + */ + resaltar(id: string) { + const [, anio, curso, lab, grupo] = id.split("_") + if (anio === undefined || curso === undefined) { + console.error("Error al intentar resaltar celda: anio o curso son undefined:", anio, curso) + return + } + + this.setResaltado({ + anio, + curso, + esLab: lab === "L", + grupo, + }) } quitarResaltado() { @@ -64,7 +122,7 @@ export class TablaObserver { anio: undefined, curso: undefined, esLab: undefined, - grupo: undefined - }); + grupo: undefined, + }) } }