Agregar linter

master
Araozu 2021-03-25 21:39:34 -05:00
parent e2503967cf
commit f325f08fc8
22 changed files with 1845 additions and 810 deletions

89
.eslintrc.yml Normal file
View File

@ -0,0 +1,89 @@
env:
browser: true
es2021: true
extends:
- 'eslint:recommended'
- 'plugin:@typescript-eslint/recommended'
parser: '@typescript-eslint/parser'
parserOptions:
ecmaVersion: 12
sourceType: module
plugins:
- '@typescript-eslint'
- react
rules:
"@typescript-eslint/ban-ts-comment": off
"@typescript-eslint/no-empty-function": off
indent:
- error
- 4
- SwitchCase: 1
linebreak-style:
- error
- unix
quotes:
- error
- double
semi:
- error
- never
react/jsx-pascal-case: error
react/jsx-closing-bracket-location: error
react/jsx-closing-tag-location: error
no-multi-spaces: error
react/jsx-tag-spacing: error
react/jsx-boolean-value: error
react/jsx-wrap-multilines: error
react/self-closing-comp: error
prefer-const: error
no-const-assign: error
no-var: error
array-callback-return: error
prefer-template: error
template-curly-spacing: error
no-useless-escape: error
wrap-iife: error
no-loop-func: error
default-param-last: error
space-before-function-paren:
- error
- never
space-before-blocks: error
no-param-reassign: error
function-paren-newline: error
comma-dangle:
- error
- always-multiline
arrow-spacing: error
arrow-parens: error
arrow-body-style: error
no-confusing-arrow: error
implicit-arrow-linebreak: error
no-duplicate-imports: error
object-curly-newline: error
dot-notation: error
one-var:
- error
- never
no-multi-assign: error
no-plusplus: error
operator-linebreak: error
eqeqeq: error
no-case-declarations: error
no-nested-ternary: error
no-unneeded-ternary: error
no-mixed-operators: error
nonblock-statement-body-position: error
brace-style: error
keyword-spacing: error
space-infix-ops: error
eol-last: error
newline-per-chained-call: error
no-whitespace-before-property: error
space-in-parens: error
array-bracket-spacing: error
key-spacing: error
no-trailing-spaces: error
comma-style: error
radix: error
no-new-wrappers: error

View File

