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.
@@ -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
- }
@@ -1,3 +0,0 @@
1
- @import "tailwindcss";
2
- @source "../../*.tsx";
3
- @import "ui/styles.css";
@@ -1,5 +0,0 @@
1
- import { createRoot } from "react-dom/client"
2
- import "./index.css"
3
- import App from "./App"
4
-
5
- createRoot(document.getElementById("root")!).render(<App />)
@@ -1,12 +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
- },
11
- "include": ["src"]
12
- }
@@ -1,10 +0,0 @@
1
- import { defineConfig } from "vite"
2
- import react from "@vitejs/plugin-react"
3
- import tailwindcss from "@tailwindcss/vite"
4
-
5
- export default defineConfig({
6
- plugins: [react(), tailwindcss()],
7
- optimizeDeps: {
8
- include: ["highlight.js"],
9
- },
10
- })
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
- }