This commit is contained in:
2025-12-22 21:05:35 -06:00
parent b303398cd4
commit 2f4f445ff0
7 changed files with 205 additions and 9 deletions

View File

@@ -13,6 +13,7 @@
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit" "source.fixAll.eslint": "explicit"
}, },
"editor.tabSize": 2,
"eslint.validate": [ "eslint.validate": [
"javascript", "javascript",
"javascriptreact", "javascriptreact",

View File

@@ -5,6 +5,7 @@ const config = {
semi: false, semi: false,
singleQuote: true, singleQuote: true,
trailingComma: 'all', trailingComma: 'all',
tabWidth: 2,
plugins: ['prettier-plugin-tailwindcss'], plugins: ['prettier-plugin-tailwindcss'],
tailwindFunctions: ['clsx', 'cn', 'cva'], tailwindFunctions: ['clsx', 'cn', 'cva'],
endOfLine: 'lf', endOfLine: 'lf',

View File

@@ -0,0 +1,29 @@
import { SearchIcon } from 'lucide-react'
import { useId } from 'react'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
const InputSearchIconDemo = () => {
const id = useId()
return (
<div className="w-full max-w-xs space-y-2">
<Label htmlFor={id}>Search input with icon and button</Label>
<div className="relative">
<div className="text-muted-foreground pointer-events-none absolute inset-y-0 left-0 flex items-center justify-center pl-3 peer-disabled:opacity-50">
<SearchIcon className="size-4" />
<span className="sr-only">Search</span>
</div>
<Input
id={id}
type="search"
placeholder="Search..."
className="peer px-9 [&::-webkit-search-cancel-button]:appearance-none [&::-webkit-search-decoration]:appearance-none [&::-webkit-search-results-button]:appearance-none [&::-webkit-search-results-decoration]:appearance-none"
/>
</div>
</div>
)
}
export default InputSearchIconDemo

View File

@@ -1,6 +1,6 @@
import { ArrowRight } from 'lucide-react' import { ArrowRight } from 'lucide-react'
import type {LucideIcon} from 'lucide-react'; import type { LucideIcon } from 'lucide-react'
import { Badge } from '@/components/ui/badge' import { Badge } from '@/components/ui/badge'
import { Card, CardContent, CardFooter, CardHeader } from '@/components/ui/card' import { Card, CardContent, CardFooter, CardHeader } from '@/components/ui/card'
@@ -36,7 +36,7 @@ export default function PlanEstudiosCard({
<Card <Card
onClick={onClick} onClick={onClick}
className={cn( className={cn(
'group relative flex h-full cursor-pointer flex-col justify-between overflow-hidden border-l-4 transition-all hover:shadow-lg', 'group relative flex h-full cursor-pointer flex-col justify-between gap-2 overflow-hidden border-l-4 transition-all hover:shadow-lg',
)} )}
// Aplicamos el color de la facultad dinámicamente al borde y un fondo muy sutil // Aplicamos el color de la facultad dinámicamente al borde y un fondo muy sutil
style={{ style={{
@@ -61,14 +61,14 @@ export default function PlanEstudiosCard({
</h4> </h4>
</CardHeader> </CardHeader>
<CardContent className="text-muted-foreground space-y-1 pb-4 text-sm"> <CardContent className="text-muted-foreground space-y-1 text-sm">
<p className="text-foreground font-medium"> <p className="text-foreground font-medium">
{nivel} {ciclos} {nivel} {ciclos}
</p> </p>
<p>{facultad}</p> <p>{facultad}</p>
</CardContent> </CardContent>
<CardFooter className="bg-background/50 flex items-center justify-between border-t px-6 py-3 backdrop-blur-sm"> <CardFooter className="bg-background/50 flex items-center justify-between border-t px-6 pb-3 backdrop-blur-sm [.border-t]:pt-3">
<Badge className={`text-sm font-semibold ${claseColorEstado}`}> <Badge className={`text-sm font-semibold ${claseColorEstado}`}>
{estado} {estado}
</Badge> </Badge>

View File

@@ -9,11 +9,17 @@
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
import { Route as rootRouteImport } from './routes/__root' import { Route as rootRouteImport } from './routes/__root'
import { Route as PlanesRouteImport } from './routes/planes'
import { Route as LoginRouteImport } from './routes/login' import { Route as LoginRouteImport } from './routes/login'
import { Route as DashboardRouteImport } from './routes/dashboard' import { Route as DashboardRouteImport } from './routes/dashboard'
import { Route as IndexRouteImport } from './routes/index' import { Route as IndexRouteImport } from './routes/index'
import { Route as DemoTanstackQueryRouteImport } from './routes/demo/tanstack-query' import { Route as DemoTanstackQueryRouteImport } from './routes/demo/tanstack-query'
const PlanesRoute = PlanesRouteImport.update({
id: '/planes',
path: '/planes',
getParentRoute: () => rootRouteImport,
} as any)
const LoginRoute = LoginRouteImport.update({ const LoginRoute = LoginRouteImport.update({
id: '/login', id: '/login',
path: '/login', path: '/login',
@@ -39,12 +45,14 @@ export interface FileRoutesByFullPath {
'/': typeof IndexRoute '/': typeof IndexRoute
'/dashboard': typeof DashboardRoute '/dashboard': typeof DashboardRoute
'/login': typeof LoginRoute '/login': typeof LoginRoute
'/planes': typeof PlanesRoute
'/demo/tanstack-query': typeof DemoTanstackQueryRoute '/demo/tanstack-query': typeof DemoTanstackQueryRoute
} }
export interface FileRoutesByTo { export interface FileRoutesByTo {
'/': typeof IndexRoute '/': typeof IndexRoute
'/dashboard': typeof DashboardRoute '/dashboard': typeof DashboardRoute
'/login': typeof LoginRoute '/login': typeof LoginRoute
'/planes': typeof PlanesRoute
'/demo/tanstack-query': typeof DemoTanstackQueryRoute '/demo/tanstack-query': typeof DemoTanstackQueryRoute
} }
export interface FileRoutesById { export interface FileRoutesById {
@@ -52,25 +60,40 @@ export interface FileRoutesById {
'/': typeof IndexRoute '/': typeof IndexRoute
'/dashboard': typeof DashboardRoute '/dashboard': typeof DashboardRoute
'/login': typeof LoginRoute '/login': typeof LoginRoute
'/planes': typeof PlanesRoute
'/demo/tanstack-query': typeof DemoTanstackQueryRoute '/demo/tanstack-query': typeof DemoTanstackQueryRoute
} }
export interface FileRouteTypes { export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath fileRoutesByFullPath: FileRoutesByFullPath
fullPaths: '/' | '/dashboard' | '/login' | '/demo/tanstack-query' fullPaths: '/' | '/dashboard' | '/login' | '/planes' | '/demo/tanstack-query'
fileRoutesByTo: FileRoutesByTo fileRoutesByTo: FileRoutesByTo
to: '/' | '/dashboard' | '/login' | '/demo/tanstack-query' to: '/' | '/dashboard' | '/login' | '/planes' | '/demo/tanstack-query'
id: '__root__' | '/' | '/dashboard' | '/login' | '/demo/tanstack-query' id:
| '__root__'
| '/'
| '/dashboard'
| '/login'
| '/planes'
| '/demo/tanstack-query'
fileRoutesById: FileRoutesById fileRoutesById: FileRoutesById
} }
export interface RootRouteChildren { export interface RootRouteChildren {
IndexRoute: typeof IndexRoute IndexRoute: typeof IndexRoute
DashboardRoute: typeof DashboardRoute DashboardRoute: typeof DashboardRoute
LoginRoute: typeof LoginRoute LoginRoute: typeof LoginRoute
PlanesRoute: typeof PlanesRoute
DemoTanstackQueryRoute: typeof DemoTanstackQueryRoute DemoTanstackQueryRoute: typeof DemoTanstackQueryRoute
} }
declare module '@tanstack/react-router' { declare module '@tanstack/react-router' {
interface FileRoutesByPath { interface FileRoutesByPath {
'/planes': {
id: '/planes'
path: '/planes'
fullPath: '/planes'
preLoaderRoute: typeof PlanesRouteImport
parentRoute: typeof rootRouteImport
}
'/login': { '/login': {
id: '/login' id: '/login'
path: '/login' path: '/login'
@@ -106,6 +129,7 @@ const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute, IndexRoute: IndexRoute,
DashboardRoute: DashboardRoute, DashboardRoute: DashboardRoute,
LoginRoute: LoginRoute, LoginRoute: LoginRoute,
PlanesRoute: PlanesRoute,
DemoTanstackQueryRoute: DemoTanstackQueryRoute, DemoTanstackQueryRoute: DemoTanstackQueryRoute,
} }
export const routeTree = rootRouteImport export const routeTree = rootRouteImport

View File

@@ -13,7 +13,7 @@ import {
} from 'lucide-react' } from 'lucide-react'
import DashboardHeader from '@/components/dashboard/DashboardHeader' import DashboardHeader from '@/components/dashboard/DashboardHeader'
import PlanEstudiosCard from '@/components/plan_estudios/PlanEstudiosCard' import PlanEstudiosCard from '@/components/planes/PlanEstudiosCard'
export const Route = createFileRoute('/dashboard')({ export const Route = createFileRoute('/dashboard')({
component: RouteComponent, component: RouteComponent,

141
src/routes/planes.tsx Normal file
View File

@@ -0,0 +1,141 @@
import { createFileRoute } from '@tanstack/react-router'
import {
Activity,
BookOpenText,
Calculator,
FlaskConical,
Laptop,
PencilRuler,
Plus,
Scale,
Stethoscope,
} from 'lucide-react'
import PlanEstudiosCard from '@/components/planes/PlanEstudiosCard'
export const Route = createFileRoute('/planes')({
component: RouteComponent,
})
function RouteComponent() {
return (
<main className="bg-background min-h-screen w-full">
<div className="mx-auto flex w-full max-w-7xl flex-col gap-4 px-4 py-6 md:px-6 lg:px-8">
<div className="flex flex-col gap-4 lg:col-span-3">
<div className="flex flex-col items-stretch justify-between gap-4 sm:flex-row sm:items-center">
<div className="flex items-center gap-3">
<div className="bg-primary/10 text-primary flex h-10 w-10 items-center justify-center rounded-xl">
<BookOpenText className="h-5 w-5" strokeWidth={2} />
</div>
<div>
<h1 className="font-display text-foreground text-2xl font-bold">
Planes de Estudio
</h1>
<p className="text-muted-foreground text-sm">
Gestiona los planes curriculares de tu institución
</p>
</div>
</div>
<button
type="button"
className={
'ring-offset-background focus-visible:ring-ring bg-primary text-primary-foreground hover:bg-primary/90 inline-flex h-11 items-center justify-center gap-2 rounded-md px-8 text-sm font-medium whitespace-nowrap shadow-md transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:h-4 [&_svg]:w-4 [&_svg]:shrink-0'
}
aria-label="Nuevo plan de estudios"
title="Nuevo plan de estudios"
>
<Plus className="" />
Nuevo plan de estudios
</button>
</div>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<PlanEstudiosCard
Icono={Laptop}
nombrePrograma="Ingeniería en Sistemas Computacionales"
nivel="Licenciatura"
ciclos="8 semestres"
facultad="Facultad de Ingeniería"
estado="Revisión expertos"
claseColorEstado="bg-amber-600"
colorFacultad="#2563eb"
onClick={() => console.log('Navegar a Sistemas...')}
/>
<PlanEstudiosCard
Icono={Stethoscope}
nombrePrograma="Médico Cirujano"
nivel="Licenciatura"
ciclos="10 semestres"
facultad="Facultad de Medicina"
estado="Aprobado"
claseColorEstado="bg-emerald-600"
colorFacultad="#dc2626"
/>
<PlanEstudiosCard
Icono={Calculator}
nombrePrograma="Licenciatura en Actuaría"
nivel="Licenciatura"
ciclos="9 semestres"
facultad="Facultad de Negocios"
estado="Aprobado"
claseColorEstado="bg-emerald-600"
colorFacultad="#059669"
onClick={() => console.log('Ver Actuaría')}
/>
<PlanEstudiosCard
Icono={PencilRuler}
nombrePrograma="Licenciatura en Arquitectura"
nivel="Licenciatura"
ciclos="10 semestres"
facultad="Facultad Mexicana de Arquitectura, Diseño y Comunicación"
estado="En proceso"
claseColorEstado="bg-orange-500"
colorFacultad="#ea580c"
onClick={() => console.log('Ver Arquitectura')}
/>
<PlanEstudiosCard
Icono={Activity}
nombrePrograma="Licenciatura en Fisioterapia"
nivel="Licenciatura"
ciclos="8 semestres"
facultad="Escuela de Altos Estudios en Salud"
estado="Revisión expertos"
claseColorEstado="bg-amber-600"
colorFacultad="#0891b2"
onClick={() => console.log('Ver Fisioterapia')}
/>
<PlanEstudiosCard
Icono={Scale}
nombrePrograma="Licenciatura en Derecho"
nivel="Licenciatura"
ciclos="10 semestres"
facultad="Facultad de Derecho"
estado="Pendiente"
claseColorEstado="bg-yellow-500"
colorFacultad="#7c3aed"
onClick={() => console.log('Ver Derecho')}
/>
<PlanEstudiosCard
Icono={FlaskConical}
nombrePrograma="Químico Farmacéutico Biólogo"
nivel="Licenciatura"
ciclos="9 semestres"
facultad="Facultad de Ciencias Químicas"
estado="Actualización"
claseColorEstado="bg-lime-600"
colorFacultad="#65a30d"
onClick={() => console.log('Ver QFB')}
/>
</div>
</div>
</div>
</main>
)
}