@ -5,7 +5,11 @@
"devDependencies": { "devDependencies": {
"@types/jest": "26.0.20", "@types/jest": "26.0.20",
"@types/node": "14.14.20", "@types/node": "14.14.20",
"@typescript-eslint/eslint-plugin": "^4.19.0",
"@typescript-eslint/parser": "^4.19.0",
"aphrodite": "^2.4.0", "aphrodite": "^2.4.0",
"eslint": "^7.22.0",
"eslint-plugin-react": "^7.23.1",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",
"solid-js": "^0.23.11", "solid-js": "^0.23.11",
"solid-scripts": "0.0.50", "solid-scripts": "0.0.50",

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +1,22 @@
import { BarraSuperior } from "./BarraSuperior"; import { BarraSuperior } from "./BarraSuperior"
import { ContenedorHorarios } from "./ContenedorHorarios/ContenedorHorarios"; import { ContenedorHorarios } from "./ContenedorHorarios/ContenedorHorarios"
import { Wallpaper } from "./Wallpaper"; import { Wallpaper } from "./Wallpaper"
import { Show, createSignal } from "solid-js"; import { Show, createSignal } from "solid-js"
import { css } from "aphrodite"; import { css } from "aphrodite"
import { estilosGlobales } from "./Estilos"; import { estilosGlobales } from "./Estilos"
import { Creditos } from "./Creditos"; import { Creditos } from "./Creditos"
function App() { function App() {
/// @ts-ignore /// @ts-ignore
const soportaBackdropFilter = document.body.style.backdropFilter !== undefined; 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); const [mostrarMensajeBackdropFilter, setMostrarMensaje] = createSignal(mostrarMensajeBackdropFilterRaw)
const ocultarMensajeBackdropFilter = () => { const ocultarMensajeBackdropFilter = () => {
setMostrarMensaje(false); setMostrarMensaje(false)
localStorage.setItem("mensaje-backdrop-filter-oculto", "true"); localStorage.setItem("mensaje-backdrop-filter-oculto", "true")
}; }
return ( return (
<div class="App"> <div class="App">
@ -26,7 +26,8 @@ function App() {
<div className={css(estilosGlobales.contenedor)}> <div className={css(estilosGlobales.contenedor)}>
Tu navegador no soporta "backdrop-filter". Este es solo un efecto Tu navegador no soporta "backdrop-filter". Este es solo un efecto
visual, no afecta la funcionalidad de la página.&nbsp; visual, no afecta la funcionalidad de la página.&nbsp;
<span className={css(estilosGlobales.contenedorCursor, estilosGlobales.contenedorCursorSoft)} <span
className={css(estilosGlobales.contenedorCursor, estilosGlobales.contenedorCursorSoft)}
onClick={ocultarMensajeBackdropFilter} onClick={ocultarMensajeBackdropFilter}
> >
No volver a mostrar. No volver a mostrar.
@ -37,7 +38,7 @@ function App() {
<ContenedorHorarios /> <ContenedorHorarios />
<Creditos /> <Creditos />
</div> </div>
); )
} }
export default App; export default App

View File

@ -1,101 +1,107 @@
import { estilosGlobales } from "./Estilos"; import { estilosGlobales } from "./Estilos"
import { StyleSheet, css } from "aphrodite"; import { StyleSheet, css } from "aphrodite"
import { numWallpaper, setNumWallpaper } from "./Store"; import { numWallpaper, setNumWallpaper } from "./Store"
const totalWallpapers = 5; const totalWallpapers = 5
const e = StyleSheet.create({ const e = StyleSheet.create({
contCambiador: { contCambiador: {
userSelect: "none" userSelect: "none",
}, },
boton: { boton: {
cursor: "pointer", cursor: "pointer",
textDecoration: "underline", textDecoration: "underline",
"::before": { "::before": {
fontSize: "1rem", fontSize: "1rem",
transform: "translateY(0.2rem)" transform: "translateY(0.2rem)",
} },
}, },
botonDesactivado: { botonDesactivado: {
cursor: "not-allowed", cursor: "not-allowed",
textDecoration: "none" textDecoration: "none",
}, },
botonLeft: { botonLeft: {
paddingRight: "0.5rem", paddingRight: "0.5rem",
marginRight: "0.25rem" marginRight: "0.25rem",
}, },
botonRight: { botonRight: {
paddingLeft: "0.5rem", paddingLeft: "0.5rem",
marginRight: "0.25rem" marginRight: "0.25rem",
} },
}); })
const retrocederWallpaper = () => { const retrocederWallpaper = () => {
const num = numWallpaper(); const num = numWallpaper()
if (num > 0) { if (num > 0) {
setNumWallpaper(num - 1); setNumWallpaper(num - 1)
localStorage.setItem("num-img", (num - 1).toString()); localStorage.setItem("num-img", (num - 1).toString())
} else { } else {
setNumWallpaper(totalWallpapers); setNumWallpaper(totalWallpapers)
localStorage.setItem("num-img", (totalWallpapers).toString()); localStorage.setItem("num-img", (totalWallpapers).toString())
}
} }
};
const avanzarWallpaper = () => { const avanzarWallpaper = () => {
const num = numWallpaper(); const num = numWallpaper()
if (num < totalWallpapers) { if (num < totalWallpapers) {
setNumWallpaper(num + 1); setNumWallpaper(num + 1)
localStorage.setItem("num-img", (num + 1).toString()); localStorage.setItem("num-img", (num + 1).toString())
} else { } else {
setNumWallpaper(0); setNumWallpaper(0)
localStorage.setItem("num-img", (0).toString()); localStorage.setItem("num-img", (0).toString())
}
} }
};
function CambiadorImg() { function CambiadorImg() {
return <div className={css(estilosGlobales.inlineBlock, e.contCambiador)}> return (
<div className={css(estilosGlobales.inlineBlock, e.contCambiador)}>
<span className={css(estilosGlobales.contenedor, estilosGlobales.inlineBlock)}> <span className={css(estilosGlobales.contenedor, estilosGlobales.inlineBlock)}>
<i <i
className={"ph-arrow-left " + css(e.boton, e.botonLeft, estilosGlobales.contenedorCursorSoft)} className={`ph-arrow-left ${css(e.boton, e.botonLeft, estilosGlobales.contenedorCursorSoft)}`}
onClick={retrocederWallpaper} onClick={retrocederWallpaper}
title={"Cambiar imagen de fondo"} title={"Cambiar imagen de fondo"}
/> />
Img. {numWallpaper() + 1} Img. {numWallpaper() + 1}
<i <i
className={"ph-arrow-right " + css(e.boton, e.botonRight, estilosGlobales.contenedorCursorSoft)} className={`ph-arrow-right ${css(e.boton, e.botonRight, estilosGlobales.contenedorCursorSoft)}`}
onClick={avanzarWallpaper} onClick={avanzarWallpaper}
title={"Cambiar imagen de fondo"} title={"Cambiar imagen de fondo"}
/> />
</span> </span>
</div>; </div>
)
} }
const estilos = StyleSheet.create({ const estilos = StyleSheet.create({
tituloPrincipal: { tituloPrincipal: {
fontWeight: "bold" fontWeight: "bold",
} },
}); })
export function BarraSuperior() { export function BarraSuperior() {
return <header> return (
<header>
<span className={css( <span className={css(
estilosGlobales.contenedor, estilosGlobales.contenedor,
estilosGlobales.inlineBlock, estilosGlobales.inlineBlock,
estilos.tituloPrincipal estilos.tituloPrincipal,
)}> )}
>
Horarios Unsa Horarios Unsa
</span> </span>
<a href="https://github.com/Araozu/horarios-unsa-2/" target="_blank" title={"Ver codigo fuente en GitHub"} <a href="https://github.com/Araozu/horarios-unsa-2/" target="_blank" title={"Ver codigo fuente en GitHub"}
className={css( className={css(
estilosGlobales.contenedor, estilosGlobales.contenedor,
estilosGlobales.inlineBlock, estilosGlobales.inlineBlock,
estilosGlobales.contenedorCursor estilosGlobales.contenedorCursor,
)}> )}
>
GitHub GitHub
<i class="ph-arrow-up-right" /> <i class="ph-arrow-up-right" />
</a> </a>
<CambiadorImg /> <CambiadorImg />
<span className={css(estilosGlobales.contenedor, estilosGlobales.inlineBlock)}>2021-A</span> <span className={css(estilosGlobales.contenedor, estilosGlobales.inlineBlock)}>2021-A</span>
<span className={css(estilosGlobales.contenedor, estilosGlobales.inlineBlock)}>Ingeniería de Sistemas</span> <span className={css(estilosGlobales.contenedor, estilosGlobales.inlineBlock)}>Ingeniería de Sistemas</span>
</header>; </header>
)
} }

View File

@ -1,5 +1,5 @@
import { css } from "aphrodite"; import { css } from "aphrodite"
import { estilosGlobales } from "../Estilos"; import { estilosGlobales } from "../Estilos"
interface BotonMaxMinProps { interface BotonMaxMinProps {
icono: string, icono: string,
@ -8,16 +8,18 @@ interface BotonMaxMinProps {
} }
export function BotonIcono(props: BotonMaxMinProps) { export function BotonIcono(props: BotonMaxMinProps) {
return <div title={props.titulo} return (
<div title={props.titulo}
onClick={props.onClick} onClick={props.onClick}
className={css( className={css(
estilosGlobales.contenedor, estilosGlobales.contenedor,
estilosGlobales.inlineBlock, estilosGlobales.inlineBlock,
estilosGlobales.contenedorCursor, estilosGlobales.contenedorCursor,
estilosGlobales.contenedorCursorSoft, estilosGlobales.contenedorCursorSoft,
estilosGlobales.contenedorPhospor estilosGlobales.contenedorPhospor,
)} )}
> >
<i className={css(estilosGlobales.botonPhospor) + " " + props.icono}/> <i className={`${css(estilosGlobales.botonPhospor)} ${props.icono}`} />
</div> </div>
)
} }

View File

@ -1,6 +1,6 @@
import { css } from "aphrodite"; import { css } from "aphrodite"
import { estilosGlobales } from "../Estilos"; import { estilosGlobales } from "../Estilos"
import { EstadoLayout } from "./ContenedorHorarios"; import { EstadoLayout } from "./ContenedorHorarios"
interface BotonMaxMinProps { interface BotonMaxMinProps {
fnMaximizar: () => void, fnMaximizar: () => void,
@ -10,30 +10,33 @@ interface BotonMaxMinProps {
} }
export function BotonMaxMin(props: BotonMaxMinProps) { export function BotonMaxMin(props: BotonMaxMinProps) {
const horariosMax = () => props.estadoActualLayout() === props.estadoLayoutMax; const horariosMax = () => props.estadoActualLayout() === props.estadoLayoutMax
const tituloBoton = () => horariosMax() ? "Minimizar" : "Maximizar"; const tituloBoton = () => (horariosMax() ? "Minimizar" : "Maximizar")
const iconoBoton = () => horariosMax() ? "ph-arrows-in" : "ph-arrows-out"; const iconoBoton = () => (horariosMax() ? "ph-arrows-in" : "ph-arrows-out")
const funcionBoton = () => { const funcionBoton = () => {
const estaMaximizado = horariosMax(); const estaMaximizado = horariosMax()
if (estaMaximizado) { if (estaMaximizado) {
props.fnMinimizar(); props.fnMinimizar()
} else { } else {
props.fnMaximizar(); props.fnMaximizar()
}
} }
};
return <div title={tituloBoton()} return (
<div
title={tituloBoton()}
onClick={funcionBoton} onClick={funcionBoton}
className={css( className={css(
estilosGlobales.contenedor, estilosGlobales.contenedor,
estilosGlobales.inlineBlock, estilosGlobales.inlineBlock,
estilosGlobales.contenedorCursor, estilosGlobales.contenedorCursor,
estilosGlobales.contenedorCursorSoft, estilosGlobales.contenedorCursorSoft,
estilosGlobales.contenedorPhospor estilosGlobales.contenedorPhospor,
)} )}
> >
<i className={css(estilosGlobales.botonPhospor) + " " + iconoBoton()}/> <i className={`${css(estilosGlobales.botonPhospor)} ${iconoBoton()}`} />
</div> </div>
)
} }

View File

@ -1,7 +1,7 @@
import YAML from "yaml"; import YAML from "yaml"
import { css, StyleSheet } from "aphrodite"; import { css, StyleSheet } from "aphrodite"
import { MiHorario } from "./MiHorario"; import { MiHorario } from "./MiHorario"
import { Horarios } from "./Horarios"; import { Horarios } from "./Horarios"
import { import {
Anios, Anios,
Cursos, Cursos,
@ -10,110 +10,113 @@ import {
DatosHorario, DatosHorario,
DatosHorarioRaw, DatosHorarioRaw,
DatosGrupo, DatosGrupo,
ListaCursosUsuario ListaCursosUsuario,
} from "../types/DatosHorario"; } from "../types/DatosHorario"
import { estilosGlobales } from "../Estilos"; import { estilosGlobales } from "../Estilos"
import { batch, createEffect, createMemo, createSignal, createState, Show } from "solid-js"; import { batch, createEffect, createMemo, createSignal, createState, Show } from "solid-js"
import { useListaCursos } from "./useListaCursos"; import { useListaCursos } from "./useListaCursos"
const datosPromise = (async() => { const datosPromise = (async() => {
const file = await fetch("/horarios/2020_2_fps_ingenieriadesistemas.yaml"); const file = await fetch("/horarios/2020_2_fps_ingenieriadesistemas.yaml")
const text = await file.text(); const text = await file.text()
const datosRaw = YAML.parse(text) as DatosHorarioRaw; const datosRaw = YAML.parse(text) as DatosHorarioRaw
// Agregar los campos faltantes a DatosHorarioRaw para que sea DatosHorario // Agregar los campos faltantes a DatosHorarioRaw para que sea DatosHorario
const datos: DatosHorario = { const datos: DatosHorario = {
...datosRaw, ...datosRaw,
años: {} años: {},
}; }
const anios: Anios = {} const anios: Anios = {}
for (const [nombreAnio, anio] of Object.entries(datosRaw.años)) { for (const [nombreAnio, anio] of Object.entries(datosRaw.años)) {
const anioData: Cursos = {}; const anioData: Cursos = {}
for (const [nombreCurso, curso] of Object.entries(anio)) { for (const [nombreCurso, curso] of Object.entries(anio)) {
const gruposTeoria: { [k: string]: DatosGrupo } = {}; const gruposTeoria: { [k: string]: DatosGrupo } = {}
for (const [key, data] of Object.entries(curso.Teoria)) { for (const [key, data] of Object.entries(curso.Teoria)) {
gruposTeoria[key] = Object.assign({seleccionado: false}, data); gruposTeoria[key] = Object.assign({seleccionado: false}, data)
} }
const gruposLab: { [k: string]: DatosGrupo } = {}; const gruposLab: { [k: string]: DatosGrupo } = {}
for (const [key, data] of Object.entries(curso.Laboratorio ?? {})) { for (const [key, data] of Object.entries(curso.Laboratorio ?? {})) {
gruposLab[key] = Object.assign({seleccionado: false}, data); gruposLab[key] = Object.assign({seleccionado: false}, data)
} }
anioData[nombreCurso] = { anioData[nombreCurso] = {
...curso, ...curso,
oculto: false, oculto: false,
Teoria: gruposTeoria, Teoria: gruposTeoria,
Laboratorio: gruposLab Laboratorio: gruposLab,
}; }
} }
anios[nombreAnio] = anioData; anios[nombreAnio] = anioData
} }
datos.años = anios; datos.años = anios
return datos; return datos
})(); })()
const ElemCargando = () => const ElemCargando = () => (
<div className={css(estilosGlobales.contenedor, estilosGlobales.inlineBlock)}> <div className={css(estilosGlobales.contenedor, estilosGlobales.inlineBlock)}>
Recuperando horarios... Recuperando horarios...
</div> </div>
)
export type EstadoLayout = "MaxPersonal" | "Normal" | "MaxHorarios"; export type EstadoLayout = "MaxPersonal" | "Normal" | "MaxHorarios";
const { const {
listaCursos: cursosUsuario, listaCursos: cursosUsuario,
setListaCursos: setCursosUsuarios, setListaCursos: setCursosUsuarios,
agregarCursoALista: agregarCursoUsuario agregarCursoALista: agregarCursoUsuario,
} = useListaCursos(); } = useListaCursos()
export function ContenedorHorarios() { export function ContenedorHorarios() {
const [datosCargados, setDatosCargados] = createSignal(false); const [datosCargados, setDatosCargados] = createSignal(false)
const [datos, setDatos] = createSignal<DatosHorario | null>(null); const [datos, setDatos] = createSignal<DatosHorario | null>(null)
const [estadoLayout, setEstadoLayout] = createSignal<EstadoLayout>( const [estadoLayout, setEstadoLayout] = (
localStorage.getItem("estadoLayout") as EstadoLayout || "Normal" createSignal<EstadoLayout>(localStorage.getItem("estadoLayout") as EstadoLayout || "Normal")
); )
const e = createMemo(() => { const e = createMemo(() => {
let templateColumns = ""; let templateColumns = ""
switch (estadoLayout()) { switch (estadoLayout()) {
case "MaxHorarios": { case "MaxHorarios": {
templateColumns = "4rem auto"; templateColumns = "4rem auto"
break; break
} }
case "MaxPersonal": { case "MaxPersonal": {
templateColumns = "auto 4rem"; templateColumns = "auto 4rem"
break; break
} }
case "Normal": { case "Normal": {
templateColumns = "50% 50%" templateColumns = "50% 50%"
} }
} }
localStorage.setItem("estadoLayout", estadoLayout()); localStorage.setItem("estadoLayout", estadoLayout())
return StyleSheet.create({ return StyleSheet.create({
contenedor: { contenedor: {
display: "grid", display: "grid",
gridTemplateColumns: templateColumns gridTemplateColumns: templateColumns,
} },
}); })
}); })
createEffect(async() => { createEffect(async() => {
const datos = await datosPromise; const datos = await datosPromise
batch(() => { batch(() => {
setDatos(datos); setDatos(datos)
setDatosCargados(true); setDatosCargados(true)
}); })
}); })
return <div className={css(e().contenedor)}> return (
<div className={css(e().contenedor)}>
<div> <div>
<MiHorario estadoLayout={estadoLayout()} <MiHorario
estadoLayout={estadoLayout()}
setEstadoLayout={setEstadoLayout} setEstadoLayout={setEstadoLayout}
cursosUsuario={cursosUsuario} cursosUsuario={cursosUsuario}
fnAgregarCurso={agregarCursoUsuario} fnAgregarCurso={agregarCursoUsuario}
@ -122,7 +125,8 @@ export function ContenedorHorarios() {
</div> </div>
<div> <div>
<Show when={datosCargados()}> <Show when={datosCargados()}>
<Horarios data={datos()!!} <Horarios
data={datos()!}
estadoLayout={estadoLayout()} estadoLayout={estadoLayout()}
setEstadoLayout={setEstadoLayout} setEstadoLayout={setEstadoLayout}
fnAgregarCurso={(c) => agregarCursoUsuario(JSON.parse(JSON.stringify(c)))} fnAgregarCurso={(c) => agregarCursoUsuario(JSON.parse(JSON.stringify(c)))}
@ -131,5 +135,6 @@ export function ContenedorHorarios() {
/> />
</Show> </Show>
</div> </div>
</div>; </div>
)
} }

View File

@ -1,32 +1,32 @@
import { Cursos, CursoRaw, DatosGrupo, ListaCursosUsuario, Curso } from "../types/DatosHorario"; import { Cursos, CursoRaw, DatosGrupo, ListaCursosUsuario, Curso } from "../types/DatosHorario"
import { createEffect, createMemo, For, SetStateFunction } from "solid-js"; import { createEffect, createMemo, For, SetStateFunction } from "solid-js"
import { StyleSheet, css } from "aphrodite"; import { StyleSheet, css } from "aphrodite"
import { estilosGlobales } from "../Estilos"; import { estilosGlobales } from "../Estilos"
const e = StyleSheet.create({ const e = StyleSheet.create({
inline: { inline: {
display: "inline-block" display: "inline-block",
}, },
lineaTexto: { lineaTexto: {
marginBottom: "0.5rem" marginBottom: "0.5rem",
}, },
tablaGrupos: { tablaGrupos: {
whiteSpace: "pre", whiteSpace: "pre",
borderCollapse: "collapse", borderCollapse: "collapse",
borderSpacing: 0 borderSpacing: 0,
}, },
contenedorCurso: { contenedorCurso: {
display: "inline-block", display: "inline-block",
verticalAlign: "top" verticalAlign: "top",
}, },
cursoOculto: { cursoOculto: {
display: "none" display: "none",
}, },
botonTexto: { botonTexto: {
padding: "0.25rem 0.35rem", padding: "0.25rem 0.35rem",
borderRadius: "5px" borderRadius: "5px",
} },
}); })
interface Props { interface Props {
dataAnio: Cursos, dataAnio: Cursos,
@ -50,8 +50,9 @@ interface PropsIndicadorGrupo {
} }
function IndicadorGrupo(props: PropsIndicadorGrupo) { function IndicadorGrupo(props: PropsIndicadorGrupo) {
const id = `${props.idParcial}_${props.esLab ? 'L' : 'T'}_${props.nombre}`; const id = `${props.idParcial}_${props.esLab ? "L" : "T"}_${props.nombre}`
return <span className={css(e.botonTexto, estilosGlobales.contenedorCursor, estilosGlobales.contenedorCursorSoft)} return (
<span className={css(e.botonTexto, estilosGlobales.contenedorCursor, estilosGlobales.contenedorCursorSoft)}
style={props.esLab ? {"font-style": "italic"} : {"font-weight": "bold"}} style={props.esLab ? {"font-style": "italic"} : {"font-weight": "bold"}}
onMouseEnter={() => props.setIdHover(id)} onMouseEnter={() => props.setIdHover(id)}
onMouseLeave={() => props.setIdHover("")} onMouseLeave={() => props.setIdHover("")}
@ -59,14 +60,20 @@ function IndicadorGrupo(props: PropsIndicadorGrupo) {
> >
{props.esLab ? "L" : ""}{props.nombre} {props.esLab ? "L" : ""}{props.nombre}
</span> </span>
)
} }
const agruparProfesores = (datos: { [k: string]: DatosGrupo }, indiceCurso: number, esLab: boolean, setCursosUsuarios: FnSetCursosUsuarios) => { const agruparProfesores = (
const profesores: { [k: string]: [string, () => void][] } = {}; datos: { [k: string]: DatosGrupo },
indiceCurso: number,
esLab: boolean,
setCursosUsuarios: FnSetCursosUsuarios,
) => {
const profesores: { [k: string]: [string, () => void][] } = {}
for (const [grupo, datosGrupo] of Object.entries(datos)) { for (const [grupo, datosGrupo] of Object.entries(datos)) {
const nombreProfesor = datosGrupo.Docente; const nombreProfesor = datosGrupo.Docente
if (!profesores[nombreProfesor]) { if (!profesores[nombreProfesor]) {
profesores[nombreProfesor] = []; profesores[nombreProfesor] = []
} }
profesores[nombreProfesor].push([ profesores[nombreProfesor].push([
grupo, grupo,
@ -78,48 +85,46 @@ const agruparProfesores = (datos: { [k: string]: DatosGrupo }, indiceCurso: numb
/// @ts-ignore /// @ts-ignore
grupo, grupo,
"seleccionado", "seleccionado",
x => !x (x) => !x,
); )
},
])
} }
]); return profesores
} }
return profesores;
};
export function CursosElem(props: Props) { export function CursosElem(props: Props) {
const anio = () => props.anioActual().substring(0, props.anioActual().indexOf(" ")); const anio = () => props.anioActual().substring(0, props.anioActual().indexOf(" "))
const claseCursoNoAgregado = css( const claseCursoNoAgregado = css(
e.contenedorCurso, e.contenedorCurso,
estilosGlobales.contenedor estilosGlobales.contenedor,
); )
const claseCursoAgregado = css( const claseCursoAgregado = css(
e.contenedorCurso, e.contenedorCurso,
estilosGlobales.contenedor, estilosGlobales.contenedor,
!props.esCursoMiHorario && estilosGlobales.contenedorCursorActivo, !props.esCursoMiHorario && estilosGlobales.contenedorCursorActivo,
); )
const claseCursoOculto = css(e.cursoOculto); const claseCursoOculto = css(e.cursoOculto)
return <> return (
<>
<For each={Object.entries(props.dataAnio)}> <For each={Object.entries(props.dataAnio)}>
{([indiceCurso, datosCurso]) => { {([indiceCurso, datosCurso]) => {
const idCurso = `${anio()}_${datosCurso.abreviado}`; const idCurso = `${anio()}_${datosCurso.abreviado}`
const cursoAgregadoMemo = createMemo( const cursoAgregadoMemo = createMemo(
() => props.listaCursosUsuario.cursos.find(x => { () => props.listaCursosUsuario.cursos.find((x) => x.nombre === datosCurso.nombre && !x.oculto) !== undefined,
return x.nombre === datosCurso.nombre && !x.oculto
}) !== undefined,
undefined, undefined,
(x, y) => x === y (x, y) => x === y,
); )
const tituloMemo = createMemo(() => cursoAgregadoMemo() const tituloMemo = createMemo(() => (cursoAgregadoMemo()
? `Remover de mi horario` ? "Remover de mi horario"
: `Agregar a mi horario` : "Agregar a mi horario"))
);
const claseMemo = createMemo(() => { const claseMemo = createMemo(() => {
if (props.esCursoMiHorario && datosCurso.oculto) { if (props.esCursoMiHorario && datosCurso.oculto) {
@ -128,22 +133,23 @@ export function CursosElem(props: Props) {
return cursoAgregadoMemo() return cursoAgregadoMemo()
? claseCursoAgregado ? claseCursoAgregado
: claseCursoNoAgregado : claseCursoNoAgregado
}); })
const profesoresTeoria = createMemo(() => agruparProfesores( const profesoresTeoria = createMemo(() => agruparProfesores(
datosCurso.Teoria, datosCurso.Teoria,
parseInt(indiceCurso), Number(indiceCurso),
false, false,
props.setCursosUsuarios props.setCursosUsuarios,
)); ))
const profesoresLab = createMemo(() => agruparProfesores( const profesoresLab = createMemo(() => agruparProfesores(
datosCurso.Laboratorio ?? {}, datosCurso.Laboratorio ?? {},
parseInt(indiceCurso), Number(indiceCurso),
true, true,
props.setCursosUsuarios props.setCursosUsuarios,
)); ))
return <div className={claseMemo()}> return (
<div className={claseMemo()}>
<div <div
className={css(e.inline, e.lineaTexto, e.botonTexto, estilosGlobales.contenedorCursor, estilosGlobales.contenedorCursorSoft)} className={css(e.inline, e.lineaTexto, e.botonTexto, estilosGlobales.contenedorCursor, estilosGlobales.contenedorCursorSoft)}
onMouseEnter={() => props.setIdHover(idCurso)} onMouseEnter={() => props.setIdHover(idCurso)}
@ -155,44 +161,46 @@ export function CursosElem(props: Props) {
<tbody> <tbody>
<tr> <tr>
<For each={Object.entries(profesoresTeoria())}> <For each={Object.entries(profesoresTeoria())}>
{([profesor, grupos]) => { {([profesor, grupos]) => (
return <td style={{"padding-bottom": "0.5rem", "padding-right": "0.75rem"}}> <td style={{"padding-bottom": "0.5rem", "padding-right": "0.75rem"}}>
<span> <span>
{profesor}&nbsp; {profesor}&nbsp;
</span> </span>
<For each={grupos}> <For each={grupos}>
{([x, fnOnClick]) => {([x, fnOnClick]) => (
<IndicadorGrupo nombre={x} <IndicadorGrupo nombre={x}
esLab={false} esLab={false}
idParcial={idCurso} idParcial={idCurso}
setIdHover={props.setIdHover} setIdHover={props.setIdHover}
onClick={fnOnClick} onClick={fnOnClick}
/> />
)
} }
</For> </For>
</td> </td>
}} )}
</For> </For>
</tr> </tr>
<tr> <tr>
<For each={Object.entries(profesoresLab())}> <For each={Object.entries(profesoresLab())}>
{([profesor, grupos]) => { {([profesor, grupos]) => (
return <td style={{"padding-bottom": "0.5rem", "padding-right": "0.75rem"}}> <td style={{"padding-bottom": "0.5rem", "padding-right": "0.75rem"}}>
<span> <span>
{profesor}&nbsp; {profesor}&nbsp;
</span> </span>
<For each={grupos}> <For each={grupos}>
{([x, fnOnClick]) => {([x, fnOnClick]) => (
<IndicadorGrupo nombre={x} <IndicadorGrupo nombre={x}
esLab={true} esLab
idParcial={idCurso} idParcial={idCurso}
setIdHover={props.setIdHover} setIdHover={props.setIdHover}
onClick={fnOnClick} onClick={fnOnClick}
/> />
)
} }
</For> </For>
</td> </td>
}} )}
</For> </For>
</tr> </tr>
</tbody> </tbody>
@ -204,7 +212,9 @@ export function CursosElem(props: Props) {
{tituloMemo} {tituloMemo}
</span> </span>
</div> </div>
)
}} }}
</For> </For>
</>; </>
)
} }

View File

@ -1,12 +1,12 @@
import { Curso, Cursos, DatosHorario, ListaCursosUsuario } from "../types/DatosHorario"; import { Curso, Cursos, DatosHorario, ListaCursosUsuario } from "../types/DatosHorario"
import { batch, createMemo, createSignal, For, Match, SetStateFunction, Switch, untrack } from "solid-js"; import { batch, createMemo, createSignal, For, Match, SetStateFunction, Switch, untrack } from "solid-js"
import { css } from "aphrodite"; import { css } from "aphrodite"
import { estilosGlobales } from "../Estilos"; import { estilosGlobales } from "../Estilos"
import { Tabla } from "./Tabla"; import { Tabla } from "./Tabla"
import { CursosElem } from "./CursosElem"; import { CursosElem } from "./CursosElem"
import { EstadoLayout } from "./ContenedorHorarios"; import { EstadoLayout } from "./ContenedorHorarios"
import { BotonMaxMin } from "./BotonMaxMin"; import { BotonMaxMin } from "./BotonMaxMin"
import { useListaCursos } from "./useListaCursos"; import { useListaCursos } from "./useListaCursos"
interface HorariosProps { interface HorariosProps {
data: DatosHorario, data: DatosHorario,
@ -20,65 +20,71 @@ interface HorariosProps {
const { const {
setListaCursos, setListaCursos,
agregarCursoALista, agregarCursoALista,
eliminarCursosDeLista eliminarCursosDeLista,
} = useListaCursos(); } = useListaCursos()
export function Horarios(props: HorariosProps) { export function Horarios(props: HorariosProps) {
const [anioActual, setAnioActual] = createSignal("1er año"); const [anioActual, setAnioActual] = createSignal("1er año")
// ID que indica cuales celdas resaltar. // ID que indica cuales celdas resaltar.
const [idHover, setIdHover] = createSignal(""); const [idHover, setIdHover] = createSignal("")
const elAnios = <For each={Object.entries(props.data.años)}> const elAnios = (
<For each={Object.entries(props.data.años)}>
{([nombre]) => { {([nombre]) => {
const clases = createMemo(() => { const clases = createMemo(() => {
const vAnio = anioActual(); const vAnio = anioActual()
return css( return css(
estilosGlobales.contenedor, estilosGlobales.contenedor,
estilosGlobales.inlineBlock, estilosGlobales.inlineBlock,
estilosGlobales.contenedorCursor, estilosGlobales.contenedorCursor,
estilosGlobales.contenedorCursorSoft, estilosGlobales.contenedorCursorSoft,
nombre === vAnio && estilosGlobales.contenedorCursorActivo nombre === vAnio && estilosGlobales.contenedorCursorActivo,
); )
}); })
return <div className={clases()} title={"Cambiar a " + nombre} onClick={() => setAnioActual(nombre)}> return (
<div className={clases()} title={`Cambiar a ${nombre}`} onClick={() => setAnioActual(nombre)}>
{nombre} {nombre}
</div> </div>
)
}} }}
</For>; </For>
)
const dataTabla = createMemo(() => { const dataTabla = createMemo(() => {
const anio = anioActual(); const anio = anioActual()
const obj: Cursos = {}; const obj: Cursos = {}
untrack(() => { untrack(() => {
const cursos = props.data.años[anio]; const cursos = props.data.años[anio]
batch(() => { batch(() => {
eliminarCursosDeLista(); eliminarCursosDeLista()
let i = 0; let i = 0
for (const [, curso] of Object.entries(cursos)) { for (const [, curso] of Object.entries(cursos)) {
// El curso devuelto por esta fun. es reactivo // El curso devuelto por esta fun. es reactivo
obj[i] = agregarCursoALista(curso); obj[i] = agregarCursoALista(curso)
i++; i += 1
} }
}); })
}); })
return obj; return obj
}); })
const fnMaximizar = () => props.setEstadoLayout("MaxHorarios"); const fnMaximizar = () => props.setEstadoLayout("MaxHorarios")
const fnMinimizar = () => props.setEstadoLayout("Normal"); const fnMinimizar = () => props.setEstadoLayout("Normal")
const estadoActualLayout = () => props.estadoLayout; const estadoActualLayout = () => props.estadoLayout
return <div> return (
<div>
<Switch> <Switch>
<Match when={props.estadoLayout === "Normal" || props.estadoLayout === "MaxHorarios"}> <Match when={props.estadoLayout === "Normal" || props.estadoLayout === "MaxHorarios"}>
<div> <div>
<div className={css( <div className={css(
estilosGlobales.inlineBlock, estilosGlobales.inlineBlock,
estilosGlobales.contenedor estilosGlobales.contenedor,
)}> )}
>
Horarios disponibles Horarios disponibles
</div> </div>
</div> </div>
@ -92,7 +98,8 @@ export function Horarios(props: HorariosProps) {
/> />
<br /> <br />
<div className={css(estilosGlobales.contenedor)}> <div className={css(estilosGlobales.contenedor)}>
<Tabla data={dataTabla()} <Tabla
data={dataTabla()}
version={props.data.version} version={props.data.version}
anio={anioActual()} anio={anioActual()}
idHover={idHover} idHover={idHover}
@ -101,7 +108,8 @@ export function Horarios(props: HorariosProps) {
/> />
</div> </div>
<div> <div>
<CursosElem dataAnio={dataTabla()} <CursosElem
dataAnio={dataTabla()}
anioActual={anioActual} anioActual={anioActual}
fnAgregarCurso={props.fnAgregarCurso} fnAgregarCurso={props.fnAgregarCurso}
listaCursosUsuario={props.listaCursosUsuario} listaCursosUsuario={props.listaCursosUsuario}
@ -122,5 +130,6 @@ export function Horarios(props: HorariosProps) {
</Match> </Match>
</Switch> </Switch>
</div>; </div>
)
} }

View File

@ -1,13 +1,13 @@
import { estilosGlobales } from "../Estilos"; import { estilosGlobales } from "../Estilos"
import { StyleSheet, css } from "aphrodite"; import { StyleSheet, css } from "aphrodite"
import { Tabla } from "./Tabla"; import { Tabla } from "./Tabla"
import { mostrarDescansos } from "../Store"; import { mostrarDescansos } from "../Store"
import { EstadoLayout } from "./ContenedorHorarios"; import { EstadoLayout } from "./ContenedorHorarios"
import { Switch, Match, For, createMemo, createSignal, SetStateFunction } from "solid-js"; import { Switch, Match, For, createMemo, createSignal, SetStateFunction } from "solid-js"
import { BotonMaxMin } from "./BotonMaxMin"; import { BotonMaxMin } from "./BotonMaxMin"
import { BotonIcono } from "./BotonIcono"; import { BotonIcono } from "./BotonIcono"
import { Curso, Cursos, ListaCursosUsuario } from "../types/DatosHorario"; import { Curso, Cursos, ListaCursosUsuario } from "../types/DatosHorario"
import { CursosElem } from "./CursosElem"; import { CursosElem } from "./CursosElem"
interface MiHorarioProps { interface MiHorarioProps {
estadoLayout: EstadoLayout, estadoLayout: EstadoLayout,
@ -25,39 +25,41 @@ const e = StyleSheet.create({
"::before": { "::before": {
fontSize: "1rem", fontSize: "1rem",
// transform: "translateY(0.2rem)", // transform: "translateY(0.2rem)",
textDecoration: "none" textDecoration: "none",
} },
} },
}); })
export function MiHorario(props: MiHorarioProps) { export function MiHorario(props: MiHorarioProps) {
const [idHover, setIdHover] = createSignal(""); const [idHover, setIdHover] = createSignal("")
const datosMiHorario = createMemo(() => { const datosMiHorario = createMemo(() => {
const obj: Cursos = {}; const obj: Cursos = {}
props.cursosUsuario.cursos.forEach((x, i) => { props.cursosUsuario.cursos.forEach((x, i) => {
obj[i] = x; obj[i] = x
}); })
return obj; return obj
}); })
const fnMaximizar = () => props.setEstadoLayout("MaxPersonal"); const fnMaximizar = () => props.setEstadoLayout("MaxPersonal")
const fnMinimizar = () => props.setEstadoLayout("Normal"); const fnMinimizar = () => props.setEstadoLayout("Normal")
const estadoActualLayout = () => props.estadoLayout; const estadoActualLayout = () => props.estadoLayout
/* TODO: En barra superior colocar todos los horarios. En barra inferior el horario /* TODO: En barra superior colocar todos los horarios. En barra inferior el horario
actual. actual.
Al hacer click en un horario de la barra superior, llevarlo al inicio de la lista. Al hacer click en un horario de la barra superior, llevarlo al inicio de la lista.
*/ */
return <div> return (
<div>
<Switch> <Switch>
<Match when={props.estadoLayout === "Normal" || props.estadoLayout === "MaxPersonal"}> <Match when={props.estadoLayout === "Normal" || props.estadoLayout === "MaxPersonal"}>
<div> <div>
<div className={css( <div className={css(
estilosGlobales.inlineBlock, estilosGlobales.inlineBlock,
estilosGlobales.contenedor estilosGlobales.contenedor,
)}> )}
>
Mi horario Mi horario
</div> </div>
</div> </div>
@ -65,30 +67,30 @@ export function MiHorario(props: MiHorarioProps) {
<div> <div>
<div className={css( <div className={css(
estilosGlobales.inlineBlock, estilosGlobales.inlineBlock,
estilosGlobales.contenedor estilosGlobales.contenedor,
)}> )}
>
Mi horario Mi horario
</div> </div>
| |
<BotonIcono titulo={"Nuevo horario en blanco"} <BotonIcono
titulo={"Nuevo horario en blanco"}
icono={"ph-plus"} icono={"ph-plus"}
onClick={() => { onClick={() => {}}
}}
/> />
<BotonIcono titulo={"Reiniciar horario"} <BotonIcono
titulo={"Reiniciar horario"}
icono={"ph-arrow-counter-clockwise"} icono={"ph-arrow-counter-clockwise"}
onClick={() => { onClick={() => {}}
}}
/> />
<BotonIcono titulo={"Duplicar horario"} <BotonIcono
titulo={"Duplicar horario"}
icono={"ph-copy"} icono={"ph-copy"}
onClick={() => { onClick={() => {}}
}}
/> />
<BotonIcono titulo={"Eliminar horario"} <BotonIcono titulo={"Eliminar horario"}
icono={"ph-trash"} icono={"ph-trash"}
onClick={() => { onClick={() => {}}
}}
/> />
| |
<BotonMaxMin <BotonMaxMin
@ -101,9 +103,11 @@ export function MiHorario(props: MiHorarioProps) {
<div className={css( <div className={css(
e.horario, e.horario,
estilosGlobales.contenedor estilosGlobales.contenedor,
)}> )}
<Tabla data={datosMiHorario()} >
<Tabla
data={datosMiHorario()}
anio={"Mi horario"} anio={"Mi horario"}
version={1} version={1}
idHover={idHover} idHover={idHover}
@ -112,13 +116,14 @@ export function MiHorario(props: MiHorarioProps) {
/> />
</div> </div>
<CursosElem anioActual={() => "Mi horario"} <CursosElem
anioActual={() => "Mi horario"}
dataAnio={datosMiHorario()} dataAnio={datosMiHorario()}
fnAgregarCurso={props.fnAgregarCurso} fnAgregarCurso={props.fnAgregarCurso}
listaCursosUsuario={props.cursosUsuario} listaCursosUsuario={props.cursosUsuario}
idHover={idHover} idHover={idHover}
setIdHover={setIdHover} setIdHover={setIdHover}
esCursoMiHorario={true} esCursoMiHorario
setCursosUsuarios={props.setCursosUsuarios} setCursosUsuarios={props.setCursosUsuarios}
/> />
</Match> </Match>
@ -131,5 +136,6 @@ export function MiHorario(props: MiHorarioProps) {
/> />
</Match> </Match>
</Switch> </Switch>
</div>; </div>
)
} }

View File

@ -1,31 +1,30 @@
import { StyleSheet, css } from "aphrodite"; import { StyleSheet, css } from "aphrodite"
import { createEffect, createMemo, createSignal, createState, For, SetStateFunction } from "solid-js"; import { createMemo, For, SetStateFunction } from "solid-js"
import { estilosGlobales } from "../Estilos"; import { estilosGlobales } from "../Estilos"
import { Cursos, Curso, ListaCursosUsuario } from "../types/DatosHorario"; import { Cursos, ListaCursosUsuario, DataProcesada } from "../types/DatosHorario"
import { Dia, dias, horas } from "../Store"; import { Dia, dias, horas } from "../Store"
import { DataProcesada } from "../types/DatosHorario"; import { FilaTabla } from "./Tabla/FilaTabla"
import { FilaTabla } from "./Tabla/FilaTabla";
export const coloresBorde = Object.freeze([ export const coloresBorde = Object.freeze([
"rgba(33,150,243,1)", "rgba(33,150,243,1)",
"rgba(255,214,0 ,1)", "rgba(255,214,0 ,1)",
"rgba(236,64,122 ,1)", "rgba(236,64,122 ,1)",
"rgba(29,233,182 ,1)", "rgba(29,233,182 ,1)",
"rgba(244,67,54,1)" "rgba(244,67,54,1)",
]); ])
export const diaANum = (d: Dia) => { export const diaANum = (d: Dia) => {
switch (d) { switch (d) {
case "Lunes": case "Lunes":
return 0; return 0
case "Martes": case "Martes":
return 1; return 1
case "Miercoles": case "Miercoles":
return 2; return 2
case "Jueves": case "Jueves":
return 3; return 3
case "Viernes": case "Viernes":
return 4; return 4
} }
} }
@ -40,7 +39,7 @@ const e = StyleSheet.create({
minHeight: "1.5rem", minHeight: "1.5rem",
":hover": { ":hover": {
// backgroundColor: "rgba(200, 200, 200, 0.25)" // backgroundColor: "rgba(200, 200, 200, 0.25)"
} },
}, },
filaBorde: { filaBorde: {
position: "absolute", position: "absolute",
@ -48,65 +47,65 @@ const e = StyleSheet.create({
height: "1px", height: "1px",
width: "100%", width: "100%",
backgroundColor: "rgba(200, 200, 200, 0.25)", backgroundColor: "rgba(200, 200, 200, 0.25)",
zIndex: 1 zIndex: 1,
}, },
celdaHora: { celdaHora: {
textAlign: "center", textAlign: "center",
width: "4rem", width: "4rem",
padding: "0.25rem 0", padding: "0.25rem 0",
position: "absolute", position: "absolute",
top: "-0.75rem" top: "-0.75rem",
}, },
celdaComun: { celdaComun: {
width: "20%", width: "20%",
textAlign: "center", textAlign: "center",
padding: "0 0.5rem", padding: "0 0.5rem",
boxSizing: "border-box" boxSizing: "border-box",
}, },
celdaDia: { celdaDia: {
padding: "0.3rem 0" padding: "0.3rem 0",
}, },
celdaCurso: { celdaCurso: {
display: "inline-block", display: "inline-block",
padding: "0.25rem 0.35rem", padding: "0.25rem 0.35rem",
cursor: "pointer", cursor: "pointer",
borderRadius: "5px", borderRadius: "5px",
transition: "background-color 100ms" transition: "background-color 100ms",
}, },
celdaCursoActiva: { celdaCursoActiva: {
backgroundColor: "rgba(200, 200, 200, 0.25)" backgroundColor: "rgba(200, 200, 200, 0.25)",
}, },
celdaCursoTeoria: { celdaCursoTeoria: {
fontWeight: "bold" fontWeight: "bold",
} },
}); })
type FnSetCursosUsuarios = SetStateFunction<ListaCursosUsuario>; type FnSetCursosUsuarios = SetStateFunction<ListaCursosUsuario>;
const procesarAnio = (data: Cursos, anio: string, version: number, setCursosUsuarios: FnSetCursosUsuarios) => { const procesarAnio = (data: Cursos, anio: string, version: number, setCursosUsuarios: FnSetCursosUsuarios) => {
const obj: DataProcesada = {}; const obj: DataProcesada = {}
for (const [indiceCurso, curso] of Object.entries(data)) { for (const [indiceCurso, curso] of Object.entries(data)) {
if (curso.oculto) continue; if (curso.oculto) continue
const nombreAbreviado = curso.abreviado; const nombreAbreviado = curso.abreviado
for (const [grupoStr, grupo] of Object.entries(curso.Teoria)) { for (const [grupoStr, grupo] of Object.entries(curso.Teoria)) {
for (const hora of grupo.Horas) { for (const hora of grupo.Horas) {
const dia = hora.substring(0, 2); const dia = hora.substring(0, 2)
const horas = hora.substring(2, 4); const horas = hora.substring(2, 4)
const minutos = hora.substr(4); const minutos = hora.substr(4)
const horaCompleta = horas + ":" + minutos; const horaCompleta = `${horas}:${minutos}`
const id = `${version}_${anio}_${nombreAbreviado}_T_${grupoStr}`; const id = `${version}_${anio}_${nombreAbreviado}_T_${grupoStr}`
if (!(horaCompleta in obj)) { if (!(horaCompleta in obj)) {
obj[horaCompleta] = {}; obj[horaCompleta] = {}
} }
if (!(dia in obj[horaCompleta])) { if (!(dia in obj[horaCompleta])) {
obj[horaCompleta][dia] = []; obj[horaCompleta][dia] = []
} }
obj[horaCompleta][dia].push({ obj[horaCompleta][dia].push({
@ -116,28 +115,28 @@ const procesarAnio = (data: Cursos, anio: string, version: number, setCursosUsua
datosGrupo: grupo, datosGrupo: grupo,
fnSeleccionar: () => { fnSeleccionar: () => {
/// @ts-ignore /// @ts-ignore
setCursosUsuarios("cursos", indiceCurso, "Teoria", grupoStr, "seleccionado", x => !x); setCursosUsuarios("cursos", indiceCurso, "Teoria", grupoStr, "seleccionado", (x) => !x)
} },
}); })
} }
} }
for (const [grupoStr, grupo] of Object.entries(curso.Laboratorio ?? {})) { for (const [grupoStr, grupo] of Object.entries(curso.Laboratorio ?? {})) {
for (const hora of grupo.Horas) { for (const hora of grupo.Horas) {
const dia = hora.substring(0, 2); const dia = hora.substring(0, 2)
const horas = hora.substring(2, 4); const horas = hora.substring(2, 4)
const minutos = hora.substr(4); const minutos = hora.substr(4)
const horaCompleta = horas + ":" + minutos; const horaCompleta = `${horas}:${minutos}`
const id = `${version}_${anio}_${nombreAbreviado}_L_${grupoStr}`; const id = `${version}_${anio}_${nombreAbreviado}_L_${grupoStr}`
if (!(horaCompleta in obj)) { if (!(horaCompleta in obj)) {
obj[horaCompleta] = {}; obj[horaCompleta] = {}
} }
if (!(dia in obj[horaCompleta])) { if (!(dia in obj[horaCompleta])) {
obj[horaCompleta][dia] = []; obj[horaCompleta][dia] = []
} }
obj[horaCompleta][dia].push({ obj[horaCompleta][dia].push({
@ -147,14 +146,14 @@ const procesarAnio = (data: Cursos, anio: string, version: number, setCursosUsua
datosGrupo: grupo, datosGrupo: grupo,
fnSeleccionar: () => { fnSeleccionar: () => {
/// @ts-ignore /// @ts-ignore
setCursosUsuarios("cursos", indiceCurso, "Laboratorio", grupoStr, "seleccionado", x => !x); setCursosUsuarios("cursos", indiceCurso, "Laboratorio", grupoStr, "seleccionado", (x) => !x)
} },
}); })
} }
} }
} }
return obj; return obj
} }
interface Props { interface Props {
@ -167,35 +166,40 @@ interface Props {
} }
export function Tabla(props: Props) { export function Tabla(props: Props) {
const anio = () => props.anio.substring(0, props.anio.indexOf(" ")); const anio = () => props.anio.substring(0, props.anio.indexOf(" "))
const data = createMemo(() => procesarAnio(props.data, anio(), props.version, props.setCursosUsuarios)); const data = createMemo(() => procesarAnio(props.data, anio(), props.version, props.setCursosUsuarios))
const idHover = props.idHover; const idHover = props.idHover
const setIdHover = props.setIdHover; const setIdHover = props.setIdHover
const celdas = createMemo(() => { const celdas = createMemo(() => {
// Hace reaccionar a la reactividad de Solid // Hace reaccionar a la reactividad de Solid
props.data; props.data
return <For each={horas}> return (
{hora => { <For each={horas}>
return <FilaTabla data={data()} {(hora) => (
<FilaTabla
data={data()}
hora={hora} hora={hora}
idHover={idHover} idHover={idHover}
setIdHover={setIdHover} setIdHover={setIdHover}
/> />
}} )}
</For> </For>
}); )
})
return <div> return (
<div>
<div className={css(e.fila)}> <div className={css(e.fila)}>
<For each={dias}> <For each={dias}>
{dia => {(dia) => (
<div className={css(e.celdaComun, estilosGlobales.inlineBlock, e.celdaDia)}> <div className={css(e.celdaComun, estilosGlobales.inlineBlock, e.celdaDia)}>
{dia} {dia}
</div> </div>
} )}
</For> </For>
</div> </div>
{celdas()} {celdas()}
</div> </div>
)
} }

View File

@ -1,8 +1,8 @@
import { StyleSheet, css } from "aphrodite"; import { StyleSheet, css } from "aphrodite"
import { estilosGlobales } from "../../Estilos"; import { estilosGlobales } from "../../Estilos"
import { For, createSignal, createMemo, createEffect, SetStateFunction } from "solid-js"; import { For, createSignal, createMemo, createEffect, SetStateFunction } from "solid-js"
import { Dia } from "../../Store"; import { Dia } from "../../Store"
import { DatosGrupo, ListaCursosUsuario } from "../../types/DatosHorario"; import { DatosGrupo, ListaCursosUsuario } from "../../types/DatosHorario"
const e = StyleSheet.create({ const e = StyleSheet.create({
celdaComun: { celdaComun: {
@ -10,7 +10,7 @@ const e = StyleSheet.create({
textAlign: "center", textAlign: "center",
padding: "0 0.7rem", padding: "0 0.7rem",
boxSizing: "border-box", boxSizing: "border-box",
userSelect: "none" userSelect: "none",
}, },
celdaCurso: { celdaCurso: {
display: "inline-block", display: "inline-block",
@ -23,39 +23,42 @@ const e = StyleSheet.create({
// color: "#151515" // color: "#151515"
}, },
celdaCursoTeoria: { celdaCursoTeoria: {
fontWeight: "bold" fontWeight: "bold",
}, },
celdaCursoLab: { celdaCursoLab: {
fontStyle: "italic" fontStyle: "italic",
} },
}); celdaSeleccionada: {
textDecoration: "underline",
},
})
const eColores = StyleSheet.create({ const eColores = StyleSheet.create({
lunes: { lunes: {
backgroundColor: "rgba(33,150,243,1)" backgroundColor: "rgba(33,150,243,1)",
}, },
martes: { martes: {
backgroundColor: "rgba(255,214,0 ,1)", backgroundColor: "rgba(255,214,0 ,1)",
color: "#151515" color: "#151515",
}, },
miercoles: { miercoles: {
backgroundColor: "rgba(236,64,122 ,1)" backgroundColor: "rgba(236,64,122 ,1)",
}, },
jueves: { jueves: {
backgroundColor: "rgba(29,233,182 ,1)", backgroundColor: "rgba(29,233,182 ,1)",
color: "#151515" color: "#151515",
}, },
viernes: { viernes: {
backgroundColor: "rgba(244,67,54,1)" backgroundColor: "rgba(244,67,54,1)",
} },
}); })
const clasesColores = { const clasesColores = {
Lunes: css(eColores.lunes), Lunes: css(eColores.lunes),
Martes: css(eColores.martes), Martes: css(eColores.martes),
Miercoles: css(eColores.miercoles), Miercoles: css(eColores.miercoles),
Jueves: css(eColores.jueves), Jueves: css(eColores.jueves),
Viernes: css(eColores.viernes) Viernes: css(eColores.viernes),
} }
interface Props { interface Props {
@ -79,64 +82,68 @@ interface Props {
setIdHover: (v: string) => string, setIdHover: (v: string) => string,
fnResaltarFila: () => void, fnResaltarFila: () => void,
fnDesresaltarFila: () => void, fnDesresaltarFila: () => void,
dia: Dia dia: Dia,
} }
const claseSeldaSeleccionada = css(e.celdaSeleccionada)
export function CeldaFila(props: Props) { export function CeldaFila(props: Props) {
const datos = props.datos; const datos = props.datos
const idHover = props.idHover; const idHover = props.idHover
const setIdHover = props.setIdHover; const setIdHover = props.setIdHover
const fnOnMouseEnter = (id: string) => setIdHover(id); const fnOnMouseEnter = (id: string) => setIdHover(id)
const fnOnMouseLeave = () => setIdHover(""); const fnOnMouseLeave = () => setIdHover("")
return <div className={css(e.celdaComun, estilosGlobales.inlineBlock)}> return (
<div className={css(e.celdaComun, estilosGlobales.inlineBlock)}>
<For each={datos}> <For each={datos}>
{datos => { {(datos) => {
const id = datos.id; const id = datos.id
const txt = datos.txt; const txt = datos.txt
const esLab = datos.esLab; const esLab = datos.esLab
const fnSeleccionar = datos.fnSeleccionar; const fnSeleccionar = datos.fnSeleccionar
const [estabaResaltado, setEstabaResaltado] = createSignal(false); const [estabaResaltado, setEstabaResaltado] = createSignal(false)
const estaSeleccionado = createMemo(() => { const estaSeleccionado = createMemo(() => datos.datosGrupo.seleccionado)
return datos.datosGrupo.seleccionado;
});
const clases = createMemo( const clases = createMemo(
() => { () => {
const clases = [ const clases = [
e.celdaCurso, e.celdaCurso,
esLab ? e.celdaCursoLab : e.celdaCursoTeoria, esLab ? e.celdaCursoLab : e.celdaCursoTeoria,
estaSeleccionado() && estilosGlobales.contenedorCursorActivo estaSeleccionado() && e.celdaSeleccionada,
]; ]
let adicional = ""; let adicional = ""
const idHoverS = idHover(); const idHoverS = idHover()
if (idHoverS !== "" && id.search(idHoverS) !== -1) { if (idHoverS !== "" && id.search(idHoverS) !== -1) {
props.fnResaltarFila(); props.fnResaltarFila()
clases.push(e.celdaCursoActiva); clases.push(e.celdaCursoActiva)
adicional = clasesColores[props.dia]; adicional = clasesColores[props.dia]
setEstabaResaltado(true); setEstabaResaltado(true)
} else if (estabaResaltado()) { } else if (estabaResaltado()) {
props.fnDesresaltarFila(); props.fnDesresaltarFila()
setEstabaResaltado(false); setEstabaResaltado(false)
} }
return css(...clases) + " " + adicional; return `${css(...clases)} ${adicional}`
}, },
undefined, undefined,
(x, y) => x === y (x, y) => x === y,
); )
return <span className={clases()} return (
<span className={clases()}
onMouseEnter={() => fnOnMouseEnter(id)} onMouseEnter={() => fnOnMouseEnter(id)}
onMouseLeave={fnOnMouseLeave} onMouseLeave={fnOnMouseLeave}
onClick={fnSeleccionar} onClick={fnSeleccionar}
> >
{txt} {txt}
</span>; </span>
)
}} }}
</For> </For>
</div> </div>
)
} }

View File

@ -1,10 +1,10 @@
import { StyleSheet, css } from "aphrodite"; import { StyleSheet, css } from "aphrodite"
import { estilosGlobales } from "../../Estilos"; import { estilosGlobales } from "../../Estilos"
import { For, createSignal, createMemo, createState, createEffect, State, SetStateFunction } from "solid-js"; import { For, createSignal, createMemo, createState, createEffect, State, SetStateFunction } from "solid-js"
import { Dia, dias } from "../../Store"; import { Dia, dias } from "../../Store"
import { CeldaFila } from "./CeldaFila"; import { CeldaFila } from "./CeldaFila"
import { DataProcesada, ListaCursosUsuario } from "../../types/DatosHorario"; import { DataProcesada, ListaCursosUsuario } from "../../types/DatosHorario"
import { coloresBorde, diaANum } from "../Tabla"; import { coloresBorde, diaANum } from "../Tabla"
const e = StyleSheet.create({ const e = StyleSheet.create({
celdaHora: { celdaHora: {
@ -12,13 +12,13 @@ const e = StyleSheet.create({
width: "3rem", width: "3rem",
padding: "0.25rem 0", padding: "0.25rem 0",
position: "absolute", position: "absolute",
top: "-0.75rem" top: "-0.75rem",
}, },
filaResaltado: { filaResaltado: {
position: "absolute", position: "absolute",
zIndex: -1, zIndex: -1,
height: "100%", height: "100%",
transform: "translateX(-1.5rem)" transform: "translateX(-1.5rem)",
}, },
fila: { fila: {
position: "relative", position: "relative",
@ -30,7 +30,7 @@ const e = StyleSheet.create({
minHeight: "1.2rem", minHeight: "1.2rem",
":hover": { ":hover": {
// backgroundColor: "rgba(200, 200, 200, 0.25)" // backgroundColor: "rgba(200, 200, 200, 0.25)"
} },
}, },
filaBorde: { filaBorde: {
position: "absolute", position: "absolute",
@ -38,17 +38,17 @@ const e = StyleSheet.create({
height: "1px", height: "1px",
width: "100%", width: "100%",
backgroundColor: "rgba(200, 200, 200, 0.25)", backgroundColor: "rgba(200, 200, 200, 0.25)",
zIndex: -1 zIndex: -1,
}, },
celdaResaltado: { celdaResaltado: {
height: "101%", height: "101%",
width: "5px", width: "5px",
display: "inline-block" display: "inline-block",
}, },
celdaResaltadoTransparente: { celdaResaltadoTransparente: {
backgroundColor: "transparent" backgroundColor: "transparent",
} },
}); })
const [diasResaltados, setDiasResaltados] = createState({ const [diasResaltados, setDiasResaltados] = createState({
Lunes: 0, Lunes: 0,
@ -56,7 +56,7 @@ const [diasResaltados, setDiasResaltados] = createState({
Miercoles: 0, Miercoles: 0,
Jueves: 0, Jueves: 0,
Viernes: 0, Viernes: 0,
} as { [k: string]: number }); } as { [k: string]: number })
interface Props { interface Props {
hora: string, hora: string,
@ -65,12 +65,10 @@ interface Props {
setIdHover: (v: string) => string setIdHover: (v: string) => string
} }
const diasFilter = createMemo(() => { const diasFilter = createMemo(() => Object.entries(diasResaltados)
return Object.entries(diasResaltados) .filter((x) => x[1] > 0)
.filter(x => x[1] > 0) .map((x) => x[0] as Dia)
.map(x => x[0] as Dia) .sort((x, y) => (diaANum(x) > diaANum(y) ? 1 : -1)))
.sort((x, y) => diaANum(x) > diaANum(y) ? 1 : -1);
});
const useDiasResaltados: () => [ const useDiasResaltados: () => [
State<{ [k: string]: boolean }>, State<{ [k: string]: boolean }>,
@ -83,54 +81,64 @@ const useDiasResaltados: () => [
Miercoles: false, Miercoles: false,
Jueves: false, Jueves: false,
Viernes: false, Viernes: false,
} as { [k: string]: boolean }); } as { [k: string]: boolean })
const fnResaltar = (d: Dia) => { const fnResaltar = (d: Dia) => {
setDiasResaltadosLocal(d, true); setDiasResaltadosLocal(d, true)
setDiasResaltados(d, v => v + 1); setDiasResaltados(d, (v) => v + 1)
}; }
const fnDesresaltar = (d: Dia) => { const fnDesresaltar = (d: Dia) => {
setDiasResaltadosLocal(d, false); setDiasResaltadosLocal(d, false)
setDiasResaltados(d, v => v - 1); setDiasResaltados(d, (v) => v - 1)
}; }
return [diasResaltadosLocal, fnResaltar, fnDesresaltar]; return [diasResaltadosLocal, fnResaltar, fnDesresaltar]
}; }
export function FilaTabla(props: Props) { export function FilaTabla(props: Props) {
const [diasResaltadosLocal, fnResaltar, fnDesresaltar] = useDiasResaltados(); const [diasResaltadosLocal, fnResaltar, fnDesresaltar] = useDiasResaltados()
const hora = props.hora; const hora = props.hora
const data = props.data; const data = props.data
return <div style={{position: "relative"}}> return (
<div style={{position: "relative"}}>
<div className={css(e.celdaHora, estilosGlobales.inlineBlock)}> <div className={css(e.celdaHora, estilosGlobales.inlineBlock)}>
{hora.substring(0, 5)} {hora.substring(0, 5)}
</div> </div>
<div className={css(e.fila)}> <div className={css(e.fila)}>
<div className={css(estilosGlobales.inlineBlock, e.filaResaltado)}> <div className={css(estilosGlobales.inlineBlock, e.filaResaltado)}>
<div className={css(e.celdaResaltado, diasResaltadosLocal.Lunes ? null : e.celdaResaltadoTransparente)} <div
style={{"background-color": coloresBorde[0]}}/> className={css(e.celdaResaltado, diasResaltadosLocal.Lunes ? null : e.celdaResaltadoTransparente)}
<div className={css(e.celdaResaltado, diasResaltadosLocal.Martes ? null : e.celdaResaltadoTransparente)} style={{"background-color": coloresBorde[0]}}
style={{"background-color": coloresBorde[1]}}/> />
<div
className={css(e.celdaResaltado, diasResaltadosLocal.Martes ? null : e.celdaResaltadoTransparente)}
style={{"background-color": coloresBorde[1]}}
/>
<div <div
className={css(e.celdaResaltado, diasResaltadosLocal.Miercoles ? null : e.celdaResaltadoTransparente)} className={css(e.celdaResaltado, diasResaltadosLocal.Miercoles ? null : e.celdaResaltadoTransparente)}
style={{"background-color": coloresBorde[2]}}/> style={{"background-color": coloresBorde[2]}}
<div className={css(e.celdaResaltado, diasResaltadosLocal.Jueves ? null : e.celdaResaltadoTransparente)} />
style={{"background-color": coloresBorde[3]}}/> <div
className={css(e.celdaResaltado, diasResaltadosLocal.Jueves ? null : e.celdaResaltadoTransparente)}
style={{"background-color": coloresBorde[3]}}
/>
<div <div
className={css(e.celdaResaltado, diasResaltadosLocal.Viernes ? null : e.celdaResaltadoTransparente)} className={css(e.celdaResaltado, diasResaltadosLocal.Viernes ? null : e.celdaResaltadoTransparente)}
style={{"background-color": coloresBorde[4]}}/> style={{"background-color": coloresBorde[4]}}
/>
</div> </div>
<For each={dias}> <For each={dias}>
{dia => { {(dia) => {
const diaStr = dia.substring(0, 2); const diaStr = dia.substring(0, 2)
const horaStr = hora.substring(0, 5); const horaStr = hora.substring(0, 5)
const datos = data?.[horaStr]?.[diaStr] ?? []; const datos = data?.[horaStr]?.[diaStr] ?? []
return <CeldaFila return (
<CeldaFila
datos={datos} datos={datos}
idHover={props.idHover} idHover={props.idHover}
setIdHover={props.setIdHover} setIdHover={props.setIdHover}
@ -138,9 +146,11 @@ export function FilaTabla(props: Props) {
fnDesresaltarFila={() => fnDesresaltar(dia)} fnDesresaltarFila={() => fnDesresaltar(dia)}
dia={dia} dia={dia}
/> />
)
}} }}
</For> </For>
<div className={css(e.filaBorde)} /> <div className={css(e.filaBorde)} />
</div> </div>
</div>; </div>
)
} }

View File

@ -0,0 +1,70 @@
/**
* - Normal
* - Oculto - Otro grupo seleccionado
* - Seleccionado - Cursor ensima
* - Resaltado - Grupo seleccionado
* - ResaltadoSeleccionado - Grupo seleccionado y cursor encima
* - ResaltadoOculto - Otro grupo seleccionado y cursor encima
*/
import { createMemo, createState, SetStateFunction, State } from "solid-js";
type EstadoCelda =
| "Normal"
| "Oculto"
| "Seleccionado"
| "Resaltado"
| "ResaltadoSeleccionado"
| "ResaltadoOculto"
interface Datos {
anio?: string,
curso?: string,
esLab?: boolean,
grupo?: string
}
export class TablaObserver {
private readonly resaltado: State<Datos>
private readonly setResaltado: SetStateFunction<Datos>
private gruposSeleccionados = {}
constructor() {
const [resaltado, setResaltado] = createState<Datos>({
anio: undefined,
curso: undefined,
esLab: undefined,
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,
undefined,
(x, y) => x === y
);
}
resaltar(id: string) {
}
quitarResaltado() {
this.setResaltado({
anio: undefined,
curso: undefined,
esLab: undefined,
grupo: undefined
});
}
}

View File

@ -1,5 +1,5 @@
import { createState, SetStateFunction, State } from "solid-js"; import { createState, SetStateFunction, State } from "solid-js"
import { Curso, ListaCursosUsuario } from "../types/DatosHorario"; import { Curso, ListaCursosUsuario } from "../types/DatosHorario"
interface ReturnType { interface ReturnType {
listaCursos: State<ListaCursosUsuario>, listaCursos: State<ListaCursosUsuario>,
@ -11,31 +11,31 @@ interface ReturnType {
export const useListaCursos = (): ReturnType => { export const useListaCursos = (): ReturnType => {
const [listaCursos, setListaCursos] = createState<ListaCursosUsuario>({ const [listaCursos, setListaCursos] = createState<ListaCursosUsuario>({
sigIndice: 0, sigIndice: 0,
cursos: [] cursos: [],
}); })
const agregarCursoALista = (curso: Curso): Curso => { const agregarCursoALista = (curso: Curso): Curso => {
// Si el horario ya se habia agregado, ocultarlo // Si el horario ya se habia agregado, ocultarlo
const cursoActualIndex = listaCursos.cursos.findIndex(x => x.nombre === curso.nombre); const cursoActualIndex = listaCursos.cursos.findIndex((x) => x.nombre === curso.nombre)
if (cursoActualIndex !== -1) { if (cursoActualIndex !== -1) {
setListaCursos("cursos", cursoActualIndex, "oculto", x => !x); setListaCursos("cursos", cursoActualIndex, "oculto", (x) => !x)
return listaCursos.cursos[cursoActualIndex]; return listaCursos.cursos[cursoActualIndex]
} else { } else {
setListaCursos("cursos", listaCursos.sigIndice, curso); setListaCursos("cursos", listaCursos.sigIndice, curso)
setListaCursos("sigIndice", x => x + 1); setListaCursos("sigIndice", (x) => x + 1)
return listaCursos.cursos[listaCursos.sigIndice - 1]; return listaCursos.cursos[listaCursos.sigIndice - 1]
}
} }
};
const eliminarCursosDeLista = () => { const eliminarCursosDeLista = () => {
setListaCursos("cursos", []); setListaCursos("cursos", [])
setListaCursos("sigIndice", 0); setListaCursos("sigIndice", 0)
}; }
return { return {
listaCursos, listaCursos,
setListaCursos, setListaCursos,
agregarCursoALista, agregarCursoALista,
eliminarCursosDeLista eliminarCursosDeLista,
}; }
}; }

View File

@ -1,15 +1,17 @@
import { StyleSheet, css } from "aphrodite"; import { StyleSheet, css } from "aphrodite"
const e = StyleSheet.create({ const e = StyleSheet.create({
creditos: { creditos: {
textAlign: "center", textAlign: "center",
paddingTop: "7.5rem", paddingTop: "7.5rem",
paddingBottom: "1rem" paddingBottom: "1rem",
} },
}); })
export function Creditos() { export function Creditos() {
return <div className={css(e.creditos)}> return (
<div className={css(e.creditos)}>
Desarrollado por Fernando Araoz con TypeScript, JSX y Solid.js. Desarrollado por Fernando Araoz con TypeScript, JSX y Solid.js.
</div> </div>
)
} }

View File

@ -1,4 +1,4 @@
import {StyleSheet} from "aphrodite"; import {StyleSheet} from "aphrodite"
export const estilosGlobales = StyleSheet.create({ export const estilosGlobales = StyleSheet.create({
contenedor: { contenedor: {
@ -7,7 +7,7 @@ export const estilosGlobales = StyleSheet.create({
borderRadius: "10px", borderRadius: "10px",
backdropFilter: "blur(40px)", backdropFilter: "blur(40px)",
backgroundColor: "rgba(100, 100, 100, 0.25)", backgroundColor: "rgba(100, 100, 100, 0.25)",
color: "var(--color-texto)" color: "var(--color-texto)",
}, },
contenedorCursor: { contenedorCursor: {
cursor: "pointer", cursor: "pointer",
@ -15,27 +15,27 @@ export const estilosGlobales = StyleSheet.create({
transition: "background-color 200ms", transition: "background-color 200ms",
textDecoration: "underline solid white 2px", textDecoration: "underline solid white 2px",
":hover": { ":hover": {
backgroundColor: "rgba(200, 200, 200, 0.3)" backgroundColor: "rgba(200, 200, 200, 0.3)",
} },
}, },
contenedorCursorSoft: { contenedorCursorSoft: {
textDecoration: "underline rgba(255, 255, 255, 0.4)" textDecoration: "underline rgba(255, 255, 255, 0.4)",
}, },
contenedorCursorActivo: { contenedorCursorActivo: {
backgroundColor: "rgba(200, 200, 200, 0.3)" backgroundColor: "rgba(200, 200, 200, 0.3)",
}, },
contenedorPhospor: { contenedorPhospor: {
padding: "0.5rem 0.65rem", padding: "0.5rem 0.65rem",
transform: "translateY(0.2rem)" transform: "translateY(0.2rem)",
}, },
inlineBlock: { inlineBlock: {
display: "inline-block" display: "inline-block",
}, },
botonPhospor: { botonPhospor: {
"::before": { "::before": {
fontSize: "1.25rem", fontSize: "1.25rem",
// transform: "translateY(0.2rem)", // transform: "translateY(0.2rem)",
textDecoration: "underline rgba(255, 255, 255, 0.4)", textDecoration: "underline rgba(255, 255, 255, 0.4)",
}
}, },
}); },
})

View File

@ -1,4 +1,4 @@
import { createSignal, createEffect } from "solid-js"; import { createSignal} from "solid-js"
enum ModoColor { enum ModoColor {
Claro, Claro,
@ -8,7 +8,7 @@ enum ModoColor {
export type Dia = "Lunes" | "Martes" | "Miercoles" | "Jueves" | "Viernes"; export type Dia = "Lunes" | "Martes" | "Miercoles" | "Jueves" | "Viernes";
export const dias: Dia[] = ["Lunes", "Martes", "Miercoles", "Jueves", "Viernes"]; export const dias: Dia[] = ["Lunes", "Martes", "Miercoles", "Jueves", "Viernes"]
export const horas = [ export const horas = [
"07:00 - 07:50", "07:00 - 07:50",
"07:50 - 08:40", "07:50 - 08:40",
@ -30,17 +30,17 @@ export const horas = [
"18:30 - 19:20", "18:30 - 19:20",
"19:20 - 20:10", "19:20 - 20:10",
"20:10 - 21:00", "20:10 - 21:00",
"21:00 - 21:00" "21:00 - 21:00",
]; ]
export const horasDescanso = [ export const horasDescanso = [
"08:40 - 08:50", "08:40 - 08:50",
"10:30 - 10:40", "10:30 - 10:40",
"15:40 - 15:50", "15:40 - 15:50",
"17:30 - 17:40" "17:30 - 17:40",
]; ]
const numImgGuardado = parseInt(localStorage.getItem("num-img") ?? "3"); const numImgGuardado = Number(localStorage.getItem("num-img") ?? "3")
export const [modoColor, setModoColor] = createSignal(ModoColor.Oscuro); export const [modoColor, setModoColor] = createSignal(ModoColor.Oscuro)
export const [numWallpaper, setNumWallpaper] = createSignal(numImgGuardado); export const [numWallpaper, setNumWallpaper] = createSignal(numImgGuardado)
export const [mostrarDescansos, setMostrarDescansos] = createSignal(true); export const [mostrarDescansos, setMostrarDescansos] = createSignal(true)

View File

@ -1,12 +1,12 @@
import { StyleSheet, css } from "aphrodite"; import { StyleSheet, css } from "aphrodite"
import { numWallpaper } from "./Store"; import { numWallpaper } from "./Store"
import { createEffect, createState } from "solid-js"; import { createEffect, createState } from "solid-js"
const duracionTransicion = 250; const duracionTransicion = 250
export function Wallpaper() { export function Wallpaper() {
/// @ts-ignore /// @ts-ignore
const soportaBackdropFilter = document.body.style.backdropFilter !== undefined; const soportaBackdropFilter = document.body.style.backdropFilter !== undefined
const estilos = StyleSheet.create({ const estilos = StyleSheet.create({
contenedorCover: { contenedorCover: {
@ -16,7 +16,7 @@ export function Wallpaper() {
top: "0", top: "0",
left: "0", left: "0",
backgroundColor: "#212121", backgroundColor: "#212121",
zIndex: -1 zIndex: -1,
}, },
cover: { cover: {
width: "100vw", width: "100vw",
@ -25,43 +25,45 @@ export function Wallpaper() {
backgroundSize: "cover", backgroundSize: "cover",
zIndex: -1, zIndex: -1,
transition: `opacity ${duracionTransicion}ms`, transition: `opacity ${duracionTransicion}ms`,
filter: soportaBackdropFilter? "": "blur(40px)" filter: soportaBackdropFilter ? "" : "blur(40px)",
}, },
coverTransicion: { coverTransicion: {
opacity: 0 opacity: 0,
} },
}); })
const [estilosRaw, setEstilosRaw] = createState({ const [estilosRaw, setEstilosRaw] = createState({
"background-image": `none`, "background-image": "none",
opacity: 1 opacity: 1,
}); })
createEffect(() => { createEffect(() => {
const numImg = numWallpaper(); const numImg = numWallpaper()
setEstilosRaw("opacity", 0); setEstilosRaw("opacity", 0)
const promesa250ms = new Promise(resolve => { const promesa250ms = new Promise((resolve) => {
setTimeout(resolve, duracionTransicion); setTimeout(resolve, duracionTransicion)
}); })
const url = `/img/wall${numImg}.webp`; const url = `/img/wall${numImg}.webp`
const img = new Image(); const img = new Image()
img.addEventListener("load", async() => { img.addEventListener("load", async() => {
await promesa250ms; await promesa250ms
setEstilosRaw({ setEstilosRaw({
"background-image": `url('${url}')`, "background-image": `url('${url}')`,
opacity: 1 opacity: 1,
}); })
}); })
img.src = url; img.src = url
}); })
return <div className={css(estilos.contenedorCover)}> return (
<div className={css(estilos.contenedorCover)}>
<div <div
className={css(estilos.cover)} className={css(estilos.cover)}
style={{"background-image": estilosRaw["background-image"], opacity: estilosRaw.opacity}} style={{"background-image": estilosRaw["background-image"], opacity: estilosRaw.opacity}}
/> />
</div> </div>
)
} }

View File

@ -1,7 +1,7 @@
import "solid-js"; import "solid-js"
import { render } from 'solid-js/web'; import { render } from "solid-js/web"
import App from './App'; import App from "./App"
import "normalize.css"; import "normalize.css"
import "./styles/global.css"; import "./styles/global.css"
render(App, document.getElementById('root') as Node); render(App, document.getElementById("root") as Node)