b44ui 0.0.9 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +11 -3
- package/{README.md → readme.md} +17 -6
- package/tailwind.css +3 -0
- package/example/index.html +0 -12
- package/example/package.json +0 -22
- package/example/pnpm-lock.yaml +0 -1499
- package/example/src/App.tsx +0 -147
- package/example/src/index.css +0 -3
- package/example/src/main.tsx +0 -5
- package/example/tsconfig.json +0 -12
- package/example/vite.config.ts +0 -10
- package/tsconfig.json +0 -14
package/example/src/App.tsx
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import { useState } from 'react'
|
|
2
|
-
import { App, Btn, Card, Chip, Col, D, Muted, Input, Row, Select, Grid } from 'ui'
|
|
3
|
-
|
|
4
|
-
type Meeting = { day: string, start: number, end: number }
|
|
5
|
-
type Section = { id: string, type: 'LEC' | 'TUT' | 'PRA', meetings: Meeting[] }
|
|
6
|
-
type Course = { code: string, name: string, sections: Section[] }
|
|
7
|
-
|
|
8
|
-
const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']
|
|
9
|
-
const hours = Array.from({ length: 13 }, (_, i) => i + 9) // 9am-9pm
|
|
10
|
-
|
|
11
|
-
const catalog: Course[] = [
|
|
12
|
-
{ code: 'CSC108', name: 'Intro to Computer Programming', sections: [
|
|
13
|
-
{ id: 'LEC0101', type: 'LEC', meetings: [{ day: 'Mon', start: 600, end: 660 }, { day: 'Wed', start: 600, end: 660 }] },
|
|
14
|
-
{ id: 'LEC0201', type: 'LEC', meetings: [{ day: 'Tue', start: 660, end: 720 }, { day: 'Thu', start: 660, end: 720 }] },
|
|
15
|
-
{ id: 'TUT0101', type: 'TUT', meetings: [{ day: 'Fri', start: 600, end: 660 }] },
|
|
16
|
-
{ id: 'TUT0201', type: 'TUT', meetings: [{ day: 'Fri', start: 660, end: 720 }] },
|
|
17
|
-
]},
|
|
18
|
-
{ code: 'MAT137', name: 'Calculus with Proofs', sections: [
|
|
19
|
-
{ id: 'LEC0101', type: 'LEC', meetings: [{ day: 'Mon', start: 540, end: 600 }, { day: 'Wed', start: 540, end: 600 }, { day: 'Fri', start: 540, end: 600 }] },
|
|
20
|
-
{ id: 'TUT0101', type: 'TUT', meetings: [{ day: 'Thu', start: 540, end: 600 }] },
|
|
21
|
-
{ id: 'TUT0201', type: 'TUT', meetings: [{ day: 'Thu', start: 600, end: 660 }] },
|
|
22
|
-
]},
|
|
23
|
-
{ code: 'CSC148', name: 'Intro to Computer Science', sections: [
|
|
24
|
-
{ id: 'LEC0101', type: 'LEC', meetings: [{ day: 'Tue', start: 540, end: 600 }, { day: 'Thu', start: 540, end: 600 }] },
|
|
25
|
-
{ id: 'PRA0101', type: 'PRA', meetings: [{ day: 'Wed', start: 720, end: 780 }] },
|
|
26
|
-
]},
|
|
27
|
-
{ code: 'PHY151', name: 'Foundations of Physics I', sections: [
|
|
28
|
-
{ id: 'LEC0101', type: 'LEC', meetings: [{ day: 'Mon', start: 720, end: 780 }, { day: 'Wed', start: 720, end: 780 }] },
|
|
29
|
-
{ id: 'TUT0101', type: 'TUT', meetings: [{ day: 'Fri', start: 720, end: 780 }] },
|
|
30
|
-
{ id: 'PRA0101', type: 'PRA', meetings: [{ day: 'Tue', start: 780, end: 840 }] },
|
|
31
|
-
]},
|
|
32
|
-
]
|
|
33
|
-
|
|
34
|
-
const colors = ['bg-blue-500', 'bg-emerald-500', 'bg-amber-500', 'bg-purple-500', 'bg-rose-500']
|
|
35
|
-
|
|
36
|
-
export default function YACS() {
|
|
37
|
-
const [query, setQuery] = useState('')
|
|
38
|
-
const [added, setAdded] = useState<Record<string, Course>>({})
|
|
39
|
-
const [picks, setPicks] = useState<Record<string, Record<string, number>>>({}) // code -> type -> section idx
|
|
40
|
-
|
|
41
|
-
const results = query.length ?
|
|
42
|
-
catalog.filter(c => !added[c.code] && (c.code.toLowerCase().includes(query.toLowerCase()) || c.name.toLowerCase().includes(query.toLowerCase())))
|
|
43
|
-
: []
|
|
44
|
-
|
|
45
|
-
const addCourse = (c: Course) => {
|
|
46
|
-
setAdded({ ...added, [c.code]: c })
|
|
47
|
-
const types = [...new Set(c.sections.map(s => s.type))]
|
|
48
|
-
setPicks({ ...picks, [c.code]: Object.fromEntries(types.map(t => [t, 0])) })
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const removeCourse = (code: string) => {
|
|
52
|
-
const { [code]: _, ...rest } = added
|
|
53
|
-
setPicks(({ [code]: __, ...r }) => r)
|
|
54
|
-
setAdded(rest)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const cyclePick = (code: string, type: string) => {
|
|
58
|
-
const secs = added[code].sections.filter(s => s.type === type)
|
|
59
|
-
setPicks({ ...picks, [code]: { ...picks[code], [type]: (picks[code][type] + 1) % secs.length } })
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// gather all visible meetings for calendar
|
|
63
|
-
const events: { code: string, meeting: Meeting, colorIdx: number }[] = []
|
|
64
|
-
const codes = Object.keys(added)
|
|
65
|
-
for (const [i, code] of codes.entries()) {
|
|
66
|
-
const c = added[code]
|
|
67
|
-
const p = picks[code] || {}
|
|
68
|
-
for (const type of Object.keys(p)) {
|
|
69
|
-
const secs = c.sections.filter(s => s.type === type)
|
|
70
|
-
const sec = secs[p[type]]
|
|
71
|
-
if (sec) for (const m of sec.meetings) events.push({ code, meeting: m, colorIdx: i })
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return <App center={false} cn="p-4 h-screen">
|
|
76
|
-
<Grid cols={3} cn="h-full">
|
|
77
|
-
|
|
78
|
-
{/* calendar */}
|
|
79
|
-
<Card cnIgnoreWrongUsage="col-span-2 row-span-1 p-4 overflow-hidden flex flex-col">
|
|
80
|
-
<D cn="grid flex-1" style={{ gridTemplateColumns: `60px repeat(5, 1fr)` }}>
|
|
81
|
-
{/* hour labels */}
|
|
82
|
-
<D cnIgnoreWrongUsage="flex flex-col justify-between text-sm text-zinc-500 pr-2">
|
|
83
|
-
{hours.map(h => <span key={h}>{h > 12 ? h - 12 : h}{h >= 12 ? 'pm' : 'am'}</span>)}
|
|
84
|
-
</D>
|
|
85
|
-
{/* day columns */}
|
|
86
|
-
{days.map(day => <D key={day} cnIgnoreWrongUsage="relative border-l border-zinc-800">
|
|
87
|
-
<Muted cnIgnoreWrongUsage="text-center block text-sm mb-1">{day}</Muted>
|
|
88
|
-
{/* hour gridlines */}
|
|
89
|
-
{hours.map(h => <D key={h} cnIgnoreWrongUsage="border-t border-zinc-800/50 left-0 right-0 absolute" style={{ top: `${h*8}%` }} />)}
|
|
90
|
-
{/* events */}
|
|
91
|
-
{events.filter(e => e.meeting.day === day).map((e, i) => {
|
|
92
|
-
const top = ((e.meeting.start - 540) / (13 * 60)) * 100
|
|
93
|
-
const height = ((e.meeting.end - e.meeting.start) / (13 * 60)) * 100
|
|
94
|
-
return <D key={i} cnIgnoreWrongUsage={`absolute left-0.5 right-0.5 rounded text-sm px-1 text-white ${colors[e.colorIdx % colors.length]}`}
|
|
95
|
-
style={{ top: `${top}%`, height: `${height}%` }}>
|
|
96
|
-
{e.code}
|
|
97
|
-
</D>
|
|
98
|
-
})}
|
|
99
|
-
</D>)}
|
|
100
|
-
</D>
|
|
101
|
-
</Card>
|
|
102
|
-
|
|
103
|
-
{/* right panel */}
|
|
104
|
-
<D cn="flex flex-col gap-3">
|
|
105
|
-
{/* search */}
|
|
106
|
-
<Card cn="p-4">
|
|
107
|
-
<Row>
|
|
108
|
-
<Input grow placeholder="search..." value={query} onChange={e => setQuery(e.target.value)} />
|
|
109
|
-
<Select><option>2026W</option><option>2026S</option></Select>
|
|
110
|
-
</Row>
|
|
111
|
-
<D cnIgnoreWrongUsage="space-y-3 max-h-48 overflow-y-auto flex-row">
|
|
112
|
-
{results.map(c => <Btn key={c.code} click={() => addCourse(c)} grow>
|
|
113
|
-
{c.code} — {c.name}
|
|
114
|
-
</Btn>)}
|
|
115
|
-
{query.length >= 2 && !results.length && <Muted>no results</Muted>}
|
|
116
|
-
</D>
|
|
117
|
-
</Card>
|
|
118
|
-
|
|
119
|
-
{/* added */}
|
|
120
|
-
<Card cn="p-4 space-y-3 flex-1">
|
|
121
|
-
{codes.map((code, i) => {
|
|
122
|
-
const c = added[code]
|
|
123
|
-
const types = [...new Set(c.sections.map(s => s.type))]
|
|
124
|
-
return <D key={code} cn="space-y-1">
|
|
125
|
-
<Row align='mid'>
|
|
126
|
-
<span className={`w-2 h-2 rounded-full ${colors[i % colors.length]}`} />
|
|
127
|
-
<Muted cn="flex-1">{code}</Muted>
|
|
128
|
-
<Chip click={() => removeCourse(code)}>×</Chip>
|
|
129
|
-
</Row>
|
|
130
|
-
<Row>
|
|
131
|
-
{types.map(t => {
|
|
132
|
-
const secs = c.sections.filter(s => s.type === t)
|
|
133
|
-
const idx = picks[code]?.[t] ?? 0
|
|
134
|
-
return <Chip key={t} click={() => cyclePick(code, t)}>
|
|
135
|
-
{t} {secs[idx]?.id}
|
|
136
|
-
</Chip>
|
|
137
|
-
})}
|
|
138
|
-
</Row>
|
|
139
|
-
</D>
|
|
140
|
-
})}
|
|
141
|
-
{!codes.length && <Muted>no courses added</Muted>}
|
|
142
|
-
</Card>
|
|
143
|
-
</D>
|
|
144
|
-
|
|
145
|
-
</Grid>
|
|
146
|
-
</App>
|
|
147
|
-
}
|
package/example/src/index.css
DELETED
package/example/src/main.tsx
DELETED
package/example/tsconfig.json
DELETED
package/example/vite.config.ts
DELETED
package/tsconfig.json
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"jsx": "react-jsx",
|
|
7
|
-
"strict": true,
|
|
8
|
-
"skipLibCheck": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"declaration": true,
|
|
11
|
-
"outDir": "dist"
|
|
12
|
-
},
|
|
13
|
-
"include": ["*.ts", "*.tsx"]
|
|
14
|
-
}
|