diff --git a/.claude/launch.json b/.claude/launch.json new file mode 100644 index 0000000..65b40a7 --- /dev/null +++ b/.claude/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.1", + "configurations": [ + { + "name": "siteforge", + "runtimeExecutable": "node", + "runtimeArgs": ["--env-file=.env", "server.js"], + "port": 4173 + } + ] +} diff --git a/data/study-progress/3307bdd7-a770-4fad-a28e-cf2d0c2a6e34.json b/data/study-progress/3307bdd7-a770-4fad-a28e-cf2d0c2a6e34.json index 6ee413f..aa027c9 100644 --- a/data/study-progress/3307bdd7-a770-4fad-a28e-cf2d0c2a6e34.json +++ b/data/study-progress/3307bdd7-a770-4fad-a28e-cf2d0c2a6e34.json @@ -2,7 +2,8 @@ "byStudy": { "colossians": { "completedSectionIds": [ - "1-1-2" + "1-1-2", + "1-3-8" ], "quizAnswers": { "1-1-2": [ @@ -12,5 +13,5 @@ } } }, - "updatedAt": "2026-06-03T18:15:19.898Z" + "updatedAt": "2026-06-08T20:30:19.689Z" } \ No newline at end of file diff --git a/data/study-reminders.json b/data/study-reminders.json index df9ebfa..caa9aa5 100644 --- a/data/study-reminders.json +++ b/data/study-reminders.json @@ -1,4 +1,4 @@ { "users": {}, - "updatedAt": "2026-06-08T18:21:54.358Z" + "updatedAt": "2026-06-08T20:46:20.016Z" } \ No newline at end of file diff --git a/data/study-users.json b/data/study-users.json index 9b022c5..b1149ae 100644 --- a/data/study-users.json +++ b/data/study-users.json @@ -9,8 +9,15 @@ "studyRemindersEnabled": false, "enrolledStudySlugs": [], "avatarUrl": "", + "createdAt": null, + "updatedAt": null, "lastLoginAt": "2026-05-21T15:41:16.259Z", - "pendingEmailChange": null + "pendingEmailChange": null, + "twoFaMethod": null, + "totpSecret": null, + "totpVerified": false, + "totpEnabledAt": null, + "totpRecoveryCodes": [] }, { "id": "3307bdd7-a770-4fad-a28e-cf2d0c2a6e34", @@ -23,9 +30,15 @@ "colossians" ], "avatarUrl": "data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2288%22%20height%3D%2288%22%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20rx%3D%2218%22%20ry%3D%2218%22%20fill%3D%22%2311100d%22%2F%3E%3Ctext%20x%3D%2250%25%22%20y%3D%2250%25%22%20dominant-baseline%3D%22middle%22%20text-anchor%3D%22middle%22%20font-size%3D%2256%22%3E%F0%9F%A6%81%3C%2Ftext%3E%3C%2Fsvg%3E", - "lastLoginAt": "2026-06-03T17:47:53.877Z", + "createdAt": null, + "updatedAt": "2026-06-08T20:46:30.804Z", + "lastLoginAt": "2026-06-08T20:46:30.804Z", "pendingEmailChange": null, - "updatedAt": "2026-06-03T17:47:59.104Z", + "twoFaMethod": null, + "totpSecret": null, + "totpVerified": false, + "totpEnabledAt": null, + "totpRecoveryCodes": [], "totpSecretPending": "FGR7UI5TWA4HB4DURCXEUXATTVVVJDJ5" }, { @@ -37,9 +50,16 @@ "studyRemindersEnabled": false, "enrolledStudySlugs": [], "avatarUrl": "data:image/svg+xml;utf8,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"88\" height=\"88\"%3E%3Crect width=\"100%\" height=\"100%\" rx=\"18\" ry=\"18\" fill=\"%2311100d\"/%3E%3Ctext x=\"50%\" y=\"50%\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"56\"%3E🐱%3C/text%3E%3C/svg%3E", + "createdAt": null, + "updatedAt": null, "lastLoginAt": "2026-06-02T17:33:13.669Z", - "pendingEmailChange": null + "pendingEmailChange": null, + "twoFaMethod": null, + "totpSecret": null, + "totpVerified": false, + "totpEnabledAt": null, + "totpRecoveryCodes": [] } ], - "updatedAt": "2026-06-03T17:47:59.104Z" + "updatedAt": "2026-06-08T20:46:30.806Z" } \ No newline at end of file diff --git a/src/App.css b/src/App.css index e97dcb3..47262ab 100644 --- a/src/App.css +++ b/src/App.css @@ -1650,10 +1650,14 @@ padding: 3.75rem 0 1.75rem; } +.section-study-classroom .section-inner { + max-width: 1320px; +} + .study-classroom-shell { display: grid; - grid-template-columns: minmax(0, 1.15fr) minmax(260px, 0.85fr); - gap: 1rem; + grid-template-columns: minmax(0, 1.55fr) minmax(300px, 0.9fr); + gap: 1.75rem; align-items: start; } @@ -1732,6 +1736,98 @@ margin-top: 0.5rem; } +.study-track-switcher { + margin: 1rem 0; +} + +.study-track-switcher-tabs { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + margin-top: 0.5rem; +} + +.study-track-tab { + display: inline-block; + padding: 0.45rem 1rem; + border-radius: 999px; + border: 1px solid rgba(201, 168, 76, 0.3); + color: var(--brand-muted); + font-size: 0.85rem; + font-family: 'Barlow', sans-serif; + text-decoration: none; + transition: background 0.18s, color 0.18s, border-color 0.18s; +} + +.study-track-tab:hover { + background: rgba(201, 168, 76, 0.1); + border-color: rgba(201, 168, 76, 0.6); + color: #e8d8b0; +} + +.study-track-tab--active { + background: rgba(201, 168, 76, 0.18); + border-color: var(--brand-gold); + color: var(--brand-gold); + font-weight: 600; + pointer-events: none; +} + +.study-notebook { + margin-top: 1rem; +} + +.study-notebook-tabs { + display: flex; + flex-wrap: wrap; + gap: 0.3rem; + padding-left: 0.5rem; +} + +.study-notebook-tab { + background: rgba(18, 18, 16, 0.6); + border: 1px solid rgba(201, 168, 76, 0.18); + border-bottom: none; + color: var(--brand-muted); + padding: 0.55rem 1.1rem; + border-radius: 10px 10px 0 0; + cursor: pointer; + font-size: 0.82rem; + font-family: 'Barlow', sans-serif; + transition: background 0.18s, color 0.18s; + position: relative; + top: 1px; +} + +.study-notebook-tab:hover { + background: rgba(201, 168, 76, 0.1); + color: #e8d8b0; +} + +.study-notebook-tab--active { + background: rgba(18, 18, 16, 0.86); + border-color: rgba(201, 168, 76, 0.35); + color: var(--brand-gold); + font-weight: 600; +} + +.study-notebook-page { + padding: 1.25rem; + border-radius: 0 12px 12px 12px; + border: 1px solid rgba(201, 168, 76, 0.35); + background: rgba(18, 18, 16, 0.86); +} + +.study-notebook-page h3 { + margin: 0.2rem 0 0; + font-family: var(--brand-font-heading); + color: var(--brand-warm-white); +} + +.study-notebook-page .study-module-focus { + margin-top: 1rem; +} + .study-classroom-sidebar { position: sticky; top: 5.75rem; diff --git a/src/colossiansStudy.tsx b/src/colossiansStudy.tsx index 57a72cd..4cae073 100644 --- a/src/colossiansStudy.tsx +++ b/src/colossiansStudy.tsx @@ -1965,6 +1965,7 @@ export function ColossiansStudyNotesPage({ content }: Props) { const [notes, setNotes] = useState({}) const [loading, setLoading] = useState(true) const [message, setMessage] = useState('') + const [activeNoteTab, setActiveNoteTab] = useState('') useEffect(() => { document.title = study ? `My Notes | ${study.title}` : 'My Study Notes' @@ -2039,6 +2040,10 @@ export function ColossiansStudyNotesPage({ content }: Props) { }) .filter(item => item.note && item.note.trim()) + const enrolledStudies = !loading && auth.authenticated + ? getStudies(content).filter(s => (auth.enrolledStudySlugs ?? []).includes(s.slug.toLowerCase())) + : [] + return (
@@ -2047,6 +2052,22 @@ export function ColossiansStudyNotesPage({ content }: Props) {

Student Workspace

My Lesson Notes

{!loading && auth.authenticated &&

Signed in as {auth.username}

} + {enrolledStudies.length > 1 && ( +
+

Switch Track

+
+ {enrolledStudies.map(s => ( + + {s.title} + + ))} +
+
+ )} {!loading && auth.authenticated && (
My Account @@ -2076,24 +2097,40 @@ export function ColossiansStudyNotesPage({ content }: Props) { {study.sections[0] && Open First Lesson} )} - {!loading && auth.authenticated && enrolled && entries.length > 0 && ( -
- {entries.map(({ sectionId, section, note }) => ( -
-
-

{section ? `Lesson ${getLessonNumber(study.sections, section.id)}` : 'Saved Note'}

-

{section?.title ?? sectionId}

-

{section ? section.reference : 'Lesson reference unavailable'}

-
-
-

Your Note

-

{note}

- {section && Open Lesson} -
+ {!loading && auth.authenticated && enrolled && entries.length > 0 && (() => { + const sorted = [...entries].sort((a, b) => { + const aNum = a.section ? getLessonNumber(study.sections, a.section.id) : 0 + const bNum = b.section ? getLessonNumber(study.sections, b.section.id) : 0 + return aNum - bNum + }) + const active = sorted.find(item => item.sectionId === activeNoteTab) ?? sorted[0] + return ( +
+
+ {sorted.map(({ sectionId, section }) => ( + + ))} +
+
+

{active.section ? `Lesson ${getLessonNumber(study.sections, active.section.id)}` : 'Saved Note'}

+

{active.section?.title ?? active.sectionId}

+

{active.section ? active.section.reference : 'Lesson reference unavailable'}

+

Your Note

+

{active.note}

+ {active.section && Open Lesson}
- ))} -
- )} +
+ ) + })()} {message &&

{message}

}