docs(prd): add learning paths PRD with end-to-end HTML prototypes
Full spec for ordered, sequentially unlocked, bundle-priced learning paths, plus 16 clickable prototypes (public org site, learner LMS, and teacher workspace) built on the packages/ui tokens and the minimal org-landing theme. The prototypes are the UX source of truth; start at prototypes/learning-paths/index.html. Also adds the write-prd skill codifying the clarify -> write -> prototype workflow.
This commit is contained in:
@@ -0,0 +1,277 @@
|
||||
# Learning Paths PRD
|
||||
|
||||
## Status
|
||||
|
||||
- Draft (prototyped, ready for engineering review)
|
||||
|
||||
## Prototypes — the UX source of truth
|
||||
|
||||
**The UX of this feature must be taken from the prototype folder.** Interactive HTML prototypes for every surface live in [`prototypes/learning-paths/`](../../prototypes/learning-paths/) and are the approved design reference for layout, states (done / in progress / locked), copy, and navigation flow. When this document and a prototype disagree on a UI detail, the prototype wins.
|
||||
|
||||
**Start here:**
|
||||
|
||||
```
|
||||
prototypes/learning-paths/index.html
|
||||
```
|
||||
|
||||
Open it in a browser (`open prototypes/learning-paths/index.html`) — it maps all three journeys (visitor → learner → teacher) and every page cross-links so you can click through each flow end to end. Each page has a light/dark toggle.
|
||||
|
||||
The prototypes are built on the real design tokens (`packages/ui/src/index.css` for app pages via `app-theme.css`, the `minimal` org-landing theme for public pages via `landing-theme.css`) and encode every decision below.
|
||||
|
||||
| Surface | Files |
|
||||
| --- | --- |
|
||||
| Public (org site) | `org-landing.html`, `public-paths.html`, `public-path.html` |
|
||||
| Learner (LMS) | `lms-home.html`, `paths.html`, `path-detail.html`, `course-in-path.html` |
|
||||
| Teacher (admin) | `teacher-paths.html`, `teacher-path-setup.html`, `teacher-path-builder.html`, `teacher-path-people.html`, `teacher-path-analytics.html`, `teacher-path-landing-editor.html`, `teacher-path-certificate.html`, `teacher-path-settings.html` |
|
||||
|
||||
## Purpose
|
||||
|
||||
Let orgs package multiple courses into an **ordered, sequentially unlocked, bundle-priced learning path** that is sold on the org's public site, completed step-by-step in the LMS, and finished with an optional path certificate. Reference experience: Coursera Professional Certificates (e.g. IBM Data Science).
|
||||
|
||||
## Problem Statement
|
||||
|
||||
- Courses can only be sold and taken individually; there is no way to sell a curriculum as one product with one price.
|
||||
- Programs (shipped) group courses for cohort admin purposes but are explicitly **unordered**, have no gating, no public page, no pricing, and no path-level certificate.
|
||||
- Instructors who run structured curricula cannot enforce prerequisites ("finish JS before React").
|
||||
- The org landing page has no product above the individual course, so multi-course offerings are invisible to visitors.
|
||||
|
||||
## Confirmed Decisions
|
||||
|
||||
1. **New entity, separate from Programs.** `learning_path` is its own table set. Programs remain unchanged (cohort hub + newsfeed). No migration.
|
||||
2. **Terminology**: "Learning Path" everywhere (admin, LMS, public site).
|
||||
3. **Self-enrollment with bundle pricing.** A path is public on the org landing site with one price. Enrolling (buy or free) auto-enrolls the learner in every course in the path.
|
||||
4. **Show savings.** The public page shows the bundle price against the summed individual course prices ("$199 ~~$280~~ · Save $81 (29%)"). Toggleable per path.
|
||||
5. **Unlock rule = lessons + exercises.** Course N+1 unlocks when course N has every lesson complete AND every exercise submitted/passed. Sequential unlocking is a per-path toggle (off = take in any order).
|
||||
6. **Path certificate is a teacher toggle** with its own admin tab; issued automatically on full completion; appears in the learner's LMS Certificates page.
|
||||
7. **Teacher workspace tabs**: Courses (ordering), People, Analytics, Landing page, Certificate, Settings. **No path newsfeed** (Programs covers cohort communication).
|
||||
8. **Visitor access is teacher-configurable**: teaser only / full syllabus / syllabus + preview lessons.
|
||||
9. **Public path page follows the Coursera professional-certificate shape**: hero with stats + enroll CTA, what-you'll-learn, skills tags, sequential course cards with per-course outcomes and lesson outlines, certificate block, instructors, testimonials, FAQ accordion, pricing card.
|
||||
10. **Org landing page: Learning Paths section sits ABOVE the Courses section.** Plus a `/paths` catalog page and `/path/[slug]` detail page mirroring how `/courses` and `/course/[slug]` work today.
|
||||
11. **Course independence**: a course can be in multiple paths and remain individually sellable. Removing a course from a path or a learner from a path never deletes `groupmember` rows or progress.
|
||||
12. **Statuses**: `ACTIVE` (public + LMS), `DRAFT` (hidden while building), `ARCHIVED` (hidden everywhere, restorable).
|
||||
|
||||
## Current-State Audit
|
||||
|
||||
| Capability | Current state | Notes |
|
||||
| --- | --- | --- |
|
||||
| Grouping above course | `program` tables (unordered, admin-enrolled, newsfeed) | Keep as-is; do not extend |
|
||||
| Enrollment | `groupmember` per course group; `enrollInCourse()` in `apps/api/src/services/course/invite.ts` | Reuse for auto-enrollment |
|
||||
| Course completion | lesson completion + exercise submissions tracked per course | Source data for the unlock rule |
|
||||
| Public org site | `(org-site)` routes + `packages/ui/src/custom/org-landing-page/` (10 themes, default `minimal`) | Mirror for paths section/list/detail |
|
||||
| Course landing page | theme `course.svelte` composer: hero → anchor nav → social proof → info blocks → curriculum → chips → instructor → reviews → pricing | Path page reuses these shared components where possible |
|
||||
| Payments | course payment flow on paid enroll CTA (`course-landing-page.svelte`) | Path enroll reuses the same flow with the path as the product |
|
||||
| Certificates | course certificate system + LMS Certificates page | Add path-level issuance |
|
||||
| Setup checklist pattern | `routes/(app)/org/[slug]/setup/+page.svelte` + `PercentRingProgress` + `Item.*` | Reuse for "Set up your path" and learner checklist view |
|
||||
|
||||
## Product Goals
|
||||
|
||||
1. A visitor can discover a path on the org landing page, read a full Coursera-style path page, and self-enroll (paid or free).
|
||||
2. Enrolling in a path creates path membership and `groupmember` rows for every course in it.
|
||||
3. A learner sees paths in the LMS (home section + Learning Paths nav), opens a path hub with per-course progress and locked/unlocked states, and moves through courses in order.
|
||||
4. Inside a course that belongs to a path, the learner sees path context (position stepper, "next course unlocks when…").
|
||||
5. Teachers create a path via a setup checklist, order courses by drag, price the bundle, customize the public page, configure the certificate, and track a per-course funnel.
|
||||
6. Completing all courses issues the path certificate (when enabled).
|
||||
7. Programs, standalone courses, and existing enrollments are untouched (zero regression).
|
||||
|
||||
## Non-Goals (v1)
|
||||
|
||||
- Branching / non-linear paths (graphs, optional courses, parallel tracks).
|
||||
- Path-level newsfeed or community.
|
||||
- Subscriptions or installment pricing; coupon codes beyond what courses support.
|
||||
- Path templates, cloning, or cross-org sharing.
|
||||
- Per-learner overrides of the unlock rule (admin "skip ahead" can be a fast-follow).
|
||||
- Team/B2B seat purchasing.
|
||||
|
||||
---
|
||||
|
||||
## Functional Requirements
|
||||
|
||||
### 1. Public — org landing site
|
||||
|
||||
**Landing page section** (above Courses; see `org-landing.html`):
|
||||
- Section heading "Learning Paths" + lead line; grid of path cards.
|
||||
- Path card: "Learning Path" chip, name, description, ordered course preview list (first 3 + "+N more"), meta row (course count, total hours, certificate), bundle price with struck-through sum.
|
||||
- "View all learning paths" → `/paths`.
|
||||
- Rendered per landing-page theme like the courses section (start with `minimal`; other themes can fall back to base styling).
|
||||
|
||||
**Catalog page `/paths`** (see `public-paths.html`): compact hero with search, filter sidebar (topic/tags, pricing, length), path card list, pagination. Mirrors `(org-site)/courses`.
|
||||
|
||||
**Detail page `/path/[slug]`** (see `public-path.html`), section order:
|
||||
1. Hero: chip, headline, subheadline (teacher-editable), instructor avatar stack, Enroll CTA with price + savings chip, sticky enroll box (price, savings, feature list, CTA, enrolled/rating counts).
|
||||
2. Stats row: courses, total hours, level, rating.
|
||||
3. Sticky anchor nav: About / Courses / Certificate / Instructors / Testimonials / FAQ.
|
||||
4. What you'll learn (outcome bullets) + Skills tags.
|
||||
5. Course series: one card per course in order — number, title, lesson count + duration, per-course outcome bullets, expandable lesson outline (lessons marked preview are openable when the teacher allows).
|
||||
6. Certificate block (when enabled).
|
||||
7. Instructors (auto-derived from course tutors, hideable).
|
||||
8. Testimonials (teacher-managed, hideable).
|
||||
9. FAQ accordion (teacher-managed, hideable).
|
||||
10. Pricing card + footer.
|
||||
- Enroll: free path → enroll flow like `/course/{slug}/enroll`; paid path → payment flow with the path as product. Requires auth like course enrollment.
|
||||
- Visitor access level (teaser / syllabus / syllabus+preview) gates sections 5's lesson detail.
|
||||
- JSON-LD `Course`/`LearningResource` schema like the course page.
|
||||
|
||||
### 2. Learner — LMS
|
||||
|
||||
**Home** (`lms-home.html`): "Learning Paths" section above Courses when `enrolledPaths.length > 0`; path cards show segmented per-course progress (one segment per course: done/current/locked) + overall %, and "Next: {course}". Course cards belonging to a path carry a "{path} · i/N" chip.
|
||||
|
||||
**Nav**: "Learning Paths" item in the LMS sidebar with enrolled count badge, shown only when enrolled in ≥1 path.
|
||||
|
||||
**List `/lms/paths`** (`paths.html`): tabs In progress / Completed / All; rows with segment bar, next course, Continue / View certificate.
|
||||
|
||||
**Path hub `/lms/paths/[id]`** (`path-detail.html`): the journey spine — a vertical rail of course nodes that fills as courses complete. Per course: state (Completed / In progress / Locked), progress bar, lesson+exercise counts, unlock note ("Unlocks after Course N"), certificate end-row.
|
||||
|
||||
**Course in path** (`course-in-path.html`): when the visited course belongs to a path the learner is in, wrap the course view with a path ribbon — back pill to the path, "Course 3 of 5", overall path %, horizontal stepper (done/current/locked) — and a "Next in your path" callout under the lesson showing what completing this course unlocks.
|
||||
|
||||
**Unlock enforcement**: locked courses are not openable from path surfaces; direct navigation to a locked course (URL) shows a "locked — finish {course} first" state. Learners enrolled in a course independently (outside the path) keep their normal access.
|
||||
|
||||
### 3. Teacher — admin dashboard
|
||||
|
||||
**Org listing `/org/[slug]/paths`** (`teacher-paths.html`): nav item "Learning Paths" after Courses; stat cards (active paths, enrolled learners, completions); table (name, courses, learners, status); Create path → creation modal → setup checklist.
|
||||
|
||||
**Setup checklist `/paths/[id]/setup`** (`teacher-path-setup.html`): Get Started pattern (ring + dots + item rows): name/describe ✓ auto, add courses, set order, set price, customize landing page, activate. Each step deep-links to its tab. Shown until complete; "Finish setup · N%" chip in the workspace top bar.
|
||||
|
||||
**Path workspace `/paths/[id]/*`** — course-style sidebar (back link, path identity + status, tabs):
|
||||
|
||||
| Tab | File | Contents |
|
||||
| --- | --- | --- |
|
||||
| Courses | `teacher-path-builder.html` | "Unlock courses in order" toggle; drag-to-reorder course rows (order, thumb, lessons/exercises/price, open/remove); add-course picker (org courses not in path); certificate end-row. Remove-course confirmation notes nobody is unenrolled. |
|
||||
| People | `teacher-path-people.html` | Auto-enroll info banner; search + progress filter; table: learner, path progress bar, current course, enrolled date, actions (view, remove — preserves course access). Add learners (batch email, like course invites). |
|
||||
| Analytics | `teacher-path-analytics.html` | Stat cards (enrolled, active, completion rate, avg time); per-course funnel with drop-off callouts; "stuck" list (lessons/exercises blocking most learners). |
|
||||
| Landing page | `teacher-path-landing-editor.html` | Hero headline/subheadline; visitor access radio (teaser / syllabus / syllabus+previews); what-you'll-learn bullets; skills tags; instructors toggle (auto from course tutors); testimonials CRUD + toggle; FAQ CRUD + toggle; "View live page". |
|
||||
| Certificate | `teacher-path-certificate.html` | Award toggle; requirements summary (all lessons + all exercises); title + issuer fields; live preview; awarded count. |
|
||||
| Settings | `teacher-path-settings.html` | General (name, description, cover); Pricing (bundle price, currency, show-savings toggle with computed sum); Enrollment & flow (self-enrollment toggle, unlock-in-order toggle, auto-enroll toggle); Status radio (Active / Draft / Archived); Danger zone (delete path — courses & progress preserved). |
|
||||
|
||||
### 4. Access control
|
||||
|
||||
- Org admins manage all paths; path-level TUTOR role can manage content but not delete (mirror Programs roles: ADMIN/TUTOR/STUDENT via `roleId`).
|
||||
- Students: read path data they're members of; public endpoints serve ACTIVE paths only.
|
||||
- DRAFT paths: admin/tutor only. ARCHIVED: hidden everywhere, data preserved.
|
||||
|
||||
---
|
||||
|
||||
## Technical Design
|
||||
|
||||
### Data model (`packages/db/src/schema.ts`)
|
||||
|
||||
```
|
||||
learning_path
|
||||
id uuid PK · organizationId FK(organization, cascade) · name varchar · slug varchar (unique per org)
|
||||
description text · coverImage text · status LEARNING_PATH_STATUS default 'DRAFT'
|
||||
cost numeric · currency varchar default 'USD' · showSavings boolean default true
|
||||
sequentialUnlock boolean default true · selfEnrollment boolean default true · autoEnroll boolean default true
|
||||
certificateEnabled boolean default true · certificateTitle text · certificateIssuer text
|
||||
landingPage jsonb -- { headline, subheadline, visitorAccess: 'teaser'|'syllabus'|'preview',
|
||||
-- outcomes: string[], skills: string[], showInstructors, testimonials: [...],
|
||||
-- showTestimonials, faqs: [...], showFaqs }
|
||||
visitorAccess is inside landingPage; no relational IDs inside the jsonb (per repo rule)
|
||||
createdByProfileId FK(profile) · createdAt / updatedAt
|
||||
|
||||
learning_path_course
|
||||
id uuid PK · pathId FK(learning_path, cascade) · courseId FK(course, cascade)
|
||||
order integer NOT NULL -- 1-based position; the gating sequence
|
||||
unique(pathId, courseId) · unique(pathId, order) · index(pathId)
|
||||
|
||||
learning_path_member
|
||||
id uuid PK · pathId FK(learning_path, cascade) · profileId FK(profile) · roleId FK(role)
|
||||
enrolledAt timestamptz · completedAt timestamptz nullable
|
||||
certificateIssuedAt timestamptz nullable · certificateId varchar nullable
|
||||
unique(pathId, profileId) · index(pathId) · index(profileId)
|
||||
|
||||
enum LEARNING_PATH_STATUS: ACTIVE | DRAFT | ARCHIVED
|
||||
```
|
||||
|
||||
Notes:
|
||||
- No denormalized progress on `learning_path_member` beyond `completedAt`; per-course progress is computed from existing lesson-completion + exercise-submission data (already queried for course cards).
|
||||
- Savings figure is computed at read time from the sum of `course.cost` over path courses — never stored.
|
||||
- Schema work stops at a passing `@cio/db` build; migrations are handled outside this workflow.
|
||||
|
||||
### Completion / unlock logic (service layer)
|
||||
|
||||
```
|
||||
courseCompleteForPath(profileId, courseId):
|
||||
lessonsComplete = completedLessons == totalLessons
|
||||
exercisesComplete = submittedOrPassedExercises == totalExercises
|
||||
return lessonsComplete && exercisesComplete
|
||||
|
||||
unlockedCourses(path, profileId):
|
||||
if !path.sequentialUnlock → all
|
||||
else → courses[0..k] where k = first index whose course is not complete
|
||||
```
|
||||
|
||||
Path completion: all courses complete → set `completedAt`; if `certificateEnabled`, issue certificate (id `LP-XXXX-XXXX`), set `certificateIssuedAt`. Evaluate on lesson/exercise completion events for members of paths containing that course (reuse the pattern used by course-completion side effects).
|
||||
|
||||
### API routes (`apps/api/src/routes/learning-path/`)
|
||||
|
||||
Follow the standard layering (validation in `packages/utils/src/validation/learning-path/`, queries in `packages/db/src/queries/learning-path/`, services in `apps/api/src/services/learning-path/`). Mount as a single root segment: `.route('/learning-path', learningPathRouter)`.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| GET | `/learning-path` | org admin | List org paths (admin) |
|
||||
| POST | `/learning-path` | org admin | Create (name, description) → DRAFT |
|
||||
| GET | `/learning-path/:pathId` | member/admin | Detail incl. ordered courses + caller progress |
|
||||
| PUT | `/learning-path/:pathId` | admin/tutor | Update settings/pricing/landingPage/status |
|
||||
| DELETE | `/learning-path/:pathId` | org admin | Delete (courses/progress preserved) |
|
||||
| POST | `/learning-path/:pathId/courses` | admin/tutor | Add course (+ auto-enroll existing students) |
|
||||
| PUT | `/learning-path/:pathId/courses/order` | admin/tutor | Reorder (array of courseIds) |
|
||||
| DELETE | `/learning-path/:pathId/courses/:courseId` | admin/tutor | Remove (no unenrollment) |
|
||||
| GET | `/learning-path/:pathId/members` | admin/tutor | Members + per-course progress |
|
||||
| POST | `/learning-path/:pathId/members` | admin/tutor | Batch add (email+role) + auto-enroll |
|
||||
| DELETE | `/learning-path/:pathId/members/:memberId` | admin/tutor | Remove (course access preserved) |
|
||||
| GET | `/learning-path/:pathId/analytics` | admin/tutor | Funnel + stuck items |
|
||||
| POST | `/learning-path/:pathId/enroll` | auth user | Self-enroll (free) / post-payment callback (paid) |
|
||||
| GET | `/organization/learning-paths/enrolled` | auth user | LMS: caller's paths with progress + unlock states |
|
||||
|
||||
Public (org-site loaders, no auth): list ACTIVE paths for landing/catalog; get path by slug with landingPage content filtered by `visitorAccess`.
|
||||
|
||||
### Frontend plan (dashboard)
|
||||
|
||||
Follow CLAUDE.md conventions: types in `features/learning-path/utils/types.ts` inferred from the API, API classes in `features/learning-path/api/*.svelte.ts`, thin components, all copy in `en.json` under `"learningPath"`, `ui:` prefix for theme colors.
|
||||
|
||||
- **Admin**: nav item in `org-navigation.ts` after Courses; routes `org/[slug]/paths/+page.svelte` and `paths/[id]/{setup,courses,people,analytics,landing,certificate,settings}` with a `PathSidebar` mirroring the course sidebar pattern. Reuse `Item.*`, `PercentRingProgress`, `Field.*`, existing drag-reorder approach from lesson ordering if present.
|
||||
- **LMS**: `lms/paths` + `lms/paths/[id]`; path ribbon injected in the course layout when course ∈ caller's path; reuse `course-progress-card` math for per-course %.
|
||||
- **Public**: paths section added to org landing themes (start `minimal`), `(org-site)/paths` and `(org-site)/path/[slug]` mirroring the courses equivalents; reuse `CourseSectionNav`, `CourseSocialProof`, `CourseCurriculum`-style rows, `CoursePricing` card, `LandingButton`, footer.
|
||||
|
||||
### Build verification
|
||||
|
||||
```bash
|
||||
pnpm --filter @cio/utils build && pnpm --filter @cio/db build && pnpm --filter @cio/api build
|
||||
pnpm --filter @cio/dashboard^... build && pnpm --filter @cio/dashboard build
|
||||
pnpm format:check
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Order
|
||||
|
||||
1. **Schema + validation + queries** (`learning_path*` tables, Zod schemas, query layer).
|
||||
2. **API**: CRUD + course ordering + members + enroll service (auto-enroll transaction, `ON CONFLICT DO NOTHING` idempotency) + unlock/completion service + enrolled-paths endpoint.
|
||||
3. **Admin UI**: listing → workspace shell + Courses tab → Settings → People → setup checklist → Landing editor → Certificate → Analytics.
|
||||
4. **LMS**: enrolled section on home + nav, list, path hub (pick journey or checklist), course-in-path ribbon + lock enforcement.
|
||||
5. **Public**: landing section (minimal theme) → catalog → detail page → enroll flow (free first, then paid via existing payment flow).
|
||||
6. **Certificate issuance** + LMS Certificates page integration.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
1. Teacher can create a path, add + reorder courses, set a bundle price, and activate it; the setup checklist reflects real completion.
|
||||
2. ACTIVE paths appear on the org landing page above courses, in `/paths`, and at `/path/[slug]` with all enabled sections; DRAFT/ARCHIVED paths do not.
|
||||
3. Savings displays as bundle price vs summed course prices and updates when course prices change.
|
||||
4. Visitor access level correctly gates lesson outlines/previews for non-enrolled visitors.
|
||||
5. Enrolling (free or paid) creates the member row and `groupmember` rows for all path courses, idempotently.
|
||||
6. With sequential unlock on, course N+1 is locked until course N's lessons AND exercises are complete — enforced in UI and API; toggle off restores free order.
|
||||
7. Learner LMS shows path progress (segments + %), locked states, and the in-course path ribbon; direct URL access to a locked course is blocked with an explanatory state.
|
||||
8. Completing all courses sets `completedAt` and (when enabled) issues the path certificate, visible in LMS Certificates.
|
||||
9. Removing a course from a path or a member from a path never deletes course enrollments or progress.
|
||||
10. Adding a course to a path with existing students auto-enrolls them in that course.
|
||||
11. Analytics funnel counts match member course-completion data.
|
||||
12. Programs and standalone courses behave exactly as before.
|
||||
13. All user-facing strings use translation keys; all builds and `pnpm format:check` pass.
|
||||
|
||||
## Risks and Mitigations
|
||||
|
||||
- **Unlock-rule evaluation cost** (checked on every lesson/exercise completion): scope the check to paths containing that course with the learner as member; index `learning_path_course.courseId`.
|
||||
- **Auto-enroll transaction size** for large paths/cohorts: batch inserts with `ON CONFLICT DO NOTHING`; >500 members → background job (same mitigation as Programs).
|
||||
- **Price drift**: savings computed at read time, so course price changes are always reflected; if a course in an active path becomes free/pricier, surface a notice in the Settings pricing section.
|
||||
- **Learner already enrolled in a member course independently**: idempotent enrollment; their existing progress counts toward the unlock rule immediately (decide: acceptable and desirable).
|
||||
- **Locked-course deep links** shared between learners: API must enforce the lock (not just UI), returning a typed error the frontend renders as the locked state.
|
||||
- **Landing theme sprawl** (10 themes): v1 ships the paths section/pages for the base + `minimal` theme with a neutral fallback for others, mirroring how course landing tokens are layered.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,304 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Course in Path · ClassroomIO LMS</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="app-theme.css" />
|
||||
<script>
|
||||
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
<style>
|
||||
.shell { display: grid; grid-template-columns: 300px 1fr; min-height: 100vh; }
|
||||
|
||||
/* ============ COURSE SIDEBAR (matches app course content sidebar) ============ */
|
||||
.csb { background: var(--sidebar); border-right: 1px solid var(--sidebar-border); display: flex; flex-direction: column; position: sticky; top: 0; height: 100vh; }
|
||||
.csb-scroll { flex: 1; overflow-y: auto; padding: 12px; }
|
||||
|
||||
/* course identity block */
|
||||
.course-id { display: flex; align-items: center; gap: 12px; padding: 12px; border-radius: var(--radius-md); background: color-mix(in oklab, var(--primary) 7%, transparent); margin-bottom: 10px; }
|
||||
.course-id .nm { font-size: 14px; font-weight: 600; color: var(--foreground); line-height: 1.3; }
|
||||
.course-id .ct { font-size: 12px; color: var(--muted-foreground); margin-top: 1px; }
|
||||
|
||||
.back-path { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 500; color: var(--primary); padding: 4px 12px 10px; }
|
||||
.back-path svg { width: 14px; height: 14px; stroke-width: 2.2; }
|
||||
|
||||
/* Content header row */
|
||||
.content-row { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-radius: var(--radius-md); background: color-mix(in oklab, var(--primary) 8%, transparent); color: var(--primary); font-size: 14px; font-weight: 600; margin-bottom: 6px; }
|
||||
.content-row > svg { width: 16px; height: 16px; stroke-width: 2; }
|
||||
.content-row .counts { margin-left: auto; display: flex; align-items: center; gap: 10px; font-size: 12px; font-weight: 600; }
|
||||
.content-row .counts .c { display: flex; align-items: center; gap: 4px; }
|
||||
.content-row .counts svg { width: 13px; height: 13px; stroke-width: 2; }
|
||||
|
||||
/* module section rows */
|
||||
.module { display: flex; align-items: center; gap: 8px; padding: 7px 8px 7px 14px; font-size: 13.5px; font-weight: 500; color: var(--foreground); border-radius: var(--radius-md); cursor: pointer; }
|
||||
.module:hover { background: var(--sidebar-accent); }
|
||||
.module > svg:first-child { width: 15px; height: 15px; stroke-width: 2; color: var(--primary); flex-shrink: 0; }
|
||||
.module .pct { margin-left: auto; font-size: 12px; color: var(--muted-foreground); font-weight: 500; }
|
||||
.module .chev { width: 14px; height: 14px; stroke-width: 2; color: var(--muted-foreground); flex-shrink: 0; }
|
||||
|
||||
/* lesson rows */
|
||||
.lessons { padding-left: 14px; }
|
||||
.lesson { display: flex; align-items: center; gap: 8px; padding: 6px 8px 6px 10px; font-size: 13.5px; color: var(--foreground); border-radius: var(--radius-md); cursor: pointer; }
|
||||
.lesson:hover { background: var(--sidebar-accent); }
|
||||
.lesson > svg:first-child { width: 15px; height: 15px; stroke-width: 1.8; color: color-mix(in oklab, var(--primary) 70%, var(--muted-foreground)); flex-shrink: 0; }
|
||||
.lesson .t { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
||||
.lesson.active { background: color-mix(in oklab, var(--primary) 10%, transparent); color: var(--primary); font-weight: 500; }
|
||||
.lesson.active > svg:first-child { color: var(--primary); }
|
||||
.lesson .done-mark { width: 16px; height: 16px; border-radius: 999px; background: var(--foreground); color: var(--background); display: grid; place-items: center; flex-shrink: 0; }
|
||||
.lesson .done-mark svg { width: 9px; height: 9px; stroke-width: 3.4; }
|
||||
.lesson.locked { color: var(--muted-foreground); cursor: not-allowed; }
|
||||
.lesson.locked > svg:first-child { color: var(--muted-foreground); }
|
||||
.lesson .lock { width: 13px; height: 13px; stroke-width: 2; color: var(--muted-foreground); flex-shrink: 0; }
|
||||
|
||||
/* sidebar footer: progress card + powered by */
|
||||
.csb-foot { padding: 12px; border-top: 1px solid var(--sidebar-border); }
|
||||
.prog-card { background: color-mix(in oklab, var(--primary) 7%, transparent); border-radius: var(--radius-md); padding: 12px 14px; }
|
||||
.prog-card .row { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 8px; }
|
||||
.prog-card .row .l { font-size: 13px; font-weight: 600; }
|
||||
.prog-card .row .p { font-size: 13px; font-weight: 700; color: var(--primary); }
|
||||
.prog-card .cap { font-size: 11.5px; color: var(--muted-foreground); margin-top: 8px; }
|
||||
.powered { display: flex; align-items: center; justify-content: center; gap: 5px; font-size: 11.5px; color: var(--muted-foreground); padding: 12px 0 2px; }
|
||||
.powered b { color: var(--foreground); font-weight: 600; }
|
||||
|
||||
/* ============ HEADER (matches app course header) ============ */
|
||||
.chead { height: 52px; border-bottom: 1px solid var(--border); background: var(--background); position: sticky; top: 0; z-index: 100; display: flex; align-items: center; gap: 12px; padding: 0 20px; }
|
||||
.panel-btn { width: 30px; height: 30px; border: none; background: transparent; border-radius: var(--radius-md); display: grid; place-items: center; color: var(--muted-foreground); cursor: pointer; }
|
||||
.panel-btn:hover { background: var(--accent); color: var(--foreground); }
|
||||
.panel-btn svg { width: 17px; height: 17px; stroke-width: 2; }
|
||||
.chead .crumb { font-size: 14px; font-weight: 500; }
|
||||
.chead .right { margin-left: auto; display: flex; align-items: center; gap: 8px; }
|
||||
.chead .sep { width: 1px; height: 18px; background: var(--border); flex-shrink: 0; margin: 0 4px; }
|
||||
/* path widget — tinted pill so it clearly reads as the learning path */
|
||||
.path-widget {
|
||||
display: inline-flex; align-items: center; gap: 10px;
|
||||
padding: 4px 12px 4px 10px; border-radius: 999px;
|
||||
background: color-mix(in oklab, var(--primary) 8%, transparent);
|
||||
border: 1px solid color-mix(in oklab, var(--primary) 22%, transparent);
|
||||
min-width: 0;
|
||||
}
|
||||
.path-widget:hover { border-color: color-mix(in oklab, var(--primary) 45%, transparent); }
|
||||
.path-widget .pw-kind { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--primary); white-space: nowrap; }
|
||||
.path-widget .pw-kind svg { width: 13px; height: 13px; stroke-width: 2.2; }
|
||||
.mini-stepper { display: flex; align-items: center; gap: 0; min-width: 0; }
|
||||
.ms-node { display: flex; align-items: center; }
|
||||
.ms-dot { width: 22px; height: 22px; border-radius: 999px; display: grid; place-items: center; font-size: 10.5px; font-weight: 600; background: var(--muted); color: var(--muted-foreground); border: 1px solid var(--border); flex-shrink: 0; }
|
||||
.ms-dot svg { width: 11px; height: 11px; stroke-width: 2.8; }
|
||||
.ms-node.done .ms-dot { background: var(--success); border-color: var(--success); color: var(--success-foreground); }
|
||||
.ms-node.current .ms-dot { background: var(--primary); border-color: var(--primary); color: var(--primary-foreground); }
|
||||
.ms-bar { width: 22px; height: 2px; background: var(--border); flex-shrink: 0; }
|
||||
.ms-bar.filled { background: var(--success); }
|
||||
.ms-label { font-size: 12.5px; font-weight: 500; color: var(--foreground); margin-left: 8px; white-space: nowrap; }
|
||||
@media (max-width: 760px) { .path-widget, .chead .sep { display: none; } }
|
||||
|
||||
/* ============ LESSON VIEW ============ */
|
||||
.lesson-view { padding: 28px 32px 48px; min-width: 0; }
|
||||
.lv-inner { max-width: 760px; }
|
||||
.lv-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 22px; }
|
||||
.lv-title { font-size: 26px; font-weight: 600; letter-spacing: -0.02em; margin: 0; flex: 1; min-width: 200px; }
|
||||
.lv-actions { display: flex; align-items: center; gap: 8px; }
|
||||
.pill-btn { display: inline-flex; align-items: center; gap: 7px; height: 34px; padding: 0 14px; border-radius: 999px; border: 1px solid var(--input); background: var(--background); font-size: 13.5px; font-weight: 500; cursor: pointer; box-shadow: var(--shadow-2xs); }
|
||||
.pill-btn:hover { background: var(--accent); }
|
||||
.pill-btn svg { width: 15px; height: 15px; stroke-width: 2; }
|
||||
.round-btn { width: 34px; height: 34px; border-radius: 999px; border: 1px solid var(--input); background: var(--background); display: grid; place-items: center; color: var(--foreground); cursor: pointer; box-shadow: var(--shadow-2xs); }
|
||||
.round-btn:hover { background: var(--accent); }
|
||||
.round-btn svg { width: 15px; height: 15px; stroke-width: 2; }
|
||||
.lang { display: inline-flex; align-items: center; gap: 6px; height: 34px; padding: 0 12px; border-radius: var(--radius-md); border: 1px solid var(--input); background: var(--background); font-size: 13.5px; cursor: pointer; box-shadow: var(--shadow-2xs); }
|
||||
.lang svg { width: 14px; height: 14px; stroke-width: 2; color: var(--muted-foreground); }
|
||||
|
||||
.lv-rule { border: none; border-top: 1px solid var(--border); margin: 0 0 20px; }
|
||||
.video { aspect-ratio: 16 / 9; border-radius: var(--radius-xl); background: linear-gradient(135deg, oklch(0.685 0.169 237.323), oklch(0.488 0.243 264.376)); display: grid; place-items: center; box-shadow: var(--shadow-sm); margin-bottom: 22px; }
|
||||
.play { width: 56px; height: 56px; border-radius: 999px; background: oklch(1 0 0 / 0.92); display: grid; place-items: center; }
|
||||
.play svg { width: 22px; height: 22px; color: var(--primary); margin-left: 3px; }
|
||||
.lv-body p { margin: 0 0 14px; line-height: 1.65; font-size: 15px; }
|
||||
.lv-body h3 { font-size: 16px; font-weight: 600; margin: 22px 0 8px; }
|
||||
.lv-body ul { margin: 0 0 14px; padding-left: 20px; color: var(--muted-foreground); }
|
||||
.lv-body li { margin-bottom: 5px; }
|
||||
|
||||
/* next in path callout */
|
||||
.path-next { margin-top: 28px; overflow: hidden; }
|
||||
.pn-head { display: flex; align-items: center; gap: 8px; padding: 10px 16px; background: color-mix(in oklab, var(--muted) 50%, transparent); border-bottom: 1px solid var(--border); font-size: 12px; font-weight: 500; color: var(--muted-foreground); letter-spacing: 0.04em; }
|
||||
.pn-head svg { width: 14px; height: 14px; stroke-width: 2; color: var(--primary); }
|
||||
.pn-body { padding: 14px 16px; display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
|
||||
.pn-req { font-size: 12.5px; color: var(--muted-foreground); display: flex; align-items: center; gap: 6px; margin-top: 3px; }
|
||||
.pn-req svg { width: 13px; height: 13px; stroke-width: 2; color: var(--warning); }
|
||||
.pn-req b { color: var(--foreground); font-weight: 500; }
|
||||
|
||||
@media (max-width: 900px) { .shell { grid-template-columns: 1fr; } .csb { display: none; } .lesson-view { padding: 22px 18px 40px; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<!-- ============ SIDEBAR ============ -->
|
||||
<aside class="csb">
|
||||
<div class="csb-scroll">
|
||||
<div class="course-id">
|
||||
<div class="ring ring-sm" style="width: 42px; height: 42px">
|
||||
<svg viewBox="0 0 100 100">
|
||||
<circle class="track" cx="50" cy="50" r="45" fill="none" stroke-width="10" />
|
||||
<circle class="arc" cx="50" cy="50" r="45" fill="none" stroke-width="10" stroke-linecap="round" stroke-dasharray="282.7" stroke-dashoffset="155.5" />
|
||||
</svg>
|
||||
<span class="lbl tnum" style="font-size: 10px">45%</span>
|
||||
</div>
|
||||
<div style="min-width: 0">
|
||||
<div class="nm">Modern Web Development with React</div>
|
||||
<div class="ct tnum">9 of 16 completed</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a class="back-path" href="path-detail.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>Frontend Engineering Bootcamp</a>
|
||||
|
||||
<div class="content-row">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M9 3v18"/></svg>
|
||||
Content
|
||||
<span class="counts">
|
||||
<span class="c tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>12</span>
|
||||
<span class="c tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>4</span>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" style="width: 14px; height: 14px"><path d="m6 9 6 6 6-6"/></svg>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Module 1 -->
|
||||
<div class="module">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>
|
||||
Fundamentals
|
||||
<span class="pct tnum">100%</span>
|
||||
<svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg>
|
||||
</div>
|
||||
<div class="lessons">
|
||||
<div class="lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">What is React?</span><span class="done-mark"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></span></div>
|
||||
<div class="lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">JSX & rendering</span><span class="done-mark"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></span></div>
|
||||
<div class="lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">Components & props</span><span class="done-mark"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></span></div>
|
||||
</div>
|
||||
|
||||
<!-- Module 2 -->
|
||||
<div class="module">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>
|
||||
Interactivity
|
||||
<span class="pct tnum">38%</span>
|
||||
<svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg>
|
||||
</div>
|
||||
<div class="lessons">
|
||||
<div class="lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">State with useState</span><span class="done-mark"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></span></div>
|
||||
<div class="lesson active"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">Handling events</span></div>
|
||||
<div class="lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">Lists & keys</span></div>
|
||||
<div class="lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">Conditional rendering</span></div>
|
||||
<div class="lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg><span class="t">Interactivity Checkpoint</span></div>
|
||||
</div>
|
||||
|
||||
<!-- Module 3 (locked) -->
|
||||
<div class="module">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>
|
||||
Effects & Data
|
||||
<span class="pct tnum">0%</span>
|
||||
<svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg>
|
||||
</div>
|
||||
<div class="lessons">
|
||||
<div class="lesson locked"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">The useEffect hook</span><svg class="lock" viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div>
|
||||
<div class="lesson locked"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">Fetching data</span><svg class="lock" viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div>
|
||||
<div class="lesson locked"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg><span class="t">Effects Checkpoint</span><svg class="lock" viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="csb-foot">
|
||||
<div class="prog-card">
|
||||
<div class="row"><span class="l">Your progress</span><span class="p tnum">45%</span></div>
|
||||
<div class="progress progress-thin"><span style="width: 45%"></span></div>
|
||||
<div class="cap tnum">9 of 12 lessons · 2 of 4 exercises</div>
|
||||
</div>
|
||||
<div class="powered">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" style="width: 13px; height: 13px; stroke-width: 2; color: var(--primary)"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
|
||||
Powered by <b>ClassroomIO</b>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- ============ MAIN ============ -->
|
||||
<div style="display: flex; flex-direction: column; min-width: 0">
|
||||
<!-- header -->
|
||||
<header class="chead">
|
||||
<button class="panel-btn" title="Toggle sidebar" aria-label="Toggle sidebar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M9 3v18"/></svg></button>
|
||||
<span class="crumb">Content</span>
|
||||
<span class="sep"></span>
|
||||
<a class="path-widget" href="path-detail.html" title="Frontend Engineering Bootcamp — open path">
|
||||
<span class="pw-kind"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Path</span>
|
||||
<div class="mini-stepper">
|
||||
<span class="ms-node done" title="HTML & CSS Foundations"><span class="ms-dot"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></span></span>
|
||||
<span class="ms-bar filled"></span>
|
||||
<span class="ms-node done" title="JavaScript Essentials"><span class="ms-dot"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></span></span>
|
||||
<span class="ms-bar filled"></span>
|
||||
<span class="ms-node current" title="Modern Web Development with React"><span class="ms-dot tnum">3</span></span>
|
||||
<span class="ms-bar"></span>
|
||||
<span class="ms-node" title="State Management & Data Fetching"><span class="ms-dot"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></span></span>
|
||||
<span class="ms-bar"></span>
|
||||
<span class="ms-node" title="Building & Shipping a Capstone"><span class="ms-dot"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></span></span>
|
||||
<span class="ms-label tnum">Course 3 of 5</span>
|
||||
</div>
|
||||
</a>
|
||||
<div class="right">
|
||||
<button class="icon-btn" id="theme" title="Toggle theme" aria-label="Toggle theme"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg></button>
|
||||
<button class="btn btn-primary btn-sm"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 3l1.9 5.8a2 2 0 0 0 1.3 1.3L21 12l-5.8 1.9a2 2 0 0 0-1.3 1.3L12 21l-1.9-5.8a2 2 0 0 0-1.3-1.3L3 12l5.8-1.9a2 2 0 0 0 1.3-1.3z"/></svg>Assistant</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- lesson -->
|
||||
<main class="lesson-view">
|
||||
<div class="lv-inner">
|
||||
<div class="lv-head">
|
||||
<h1 class="lv-title">Handling events</h1>
|
||||
<div class="lv-actions">
|
||||
<button class="pill-btn"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="m8.5 12 2.5 2.5 5-5"/></svg>Mark as Complete</button>
|
||||
<button class="round-btn" title="Previous lesson" aria-label="Previous lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m15 18-6-6 6-6"/></svg></button>
|
||||
<button class="round-btn" title="Next lesson" aria-label="Next lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m9 18 6-6-6-6"/></svg></button>
|
||||
<button class="lang">English<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="lv-rule" />
|
||||
|
||||
<div class="video"><div class="play"><svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M8 5v14l11-7z"/></svg></div></div>
|
||||
|
||||
<div class="lv-body">
|
||||
<p>In React you respond to user interaction by passing event handlers as props to elements. Handlers are regular functions, and React normalizes the underlying browser event for you.</p>
|
||||
<h3>What you'll learn</h3>
|
||||
<ul>
|
||||
<li>Attaching <code>onClick</code>, <code>onChange</code>, and <code>onSubmit</code> handlers</li>
|
||||
<li>Reading values from the synthetic event object</li>
|
||||
<li>Updating state in response to an event</li>
|
||||
</ul>
|
||||
<p>By the end of this lesson you'll wire up a small form that updates the screen as the user types — the foundation for everything interactive you'll build in this path.</p>
|
||||
</div>
|
||||
|
||||
<div class="card path-next">
|
||||
<div class="pn-head">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>
|
||||
NEXT IN YOUR PATH
|
||||
</div>
|
||||
<div class="pn-body">
|
||||
<div class="item-media-icon item-media-lg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div>
|
||||
<div class="item-content">
|
||||
<span class="item-eyebrow">Course 4</span>
|
||||
<span class="item-title">State Management & Data Fetching</span>
|
||||
<span class="pn-req">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>
|
||||
Unlocks when you finish this course — <b>3 lessons & 2 exercises</b> to go.
|
||||
</span>
|
||||
</div>
|
||||
<span class="btn btn-outline btn-sm disabled"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>Locked</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('theme').onclick = () => {
|
||||
const dark = document.documentElement.classList.toggle('dark');
|
||||
localStorage.cioTheme = dark ? 'dark' : 'light';
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,142 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Learning Paths — Prototype Map</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="app-theme.css" />
|
||||
<script>
|
||||
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
<style>
|
||||
.page { max-width: 980px; margin: 0 auto; padding: 56px 24px 80px; }
|
||||
h1 { font-size: 32px; font-weight: 600; letter-spacing: -0.03em; margin: 8px 0 8px; }
|
||||
.lead { color: var(--muted-foreground); font-size: 15px; max-width: 70ch; margin: 0 0 12px; }
|
||||
.eyebrow { font-size: 12px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--primary); }
|
||||
.sec { font-size: 13px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted-foreground); margin: 36px 0 14px; display: flex; align-items: center; gap: 10px; }
|
||||
.sec::after { content: ''; flex: 1; height: 1px; background: var(--border); }
|
||||
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
|
||||
.shot { overflow: hidden; display: flex; flex-direction: column; transition: border-color 0.15s, box-shadow 0.15s; }
|
||||
.shot:hover { border-color: var(--ring); box-shadow: var(--shadow-md); }
|
||||
.shot .cover { height: 72px; display: grid; place-items: center; color: #fff; }
|
||||
.shot .cover svg { width: 26px; height: 26px; stroke-width: 1.8; }
|
||||
.shot .b { padding: 13px 15px 15px; }
|
||||
.shot .n { font-size: 11px; font-weight: 600; color: var(--muted-foreground); letter-spacing: 0.05em; text-transform: uppercase; }
|
||||
.shot .t { font-size: 14.5px; font-weight: 600; letter-spacing: -0.01em; margin: 3px 0 4px; }
|
||||
.shot .d { font-size: 12.5px; color: var(--muted-foreground); margin: 0; line-height: 1.5; }
|
||||
.foot { margin-top: 44px; padding-top: 20px; border-top: 1px solid var(--border); color: var(--muted-foreground); font-size: 13.5px; line-height: 1.7; }
|
||||
.foot b { color: var(--foreground); font-weight: 500; }
|
||||
.foot code { background: var(--muted); padding: 1px 6px; border-radius: 4px; font-size: 12.5px; }
|
||||
@media (max-width: 860px) { .grid { grid-template-columns: 1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<span class="eyebrow">ClassroomIO · Prototype + PRD handoff</span>
|
||||
<h1>Learning Paths</h1>
|
||||
<p class="lead">
|
||||
A <b style="color: var(--foreground)">learning path</b> is an ordered bundle of courses sold and taken as one:
|
||||
courses unlock sequentially (lessons + exercises complete → next course), one bundle price with savings,
|
||||
and an optional path certificate at the end. Built on the real <code>packages/ui</code> tokens.
|
||||
The engineering PRD lives at <code>prd/learning-paths/README.md</code>.
|
||||
</p>
|
||||
<p class="lead" style="font-size: 13.5px">Every page has a theme toggle and cross-links so you can click through each journey end to end.</p>
|
||||
|
||||
<!-- PUBLIC -->
|
||||
<div class="sec">1 · Public — org landing site (visitor)</div>
|
||||
<div class="grid">
|
||||
<a class="card shot" href="org-landing.html">
|
||||
<div class="cover" style="background: linear-gradient(135deg, oklch(0.488 0.243 264.376), oklch(0.623 0.214 259.815))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></div>
|
||||
<div class="b"><div class="n">Entry</div><div class="t">Org Landing Page</div><p class="d">Learning Paths section above Courses — mirrors the "minimal" landing theme.</p></div>
|
||||
</a>
|
||||
<a class="card shot" href="public-paths.html">
|
||||
<div class="cover" style="background: linear-gradient(135deg, oklch(0.546 0.245 262.881), oklch(0.488 0.243 264.376))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg></div>
|
||||
<div class="b"><div class="n">List</div><div class="t">Paths Catalog</div><p class="d">/paths — search, filters, and path cards with savings pricing (like /courses).</p></div>
|
||||
</a>
|
||||
<a class="card shot" href="public-path.html">
|
||||
<div class="cover" style="background: linear-gradient(135deg, oklch(0.424 0.199 265.638), oklch(0.546 0.245 262.881))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
|
||||
<div class="b"><div class="n">Detail · Coursera-style</div><div class="t">Public Path Page</div><p class="d">Hero + enroll box with savings, stats, outcomes, skills, course series with lesson outlines, certificate, instructors, testimonials, FAQ.</p></div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- LEARNER -->
|
||||
<div class="sec">2 · Learner — LMS (enrolled student)</div>
|
||||
<div class="grid">
|
||||
<a class="card shot" href="lms-home.html">
|
||||
<div class="cover" style="background: linear-gradient(135deg, oklch(0.596 0.145 163.225), oklch(0.696 0.17 162.48))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg></div>
|
||||
<div class="b"><div class="n">Entry</div><div class="t">LMS Home</div><p class="d">Paths above courses, segmented cross-course progress bars.</p></div>
|
||||
</a>
|
||||
<a class="card shot" href="paths.html">
|
||||
<div class="cover" style="background: linear-gradient(135deg, oklch(0.596 0.145 163.225), oklch(0.488 0.243 264.376))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg></div>
|
||||
<div class="b"><div class="n">List</div><div class="t">My Learning Paths</div><p class="d">In progress / Completed tabs; each row shows segment progress + next course.</p></div>
|
||||
</a>
|
||||
<a class="card shot" href="path-detail.html">
|
||||
<div class="cover" style="background: linear-gradient(135deg, oklch(0.696 0.17 162.48), oklch(0.596 0.145 163.225))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
|
||||
<div class="b"><div class="n">Detail</div><div class="t">Path Detail</div><p class="d">The journey spine — Done / Continue / Locked courses with per-course progress and a certificate end-row.</p></div>
|
||||
</a>
|
||||
<a class="card shot" href="course-in-path.html">
|
||||
<div class="cover" style="background: linear-gradient(135deg, oklch(0.685 0.169 237.323), oklch(0.488 0.243 264.376))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg></div>
|
||||
<div class="b"><div class="n">Inside a course</div><div class="t">Course in Path</div><p class="d">Lesson view wrapped in path chrome: stepper ribbon + "next course unlocks" callout.</p></div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- TEACHER -->
|
||||
<div class="sec">3 · Teacher — admin dashboard</div>
|
||||
<div class="grid">
|
||||
<a class="card shot" href="teacher-paths.html">
|
||||
<div class="cover" style="background: linear-gradient(135deg, oklch(0.37 0.044 257.287), oklch(0.279 0.041 260.031))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg></div>
|
||||
<div class="b"><div class="n">List</div><div class="t">Manage Paths</div><p class="d">Org-level listing: stats, statuses, Create path → setup checklist.</p></div>
|
||||
</a>
|
||||
<a class="card shot" href="teacher-path-setup.html">
|
||||
<div class="cover" style="background: linear-gradient(135deg, oklch(0.596 0.145 163.225), oklch(0.488 0.243 264.376))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg></div>
|
||||
<div class="b"><div class="n">Onboarding</div><div class="t">Set up your path</div><p class="d">"Get Started"-style checklist: courses → order → price → landing page → activate.</p></div>
|
||||
</a>
|
||||
<a class="card shot" href="teacher-path-builder.html">
|
||||
<div class="cover" style="background: linear-gradient(135deg, oklch(0.488 0.243 264.376), oklch(0.424 0.199 265.638))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="9" cy="6" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="18" r="1"/></svg></div>
|
||||
<div class="b"><div class="n">Tab · Courses</div><div class="t">Path Builder</div><p class="d">Drag-to-reorder course list + sequential-unlock toggle. Try dragging rows.</p></div>
|
||||
</a>
|
||||
<a class="card shot" href="teacher-path-people.html">
|
||||
<div class="cover" style="background: linear-gradient(135deg, oklch(0.546 0.245 262.881), oklch(0.488 0.243 264.376))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg></div>
|
||||
<div class="b"><div class="n">Tab · People</div><div class="t">Learners</div><p class="d">Per-learner path progress, current course, auto-enroll note, add learners.</p></div>
|
||||
</a>
|
||||
<a class="card shot" href="teacher-path-analytics.html">
|
||||
<div class="cover" style="background: linear-gradient(135deg, oklch(0.666 0.179 58.318), oklch(0.769 0.188 70.08))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/></svg></div>
|
||||
<div class="b"><div class="n">Tab · Analytics</div><div class="t">Path Funnel</div><p class="d">Course-by-course funnel, drop-off callouts, stuck lessons/exercises.</p></div>
|
||||
</a>
|
||||
<a class="card shot" href="teacher-path-landing-editor.html">
|
||||
<div class="cover" style="background: linear-gradient(135deg, oklch(0.623 0.214 259.815), oklch(0.546 0.245 262.881))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></div>
|
||||
<div class="b"><div class="n">Tab · Landing page</div><div class="t">Landing Editor</div><p class="d">Hero copy, visitor access level, outcomes, skills, instructors, testimonials, FAQ.</p></div>
|
||||
</a>
|
||||
<a class="card shot" href="teacher-path-certificate.html">
|
||||
<div class="cover" style="background: linear-gradient(135deg, oklch(0.769 0.188 70.08), oklch(0.666 0.179 58.318))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg></div>
|
||||
<div class="b"><div class="n">Tab · Certificate</div><div class="t">Path Certificate</div><p class="d">Award toggle, completion requirements, live certificate preview.</p></div>
|
||||
</a>
|
||||
<a class="card shot" href="teacher-path-settings.html">
|
||||
<div class="cover" style="background: linear-gradient(135deg, oklch(0.37 0.044 257.287), oklch(0.488 0.243 264.376))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4"/></svg></div>
|
||||
<div class="b"><div class="n">Tab · Settings</div><div class="t">Path Settings</div><p class="d">General, bundle pricing + savings, enrollment & unlock rules, status, danger zone.</p></div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="foot">
|
||||
<b>Key product decisions baked into these prototypes:</b><br />
|
||||
· Learning paths are a <b>new entity</b> (separate from Programs) — <code>learning_path</code>, <code>learning_path_course</code> (ordered), <code>learning_path_member</code>.<br />
|
||||
· <b>Self-enrollment with bundle pricing</b> from the public site; the price shows savings vs summed course prices.<br />
|
||||
· A course unlocks when the previous course's <b>lessons AND exercises</b> are complete; sequential unlocking is a per-path toggle.<br />
|
||||
· <b>Path certificate</b> is a teacher toggle with its own tab; visitor access to the syllabus is teacher-configurable.<br />
|
||||
· Public pages mirror the <b>"minimal" org-landing theme</b>; app pages mirror <code>packages/ui</code> (shadcn-svelte, Geist, OKLCH tokens).
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="icon-btn" id="theme" title="Toggle theme" aria-label="Toggle theme" style="position: fixed; bottom: 18px; right: 18px">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg>
|
||||
</button>
|
||||
<script>
|
||||
document.getElementById('theme').onclick = () => {
|
||||
const dark = document.documentElement.classList.toggle('dark');
|
||||
localStorage.cioTheme = dark ? 'dark' : 'light';
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,947 @@
|
||||
/*
|
||||
* landing-theme.css — public org-site pages for the learning-paths prototypes.
|
||||
*
|
||||
* Mirrors packages/ui/src/custom/org-landing-page/ default theme ("minimal"):
|
||||
* --landing-* CSS vars from theme-vars-base.ts, square-cornered cards
|
||||
* (--landing-radius-card: 0), no card shadows, pill floating nav, accent
|
||||
* radial-gradient hero. Accent = the org brand (default ClassroomIO indigo).
|
||||
*/
|
||||
|
||||
:root {
|
||||
--landing-bg: oklch(1 0 0);
|
||||
--landing-fg: oklch(0.185 0 0);
|
||||
--landing-fg-muted: oklch(0.5 0 0);
|
||||
--landing-border: oklch(0.9 0 0);
|
||||
--landing-card: oklch(1 0 0);
|
||||
--landing-card-soft: oklch(0.975 0 0);
|
||||
--landing-accent: oklch(0.488 0.243 264.376);
|
||||
--landing-accent-soft: oklch(0.488 0.243 264.376 / 0.08);
|
||||
--landing-button-primary-bg: oklch(0.488 0.243 264.376);
|
||||
--landing-button-primary-bg-hover: oklch(0.424 0.199 265.638);
|
||||
--landing-button-primary-fg: #fff;
|
||||
--landing-success: oklch(0.596 0.145 163.225);
|
||||
--landing-radius-card: 0px;
|
||||
--landing-radius-button: 6px;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--landing-bg: oklch(0.16 0 0);
|
||||
--landing-fg: oklch(0.96 0 0);
|
||||
--landing-fg-muted: oklch(0.68 0 0);
|
||||
--landing-border: oklch(1 0 0 / 14%);
|
||||
--landing-card: oklch(0.2 0 0);
|
||||
--landing-card-soft: oklch(0.24 0 0);
|
||||
--landing-accent: oklch(0.623 0.214 259.815);
|
||||
--landing-accent-soft: oklch(0.623 0.214 259.815 / 0.14);
|
||||
--landing-button-primary-bg: oklch(0.546 0.245 262.881);
|
||||
--landing-button-primary-bg-hover: oklch(0.623 0.214 259.815);
|
||||
--landing-success: oklch(0.696 0.17 162.48);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
border-color: var(--landing-border);
|
||||
}
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
body {
|
||||
font-family:
|
||||
'Geist',
|
||||
ui-sans-serif,
|
||||
system-ui,
|
||||
-apple-system,
|
||||
'Segoe UI',
|
||||
Roboto,
|
||||
sans-serif;
|
||||
background: var(--landing-bg);
|
||||
color: var(--landing-fg);
|
||||
font-size: 16px;
|
||||
line-height: 1.6;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
button {
|
||||
font: inherit;
|
||||
}
|
||||
.tnum {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.lp-wrap {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
}
|
||||
.lp-wrap-narrow {
|
||||
max-width: 880px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
/* ===== pill nav (minimal theme) ===== */
|
||||
.lp-nav-outer {
|
||||
padding: 20px 20px 0;
|
||||
max-width: 1240px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.lp-nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
padding: 14px 24px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid color-mix(in oklab, var(--landing-border) 60%, transparent);
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
color-mix(in oklab, var(--landing-accent) 14%, transparent),
|
||||
color-mix(in oklab, var(--landing-accent) 6%, transparent)
|
||||
);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
.lp-nav-brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-weight: 600;
|
||||
font-size: 19px;
|
||||
}
|
||||
.lp-nav-logo {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 8px;
|
||||
background: var(--landing-accent);
|
||||
color: #fff;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font-weight: 700;
|
||||
font-size: 15px;
|
||||
}
|
||||
.lp-nav-links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 28px;
|
||||
font-size: 14.5px;
|
||||
}
|
||||
.lp-nav-links > a {
|
||||
opacity: 0.72;
|
||||
}
|
||||
.lp-nav-links > a:hover,
|
||||
.lp-nav-links > a.active {
|
||||
opacity: 1;
|
||||
}
|
||||
.lp-nav-auth {
|
||||
border: 1px solid var(--landing-border);
|
||||
border-radius: 999px;
|
||||
padding: 8px 18px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
background: var(--landing-card);
|
||||
}
|
||||
.lp-nav-auth:hover {
|
||||
border-color: var(--landing-fg-muted);
|
||||
}
|
||||
@media (max-width: 760px) {
|
||||
.lp-nav-links > a {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== hero ===== */
|
||||
.lp-hero {
|
||||
position: relative;
|
||||
padding: 72px 0 80px;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
background:
|
||||
radial-gradient(60% 90% at 50% -10%, var(--landing-accent-soft) 0%, transparent 70%),
|
||||
linear-gradient(180deg, transparent, transparent);
|
||||
}
|
||||
.lp-hero-dots {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
opacity: 0.08;
|
||||
pointer-events: none;
|
||||
background-image: radial-gradient(circle, var(--landing-fg) 1px, transparent 1.5px);
|
||||
background-size: 22px 22px;
|
||||
}
|
||||
.lp-hero-inner {
|
||||
position: relative;
|
||||
max-width: 860px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
}
|
||||
.lp-hero h1 {
|
||||
font-size: clamp(34px, 6vw, 56px);
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.03em;
|
||||
line-height: 1.08;
|
||||
margin: 0 0 20px;
|
||||
text-wrap: balance;
|
||||
}
|
||||
.lp-hero .sub {
|
||||
font-size: 19px;
|
||||
font-weight: 300;
|
||||
color: color-mix(in oklab, var(--landing-fg) 72%, transparent);
|
||||
margin: 0 auto 32px;
|
||||
max-width: 60ch;
|
||||
}
|
||||
.lp-cta-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* ===== buttons ===== */
|
||||
.lp-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
border-radius: var(--landing-radius-button);
|
||||
border: 1px solid transparent;
|
||||
font-weight: 500;
|
||||
font-size: 15px;
|
||||
padding: 10px 22px;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background 0.12s,
|
||||
border-color 0.12s;
|
||||
}
|
||||
.lp-btn svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
stroke-width: 2;
|
||||
}
|
||||
.lp-btn-primary {
|
||||
background: var(--landing-button-primary-bg);
|
||||
color: var(--landing-button-primary-fg);
|
||||
}
|
||||
.lp-btn-primary:hover {
|
||||
background: var(--landing-button-primary-bg-hover);
|
||||
}
|
||||
.lp-btn-secondary {
|
||||
background: var(--landing-card);
|
||||
border-color: var(--landing-border);
|
||||
color: var(--landing-fg);
|
||||
}
|
||||
.lp-btn-secondary:hover {
|
||||
border-color: var(--landing-fg-muted);
|
||||
}
|
||||
.lp-btn-lg {
|
||||
padding: 13px 28px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.lp-btn-pill {
|
||||
border-radius: 999px;
|
||||
}
|
||||
.lp-btn-block {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* ===== sections ===== */
|
||||
.lp-section {
|
||||
padding: 72px 0;
|
||||
}
|
||||
.lp-section + .lp-section {
|
||||
border-top: 1px solid var(--landing-border);
|
||||
}
|
||||
.lp-section h2 {
|
||||
font-size: 26px;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.02em;
|
||||
margin: 0 0 8px;
|
||||
}
|
||||
.lp-section .lead {
|
||||
color: var(--landing-fg-muted);
|
||||
margin: 0 0 32px;
|
||||
max-width: 62ch;
|
||||
}
|
||||
.lp-eyebrow {
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
color: var(--landing-accent);
|
||||
margin-bottom: 10px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* ===== cards (minimal: square, hairline, no shadow) ===== */
|
||||
.lp-card {
|
||||
background: var(--landing-card);
|
||||
border: 1px solid color-mix(in oklab, var(--landing-border) 60%, transparent);
|
||||
border-radius: var(--landing-radius-card);
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
a.lp-card:hover {
|
||||
border-color: var(--landing-fg-muted);
|
||||
}
|
||||
|
||||
/* course card (minimal shape) */
|
||||
.lp-course-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 32px;
|
||||
}
|
||||
.lp-course-card h3 {
|
||||
font-size: 20px;
|
||||
font-weight: 400;
|
||||
margin: 0 0 14px;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
.lp-course-card .desc {
|
||||
font-size: 15.5px;
|
||||
line-height: 1.65;
|
||||
color: var(--landing-fg-muted);
|
||||
margin: 0 0 30px;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
.lp-meta-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
font-size: 14px;
|
||||
color: var(--landing-fg-muted);
|
||||
margin-top: auto;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.lp-meta-row .m {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.lp-meta-row svg {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
stroke-width: 1.8;
|
||||
}
|
||||
.lp-meta-row .price {
|
||||
margin-left: auto;
|
||||
font-weight: 600;
|
||||
color: var(--landing-fg);
|
||||
font-size: 15px;
|
||||
}
|
||||
.lp-meta-row .price s {
|
||||
color: var(--landing-fg-muted);
|
||||
font-weight: 400;
|
||||
font-size: 13px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
/* path badge + save chip */
|
||||
.lp-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
width: fit-content;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
color: var(--landing-accent);
|
||||
background: var(--landing-accent-soft);
|
||||
padding: 4px 10px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.lp-chip svg {
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
stroke-width: 2.2;
|
||||
}
|
||||
.lp-save {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
font-size: 12.5px;
|
||||
font-weight: 600;
|
||||
color: var(--landing-success);
|
||||
background: color-mix(in oklab, var(--landing-success) 10%, transparent);
|
||||
padding: 3px 9px;
|
||||
}
|
||||
|
||||
/* ordered course list inside a path card */
|
||||
.lp-path-courses {
|
||||
border-top: 1px solid var(--landing-border);
|
||||
margin: 22px 0;
|
||||
}
|
||||
.lp-path-course {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid var(--landing-border);
|
||||
font-size: 14.5px;
|
||||
}
|
||||
.lp-path-course .n {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 999px;
|
||||
background: var(--landing-accent-soft);
|
||||
color: var(--landing-accent);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font-size: 11.5px;
|
||||
font-weight: 600;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.lp-path-course .t {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.lp-path-course .d {
|
||||
font-size: 13px;
|
||||
color: var(--landing-fg-muted);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ===== stats row (social proof) ===== */
|
||||
.lp-stats {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
border-block: 1px solid var(--landing-border);
|
||||
padding: 28px 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.lp-stat {
|
||||
padding: 0 36px;
|
||||
text-align: center;
|
||||
border-right: 1px solid var(--landing-border);
|
||||
}
|
||||
.lp-stat:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
.lp-stat .v {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
.lp-stat .k {
|
||||
font-size: 13px;
|
||||
color: var(--landing-fg-muted);
|
||||
margin-top: 2px;
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
.lp-stat {
|
||||
padding: 10px 20px;
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== anchor nav ===== */
|
||||
.lp-anchor-nav {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 50;
|
||||
background: color-mix(in oklab, var(--landing-bg) 92%, transparent);
|
||||
backdrop-filter: blur(8px);
|
||||
border-bottom: 1px solid var(--landing-border);
|
||||
}
|
||||
.lp-anchor-nav .in {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.lp-anchor-nav a {
|
||||
padding: 14px 14px;
|
||||
font-size: 14.5px;
|
||||
color: var(--landing-fg-muted);
|
||||
border-bottom: 2px solid transparent;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.lp-anchor-nav a:hover {
|
||||
color: var(--landing-fg);
|
||||
}
|
||||
.lp-anchor-nav a.active {
|
||||
color: var(--landing-fg);
|
||||
border-bottom-color: var(--landing-accent);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* ===== outcomes / bullets ===== */
|
||||
.lp-outcomes {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16px 32px;
|
||||
}
|
||||
.lp-outcome {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
font-size: 15.5px;
|
||||
line-height: 1.55;
|
||||
}
|
||||
.lp-outcome svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
stroke-width: 2.2;
|
||||
color: var(--landing-accent);
|
||||
flex-shrink: 0;
|
||||
margin-top: 3px;
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
.lp-outcomes {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* skill tags */
|
||||
.lp-skills {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
.lp-skill {
|
||||
border: 1px solid var(--landing-border);
|
||||
padding: 7px 16px;
|
||||
font-size: 14px;
|
||||
border-radius: 999px;
|
||||
color: var(--landing-fg);
|
||||
}
|
||||
|
||||
/* ===== series (sequential course cards) ===== */
|
||||
.lp-series {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
.lp-series-card {
|
||||
padding: 26px 28px;
|
||||
}
|
||||
.lp-series-head {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
}
|
||||
.lp-series-n {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 999px;
|
||||
background: var(--landing-accent-soft);
|
||||
color: var(--landing-accent);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.lp-series-card h3 {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
margin: 4px 0 2px;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
.lp-series-sub {
|
||||
font-size: 13.5px;
|
||||
color: var(--landing-fg-muted);
|
||||
}
|
||||
.lp-series-body {
|
||||
margin: 16px 0 0 52px;
|
||||
}
|
||||
.lp-series-body .lbl {
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
color: var(--landing-fg-muted);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.lp-series-outcomes {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 8px 24px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.lp-series-outcomes .o {
|
||||
display: flex;
|
||||
gap: 9px;
|
||||
font-size: 14px;
|
||||
color: var(--landing-fg);
|
||||
line-height: 1.5;
|
||||
}
|
||||
.lp-series-outcomes .o svg {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
stroke-width: 2.2;
|
||||
color: var(--landing-accent);
|
||||
flex-shrink: 0;
|
||||
margin-top: 3px;
|
||||
}
|
||||
.lp-lessons-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--landing-accent);
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 10px 0 0;
|
||||
}
|
||||
.lp-lessons-toggle svg {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
stroke-width: 2.2;
|
||||
transition: transform 0.15s;
|
||||
}
|
||||
.lp-lessons-toggle.open svg {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
.lp-lessons {
|
||||
display: none;
|
||||
border-top: 1px solid var(--landing-border);
|
||||
margin-top: 12px;
|
||||
}
|
||||
.lp-lessons.open {
|
||||
display: block;
|
||||
}
|
||||
.lp-lesson {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 9px 0;
|
||||
border-bottom: 1px solid var(--landing-border);
|
||||
font-size: 14px;
|
||||
}
|
||||
.lp-lesson .ix {
|
||||
font-family: ui-monospace, monospace;
|
||||
font-size: 12.5px;
|
||||
color: var(--landing-fg-muted);
|
||||
min-width: 3ch;
|
||||
}
|
||||
.lp-lesson .dur {
|
||||
margin-left: auto;
|
||||
font-size: 12.5px;
|
||||
color: var(--landing-fg-muted);
|
||||
}
|
||||
.lp-lesson .prev {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--landing-accent);
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
.lp-series-outcomes {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.lp-series-body {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== instructors ===== */
|
||||
.lp-instructors {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16px;
|
||||
}
|
||||
.lp-instructor {
|
||||
padding: 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 4px;
|
||||
}
|
||||
.lp-instructor .av {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
border-radius: 999px;
|
||||
background: var(--landing-accent-soft);
|
||||
color: var(--landing-accent);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font-weight: 600;
|
||||
font-size: 17px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.lp-instructor .nm {
|
||||
font-size: 15.5px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.lp-instructor .rl {
|
||||
font-size: 13px;
|
||||
color: var(--landing-fg-muted);
|
||||
}
|
||||
.lp-instructor .bio {
|
||||
font-size: 13.5px;
|
||||
color: var(--landing-fg-muted);
|
||||
margin-top: 8px;
|
||||
line-height: 1.55;
|
||||
}
|
||||
@media (max-width: 760px) {
|
||||
.lp-instructors {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== testimonials ===== */
|
||||
.lp-testimonials {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16px;
|
||||
}
|
||||
.lp-testimonial {
|
||||
padding: 26px;
|
||||
}
|
||||
.lp-testimonial .q {
|
||||
font-size: 15.5px;
|
||||
line-height: 1.65;
|
||||
margin: 0 0 16px;
|
||||
}
|
||||
.lp-testimonial .who {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-size: 13.5px;
|
||||
}
|
||||
.lp-testimonial .who .av {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 999px;
|
||||
background: var(--landing-accent-soft);
|
||||
color: var(--landing-accent);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
}
|
||||
.lp-testimonial .who .nm {
|
||||
font-weight: 600;
|
||||
}
|
||||
.lp-testimonial .who .loc {
|
||||
color: var(--landing-fg-muted);
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
.lp-testimonials {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== FAQ accordion ===== */
|
||||
.lp-faq {
|
||||
border-top: 1px solid var(--landing-border);
|
||||
}
|
||||
.lp-faq-item {
|
||||
border-bottom: 1px solid var(--landing-border);
|
||||
}
|
||||
.lp-faq-q {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
padding: 18px 4px;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
font-size: 15.5px;
|
||||
font-weight: 500;
|
||||
color: var(--landing-fg);
|
||||
}
|
||||
.lp-faq-q svg {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
stroke-width: 2;
|
||||
color: var(--landing-fg-muted);
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.15s;
|
||||
}
|
||||
.lp-faq-item.open .lp-faq-q svg {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
.lp-faq-a {
|
||||
display: none;
|
||||
padding: 0 4px 18px;
|
||||
font-size: 14.5px;
|
||||
color: var(--landing-fg-muted);
|
||||
line-height: 1.65;
|
||||
max-width: 68ch;
|
||||
}
|
||||
.lp-faq-item.open .lp-faq-a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* ===== pricing card ===== */
|
||||
.lp-pricing-card {
|
||||
max-width: 440px;
|
||||
margin: 0 auto;
|
||||
padding: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
.lp-pricing-card .eyebrow {
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
color: var(--landing-fg-muted);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.lp-price {
|
||||
font-size: 46px;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.03em;
|
||||
line-height: 1;
|
||||
}
|
||||
.lp-price-was {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
margin: 10px 0 20px;
|
||||
font-size: 14.5px;
|
||||
color: var(--landing-fg-muted);
|
||||
}
|
||||
.lp-price-was s {
|
||||
font-size: 16px;
|
||||
}
|
||||
.lp-features {
|
||||
text-align: left;
|
||||
margin: 0 0 24px;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
.lp-features li {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
font-size: 14.5px;
|
||||
}
|
||||
.lp-features svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
stroke-width: 2.2;
|
||||
color: var(--landing-accent);
|
||||
flex-shrink: 0;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
/* certificate banner */
|
||||
.lp-cert {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 22px;
|
||||
padding: 28px 30px;
|
||||
}
|
||||
.lp-cert .frame {
|
||||
width: 130px;
|
||||
height: 92px;
|
||||
border: 1px solid var(--landing-border);
|
||||
background: var(--landing-card-soft);
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
.lp-cert .frame::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 6px;
|
||||
border: 1px solid color-mix(in oklab, var(--landing-accent) 35%, transparent);
|
||||
}
|
||||
.lp-cert .frame svg {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
stroke-width: 1.8;
|
||||
color: var(--landing-accent);
|
||||
}
|
||||
.lp-cert h3 {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin: 0 0 4px;
|
||||
}
|
||||
.lp-cert p {
|
||||
font-size: 14.5px;
|
||||
color: var(--landing-fg-muted);
|
||||
margin: 0;
|
||||
max-width: 56ch;
|
||||
}
|
||||
|
||||
/* ===== footer ===== */
|
||||
.lp-footer {
|
||||
border-top: 1px solid var(--landing-border);
|
||||
padding: 48px 0 40px;
|
||||
margin-top: 24px;
|
||||
}
|
||||
.lp-footer-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.4fr) repeat(auto-fit, minmax(140px, 1fr));
|
||||
gap: 32px;
|
||||
}
|
||||
.lp-footer h4 {
|
||||
font-size: 13px;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: var(--landing-fg-muted);
|
||||
font-weight: 600;
|
||||
margin: 0 0 12px;
|
||||
}
|
||||
.lp-footer a {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
color: var(--landing-fg-muted);
|
||||
padding: 3px 0;
|
||||
}
|
||||
.lp-footer a:hover {
|
||||
color: var(--landing-fg);
|
||||
}
|
||||
.lp-footer .brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.lp-footer .copy {
|
||||
font-size: 13px;
|
||||
color: var(--landing-fg-muted);
|
||||
margin-top: 12px;
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
.lp-footer-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* theme toggle button (prototype affordance) */
|
||||
.lp-theme-btn {
|
||||
position: fixed;
|
||||
bottom: 18px;
|
||||
right: 18px;
|
||||
z-index: 200;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--landing-border);
|
||||
background: var(--landing-card);
|
||||
color: var(--landing-fg-muted);
|
||||
cursor: pointer;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
box-shadow: 0 2px 8px rgb(0 0 0 / 0.08);
|
||||
}
|
||||
.lp-theme-btn svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
stroke-width: 2;
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>My Learning · ClassroomIO LMS</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="app-theme.css" />
|
||||
<script>
|
||||
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
<style>
|
||||
.path-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; }
|
||||
.path-card { overflow: hidden; display: flex; flex-direction: column; transition: box-shadow 0.15s, border-color 0.15s; }
|
||||
.path-card:hover { border-color: var(--ring); box-shadow: var(--shadow-md); }
|
||||
.pc-cover { height: 80px; position: relative; }
|
||||
.pc-cover .badge { position: absolute; top: 12px; left: 14px; background: oklch(1 0 0 / 0.18); color: #fff; border-color: oklch(1 0 0 / 0.3); backdrop-filter: blur(4px); }
|
||||
.pc-body { padding: 16px; display: flex; flex-direction: column; gap: 12px; flex: 1; }
|
||||
.pc-title { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; margin: 0 0 2px; }
|
||||
.pc-desc { font-size: 13px; color: var(--muted-foreground); margin: 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
||||
.seg-row { display: flex; align-items: center; gap: 10px; }
|
||||
.seg-pct { font-size: 13px; font-weight: 600; min-width: 34px; text-align: right; }
|
||||
.pc-meta { display: flex; gap: 14px; font-size: 12.5px; color: var(--muted-foreground); }
|
||||
.pc-meta .m { display: flex; align-items: center; gap: 5px; }
|
||||
.pc-meta svg { width: 14px; height: 14px; stroke-width: 2; }
|
||||
.pc-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: auto; }
|
||||
.pc-next { font-size: 12.5px; color: var(--muted-foreground); min-width: 0; }
|
||||
.pc-next strong { color: var(--foreground); font-weight: 500; }
|
||||
|
||||
.course-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
|
||||
.course-card { overflow: hidden; transition: box-shadow 0.15s, border-color 0.15s; }
|
||||
.course-card:hover { border-color: var(--ring); box-shadow: var(--shadow-md); }
|
||||
.cc-cover { height: 92px; }
|
||||
.cc-body { padding: 14px; }
|
||||
.cc-title { font-size: 14px; font-weight: 600; letter-spacing: -0.01em; margin: 0 0 4px; }
|
||||
.cc-desc { font-size: 12.5px; color: var(--muted-foreground); margin: 0 0 12px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; min-height: 34px; }
|
||||
.cc-prog { display: flex; align-items: center; gap: 9px; }
|
||||
.cc-prog .p { font-size: 12px; font-weight: 600; color: var(--muted-foreground); min-width: 32px; text-align: right; }
|
||||
.greet { font-size: 24px; font-weight: 500; letter-spacing: -0.02em; margin: 4px 0 4px; }
|
||||
@media (max-width: 980px) { .path-grid { grid-template-columns: 1fr; } .course-grid { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (max-width: 680px) { .course-grid { grid-template-columns: 1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<aside class="sidebar">
|
||||
<div class="brand"><div class="brand-mark">C</div><div class="brand-name">ClassroomIO</div></div>
|
||||
<div class="nav-label">Learn</div>
|
||||
<a class="nav-item active" href="lms-home.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>My Learning</a>
|
||||
<a class="nav-item" href="paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Paths<span class="nav-badge">2</span></a>
|
||||
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>Exercises</a>
|
||||
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>Community</a>
|
||||
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>Certificates</a>
|
||||
<div class="sidebar-foot"><div class="avatar">AO</div><div class="who"><div class="nm">Ada Okafor</div><div class="rl">Student</div></div></div>
|
||||
</aside>
|
||||
|
||||
<div class="main">
|
||||
<header class="topbar">
|
||||
<span class="top-title">My Learning</span>
|
||||
<div class="top-actions">
|
||||
<button class="icon-btn" id="theme" title="Toggle theme" aria-label="Toggle theme"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg></button>
|
||||
<button class="icon-btn" title="Notifications" aria-label="Notifications"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.7 21a2 2 0 0 1-3.4 0"/></svg></button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="content">
|
||||
<div class="wrap" style="max-width: 1040px">
|
||||
<h1 class="greet">Welcome back, Ada</h1>
|
||||
<p class="page-sub" style="margin-bottom: 8px">Pick up where you left off — you're 49% through your bootcamp.</p>
|
||||
|
||||
<div class="sec-head">
|
||||
<h2 class="sec-title" style="display: flex; align-items: center; gap: 8px">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" style="width: 16px; height: 16px; stroke-width: 2; color: var(--primary)"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>
|
||||
Learning Paths
|
||||
</h2>
|
||||
<span class="count">2</span>
|
||||
<a class="more" href="paths.html">View all <svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M12 5l7 7-7 7"/></svg></a>
|
||||
</div>
|
||||
|
||||
<div class="path-grid">
|
||||
<a class="card path-card" href="path-detail.html">
|
||||
<div class="pc-cover" style="background: linear-gradient(120deg, oklch(0.488 0.243 264.376), oklch(0.623 0.214 259.815))">
|
||||
<span class="badge"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Path</span>
|
||||
</div>
|
||||
<div class="pc-body">
|
||||
<div>
|
||||
<h3 class="pc-title">Frontend Engineering Bootcamp</h3>
|
||||
<p class="pc-desc">From HTML foundations to shipping a production React app.</p>
|
||||
</div>
|
||||
<div class="seg-row">
|
||||
<div class="segs"><span class="seg done"></span><span class="seg done"></span><span class="seg half"></span><span class="seg"></span><span class="seg"></span></div>
|
||||
<span class="seg-pct tnum text-primary">49%</span>
|
||||
</div>
|
||||
<div class="pc-meta">
|
||||
<span class="m tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>2 of 5 done</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~38h</span>
|
||||
</div>
|
||||
<div class="pc-foot">
|
||||
<div class="pc-next">Next: <strong>Modern Web Development with React</strong></div>
|
||||
<span class="btn btn-primary btn-sm">Continue<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a class="card path-card" href="paths.html">
|
||||
<div class="pc-cover" style="background: linear-gradient(120deg, oklch(0.596 0.145 163.225), oklch(0.696 0.17 162.48))">
|
||||
<span class="badge"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Path</span>
|
||||
</div>
|
||||
<div class="pc-body">
|
||||
<div>
|
||||
<h3 class="pc-title">Data Science with Python</h3>
|
||||
<p class="pc-desc">Pandas, visualization, and applied machine-learning basics.</p>
|
||||
</div>
|
||||
<div class="seg-row">
|
||||
<div class="segs"><span class="seg half"></span><span class="seg"></span><span class="seg"></span><span class="seg"></span></div>
|
||||
<span class="seg-pct tnum text-primary">8%</span>
|
||||
</div>
|
||||
<div class="pc-meta">
|
||||
<span class="m tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>0 of 4 done</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~30h</span>
|
||||
</div>
|
||||
<div class="pc-foot">
|
||||
<div class="pc-next">Just started: <strong>Intro to Python</strong></div>
|
||||
<span class="btn btn-primary btn-sm">Continue<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="sec-head">
|
||||
<h2 class="sec-title" style="display: flex; align-items: center; gap: 8px">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" style="width: 16px; height: 16px; stroke-width: 2; color: var(--primary)"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
|
||||
Courses
|
||||
</h2>
|
||||
<span class="count">4</span>
|
||||
</div>
|
||||
|
||||
<div class="course-grid">
|
||||
<a class="card course-card" href="course-in-path.html">
|
||||
<div class="cc-cover" style="background: linear-gradient(135deg, oklch(0.685 0.169 237.323), oklch(0.488 0.243 264.376))"></div>
|
||||
<div class="cc-body">
|
||||
<span class="badge badge-primary-soft" style="margin-bottom: 8px"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Frontend Bootcamp · 3/5</span>
|
||||
<h3 class="cc-title">Modern Web Development with React</h3>
|
||||
<p class="cc-desc">Components, hooks, and building interactive UIs.</p>
|
||||
<div class="cc-prog"><div class="progress progress-thin"><span style="width: 45%"></span></div><span class="p tnum">45%</span></div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a class="card course-card" href="path-detail.html">
|
||||
<div class="cc-cover" style="background: linear-gradient(135deg, oklch(0.705 0.213 47.604), oklch(0.75 0.183 55.934))"></div>
|
||||
<div class="cc-body">
|
||||
<span class="badge badge-primary-soft" style="margin-bottom: 8px"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Frontend Bootcamp · 1/5</span>
|
||||
<h3 class="cc-title">HTML & CSS Foundations</h3>
|
||||
<p class="cc-desc">Semantic markup, the box model, and responsive layout.</p>
|
||||
<div class="cc-prog"><div class="progress progress-thin progress-success"><span style="width: 100%"></span></div><span class="p tnum">100%</span></div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a class="card course-card" href="#">
|
||||
<div class="cc-cover" style="background: linear-gradient(135deg, oklch(0.585 0.233 277.117), oklch(0.606 0.25 292.717))"></div>
|
||||
<div class="cc-body">
|
||||
<h3 class="cc-title" style="margin-top: 26px">Getting Started with MVC</h3>
|
||||
<p class="cc-desc">A standalone course on the model-view-controller pattern.</p>
|
||||
<div class="cc-prog"><div class="progress progress-thin"><span style="width: 20%"></span></div><span class="p tnum">20%</span></div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a class="card course-card" href="#">
|
||||
<div class="cc-cover" style="background: linear-gradient(135deg, oklch(0.596 0.145 163.225), oklch(0.696 0.17 162.48))"></div>
|
||||
<div class="cc-body">
|
||||
<span class="badge badge-primary-soft" style="margin-bottom: 8px"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Data Science · 1/4</span>
|
||||
<h3 class="cc-title">Intro to Python</h3>
|
||||
<p class="cc-desc">Syntax, data types, and your first scripts.</p>
|
||||
<div class="cc-prog"><div class="progress progress-thin"><span style="width: 30%"></span></div><span class="p tnum">30%</span></div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('theme').onclick = () => {
|
||||
const dark = document.documentElement.classList.toggle('dark');
|
||||
localStorage.cioTheme = dark ? 'dark' : 'light';
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,184 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Acme Academy — Learn frontend, data, and product</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="landing-theme.css" />
|
||||
<script>
|
||||
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
<style>
|
||||
.paths-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; }
|
||||
.courses-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; }
|
||||
@media (max-width: 860px) { .paths-grid, .courses-grid { grid-template-columns: 1fr; } }
|
||||
.view-more { display: flex; justify-content: center; margin-top: 36px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- nav -->
|
||||
<div class="lp-nav-outer">
|
||||
<nav class="lp-nav">
|
||||
<a class="lp-nav-brand" href="org-landing.html"><span class="lp-nav-logo">A</span>Acme Academy</a>
|
||||
<div class="lp-nav-links">
|
||||
<a href="public-paths.html">Learning Paths</a>
|
||||
<a href="#courses">Courses</a>
|
||||
<a class="lp-nav-auth" href="lms-home.html">Login</a>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- hero -->
|
||||
<header class="lp-hero">
|
||||
<div class="lp-hero-dots"></div>
|
||||
<div class="lp-hero-inner">
|
||||
<h1>Practical tech skills, taught the way work actually happens</h1>
|
||||
<p class="sub">Courses and guided learning paths in engineering, data, and product — built by practitioners, finished with certificates.</p>
|
||||
<div class="lp-cta-row">
|
||||
<a class="lp-btn lp-btn-primary lp-btn-lg lp-btn-pill" href="public-paths.html">Explore learning paths</a>
|
||||
<a class="lp-btn lp-btn-secondary lp-btn-lg lp-btn-pill" href="#courses">Browse courses</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- ===== LEARNING PATHS (above courses) ===== -->
|
||||
<section class="lp-section" id="paths">
|
||||
<div class="lp-wrap">
|
||||
<span class="lp-eyebrow">Guided programs</span>
|
||||
<h2>Learning Paths</h2>
|
||||
<p class="lead">Multi-course tracks you complete in order — one enrollment, one price, one certificate at the end.</p>
|
||||
|
||||
<div class="paths-grid">
|
||||
<!-- Path card 1 -->
|
||||
<a class="lp-card lp-course-card" href="public-path.html">
|
||||
<span class="lp-chip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Path</span>
|
||||
<h3>Frontend Engineering Bootcamp</h3>
|
||||
<p class="desc">Five courses, one path — from your first HTML tag to a deployed React capstone. Learn in order, build real projects, earn a certificate.</p>
|
||||
<div class="lp-path-courses">
|
||||
<div class="lp-path-course"><span class="n tnum">1</span><span class="t">HTML & CSS Foundations</span><span class="d tnum">12 lessons</span></div>
|
||||
<div class="lp-path-course"><span class="n tnum">2</span><span class="t">JavaScript Essentials</span><span class="d tnum">10 lessons</span></div>
|
||||
<div class="lp-path-course"><span class="n tnum">3</span><span class="t">Modern Web Development with React</span><span class="d tnum">12 lessons</span></div>
|
||||
<div class="lp-path-course" style="border-bottom: none"><span class="n" style="background: transparent; color: var(--landing-fg-muted)">+</span><span class="t" style="color: var(--landing-fg-muted)">2 more courses</span></div>
|
||||
</div>
|
||||
<div class="lp-meta-row">
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>5 courses</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~38 hours</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>Certificate</span>
|
||||
<span class="price tnum">$199 <s>$280</s></span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- Path card 2 -->
|
||||
<a class="lp-card lp-course-card" href="public-path.html">
|
||||
<span class="lp-chip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Path</span>
|
||||
<h3>Data Science with Python</h3>
|
||||
<p class="desc">From Python basics to applied machine learning — pandas, visualization, and a real analysis project, in a fixed order that builds week over week.</p>
|
||||
<div class="lp-path-courses">
|
||||
<div class="lp-path-course"><span class="n tnum">1</span><span class="t">Intro to Python</span><span class="d tnum">9 lessons</span></div>
|
||||
<div class="lp-path-course"><span class="n tnum">2</span><span class="t">Data Analysis with Pandas</span><span class="d tnum">11 lessons</span></div>
|
||||
<div class="lp-path-course"><span class="n tnum">3</span><span class="t">Data Visualization</span><span class="d tnum">8 lessons</span></div>
|
||||
<div class="lp-path-course" style="border-bottom: none"><span class="n" style="background: transparent; color: var(--landing-fg-muted)">+</span><span class="t" style="color: var(--landing-fg-muted)">1 more course</span></div>
|
||||
</div>
|
||||
<div class="lp-meta-row">
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>4 courses</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~30 hours</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>Certificate</span>
|
||||
<span class="price tnum">$159 <s>$212</s></span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="view-more">
|
||||
<a class="lp-btn lp-btn-secondary lp-btn-lg" href="public-paths.html">View all learning paths</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== COURSES ===== -->
|
||||
<section class="lp-section" id="courses">
|
||||
<div class="lp-wrap">
|
||||
<h2>Our Courses</h2>
|
||||
<p class="lead">Standalone courses you can take in any order.</p>
|
||||
|
||||
<div class="courses-grid">
|
||||
<a class="lp-card lp-course-card" href="#">
|
||||
<h3>HTML & CSS Foundations</h3>
|
||||
<p class="desc">Semantic markup, the box model, flexbox, and responsive layout basics for absolute beginners.</p>
|
||||
<div class="lp-meta-row">
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>8 hours</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>Self paced</span>
|
||||
<span class="price tnum">$49</span>
|
||||
</div>
|
||||
</a>
|
||||
<a class="lp-card lp-course-card" href="#">
|
||||
<h3>JavaScript Essentials</h3>
|
||||
<p class="desc">Types, functions, the DOM, async/await, and fetching data from APIs — production JavaScript from day one.</p>
|
||||
<div class="lp-meta-row">
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>9 hours</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>Self paced</span>
|
||||
<span class="price tnum">$59</span>
|
||||
</div>
|
||||
</a>
|
||||
<a class="lp-card lp-course-card" href="#">
|
||||
<h3>Modern Web Development with React</h3>
|
||||
<p class="desc">Components, props & state, hooks, and building interactive UIs with the most-used frontend library.</p>
|
||||
<div class="lp-meta-row">
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>10 hours</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>Self paced</span>
|
||||
<span class="price tnum">$79</span>
|
||||
</div>
|
||||
</a>
|
||||
<a class="lp-card lp-course-card" href="#">
|
||||
<h3>Getting Started with MVC</h3>
|
||||
<p class="desc">A standalone deep dive on the model-view-controller pattern and where it still shines today.</p>
|
||||
<div class="lp-meta-row">
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>5 hours</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>Self paced</span>
|
||||
<span class="price">Free</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="view-more">
|
||||
<a class="lp-btn lp-btn-secondary lp-btn-lg" href="#">View more courses</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- footer -->
|
||||
<footer class="lp-footer">
|
||||
<div class="lp-wrap lp-footer-grid">
|
||||
<div>
|
||||
<div class="brand"><span class="lp-nav-logo" style="width: 26px; height: 26px; font-size: 12px">A</span>Acme Academy</div>
|
||||
<p class="copy" style="max-width: 34ch">Practical tech skills, taught by practitioners.</p>
|
||||
<p class="copy">© 2026 Acme Academy</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Learn</h4>
|
||||
<a href="public-paths.html">Learning Paths</a>
|
||||
<a href="#courses">Courses</a>
|
||||
<a href="#">Certificates</a>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Academy</h4>
|
||||
<a href="#">About</a>
|
||||
<a href="#">Contact</a>
|
||||
<a href="lms-home.html">Login</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<button class="lp-theme-btn" id="theme" title="Toggle theme" aria-label="Toggle theme">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg>
|
||||
</button>
|
||||
|
||||
<script>
|
||||
document.getElementById('theme').onclick = () => {
|
||||
const dark = document.documentElement.classList.toggle('dark');
|
||||
localStorage.cioTheme = dark ? 'dark' : 'light';
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,235 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Learning Path · ClassroomIO LMS</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="app-theme.css" />
|
||||
<script>
|
||||
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
<style>
|
||||
.path-head { overflow: hidden; }
|
||||
.ph-cover { height: 110px; background:
|
||||
radial-gradient(120% 150% at 10% -20%, oklch(0.623 0.214 259.815) 0%, transparent 55%),
|
||||
linear-gradient(120deg, oklch(0.488 0.243 264.376), oklch(0.546 0.245 262.881)); position: relative; }
|
||||
.ph-cover .badge { position: absolute; top: 14px; left: 18px; background: oklch(1 0 0 / 0.18); color: #fff; border-color: oklch(1 0 0 / 0.3); backdrop-filter: blur(4px); }
|
||||
.ph-body { padding: 20px 22px 22px; }
|
||||
.ph-title { font-size: 22px; font-weight: 600; letter-spacing: -0.02em; margin: 0 0 6px; text-wrap: balance; }
|
||||
.ph-desc { color: var(--muted-foreground); font-size: 14px; max-width: 64ch; margin: 0 0 16px; }
|
||||
.ph-meta { display: flex; flex-wrap: wrap; gap: 18px; margin-bottom: 18px; }
|
||||
.ph-meta .m { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--foreground); }
|
||||
.ph-meta svg { width: 15px; height: 15px; stroke-width: 2; color: var(--muted-foreground); }
|
||||
.ph-progress { background: color-mix(in oklab, var(--muted) 50%, transparent); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 14px 16px; }
|
||||
.pp-top { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 9px; }
|
||||
.pp-label { font-size: 13px; font-weight: 500; }
|
||||
.pp-count { font-size: 12.5px; color: var(--muted-foreground); }
|
||||
.pp-pct { font-size: 15px; font-weight: 600; color: var(--primary); }
|
||||
.pp-foot { display: flex; align-items: center; gap: 7px; margin-top: 10px; font-size: 12.5px; color: var(--muted-foreground); }
|
||||
.pp-foot svg { width: 14px; height: 14px; stroke-width: 2; }
|
||||
.pp-foot strong { color: var(--foreground); font-weight: 500; }
|
||||
|
||||
.course { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 14px 16px; display: flex; gap: 14px; align-items: flex-start; box-shadow: var(--shadow-2xs); }
|
||||
.step.s-current .course { border-color: var(--primary); box-shadow: var(--shadow-sm); }
|
||||
.step.s-locked .course { background: color-mix(in oklab, var(--muted) 40%, transparent); box-shadow: none; }
|
||||
.thumb { width: 86px; height: 62px; border-radius: var(--radius-md); flex-shrink: 0; position: relative; overflow: hidden; }
|
||||
.step.s-locked .thumb { filter: grayscale(0.75) opacity(0.7); }
|
||||
.c-main { min-width: 0; flex: 1; }
|
||||
.c-top { display: flex; align-items: center; gap: 8px; margin-bottom: 2px; flex-wrap: wrap; }
|
||||
.c-title { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; margin: 0; }
|
||||
.c-desc { font-size: 12.5px; color: var(--muted-foreground); margin: 3px 0 0; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
|
||||
.c-facts { display: flex; align-items: center; gap: 14px; margin-top: 9px; font-size: 12px; color: var(--muted-foreground); }
|
||||
.c-facts .f { display: flex; align-items: center; gap: 5px; }
|
||||
.c-facts svg { width: 13px; height: 13px; stroke-width: 2; }
|
||||
.c-progress { display: flex; align-items: center; gap: 10px; margin-top: 10px; max-width: 340px; }
|
||||
.c-progress .p { font-size: 12px; font-weight: 600; min-width: 34px; text-align: right; color: var(--muted-foreground); }
|
||||
.c-side { display: flex; flex-direction: column; align-items: flex-end; gap: 9px; flex-shrink: 0; }
|
||||
.unlock-note { font-size: 11.5px; color: var(--muted-foreground); display: flex; align-items: center; gap: 5px; text-align: right; max-width: 160px; }
|
||||
.unlock-note svg { width: 12px; height: 12px; stroke-width: 2; flex-shrink: 0; }
|
||||
.cert-card { border: 1px dashed var(--border); border-radius: var(--radius-lg); padding: 16px; display: flex; align-items: center; gap: 14px; }
|
||||
@media (max-width: 720px) { .c-side { display: none; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<aside class="sidebar">
|
||||
<div class="brand"><div class="brand-mark">C</div><div class="brand-name">ClassroomIO</div></div>
|
||||
<div class="nav-label">Learn</div>
|
||||
<a class="nav-item" href="lms-home.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>My Learning</a>
|
||||
<a class="nav-item active" href="paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Paths<span class="nav-badge">2</span></a>
|
||||
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>Exercises</a>
|
||||
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>Community</a>
|
||||
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>Certificates</a>
|
||||
<div class="sidebar-foot"><div class="avatar">AO</div><div class="who"><div class="nm">Ada Okafor</div><div class="rl">Student</div></div></div>
|
||||
</aside>
|
||||
|
||||
<div class="main">
|
||||
<header class="topbar">
|
||||
<nav class="crumbs">
|
||||
<a href="paths.html">Learning Paths</a><span class="sep">/</span>
|
||||
<span class="here">Frontend Engineering Bootcamp</span>
|
||||
</nav>
|
||||
<div class="top-actions">
|
||||
<button class="icon-btn" id="theme" title="Toggle theme" aria-label="Toggle theme"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg></button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="content">
|
||||
<div class="wrap">
|
||||
<section class="card path-head">
|
||||
<div class="ph-cover">
|
||||
<span class="badge"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Path</span>
|
||||
</div>
|
||||
<div class="ph-body">
|
||||
<h1 class="ph-title">Frontend Engineering Bootcamp</h1>
|
||||
<p class="ph-desc">A guided, five-course track that takes you from markup fundamentals to shipping a production React app. Each course unlocks the next — finish in order to earn your certificate.</p>
|
||||
<div class="ph-meta">
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>5 courses</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~38 hours</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>Sequential · unlock in order</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>Certificate on completion</span>
|
||||
</div>
|
||||
<div class="ph-progress">
|
||||
<div class="pp-top">
|
||||
<div><div class="pp-label">Your progress</div><div class="pp-count tnum">2 of 5 courses complete</div></div>
|
||||
<div class="pp-pct tnum">49%</div>
|
||||
</div>
|
||||
<div class="progress"><span style="width: 49%"></span></div>
|
||||
<div class="pp-foot">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
|
||||
Up next: continue <strong>Modern Web Development with React</strong> — 3 lessons and 2 exercises left.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="sec-head">
|
||||
<h2 class="sec-title">Path courses</h2>
|
||||
<span class="more" style="color: var(--muted-foreground); font-weight: 400">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
|
||||
Finish lessons & exercises to unlock the next course
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="journey">
|
||||
<div class="step s-done">
|
||||
<div class="rail"><div class="node"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></div></div>
|
||||
<article class="course">
|
||||
<div class="thumb" style="background: linear-gradient(135deg, oklch(0.705 0.213 47.604), oklch(0.75 0.183 55.934))"></div>
|
||||
<div class="c-main">
|
||||
<div class="c-top"><span class="item-eyebrow">Course 1</span><span class="badge badge-success-soft"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Completed</span></div>
|
||||
<h3 class="c-title">HTML & CSS Foundations</h3>
|
||||
<p class="c-desc">Semantic markup, the box model, flexbox, and responsive layout basics.</p>
|
||||
<div class="c-progress"><div class="progress progress-thin progress-success"><span style="width: 100%"></span></div><span class="p tnum">100%</span></div>
|
||||
</div>
|
||||
<div class="c-side">
|
||||
<a class="btn btn-outline btn-sm" href="course-in-path.html">Review</a>
|
||||
<span class="unlock-note" style="color: var(--success)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Finished May 12</span>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="step s-done">
|
||||
<div class="rail"><div class="node"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></div></div>
|
||||
<article class="course">
|
||||
<div class="thumb" style="background: linear-gradient(135deg, oklch(0.795 0.184 86.047), oklch(0.769 0.188 70.08))"></div>
|
||||
<div class="c-main">
|
||||
<div class="c-top"><span class="item-eyebrow">Course 2</span><span class="badge badge-success-soft"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Completed</span></div>
|
||||
<h3 class="c-title">JavaScript Essentials</h3>
|
||||
<p class="c-desc">Types, functions, the DOM, async/await, and fetching data from APIs.</p>
|
||||
<div class="c-progress"><div class="progress progress-thin progress-success"><span style="width: 100%"></span></div><span class="p tnum">100%</span></div>
|
||||
</div>
|
||||
<div class="c-side">
|
||||
<a class="btn btn-outline btn-sm" href="course-in-path.html">Review</a>
|
||||
<span class="unlock-note" style="color: var(--success)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Finished Jun 3</span>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="step s-current">
|
||||
<div class="rail"><div class="node"><svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M8 5v14l11-7z"/></svg></div></div>
|
||||
<article class="course">
|
||||
<a class="thumb" href="course-in-path.html" style="background: linear-gradient(135deg, oklch(0.685 0.169 237.323), oklch(0.488 0.243 264.376))"></a>
|
||||
<div class="c-main">
|
||||
<div class="c-top"><span class="item-eyebrow" style="color: var(--primary)">Course 3</span><span class="badge badge-primary-soft"><svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M8 5v14l11-7z"/></svg>In progress</span></div>
|
||||
<h3 class="c-title"><a href="course-in-path.html">Modern Web Development with React</a></h3>
|
||||
<p class="c-desc">Components, props & state, hooks, and building interactive UIs.</p>
|
||||
<div class="c-facts">
|
||||
<span class="f"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>9 / 12 lessons</span>
|
||||
<span class="f"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>2 / 4 exercises</span>
|
||||
</div>
|
||||
<div class="c-progress"><div class="progress progress-thin"><span style="width: 45%"></span></div><span class="p tnum">45%</span></div>
|
||||
</div>
|
||||
<div class="c-side">
|
||||
<a class="btn btn-primary btn-sm" href="course-in-path.html">Continue<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M12 5l7 7-7 7"/></svg></a>
|
||||
<span class="unlock-note"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~4h left</span>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="step s-locked">
|
||||
<div class="rail"><div class="node"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div></div>
|
||||
<article class="course">
|
||||
<div class="thumb" style="background: linear-gradient(135deg, oklch(0.585 0.233 277.117), oklch(0.606 0.25 292.717))"><div class="lock-veil"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div></div>
|
||||
<div class="c-main">
|
||||
<div class="c-top"><span class="item-eyebrow">Course 4</span><span class="badge badge-muted"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>Locked</span></div>
|
||||
<h3 class="c-title">State Management & Data Fetching</h3>
|
||||
<p class="c-desc">Context, reducers, caching, and connecting a React app to a backend.</p>
|
||||
<div class="c-facts">
|
||||
<span class="f"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>10 lessons</span>
|
||||
<span class="f"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>3 exercises</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="c-side">
|
||||
<span class="btn btn-secondary btn-sm disabled"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>Locked</span>
|
||||
<span class="unlock-note"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>Unlocks after Course 3</span>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="step s-locked">
|
||||
<div class="rail"><div class="node"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div></div>
|
||||
<article class="course">
|
||||
<div class="thumb" style="background: linear-gradient(135deg, oklch(0.645 0.246 16.439), oklch(0.586 0.253 17.585))"><div class="lock-veil"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div></div>
|
||||
<div class="c-main">
|
||||
<div class="c-top"><span class="item-eyebrow">Course 5</span><span class="badge badge-muted"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>Locked</span></div>
|
||||
<h3 class="c-title">Building & Shipping a Capstone</h3>
|
||||
<p class="c-desc">Plan, build, and deploy a full project — your portfolio piece.</p>
|
||||
<div class="c-facts">
|
||||
<span class="f"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>7 lessons</span>
|
||||
<span class="f"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>1 capstone project</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="c-side">
|
||||
<span class="btn btn-secondary btn-sm disabled"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>Locked</span>
|
||||
<span class="unlock-note"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>Unlocks after Course 4</span>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="step no-rail">
|
||||
<div class="rail"><div class="node"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg></div></div>
|
||||
<div class="cert-card">
|
||||
<div class="item-media-icon item-media-lg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg></div>
|
||||
<div class="item-content">
|
||||
<span class="item-title item-title-lg">Bootcamp Certificate</span>
|
||||
<span class="item-desc">Complete all 5 courses to unlock and download your certificate.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('theme').onclick = () => {
|
||||
const dark = document.documentElement.classList.toggle('dark');
|
||||
localStorage.cioTheme = dark ? 'dark' : 'light';
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,174 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Learning Paths · ClassroomIO LMS</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="app-theme.css" />
|
||||
<script>
|
||||
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
<style>
|
||||
.tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--border); margin-bottom: 20px; }
|
||||
.tab { padding: 9px 14px; font-size: 14px; font-weight: 500; color: var(--muted-foreground); border: none; background: none; border-bottom: 2px solid transparent; margin-bottom: -1px; cursor: pointer; display: flex; align-items: center; gap: 7px; }
|
||||
.tab:hover { color: var(--foreground); }
|
||||
.tab.active { color: var(--foreground); border-bottom-color: var(--primary); }
|
||||
.tab .n { font-size: 11.5px; font-weight: 500; background: var(--muted); border-radius: 999px; padding: 0 7px; color: var(--muted-foreground); }
|
||||
|
||||
.path-list { display: flex; flex-direction: column; gap: 14px; }
|
||||
.path-row { display: grid; grid-template-columns: 150px 1fr; overflow: hidden; transition: border-color 0.15s, box-shadow 0.15s; }
|
||||
.path-row:hover { border-color: var(--ring); box-shadow: var(--shadow-md); }
|
||||
.pr-cover { position: relative; display: grid; place-items: center; color: oklch(1 0 0 / 0.9); min-height: 120px; }
|
||||
.pr-cover svg { width: 28px; height: 28px; stroke-width: 1.8; }
|
||||
.pr-body { padding: 16px 18px; display: flex; flex-direction: column; gap: 11px; min-width: 0; }
|
||||
.pr-head { display: flex; align-items: flex-start; gap: 12px; }
|
||||
.pr-title { font-size: 15.5px; font-weight: 600; letter-spacing: -0.01em; margin: 0 0 2px; }
|
||||
.pr-desc { font-size: 13px; color: var(--muted-foreground); margin: 0; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
|
||||
.seg-row { display: flex; align-items: center; gap: 11px; }
|
||||
.seg-pct { font-size: 13.5px; font-weight: 600; min-width: 36px; text-align: right; }
|
||||
.pr-foot { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
|
||||
.pr-meta { display: flex; align-items: center; gap: 16px; font-size: 12.5px; color: var(--muted-foreground); flex: 1; flex-wrap: wrap; }
|
||||
.pr-meta .m { display: flex; align-items: center; gap: 5px; }
|
||||
.pr-meta svg { width: 14px; height: 14px; stroke-width: 2; }
|
||||
.pr-meta strong { color: var(--foreground); font-weight: 500; }
|
||||
@media (max-width: 720px) { .path-row { grid-template-columns: 1fr; } .pr-cover { min-height: 72px; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<aside class="sidebar">
|
||||
<div class="brand"><div class="brand-mark">C</div><div class="brand-name">ClassroomIO</div></div>
|
||||
<div class="nav-label">Learn</div>
|
||||
<a class="nav-item" href="lms-home.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>My Learning</a>
|
||||
<a class="nav-item active" href="paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Paths<span class="nav-badge">2</span></a>
|
||||
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>Exercises</a>
|
||||
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>Community</a>
|
||||
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>Certificates</a>
|
||||
<div class="sidebar-foot"><div class="avatar">AO</div><div class="who"><div class="nm">Ada Okafor</div><div class="rl">Student</div></div></div>
|
||||
</aside>
|
||||
|
||||
<div class="main">
|
||||
<header class="topbar">
|
||||
<span class="top-title">Learning Paths</span>
|
||||
<div class="top-actions">
|
||||
<button class="icon-btn" id="theme" title="Toggle theme" aria-label="Toggle theme"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg></button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="content">
|
||||
<div class="wrap" style="max-width: 1000px">
|
||||
<div class="page-head">
|
||||
<div>
|
||||
<h1 class="page-title">Learning Paths</h1>
|
||||
<p class="page-sub">Structured tracks you're enrolled in. Complete the courses in order to finish a path and earn its certificate.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tabs">
|
||||
<button class="tab active">In progress <span class="n">2</span></button>
|
||||
<button class="tab">Completed <span class="n">1</span></button>
|
||||
<button class="tab">All <span class="n">3</span></button>
|
||||
</div>
|
||||
|
||||
<div class="path-list">
|
||||
<a class="card path-row" href="path-detail.html">
|
||||
<div class="pr-cover" style="background: linear-gradient(135deg, oklch(0.488 0.243 264.376), oklch(0.623 0.214 259.815))">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>
|
||||
</div>
|
||||
<div class="pr-body">
|
||||
<div class="pr-head">
|
||||
<div style="min-width: 0">
|
||||
<h3 class="pr-title">Frontend Engineering Bootcamp</h3>
|
||||
<p class="pr-desc">From HTML foundations to shipping a production React app.</p>
|
||||
</div>
|
||||
<span class="badge badge-primary-soft" style="margin-left: auto; flex-shrink: 0"><svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M8 5v14l11-7z"/></svg>In progress</span>
|
||||
</div>
|
||||
<div class="seg-row">
|
||||
<div class="segs"><span class="seg done"></span><span class="seg done"></span><span class="seg half"></span><span class="seg"></span><span class="seg"></span></div>
|
||||
<span class="seg-pct tnum text-primary">49%</span>
|
||||
</div>
|
||||
<div class="pr-foot">
|
||||
<div class="pr-meta">
|
||||
<span class="m tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>2 of 5 courses</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~38h</span>
|
||||
<span class="m">Next: <strong>Modern Web Development with React</strong></span>
|
||||
</div>
|
||||
<span class="btn btn-primary btn-sm">Continue<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a class="card path-row" href="path-detail.html">
|
||||
<div class="pr-cover" style="background: linear-gradient(135deg, oklch(0.596 0.145 163.225), oklch(0.696 0.17 162.48))">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>
|
||||
</div>
|
||||
<div class="pr-body">
|
||||
<div class="pr-head">
|
||||
<div style="min-width: 0">
|
||||
<h3 class="pr-title">Data Science with Python</h3>
|
||||
<p class="pr-desc">Pandas, visualization, and applied machine-learning basics.</p>
|
||||
</div>
|
||||
<span class="badge badge-primary-soft" style="margin-left: auto; flex-shrink: 0"><svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M8 5v14l11-7z"/></svg>In progress</span>
|
||||
</div>
|
||||
<div class="seg-row">
|
||||
<div class="segs"><span class="seg half"></span><span class="seg"></span><span class="seg"></span><span class="seg"></span></div>
|
||||
<span class="seg-pct tnum text-primary">8%</span>
|
||||
</div>
|
||||
<div class="pr-foot">
|
||||
<div class="pr-meta">
|
||||
<span class="m tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>0 of 4 courses</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~30h</span>
|
||||
<span class="m">Just started: <strong>Intro to Python</strong></span>
|
||||
</div>
|
||||
<span class="btn btn-primary btn-sm">Continue<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a class="card path-row" href="path-detail.html" style="opacity: 0.85">
|
||||
<div class="pr-cover" style="background: linear-gradient(135deg, oklch(0.666 0.179 58.318), oklch(0.769 0.188 70.08))">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>
|
||||
</div>
|
||||
<div class="pr-body">
|
||||
<div class="pr-head">
|
||||
<div style="min-width: 0">
|
||||
<h3 class="pr-title">Workplace Compliance 2026</h3>
|
||||
<p class="pr-desc">Security awareness, data handling, and code of conduct.</p>
|
||||
</div>
|
||||
<span class="badge badge-success" style="margin-left: auto; flex-shrink: 0"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Completed</span>
|
||||
</div>
|
||||
<div class="seg-row">
|
||||
<div class="segs"><span class="seg done"></span><span class="seg done"></span><span class="seg done"></span></div>
|
||||
<span class="seg-pct tnum" style="color: var(--success)">100%</span>
|
||||
</div>
|
||||
<div class="pr-foot">
|
||||
<div class="pr-meta">
|
||||
<span class="m tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>3 of 3 courses</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>Certificate earned</span>
|
||||
</div>
|
||||
<span class="btn btn-outline btn-sm">View certificate<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('theme').onclick = () => {
|
||||
const dark = document.documentElement.classList.toggle('dark');
|
||||
localStorage.cioTheme = dark ? 'dark' : 'light';
|
||||
};
|
||||
document.querySelectorAll('.tab').forEach((tab) => {
|
||||
tab.addEventListener('click', () => {
|
||||
document.querySelector('.tab.active')?.classList.remove('active');
|
||||
tab.classList.add('active');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,410 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Frontend Engineering Bootcamp — Acme Academy</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="landing-theme.css" />
|
||||
<script>
|
||||
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
<style>
|
||||
.path-hero { text-align: left; padding: 56px 0 0; }
|
||||
.path-hero-grid { display: grid; grid-template-columns: 1.6fr 1fr; gap: 48px; align-items: start; max-width: 1200px; margin: 0 auto; padding: 0 20px; position: relative; }
|
||||
.path-hero h1 { font-size: clamp(30px, 4.5vw, 44px); text-align: left; }
|
||||
.path-hero .sub { text-align: left; margin-left: 0; font-size: 17px; }
|
||||
.instructors-row { display: flex; align-items: center; gap: 10px; margin-bottom: 26px; font-size: 14px; color: var(--landing-fg-muted); }
|
||||
.av-stack { display: flex; }
|
||||
.av-stack .av { width: 34px; height: 34px; border-radius: 999px; background: var(--landing-accent-soft); color: var(--landing-accent); display: grid; place-items: center; font-weight: 600; font-size: 12px; border: 2px solid var(--landing-bg); margin-left: -8px; }
|
||||
.av-stack .av:first-child { margin-left: 0; }
|
||||
.enroll-box { padding: 26px; position: sticky; top: 70px; }
|
||||
.enroll-box .amt { font-size: 38px; font-weight: 600; letter-spacing: -0.03em; line-height: 1; }
|
||||
.enroll-box .was { display: flex; align-items: center; gap: 10px; margin: 8px 0 16px; font-size: 14px; color: var(--landing-fg-muted); }
|
||||
.enroll-note { font-size: 12.5px; color: var(--landing-fg-muted); margin-top: 12px; text-align: center; }
|
||||
.hero-stats { margin-top: 44px; }
|
||||
@media (max-width: 860px) { .path-hero-grid { grid-template-columns: 1fr; } .enroll-box { position: static; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="lp-nav-outer">
|
||||
<nav class="lp-nav">
|
||||
<a class="lp-nav-brand" href="org-landing.html"><span class="lp-nav-logo">A</span>Acme Academy</a>
|
||||
<div class="lp-nav-links">
|
||||
<a class="active" href="public-paths.html">Learning Paths</a>
|
||||
<a href="org-landing.html#courses">Courses</a>
|
||||
<a class="lp-nav-auth" href="lms-home.html">Login</a>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- ===== HERO ===== -->
|
||||
<header class="lp-hero path-hero">
|
||||
<div class="lp-hero-dots"></div>
|
||||
<div class="path-hero-grid">
|
||||
<div>
|
||||
<span class="lp-chip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Path · Certificate</span>
|
||||
<h1>Become a job-ready frontend engineer</h1>
|
||||
<p class="sub">Five courses, one path — from your first HTML tag to a deployed React capstone. Learn in order, build real projects, earn a certificate.</p>
|
||||
<div class="instructors-row">
|
||||
<div class="av-stack"><span class="av">JD</span><span class="av">EO</span><span class="av">RM</span></div>
|
||||
Taught by Jordan Diallo, Efe Obi + 1 more
|
||||
</div>
|
||||
<div class="lp-cta-row" style="justify-content: flex-start">
|
||||
<a class="lp-btn lp-btn-primary lp-btn-lg" href="#pricing">Enroll · $199</a>
|
||||
<span class="lp-save tnum" style="font-size: 14px; padding: 6px 12px">Save $81 vs individual courses</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<aside class="lp-card enroll-box">
|
||||
<div class="eyebrow" style="font-size: 12px; letter-spacing: 0.12em; text-transform: uppercase; font-weight: 600; color: var(--landing-fg-muted); margin-bottom: 10px">Full path</div>
|
||||
<div class="amt tnum">$199</div>
|
||||
<div class="was tnum"><s>$280</s><span class="lp-save">Save $81 (29%)</span></div>
|
||||
<ul class="lp-features">
|
||||
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>All 5 courses, unlocked in order</li>
|
||||
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>52 lessons · 13 exercises · 1 capstone</li>
|
||||
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Path certificate on completion</li>
|
||||
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Lifetime access, learn at your pace</li>
|
||||
</ul>
|
||||
<a class="lp-btn lp-btn-primary lp-btn-lg lp-btn-block" href="lms-home.html">Enroll in this path</a>
|
||||
<p class="enroll-note tnum">942 already enrolled · 4.7 ★ from 213 reviews</p>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<div class="lp-stats hero-stats">
|
||||
<div class="lp-stat"><div class="v tnum">5</div><div class="k">courses in series</div></div>
|
||||
<div class="lp-stat"><div class="v tnum">~38h</div><div class="k">at your own pace</div></div>
|
||||
<div class="lp-stat"><div class="v">Beginner</div><div class="k">no experience required</div></div>
|
||||
<div class="lp-stat"><div class="v tnum">4.7 ★</div><div class="k tnum">213 reviews</div></div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- ===== ANCHOR NAV ===== -->
|
||||
<nav class="lp-anchor-nav">
|
||||
<div class="in">
|
||||
<a class="active" href="#about">About</a>
|
||||
<a href="#courses">Courses</a>
|
||||
<a href="#certificate">Certificate</a>
|
||||
<a href="#instructors">Instructors</a>
|
||||
<a href="#testimonials">Testimonials</a>
|
||||
<a href="#faq">FAQ</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- ===== ABOUT ===== -->
|
||||
<section class="lp-section" id="about">
|
||||
<div class="lp-wrap-narrow">
|
||||
<h2>What you'll learn</h2>
|
||||
<p class="lead">Practical, project-first skills — every course ends with something you built.</p>
|
||||
<div class="lp-outcomes">
|
||||
<div class="lp-outcome"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Build responsive, accessible websites with semantic HTML and modern CSS</div>
|
||||
<div class="lp-outcome"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Write production JavaScript: async, APIs, and the DOM</div>
|
||||
<div class="lp-outcome"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Build and ship interactive React apps with state, hooks, and data fetching</div>
|
||||
<div class="lp-outcome"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Complete a portfolio-ready capstone project, deployed to production</div>
|
||||
</div>
|
||||
|
||||
<h2 style="margin-top: 48px">Skills you'll gain</h2>
|
||||
<div class="lp-skills" style="margin-top: 18px">
|
||||
<span class="lp-skill">HTML & CSS</span>
|
||||
<span class="lp-skill">Flexbox & Grid</span>
|
||||
<span class="lp-skill">JavaScript</span>
|
||||
<span class="lp-skill">REST APIs</span>
|
||||
<span class="lp-skill">React</span>
|
||||
<span class="lp-skill">State management</span>
|
||||
<span class="lp-skill">Deployment</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== COURSE SERIES ===== -->
|
||||
<section class="lp-section" id="courses">
|
||||
<div class="lp-wrap-narrow">
|
||||
<span class="lp-eyebrow">Series · take in order</span>
|
||||
<h2>5 courses in this path</h2>
|
||||
<p class="lead">Each course unlocks the next once you finish its lessons and exercises.</p>
|
||||
|
||||
<div class="lp-series">
|
||||
<!-- Course 1 -->
|
||||
<div class="lp-card lp-series-card">
|
||||
<div class="lp-series-head">
|
||||
<span class="lp-series-n tnum">1</span>
|
||||
<div>
|
||||
<h3>HTML & CSS Foundations</h3>
|
||||
<span class="lp-series-sub tnum">Course 1 · 12 lessons · ~8 hours</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lp-series-body">
|
||||
<div class="lbl">What you'll learn</div>
|
||||
<div class="lp-series-outcomes">
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Semantic markup and document structure</span>
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>The box model, flexbox, and grid</span>
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Responsive layout from mobile up</span>
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Accessibility fundamentals</span>
|
||||
</div>
|
||||
<button class="lp-lessons-toggle">Show lesson outline<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
|
||||
<div class="lp-lessons">
|
||||
<div class="lp-lesson"><span class="ix tnum">01</span><span>Anatomy of a web page</span><span class="prev">Preview</span><span class="dur">14m</span></div>
|
||||
<div class="lp-lesson"><span class="ix tnum">02</span><span>Semantic HTML in practice</span><span class="dur">18m</span></div>
|
||||
<div class="lp-lesson"><span class="ix tnum">03</span><span>The box model</span><span class="dur">16m</span></div>
|
||||
<div class="lp-lesson" style="border-bottom: none"><span class="ix tnum">…</span><span style="color: var(--landing-fg-muted)">9 more lessons</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Course 2 -->
|
||||
<div class="lp-card lp-series-card">
|
||||
<div class="lp-series-head">
|
||||
<span class="lp-series-n tnum">2</span>
|
||||
<div>
|
||||
<h3>JavaScript Essentials</h3>
|
||||
<span class="lp-series-sub tnum">Course 2 · 10 lessons · ~9 hours</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lp-series-body">
|
||||
<div class="lbl">What you'll learn</div>
|
||||
<div class="lp-series-outcomes">
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Types, functions, and control flow</span>
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Working with the DOM</span>
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>async/await and promises</span>
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Fetching data from APIs</span>
|
||||
</div>
|
||||
<button class="lp-lessons-toggle">Show lesson outline<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
|
||||
<div class="lp-lessons">
|
||||
<div class="lp-lesson"><span class="ix tnum">01</span><span>Values, types, and variables</span><span class="prev">Preview</span><span class="dur">15m</span></div>
|
||||
<div class="lp-lesson"><span class="ix tnum">02</span><span>Functions and scope</span><span class="dur">17m</span></div>
|
||||
<div class="lp-lesson" style="border-bottom: none"><span class="ix tnum">…</span><span style="color: var(--landing-fg-muted)">8 more lessons</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Course 3 -->
|
||||
<div class="lp-card lp-series-card">
|
||||
<div class="lp-series-head">
|
||||
<span class="lp-series-n tnum">3</span>
|
||||
<div>
|
||||
<h3>Modern Web Development with React</h3>
|
||||
<span class="lp-series-sub tnum">Course 3 · 12 lessons · ~10 hours</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lp-series-body">
|
||||
<div class="lbl">What you'll learn</div>
|
||||
<div class="lp-series-outcomes">
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Components, props, and JSX</span>
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>State and event handling</span>
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Hooks and effects</span>
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Building interactive UIs</span>
|
||||
</div>
|
||||
<button class="lp-lessons-toggle">Show lesson outline<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
|
||||
<div class="lp-lessons">
|
||||
<div class="lp-lesson"><span class="ix tnum">01</span><span>What is React?</span><span class="prev">Preview</span><span class="dur">6m</span></div>
|
||||
<div class="lp-lesson"><span class="ix tnum">02</span><span>JSX & rendering</span><span class="dur">11m</span></div>
|
||||
<div class="lp-lesson" style="border-bottom: none"><span class="ix tnum">…</span><span style="color: var(--landing-fg-muted)">10 more lessons</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Course 4 -->
|
||||
<div class="lp-card lp-series-card">
|
||||
<div class="lp-series-head">
|
||||
<span class="lp-series-n tnum">4</span>
|
||||
<div>
|
||||
<h3>State Management & Data Fetching</h3>
|
||||
<span class="lp-series-sub tnum">Course 4 · 10 lessons · ~7 hours</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lp-series-body">
|
||||
<div class="lbl">What you'll learn</div>
|
||||
<div class="lp-series-outcomes">
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Context and reducers</span>
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Caching and loading states</span>
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Connecting React to a backend</span>
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Error handling patterns</span>
|
||||
</div>
|
||||
<button class="lp-lessons-toggle">Show lesson outline<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
|
||||
<div class="lp-lessons">
|
||||
<div class="lp-lesson"><span class="ix tnum">01</span><span>Lifting state up</span><span class="dur">13m</span></div>
|
||||
<div class="lp-lesson" style="border-bottom: none"><span class="ix tnum">…</span><span style="color: var(--landing-fg-muted)">9 more lessons</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Course 5 -->
|
||||
<div class="lp-card lp-series-card">
|
||||
<div class="lp-series-head">
|
||||
<span class="lp-series-n tnum">5</span>
|
||||
<div>
|
||||
<h3>Building & Shipping a Capstone</h3>
|
||||
<span class="lp-series-sub tnum">Course 5 · 7 lessons + capstone project · ~4 hours</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lp-series-body">
|
||||
<div class="lbl">What you'll learn</div>
|
||||
<div class="lp-series-outcomes">
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Scoping and planning a real project</span>
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Deploying to production</span>
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Code review and iteration</span>
|
||||
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Presenting your portfolio piece</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== CERTIFICATE ===== -->
|
||||
<section class="lp-section" id="certificate">
|
||||
<div class="lp-wrap-narrow">
|
||||
<div class="lp-card lp-cert">
|
||||
<div class="frame"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg></div>
|
||||
<div>
|
||||
<h3>Earn a shareable certificate</h3>
|
||||
<p>Complete all five courses — every lesson and exercise — and receive the Frontend Engineering Bootcamp certificate, ready to add to LinkedIn and your CV.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== INSTRUCTORS ===== -->
|
||||
<section class="lp-section" id="instructors">
|
||||
<div class="lp-wrap-narrow">
|
||||
<h2>Your instructors</h2>
|
||||
<p class="lead">The tutors behind the courses in this path.</p>
|
||||
<div class="lp-instructors">
|
||||
<div class="lp-card lp-instructor">
|
||||
<span class="av">JD</span>
|
||||
<span class="nm">Jordan Diallo</span>
|
||||
<span class="rl">Lead Instructor · Frontend</span>
|
||||
<span class="bio">10 years building web apps; previously staff engineer at a fintech scale-up.</span>
|
||||
</div>
|
||||
<div class="lp-card lp-instructor">
|
||||
<span class="av">EO</span>
|
||||
<span class="nm">Efe Obi</span>
|
||||
<span class="rl">Instructor · JavaScript</span>
|
||||
<span class="bio">Teaches JS to thousands of learners; maintainer of two OSS tooling projects.</span>
|
||||
</div>
|
||||
<div class="lp-card lp-instructor">
|
||||
<span class="av">RM</span>
|
||||
<span class="nm">Rita Mensah</span>
|
||||
<span class="rl">Instructor · React</span>
|
||||
<span class="bio">Product engineer and design-systems specialist; capstone project mentor.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== TESTIMONIALS ===== -->
|
||||
<section class="lp-section" id="testimonials">
|
||||
<div class="lp-wrap-narrow">
|
||||
<h2>What learners say</h2>
|
||||
<p class="lead">From people who finished the path.</p>
|
||||
<div class="lp-testimonials">
|
||||
<div class="lp-card lp-testimonial">
|
||||
<p class="q">"I went from zero to deploying my own React app in ten weeks. The order of the courses just makes sense — nothing assumed I knew things I didn't."</p>
|
||||
<div class="who"><span class="av">TB</span><div><div class="nm">Tunde Bello</div><div class="loc">Lagos, Nigeria</div></div></div>
|
||||
</div>
|
||||
<div class="lp-card lp-testimonial">
|
||||
<p class="q">"The locked courses kept me honest — no skipping ahead, and everything built on what came before. The certificate helped me land interviews."</p>
|
||||
<div class="who"><span class="av">MK</span><div><div class="nm">Mariam Kone</div><div class="loc">Abidjan, Côte d'Ivoire</div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== FAQ ===== -->
|
||||
<section class="lp-section" id="faq">
|
||||
<div class="lp-wrap-narrow">
|
||||
<h2>Frequently asked questions</h2>
|
||||
<div class="lp-faq" style="margin-top: 24px">
|
||||
<div class="lp-faq-item open">
|
||||
<button class="lp-faq-q">Do I need any prior experience?<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
|
||||
<div class="lp-faq-a">No — the path starts from absolute fundamentals and each course unlocks the next, so you're never dropped into material you're not ready for.</div>
|
||||
</div>
|
||||
<div class="lp-faq-item">
|
||||
<button class="lp-faq-q">Can I buy a single course instead of the whole path?<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
|
||||
<div class="lp-faq-a">Yes, every course is also sold individually — the path bundle saves you 29% and adds the path certificate.</div>
|
||||
</div>
|
||||
<div class="lp-faq-item">
|
||||
<button class="lp-faq-q">Do I have to take the courses in order?<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
|
||||
<div class="lp-faq-a">Yes — this path is sequential. Each course unlocks after you complete the previous one's lessons and exercises. That's what makes the curriculum build properly.</div>
|
||||
</div>
|
||||
<div class="lp-faq-item">
|
||||
<button class="lp-faq-q">How long do I have access?<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
|
||||
<div class="lp-faq-a">Lifetime. Learn at your own pace — most learners finish in 8–12 weeks at 4–5 hours a week.</div>
|
||||
</div>
|
||||
<div class="lp-faq-item">
|
||||
<button class="lp-faq-q">What do I need to earn the certificate?<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
|
||||
<div class="lp-faq-a">Complete every lesson and submit every exercise across all five courses, including the capstone project. The certificate is issued automatically.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== PRICING ===== -->
|
||||
<section class="lp-section" id="pricing">
|
||||
<div class="lp-wrap-narrow">
|
||||
<div class="lp-card lp-pricing-card">
|
||||
<div class="eyebrow">Enroll</div>
|
||||
<div class="lp-price tnum">$199</div>
|
||||
<div class="lp-price-was tnum"><s>$280</s><span class="lp-save">Save $81 (29%)</span></div>
|
||||
<ul class="lp-features">
|
||||
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>All 5 courses, unlocked in order</li>
|
||||
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>52 lessons, 13 exercises, 1 capstone project</li>
|
||||
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Path certificate on completion</li>
|
||||
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Lifetime access</li>
|
||||
</ul>
|
||||
<a class="lp-btn lp-btn-primary lp-btn-lg lp-btn-block" href="lms-home.html">Enroll in this path</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="lp-footer">
|
||||
<div class="lp-wrap lp-footer-grid">
|
||||
<div>
|
||||
<div class="brand"><span class="lp-nav-logo" style="width: 26px; height: 26px; font-size: 12px">A</span>Acme Academy</div>
|
||||
<p class="copy">© 2026 Acme Academy</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Learn</h4>
|
||||
<a href="public-paths.html">Learning Paths</a>
|
||||
<a href="org-landing.html#courses">Courses</a>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Academy</h4>
|
||||
<a href="#">About</a>
|
||||
<a href="lms-home.html">Login</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<button class="lp-theme-btn" id="theme" title="Toggle theme" aria-label="Toggle theme">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg>
|
||||
</button>
|
||||
|
||||
<script>
|
||||
document.getElementById('theme').onclick = () => {
|
||||
const dark = document.documentElement.classList.toggle('dark');
|
||||
localStorage.cioTheme = dark ? 'dark' : 'light';
|
||||
};
|
||||
document.querySelectorAll('.lp-lessons-toggle').forEach((btn) => {
|
||||
btn.addEventListener('click', () => {
|
||||
const lessons = btn.nextElementSibling;
|
||||
const open = lessons.classList.toggle('open');
|
||||
btn.classList.toggle('open', open);
|
||||
btn.firstChild.textContent = open ? 'Hide lesson outline' : 'Show lesson outline';
|
||||
});
|
||||
});
|
||||
document.querySelectorAll('.lp-faq-q').forEach((q) => {
|
||||
q.addEventListener('click', () => q.parentElement.classList.toggle('open'));
|
||||
});
|
||||
// highlight anchor nav on scroll
|
||||
const anchors = [...document.querySelectorAll('.lp-anchor-nav a')];
|
||||
const sections = anchors.map((a) => document.querySelector(a.getAttribute('href')));
|
||||
addEventListener('scroll', () => {
|
||||
let current = 0;
|
||||
sections.forEach((sec, i) => { if (sec && sec.getBoundingClientRect().top < 120) current = i; });
|
||||
anchors.forEach((a, i) => a.classList.toggle('active', i === current));
|
||||
}, { passive: true });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,155 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Learning Paths — Acme Academy</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="landing-theme.css" />
|
||||
<script>
|
||||
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
<style>
|
||||
.compact-hero { padding: 52px 0 44px; }
|
||||
.compact-hero h1 { font-size: clamp(28px, 4.5vw, 40px); }
|
||||
.search { max-width: 560px; margin: 0 auto; position: relative; }
|
||||
.search input {
|
||||
width: 100%; font: inherit; font-size: 15px; padding: 12px 16px 12px 44px;
|
||||
border: 1px solid var(--landing-border); background: var(--landing-card); color: var(--landing-fg);
|
||||
border-radius: var(--landing-radius-button); outline: none;
|
||||
}
|
||||
.search input:focus { border-color: var(--landing-accent); }
|
||||
.search svg { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); width: 17px; height: 17px; stroke-width: 2; color: var(--landing-fg-muted); }
|
||||
.layout { display: grid; grid-template-columns: 260px 1fr; gap: 32px; padding: 40px 0 72px; }
|
||||
.filters { position: sticky; top: 20px; align-self: start; padding: 20px; }
|
||||
.filters h3 { font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--landing-fg-muted); font-weight: 600; margin: 0 0 10px; }
|
||||
.filters .grp { padding-bottom: 16px; margin-bottom: 16px; border-bottom: 1px solid var(--landing-border); }
|
||||
.filters .grp:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; }
|
||||
.f-opt { display: flex; align-items: center; gap: 9px; border: 1px solid var(--landing-border); padding: 8px 12px; font-size: 14px; margin-bottom: 6px; cursor: pointer; border-radius: 6px; }
|
||||
.f-opt:hover { background: var(--landing-card-soft); }
|
||||
.f-opt input { accent-color: var(--landing-accent); margin: 0; }
|
||||
.f-opt .n { margin-left: auto; font-size: 12px; color: var(--landing-fg-muted); }
|
||||
.results { display: flex; flex-direction: column; gap: 20px; min-width: 0; }
|
||||
@media (max-width: 860px) { .layout { grid-template-columns: 1fr; } .filters { position: static; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="lp-nav-outer">
|
||||
<nav class="lp-nav">
|
||||
<a class="lp-nav-brand" href="org-landing.html"><span class="lp-nav-logo">A</span>Acme Academy</a>
|
||||
<div class="lp-nav-links">
|
||||
<a class="active" href="public-paths.html">Learning Paths</a>
|
||||
<a href="org-landing.html#courses">Courses</a>
|
||||
<a class="lp-nav-auth" href="lms-home.html">Login</a>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<header class="lp-hero compact-hero">
|
||||
<div class="lp-hero-dots"></div>
|
||||
<div class="lp-hero-inner">
|
||||
<h1>Learning Paths</h1>
|
||||
<p class="sub" style="margin-bottom: 26px">Guided multi-course tracks with one enrollment, ordered courses, and a certificate at the end.</p>
|
||||
<div class="search">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<input placeholder="Search learning paths…" />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="lp-wrap layout">
|
||||
<!-- filters -->
|
||||
<aside class="lp-card filters">
|
||||
<div class="grp">
|
||||
<h3>Topic</h3>
|
||||
<label class="f-opt"><input type="checkbox" checked />Engineering<span class="n tnum">1</span></label>
|
||||
<label class="f-opt"><input type="checkbox" checked />Data<span class="n tnum">1</span></label>
|
||||
<label class="f-opt"><input type="checkbox" checked />Product<span class="n tnum">1</span></label>
|
||||
</div>
|
||||
<div class="grp">
|
||||
<h3>Pricing</h3>
|
||||
<label class="f-opt"><input type="checkbox" checked />Paid<span class="n tnum">3</span></label>
|
||||
<label class="f-opt"><input type="checkbox" />Free<span class="n tnum">0</span></label>
|
||||
</div>
|
||||
<div class="grp">
|
||||
<h3>Length</h3>
|
||||
<label class="f-opt"><input type="checkbox" />Under 20 hours<span class="n tnum">1</span></label>
|
||||
<label class="f-opt"><input type="checkbox" />20–40 hours<span class="n tnum">2</span></label>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- results -->
|
||||
<div class="results">
|
||||
<a class="lp-card lp-course-card" href="public-path.html">
|
||||
<span class="lp-chip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Path</span>
|
||||
<h3>Frontend Engineering Bootcamp</h3>
|
||||
<p class="desc">Five courses, one path — from your first HTML tag to a deployed React capstone. Learn in order, build real projects, earn a certificate.</p>
|
||||
<div class="lp-meta-row">
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>5 courses</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~38 hours</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>942 enrolled</span>
|
||||
<span class="lp-save tnum">Save $81</span>
|
||||
<span class="price tnum">$199 <s>$280</s></span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a class="lp-card lp-course-card" href="public-path.html">
|
||||
<span class="lp-chip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Path</span>
|
||||
<h3>Data Science with Python</h3>
|
||||
<p class="desc">From Python basics to applied machine learning — pandas, visualization, and a real analysis project, in a fixed order that builds week over week.</p>
|
||||
<div class="lp-meta-row">
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>4 courses</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~30 hours</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>418 enrolled</span>
|
||||
<span class="lp-save tnum">Save $53</span>
|
||||
<span class="price tnum">$159 <s>$212</s></span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a class="lp-card lp-course-card" href="public-path.html">
|
||||
<span class="lp-chip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Path</span>
|
||||
<h3>Product Management Fundamentals</h3>
|
||||
<p class="desc">Discovery, prioritization, delivery, and stakeholder craft — a five-course track for new and aspiring PMs.</p>
|
||||
<div class="lp-meta-row">
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>5 courses</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~18 hours</span>
|
||||
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>207 enrolled</span>
|
||||
<span class="lp-save tnum">Save $46</span>
|
||||
<span class="price tnum">$129 <s>$175</s></span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="lp-footer">
|
||||
<div class="lp-wrap lp-footer-grid">
|
||||
<div>
|
||||
<div class="brand"><span class="lp-nav-logo" style="width: 26px; height: 26px; font-size: 12px">A</span>Acme Academy</div>
|
||||
<p class="copy">© 2026 Acme Academy</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Learn</h4>
|
||||
<a href="public-paths.html">Learning Paths</a>
|
||||
<a href="org-landing.html#courses">Courses</a>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Academy</h4>
|
||||
<a href="#">About</a>
|
||||
<a href="lms-home.html">Login</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<button class="lp-theme-btn" id="theme" title="Toggle theme" aria-label="Toggle theme">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg>
|
||||
</button>
|
||||
|
||||
<script>
|
||||
document.getElementById('theme').onclick = () => {
|
||||
const dark = document.documentElement.classList.toggle('dark');
|
||||
localStorage.cioTheme = dark ? 'dark' : 'light';
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,154 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Path Analytics · ClassroomIO</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="app-theme.css" />
|
||||
<script>
|
||||
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
<style>
|
||||
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 24px; }
|
||||
.funnel-row { display: grid; grid-template-columns: 30px 1fr; gap: 14px; align-items: center; padding: 10px 0; }
|
||||
.f-ord { width: 26px; height: 26px; border-radius: 999px; background: color-mix(in oklab, var(--primary) 10%, transparent); color: var(--primary); display: grid; place-items: center; font-weight: 600; font-size: 12px; }
|
||||
.f-top { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 6px; gap: 10px; }
|
||||
.f-name { font-size: 13.5px; font-weight: 500; }
|
||||
.f-nums { font-size: 12.5px; color: var(--muted-foreground); }
|
||||
.f-nums b { color: var(--foreground); font-weight: 600; }
|
||||
.f-bar { height: 22px; border-radius: var(--radius-sm); background: color-mix(in oklab, var(--primary) 10%, transparent); overflow: hidden; position: relative; }
|
||||
.f-bar > span { position: absolute; inset: 0 auto 0 0; border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: flex-end; padding-right: 8px; font-size: 11.5px; font-weight: 600; color: var(--primary-foreground); }
|
||||
.drop { font-size: 12px; color: var(--muted-foreground); display: flex; align-items: center; gap: 5px; margin-top: 5px; }
|
||||
.drop svg { width: 12px; height: 12px; stroke-width: 2; }
|
||||
.drop.bad { color: var(--destructive); }
|
||||
.stuck { display: flex; flex-direction: column; gap: 8px; }
|
||||
@media (max-width: 900px) { .stats { grid-template-columns: repeat(2, 1fr); } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<aside class="sidebar">
|
||||
<a class="back-link" href="teacher-paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>All Learning Paths</a>
|
||||
<div class="path-id">
|
||||
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
|
||||
<div><div class="nm">Frontend Engineering Bootcamp</div><div class="st st-active"><span class="dot"></span>Active</div></div>
|
||||
</div>
|
||||
<a class="nav-item" href="teacher-path-builder.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>Courses<span class="nav-tail tnum">5</span></a>
|
||||
<a class="nav-item" href="teacher-path-people.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>People<span class="nav-tail tnum">48</span></a>
|
||||
<a class="nav-item active" href="teacher-path-analytics.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/></svg>Analytics</a>
|
||||
<a class="nav-item" href="teacher-path-landing-editor.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>Landing page</a>
|
||||
<a class="nav-item" href="teacher-path-certificate.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>Certificate</a>
|
||||
<a class="nav-item" href="teacher-path-settings.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4"/></svg>Settings</a>
|
||||
<div class="sidebar-foot"><div class="avatar">JD</div><div class="who"><div class="nm">Jordan Diallo</div><div class="rl">Admin</div></div></div>
|
||||
</aside>
|
||||
|
||||
<div class="main">
|
||||
<header class="topbar">
|
||||
<nav class="crumbs">
|
||||
<a href="teacher-paths.html">Learning Paths</a><span class="sep">/</span>
|
||||
<a href="teacher-path-builder.html">Frontend Engineering Bootcamp</a><span class="sep">/</span>
|
||||
<span class="here">Analytics</span>
|
||||
</nav>
|
||||
<div class="top-actions">
|
||||
<button class="icon-btn" id="theme" title="Toggle theme" aria-label="Toggle theme"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg></button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="content">
|
||||
<div class="wrap" style="max-width: 920px">
|
||||
<div class="page-head">
|
||||
<div>
|
||||
<h1 class="page-title">Analytics</h1>
|
||||
<p class="page-sub">How learners are moving through the path.</p>
|
||||
</div>
|
||||
<select class="select" style="max-width: 160px"><option>Last 90 days</option><option>Last 30 days</option><option>All time</option></select>
|
||||
</div>
|
||||
|
||||
<div class="stats">
|
||||
<div class="card stat-card"><div class="k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>Enrolled</div><div class="v tnum">48</div><div class="s">+9 this month</div></div>
|
||||
<div class="card stat-card"><div class="k"><svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M8 5v14l11-7z"/></svg>Active learners</div><div class="v tnum">31</div><div class="s">worked in the last 14 days</div></div>
|
||||
<div class="card stat-card"><div class="k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>Completion rate</div><div class="v tnum">27%</div><div class="s">13 of 48 finished</div></div>
|
||||
<div class="card stat-card"><div class="k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>Avg. time to finish</div><div class="v tnum">9.4 wks</div><div class="s">across completions</div></div>
|
||||
</div>
|
||||
|
||||
<div class="card card-pad" style="margin-bottom: 20px">
|
||||
<h2 class="sec-title" style="margin-bottom: 4px">Course funnel</h2>
|
||||
<p class="page-sub" style="margin-bottom: 14px">How many learners have reached and completed each course, in order.</p>
|
||||
|
||||
<div class="funnel-row">
|
||||
<span class="f-ord tnum">1</span>
|
||||
<div>
|
||||
<div class="f-top"><span class="f-name">HTML & CSS Foundations</span><span class="f-nums tnum"><b>44</b> completed · 3 in progress</span></div>
|
||||
<div class="f-bar"><span style="width: 92%; background: var(--primary)">44</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="funnel-row">
|
||||
<span class="f-ord tnum">2</span>
|
||||
<div>
|
||||
<div class="f-top"><span class="f-name">JavaScript Essentials</span><span class="f-nums tnum"><b>36</b> completed · 6 in progress</span></div>
|
||||
<div class="f-bar"><span style="width: 75%; background: var(--primary)">36</span></div>
|
||||
<div class="drop"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 5v14M19 12l-7 7-7-7"/></svg>8 learners dropped after Course 1</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="funnel-row">
|
||||
<span class="f-ord tnum">3</span>
|
||||
<div>
|
||||
<div class="f-top"><span class="f-name">Modern Web Development with React</span><span class="f-nums tnum"><b>22</b> completed · 9 in progress</span></div>
|
||||
<div class="f-bar"><span style="width: 46%; background: var(--primary)">22</span></div>
|
||||
<div class="drop bad"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 5v14M19 12l-7 7-7-7"/></svg>14 learners dropped after Course 2 — biggest drop-off</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="funnel-row">
|
||||
<span class="f-ord tnum">4</span>
|
||||
<div>
|
||||
<div class="f-top"><span class="f-name">State Management & Data Fetching</span><span class="f-nums tnum"><b>16</b> completed · 4 in progress</span></div>
|
||||
<div class="f-bar"><span style="width: 33%; background: var(--primary)">16</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="funnel-row">
|
||||
<span class="f-ord tnum">5</span>
|
||||
<div>
|
||||
<div class="f-top"><span class="f-name">Building & Shipping a Capstone</span><span class="f-nums tnum"><b>13</b> completed · 2 in progress</span></div>
|
||||
<div class="f-bar"><span style="width: 27%; background: var(--success)">13</span></div>
|
||||
<div class="drop" style="color: var(--success)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>13 certificates awarded</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-pad">
|
||||
<h2 class="sec-title" style="margin-bottom: 4px">Where learners are stuck</h2>
|
||||
<p class="page-sub" style="margin-bottom: 14px">Lessons and exercises blocking the most learners right now.</p>
|
||||
<div class="stuck">
|
||||
<div class="item item-muted" style="padding: 12px 14px">
|
||||
<div class="item-media-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg></div>
|
||||
<div class="item-content">
|
||||
<span class="item-title">Exercise: Build a to-do app · React</span>
|
||||
<span class="item-desc">7 learners have had this exercise in progress for over 2 weeks.</span>
|
||||
</div>
|
||||
<span class="badge badge-warning" style="background: var(--warning-soft); color: var(--warning)">7 stuck</span>
|
||||
</div>
|
||||
<div class="item item-muted" style="padding: 12px 14px">
|
||||
<div class="item-media-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg></div>
|
||||
<div class="item-content">
|
||||
<span class="item-title">Lesson: The useEffect hook · React</span>
|
||||
<span class="item-desc">5 learners stopped at this lesson.</span>
|
||||
</div>
|
||||
<span class="badge badge-warning" style="background: var(--warning-soft); color: var(--warning)">5 stuck</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('theme').onclick = () => {
|
||||
const dark = document.documentElement.classList.toggle('dark');
|
||||
localStorage.cioTheme = dark ? 'dark' : 'light';
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,216 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Path Courses · ClassroomIO</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="app-theme.css" />
|
||||
<script>
|
||||
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
<style>
|
||||
.rule { display: flex; align-items: center; gap: 13px; padding: 14px 16px; margin: 18px 0; }
|
||||
.rule .ico { width: 34px; height: 34px; border-radius: var(--radius-md); background: color-mix(in oklab, var(--primary) 10%, transparent); display: grid; place-items: center; color: var(--primary); flex-shrink: 0; }
|
||||
.rule .ico svg { width: 16px; height: 16px; stroke-width: 2.2; }
|
||||
.rule .txt { flex: 1; }
|
||||
.rule .txt b { font-size: 14px; font-weight: 600; }
|
||||
.rule .txt p { margin: 1px 0 0; font-size: 13px; color: var(--muted-foreground); }
|
||||
.list-head { display: flex; align-items: center; margin: 20px 2px 12px; }
|
||||
.list-head h2 { font-size: 14px; font-weight: 600; margin: 0; }
|
||||
.list-head .hint { margin-left: auto; font-size: 12.5px; color: var(--muted-foreground); display: flex; align-items: center; gap: 6px; }
|
||||
.list-head .hint svg { width: 14px; height: 14px; stroke-width: 2; }
|
||||
.courses { display: flex; flex-direction: column; gap: 8px; }
|
||||
.row { display: grid; grid-template-columns: 24px 32px 60px 1fr auto; align-items: center; gap: 13px; background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 12px 14px; box-shadow: var(--shadow-2xs); transition: opacity 0.12s, border-color 0.12s, box-shadow 0.12s; }
|
||||
.row.dragging { opacity: 0.4; }
|
||||
.row.dragover { border-color: var(--primary); box-shadow: 0 0 0 3px color-mix(in oklab, var(--primary) 15%, transparent); }
|
||||
.grip { color: var(--muted-foreground); cursor: grab; display: grid; place-items: center; }
|
||||
.grip:active { cursor: grabbing; }
|
||||
.grip svg { width: 16px; height: 16px; stroke-width: 2; }
|
||||
.ord { width: 28px; height: 28px; border-radius: var(--radius-md); background: color-mix(in oklab, var(--primary) 10%, transparent); color: var(--primary); display: grid; place-items: center; font-weight: 600; font-size: 13px; }
|
||||
.thumb { width: 60px; height: 42px; border-radius: var(--radius-md); }
|
||||
.r-title { font-size: 14px; font-weight: 500; margin: 0; }
|
||||
.r-meta { font-size: 12px; color: var(--muted-foreground); margin: 2px 0 0; display: flex; align-items: center; gap: 12px; }
|
||||
.r-meta .m { display: flex; align-items: center; gap: 4px; }
|
||||
.r-meta svg { width: 12px; height: 12px; stroke-width: 2; }
|
||||
.r-actions { display: flex; align-items: center; gap: 2px; }
|
||||
.mini { width: 30px; height: 30px; border-radius: var(--radius-md); border: none; background: transparent; display: grid; place-items: center; color: var(--muted-foreground); cursor: pointer; }
|
||||
.mini:hover { background: var(--accent); color: var(--foreground); }
|
||||
.mini.danger:hover { color: var(--destructive); background: color-mix(in oklab, var(--destructive) 10%, transparent); }
|
||||
.mini svg { width: 15px; height: 15px; stroke-width: 2; }
|
||||
.add-course { display: flex; align-items: center; justify-content: center; gap: 8px; border: 1px dashed var(--border); border-radius: var(--radius-md); padding: 13px; color: var(--muted-foreground); font-weight: 500; font-size: 13.5px; cursor: pointer; margin-top: 8px; background: transparent; width: 100%; }
|
||||
.add-course:hover { border-color: var(--primary); color: var(--primary); background: color-mix(in oklab, var(--primary) 5%, transparent); }
|
||||
.add-course svg { width: 16px; height: 16px; stroke-width: 2.2; }
|
||||
.cert-row { display: grid; grid-template-columns: 24px 32px 60px 1fr auto; align-items: center; gap: 13px; padding: 12px 14px; border: 1px dashed var(--border); border-radius: var(--radius-md); margin-top: 8px; color: var(--muted-foreground); }
|
||||
.cert-row .ord { background: var(--muted); color: var(--muted-foreground); border-radius: 999px; }
|
||||
.cert-row .ord svg { width: 14px; height: 14px; stroke-width: 2; }
|
||||
@media (max-width: 720px) { .row, .cert-row { grid-template-columns: 22px 28px 1fr auto; } .thumb { display: none; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<aside class="sidebar">
|
||||
<a class="back-link" href="teacher-paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>All Learning Paths</a>
|
||||
<div class="path-id">
|
||||
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
|
||||
<div><div class="nm">Frontend Engineering Bootcamp</div><div class="st st-active"><span class="dot"></span>Active</div></div>
|
||||
</div>
|
||||
<a class="nav-item active" href="teacher-path-builder.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>Courses<span class="nav-tail tnum">5</span></a>
|
||||
<a class="nav-item" href="teacher-path-people.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>People<span class="nav-tail tnum">48</span></a>
|
||||
<a class="nav-item" href="teacher-path-analytics.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/></svg>Analytics</a>
|
||||
<a class="nav-item" href="teacher-path-landing-editor.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>Landing page</a>
|
||||
<a class="nav-item" href="teacher-path-certificate.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>Certificate</a>
|
||||
<a class="nav-item" href="teacher-path-settings.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4"/></svg>Settings</a>
|
||||
<div class="sidebar-foot"><div class="avatar">JD</div><div class="who"><div class="nm">Jordan Diallo</div><div class="rl">Admin</div></div></div>
|
||||
</aside>
|
||||
|
||||
<div class="main">
|
||||
<header class="topbar">
|
||||
<nav class="crumbs">
|
||||
<a href="teacher-paths.html">Learning Paths</a><span class="sep">/</span>
|
||||
<span class="here">Frontend Engineering Bootcamp</span>
|
||||
</nav>
|
||||
<div class="top-actions">
|
||||
<button class="icon-btn" id="theme" title="Toggle theme" aria-label="Toggle theme"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg></button>
|
||||
<a class="btn btn-outline btn-sm" href="teacher-path-setup.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>Finish setup · 33%</a>
|
||||
<a class="btn btn-outline btn-sm" href="path-detail.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></svg>Preview as student</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="content">
|
||||
<div class="wrap-narrow" style="max-width: 820px">
|
||||
<div class="page-head" style="margin-bottom: 4px">
|
||||
<div>
|
||||
<h1 class="page-title">Courses</h1>
|
||||
<p class="page-sub">Add courses and drag to set the order students move through them.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card rule">
|
||||
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div>
|
||||
<div class="txt">
|
||||
<b>Unlock courses in order</b>
|
||||
<p>Each course stays locked until a student completes the previous one's lessons and exercises. Turn off to allow any order.</p>
|
||||
</div>
|
||||
<label class="switch"><input type="checkbox" checked aria-label="Unlock courses in order" /><span class="track"></span><span class="knob"></span></label>
|
||||
</div>
|
||||
|
||||
<div class="list-head">
|
||||
<h2>5 courses in this path</h2>
|
||||
<span class="hint"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="9" cy="6" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="18" r="1"/></svg>Drag to reorder</span>
|
||||
</div>
|
||||
|
||||
<div class="courses" id="courses">
|
||||
<div class="row" draggable="true">
|
||||
<span class="grip" aria-label="Drag to reorder"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="9" cy="6" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="18" r="1"/></svg></span>
|
||||
<span class="ord tnum">1</span>
|
||||
<span class="thumb" style="background: linear-gradient(135deg, oklch(0.705 0.213 47.604), oklch(0.75 0.183 55.934))"></span>
|
||||
<div>
|
||||
<h3 class="r-title">HTML & CSS Foundations</h3>
|
||||
<p class="r-meta"><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>12 lessons</span><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>2 exercises</span><span class="m">$49</span></p>
|
||||
</div>
|
||||
<div class="r-actions">
|
||||
<button class="mini" title="Open course"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><path d="M15 3h6v6M10 14 21 3"/></svg></button>
|
||||
<button class="mini danger" title="Remove from path"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" draggable="true">
|
||||
<span class="grip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="9" cy="6" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="18" r="1"/></svg></span>
|
||||
<span class="ord tnum">2</span>
|
||||
<span class="thumb" style="background: linear-gradient(135deg, oklch(0.795 0.184 86.047), oklch(0.769 0.188 70.08))"></span>
|
||||
<div>
|
||||
<h3 class="r-title">JavaScript Essentials</h3>
|
||||
<p class="r-meta"><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>10 lessons</span><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>3 exercises</span><span class="m">$59</span></p>
|
||||
</div>
|
||||
<div class="r-actions">
|
||||
<button class="mini" title="Open course"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><path d="M15 3h6v6M10 14 21 3"/></svg></button>
|
||||
<button class="mini danger" title="Remove from path"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" draggable="true">
|
||||
<span class="grip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="9" cy="6" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="18" r="1"/></svg></span>
|
||||
<span class="ord tnum">3</span>
|
||||
<span class="thumb" style="background: linear-gradient(135deg, oklch(0.685 0.169 237.323), oklch(0.488 0.243 264.376))"></span>
|
||||
<div>
|
||||
<h3 class="r-title">Modern Web Development with React</h3>
|
||||
<p class="r-meta"><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>12 lessons</span><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>4 exercises</span><span class="m">$79</span></p>
|
||||
</div>
|
||||
<div class="r-actions">
|
||||
<button class="mini" title="Open course"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><path d="M15 3h6v6M10 14 21 3"/></svg></button>
|
||||
<button class="mini danger" title="Remove from path"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" draggable="true">
|
||||
<span class="grip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="9" cy="6" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="18" r="1"/></svg></span>
|
||||
<span class="ord tnum">4</span>
|
||||
<span class="thumb" style="background: linear-gradient(135deg, oklch(0.585 0.233 277.117), oklch(0.606 0.25 292.717))"></span>
|
||||
<div>
|
||||
<h3 class="r-title">State Management & Data Fetching</h3>
|
||||
<p class="r-meta"><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>10 lessons</span><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>3 exercises</span><span class="m">$59</span></p>
|
||||
</div>
|
||||
<div class="r-actions">
|
||||
<button class="mini" title="Open course"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><path d="M15 3h6v6M10 14 21 3"/></svg></button>
|
||||
<button class="mini danger" title="Remove from path"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" draggable="true">
|
||||
<span class="grip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="9" cy="6" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="18" r="1"/></svg></span>
|
||||
<span class="ord tnum">5</span>
|
||||
<span class="thumb" style="background: linear-gradient(135deg, oklch(0.645 0.246 16.439), oklch(0.586 0.253 17.585))"></span>
|
||||
<div>
|
||||
<h3 class="r-title">Building & Shipping a Capstone</h3>
|
||||
<p class="r-meta"><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>7 lessons</span><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>1 capstone</span><span class="m">$34</span></p>
|
||||
</div>
|
||||
<div class="r-actions">
|
||||
<button class="mini" title="Open course"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><path d="M15 3h6v6M10 14 21 3"/></svg></button>
|
||||
<button class="mini danger" title="Remove from path"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="add-course"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 5v14M5 12h14"/></svg>Add course to path</button>
|
||||
|
||||
<div class="cert-row">
|
||||
<span></span>
|
||||
<span class="ord"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg></span>
|
||||
<span></span>
|
||||
<div><h3 class="r-title" style="color: var(--foreground)">Path certificate</h3><p class="r-meta">Awarded automatically when a student completes all 5 courses.</p></div>
|
||||
<div class="r-actions"><a class="mini" href="teacher-path-certificate.html" title="Configure certificate"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2"/></svg></a></div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('theme').onclick = () => {
|
||||
const dark = document.documentElement.classList.toggle('dark');
|
||||
localStorage.cioTheme = dark ? 'dark' : 'light';
|
||||
};
|
||||
const listEl = document.getElementById('courses');
|
||||
let dragEl = null;
|
||||
listEl.querySelectorAll('.row').forEach((row) => {
|
||||
row.addEventListener('dragstart', () => { dragEl = row; row.classList.add('dragging'); });
|
||||
row.addEventListener('dragend', () => {
|
||||
row.classList.remove('dragging');
|
||||
listEl.querySelectorAll('.row').forEach((r) => r.classList.remove('dragover'));
|
||||
listEl.querySelectorAll('.row .ord').forEach((el, i) => { el.textContent = i + 1; });
|
||||
});
|
||||
row.addEventListener('dragover', (e) => {
|
||||
e.preventDefault();
|
||||
if (row === dragEl) return;
|
||||
const rect = row.getBoundingClientRect();
|
||||
const after = e.clientY > rect.top + rect.height / 2;
|
||||
listEl.querySelectorAll('.row').forEach((r) => r.classList.remove('dragover'));
|
||||
row.classList.add('dragover');
|
||||
listEl.insertBefore(dragEl, after ? row.nextSibling : row);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,127 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Path Certificate · ClassroomIO</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="app-theme.css" />
|
||||
<script>
|
||||
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
<style>
|
||||
.fset { margin-top: 16px; }
|
||||
.fset-head { display: flex; align-items: center; gap: 12px; padding: 16px 20px; border-bottom: 1px solid var(--border); }
|
||||
.fset-head h2 { font-size: 14.5px; font-weight: 600; margin: 0; }
|
||||
.fset-head p { font-size: 12.5px; color: var(--muted-foreground); margin: 2px 0 0; }
|
||||
.fset-body { padding: 18px 20px; }
|
||||
/* certificate preview */
|
||||
.cert-frame { border: 1px solid var(--border); border-radius: var(--radius-md); padding: 28px; background: var(--background); position: relative; }
|
||||
.cert-frame::before { content: ''; position: absolute; inset: 8px; border: 1px solid color-mix(in oklab, var(--primary) 30%, transparent); border-radius: var(--radius-sm); pointer-events: none; }
|
||||
.cert-inner { text-align: center; padding: 12px 8px; }
|
||||
.cert-org { font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted-foreground); margin-bottom: 14px; }
|
||||
.cert-title { font-size: 20px; font-weight: 600; letter-spacing: -0.01em; margin: 0 0 4px; }
|
||||
.cert-sub { font-size: 12.5px; color: var(--muted-foreground); margin: 0 0 14px; }
|
||||
.cert-name { font-size: 17px; font-weight: 500; border-bottom: 1px solid var(--border); display: inline-block; padding: 0 24px 6px; margin-bottom: 14px; }
|
||||
.cert-meta { display: flex; justify-content: center; gap: 28px; font-size: 11.5px; color: var(--muted-foreground); }
|
||||
.cert-seal { width: 44px; height: 44px; border-radius: 999px; background: color-mix(in oklab, var(--primary) 10%, transparent); color: var(--primary); display: grid; place-items: center; margin: 0 auto 12px; }
|
||||
.cert-seal svg { width: 22px; height: 22px; stroke-width: 2; }
|
||||
.req { display: flex; align-items: center; gap: 8px; font-size: 13px; margin-bottom: 8px; }
|
||||
.req svg { width: 15px; height: 15px; stroke-width: 2.2; color: var(--success); flex-shrink: 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<aside class="sidebar">
|
||||
<a class="back-link" href="teacher-paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>All Learning Paths</a>
|
||||
<div class="path-id">
|
||||
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
|
||||
<div><div class="nm">Frontend Engineering Bootcamp</div><div class="st st-active"><span class="dot"></span>Active</div></div>
|
||||
</div>
|
||||
<a class="nav-item" href="teacher-path-builder.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>Courses<span class="nav-tail tnum">5</span></a>
|
||||
<a class="nav-item" href="teacher-path-people.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>People<span class="nav-tail tnum">48</span></a>
|
||||
<a class="nav-item" href="teacher-path-analytics.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/></svg>Analytics</a>
|
||||
<a class="nav-item" href="teacher-path-landing-editor.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>Landing page</a>
|
||||
<a class="nav-item active" href="teacher-path-certificate.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>Certificate</a>
|
||||
<a class="nav-item" href="teacher-path-settings.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4"/></svg>Settings</a>
|
||||
<div class="sidebar-foot"><div class="avatar">JD</div><div class="who"><div class="nm">Jordan Diallo</div><div class="rl">Admin</div></div></div>
|
||||
</aside>
|
||||
|
||||
<div class="main">
|
||||
<header class="topbar">
|
||||
<nav class="crumbs">
|
||||
<a href="teacher-paths.html">Learning Paths</a><span class="sep">/</span>
|
||||
<a href="teacher-path-builder.html">Frontend Engineering Bootcamp</a><span class="sep">/</span>
|
||||
<span class="here">Certificate</span>
|
||||
</nav>
|
||||
<div class="top-actions">
|
||||
<button class="icon-btn" id="theme" title="Toggle theme" aria-label="Toggle theme"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg></button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="content">
|
||||
<div class="wrap-narrow">
|
||||
<div class="page-head" style="margin-bottom: 6px">
|
||||
<div>
|
||||
<h1 class="page-title">Certificate</h1>
|
||||
<p class="page-sub">Award a path-level certificate when a learner completes every course.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="card fset">
|
||||
<div class="fset-head">
|
||||
<div style="flex: 1"><h2>Award a path certificate</h2><p>Issued automatically on completion and shown in the learner's Certificates page.</p></div>
|
||||
<label class="switch"><input type="checkbox" checked aria-label="Award a path certificate" /><span class="track"></span><span class="knob"></span></label>
|
||||
</div>
|
||||
<div class="fset-body">
|
||||
<div class="req"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>All 5 courses completed — every lesson finished</div>
|
||||
<div class="req"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>All exercises submitted or passed in each course</div>
|
||||
<p class="hint" style="margin-top: 10px">Completion rules follow the path's unlock rule (lessons + exercises). 13 certificates awarded so far.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card fset">
|
||||
<div class="fset-head"><div><h2>Certificate details</h2><p>What appears on the issued certificate.</p></div></div>
|
||||
<div class="fset-body">
|
||||
<div class="field">
|
||||
<label class="label" for="ct">Certificate title</label>
|
||||
<input class="input" id="ct" value="Frontend Engineering Bootcamp Certificate" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label" for="cs">Issued by</label>
|
||||
<input class="input" id="cs" value="Acme Academy" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<span class="label">Preview</span>
|
||||
<div class="cert-frame">
|
||||
<div class="cert-inner">
|
||||
<div class="cert-seal"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg></div>
|
||||
<div class="cert-org">Acme Academy</div>
|
||||
<h3 class="cert-title">Frontend Engineering Bootcamp Certificate</h3>
|
||||
<p class="cert-sub">This certifies that</p>
|
||||
<div class="cert-name">Ada Okafor</div>
|
||||
<p class="cert-sub">has successfully completed all 5 courses in the Frontend Engineering Bootcamp learning path.</p>
|
||||
<div class="cert-meta tnum"><span>Issued · Jul 25, 2026</span><span>ID · LP-8F42-19AC</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex; gap: 8px; justify-content: flex-end">
|
||||
<button class="btn btn-ghost btn-sm">Discard</button>
|
||||
<button class="btn btn-primary btn-sm">Save changes</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('theme').onclick = () => {
|
||||
const dark = document.documentElement.classList.toggle('dark');
|
||||
localStorage.cioTheme = dark ? 'dark' : 'light';
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,227 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Path Landing Page · ClassroomIO</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="app-theme.css" />
|
||||
<script>
|
||||
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
<style>
|
||||
.fset { margin-top: 16px; }
|
||||
.fset-head { display: flex; align-items: center; gap: 12px; padding: 16px 20px; border-bottom: 1px solid var(--border); }
|
||||
.fset-head h2 { font-size: 14.5px; font-weight: 600; margin: 0; flex: 1; }
|
||||
.fset-head p { font-size: 12.5px; color: var(--muted-foreground); margin: 2px 0 0; }
|
||||
.fset-body { padding: 18px 20px; }
|
||||
.bullet-row { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
|
||||
.bullet-row svg { width: 15px; height: 15px; color: var(--success); stroke-width: 2.2; flex-shrink: 0; }
|
||||
.bullet-row .mini { margin-left: auto; }
|
||||
.tag-row { display: flex; flex-wrap: wrap; gap: 8px; }
|
||||
.tag { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--border); border-radius: 999px; padding: 4px 12px; font-size: 13px; }
|
||||
.tag button { border: none; background: none; color: var(--muted-foreground); cursor: pointer; display: grid; place-items: center; padding: 0; }
|
||||
.tag button svg { width: 12px; height: 12px; stroke-width: 2.4; }
|
||||
.mini { width: 28px; height: 28px; border-radius: var(--radius-md); border: none; background: transparent; display: grid; place-items: center; color: var(--muted-foreground); cursor: pointer; flex-shrink: 0; }
|
||||
.mini:hover { background: var(--accent); color: var(--foreground); }
|
||||
.mini svg { width: 14px; height: 14px; stroke-width: 2; }
|
||||
.add-inline { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 500; color: var(--primary); background: none; border: none; cursor: pointer; padding: 6px 0 0; }
|
||||
.add-inline svg { width: 14px; height: 14px; stroke-width: 2.2; }
|
||||
.radio-card { display: flex; align-items: flex-start; gap: 12px; border: 1px solid var(--border); border-radius: var(--radius-md); padding: 12px 14px; cursor: pointer; margin-bottom: 8px; }
|
||||
.radio-card:hover { background: color-mix(in oklab, var(--accent) 50%, transparent); }
|
||||
.radio-card.sel { border-color: var(--primary); background: color-mix(in oklab, var(--primary) 5%, transparent); }
|
||||
.rdot { width: 16px; height: 16px; border-radius: 999px; border: 1.5px solid var(--input); flex-shrink: 0; margin-top: 2px; display: grid; place-items: center; }
|
||||
.radio-card.sel .rdot { border-color: var(--primary); }
|
||||
.radio-card.sel .rdot::after { content: ''; width: 8px; height: 8px; border-radius: 999px; background: var(--primary); }
|
||||
.rt { font-size: 13.5px; font-weight: 500; }
|
||||
.rd { font-size: 12.5px; color: var(--muted-foreground); margin-top: 1px; }
|
||||
.savebar { position: sticky; bottom: 12px; margin-top: 20px; background: color-mix(in oklab, var(--background) 94%, transparent); backdrop-filter: blur(8px); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 10px 14px; display: flex; align-items: center; gap: 12px; box-shadow: var(--shadow-md); }
|
||||
.savebar .msg { font-size: 13px; color: var(--muted-foreground); }
|
||||
.savebar .actions { margin-left: auto; display: flex; gap: 8px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<aside class="sidebar">
|
||||
<a class="back-link" href="teacher-paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>All Learning Paths</a>
|
||||
<div class="path-id">
|
||||
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
|
||||
<div><div class="nm">Frontend Engineering Bootcamp</div><div class="st st-active"><span class="dot"></span>Active</div></div>
|
||||
</div>
|
||||
<a class="nav-item" href="teacher-path-builder.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>Courses<span class="nav-tail tnum">5</span></a>
|
||||
<a class="nav-item" href="teacher-path-people.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>People<span class="nav-tail tnum">48</span></a>
|
||||
<a class="nav-item" href="teacher-path-analytics.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/></svg>Analytics</a>
|
||||
<a class="nav-item active" href="teacher-path-landing-editor.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>Landing page</a>
|
||||
<a class="nav-item" href="teacher-path-certificate.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>Certificate</a>
|
||||
<a class="nav-item" href="teacher-path-settings.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4"/></svg>Settings</a>
|
||||
<div class="sidebar-foot"><div class="avatar">JD</div><div class="who"><div class="nm">Jordan Diallo</div><div class="rl">Admin</div></div></div>
|
||||
</aside>
|
||||
|
||||
<div class="main">
|
||||
<header class="topbar">
|
||||
<nav class="crumbs">
|
||||
<a href="teacher-paths.html">Learning Paths</a><span class="sep">/</span>
|
||||
<a href="teacher-path-builder.html">Frontend Engineering Bootcamp</a><span class="sep">/</span>
|
||||
<span class="here">Landing page</span>
|
||||
</nav>
|
||||
<div class="top-actions">
|
||||
<button class="icon-btn" id="theme" title="Toggle theme" aria-label="Toggle theme"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg></button>
|
||||
<a class="btn btn-outline btn-sm" href="public-path.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><path d="M15 3h6v6M10 14 21 3"/></svg>View live page</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="content">
|
||||
<div class="wrap-narrow">
|
||||
<div class="page-head" style="margin-bottom: 6px">
|
||||
<div>
|
||||
<h1 class="page-title">Landing page</h1>
|
||||
<p class="page-sub">Control what visitors see on the public path page at <span style="color: var(--foreground)">/path/frontend-engineering-bootcamp</span>.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hero -->
|
||||
<section class="card fset">
|
||||
<div class="fset-head"><div><h2>Hero</h2><p>The headline visitors see first.</p></div></div>
|
||||
<div class="fset-body">
|
||||
<div class="field">
|
||||
<label class="label" for="hl">Headline</label>
|
||||
<input class="input" id="hl" value="Become a job-ready frontend engineer" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label" for="sub">Subheadline</label>
|
||||
<textarea class="textarea" id="sub">Five courses, one path — from your first HTML tag to a deployed React capstone. Learn in order, build real projects, earn a certificate.</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Visitor access -->
|
||||
<section class="card fset">
|
||||
<div class="fset-head"><div><h2>Visitor access</h2><p>How much of the path a non-enrolled visitor can explore.</p></div></div>
|
||||
<div class="fset-body">
|
||||
<label class="radio-card"><span class="rdot"></span><span><span class="rt">Teaser only</span><span class="rd" style="display: block">Path description, course titles, and price — no lesson detail.</span></span></label>
|
||||
<label class="radio-card sel"><span class="rdot"></span><span><span class="rt">Full syllabus</span><span class="rd" style="display: block">Visitors see every course and its lesson outline, but no content.</span></span></label>
|
||||
<label class="radio-card"><span class="rdot"></span><span><span class="rt">Syllabus + preview lessons</span><span class="rd" style="display: block">Full outline, plus lessons marked as previews are free to open.</span></span></label>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- What you'll learn -->
|
||||
<section class="card fset">
|
||||
<div class="fset-head"><div><h2>What you'll learn</h2><p>Outcome bullets shown near the top of the page.</p></div></div>
|
||||
<div class="fset-body">
|
||||
<div class="bullet-row"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg><input class="input" value="Build responsive, accessible websites with semantic HTML and modern CSS" /><button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button></div>
|
||||
<div class="bullet-row"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg><input class="input" value="Write production JavaScript: async, APIs, and the DOM" /><button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button></div>
|
||||
<div class="bullet-row"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg><input class="input" value="Build and ship interactive React apps with state, hooks, and data fetching" /><button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button></div>
|
||||
<div class="bullet-row"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg><input class="input" value="Complete a portfolio-ready capstone project, deployed to production" /><button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button></div>
|
||||
<button class="add-inline"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 5v14M5 12h14"/></svg>Add outcome</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Skills -->
|
||||
<section class="card fset">
|
||||
<div class="fset-head"><div><h2>Skills</h2><p>Tags shown as "Skills you'll gain".</p></div></div>
|
||||
<div class="fset-body">
|
||||
<div class="tag-row">
|
||||
<span class="tag">HTML & CSS<button><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 6 6 18M6 6l12 12"/></svg></button></span>
|
||||
<span class="tag">Flexbox & Grid<button><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 6 6 18M6 6l12 12"/></svg></button></span>
|
||||
<span class="tag">JavaScript<button><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 6 6 18M6 6l12 12"/></svg></button></span>
|
||||
<span class="tag">REST APIs<button><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 6 6 18M6 6l12 12"/></svg></button></span>
|
||||
<span class="tag">React<button><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 6 6 18M6 6l12 12"/></svg></button></span>
|
||||
<span class="tag">State management<button><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 6 6 18M6 6l12 12"/></svg></button></span>
|
||||
<span class="tag">Deployment<button><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 6 6 18M6 6l12 12"/></svg></button></span>
|
||||
</div>
|
||||
<button class="add-inline"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 5v14M5 12h14"/></svg>Add skill</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Instructors -->
|
||||
<section class="card fset">
|
||||
<div class="fset-head">
|
||||
<div style="flex: 1"><h2>Instructors</h2><p>Pulled from the tutors of the courses in this path.</p></div>
|
||||
<label class="switch"><input type="checkbox" checked aria-label="Show instructors" /><span class="track"></span><span class="knob"></span></label>
|
||||
</div>
|
||||
<div class="fset-body" style="display: flex; gap: 10px; flex-wrap: wrap">
|
||||
<span class="badge badge-outline" style="padding: 6px 12px"><span class="avatar" style="width: 20px; height: 20px; font-size: 9px">JD</span>Jordan Diallo</span>
|
||||
<span class="badge badge-outline" style="padding: 6px 12px"><span class="avatar" style="width: 20px; height: 20px; font-size: 9px">EO</span>Efe Obi</span>
|
||||
<span class="badge badge-outline" style="padding: 6px 12px"><span class="avatar" style="width: 20px; height: 20px; font-size: 9px">RM</span>Rita Mensah</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Testimonials -->
|
||||
<section class="card fset">
|
||||
<div class="fset-head">
|
||||
<div style="flex: 1"><h2>Testimonials</h2><p>Learner quotes shown on the public page.</p></div>
|
||||
<label class="switch"><input type="checkbox" checked aria-label="Show testimonials" /><span class="track"></span><span class="knob"></span></label>
|
||||
</div>
|
||||
<div class="fset-body">
|
||||
<div class="item item-outline" style="padding: 12px 14px; margin-bottom: 8px">
|
||||
<span class="avatar">TB</span>
|
||||
<div class="item-content">
|
||||
<span class="item-title">Tunde Bello</span>
|
||||
<span class="item-desc">"I went from zero to deploying my own React app in ten weeks. The order of the courses just makes sense."</span>
|
||||
</div>
|
||||
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></svg></button>
|
||||
</div>
|
||||
<div class="item item-outline" style="padding: 12px 14px">
|
||||
<span class="avatar">MK</span>
|
||||
<div class="item-content">
|
||||
<span class="item-title">Mariam Kone</span>
|
||||
<span class="item-desc">"The locked courses kept me honest — no skipping ahead, and everything built on what came before."</span>
|
||||
</div>
|
||||
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></svg></button>
|
||||
</div>
|
||||
<button class="add-inline"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 5v14M5 12h14"/></svg>Add testimonial</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FAQ -->
|
||||
<section class="card fset">
|
||||
<div class="fset-head">
|
||||
<div style="flex: 1"><h2>FAQ</h2><p>Collapsible questions at the bottom of the page.</p></div>
|
||||
<label class="switch"><input type="checkbox" checked aria-label="Show FAQ" /><span class="track"></span><span class="knob"></span></label>
|
||||
</div>
|
||||
<div class="fset-body">
|
||||
<div class="item item-outline" style="padding: 12px 14px; margin-bottom: 8px">
|
||||
<div class="item-content">
|
||||
<span class="item-title">Do I need any prior experience?</span>
|
||||
<span class="item-desc">No — the path starts from absolute fundamentals and each course unlocks the next.</span>
|
||||
</div>
|
||||
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></svg></button>
|
||||
</div>
|
||||
<div class="item item-outline" style="padding: 12px 14px">
|
||||
<div class="item-content">
|
||||
<span class="item-title">Can I buy a single course instead?</span>
|
||||
<span class="item-desc">Yes, every course is also sold individually — the path bundle saves you 29%.</span>
|
||||
</div>
|
||||
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></svg></button>
|
||||
</div>
|
||||
<button class="add-inline"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 5v14M5 12h14"/></svg>Add question</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="savebar">
|
||||
<span class="msg">Unsaved changes</span>
|
||||
<div class="actions">
|
||||
<button class="btn btn-ghost btn-sm">Discard</button>
|
||||
<button class="btn btn-primary btn-sm">Save changes</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('theme').onclick = () => {
|
||||
const dark = document.documentElement.classList.toggle('dark');
|
||||
localStorage.cioTheme = dark ? 'dark' : 'light';
|
||||
};
|
||||
document.querySelectorAll('.radio-card').forEach((r) => {
|
||||
r.addEventListener('click', () => {
|
||||
document.querySelector('.radio-card.sel')?.classList.remove('sel');
|
||||
r.classList.add('sel');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,139 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Path People · ClassroomIO</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="app-theme.css" />
|
||||
<script>
|
||||
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
<style>
|
||||
.toolbar { display: flex; gap: 10px; margin-bottom: 16px; flex-wrap: wrap; }
|
||||
.toolbar .input { max-width: 280px; }
|
||||
.grid-cols { grid-template-columns: 1.8fr 1.4fr 1.1fr 0.8fr 36px; }
|
||||
.person { display: flex; align-items: center; gap: 10px; min-width: 0; }
|
||||
.person .nm { font-size: 14px; font-weight: 500; }
|
||||
.person .em { font-size: 12px; color: var(--muted-foreground); }
|
||||
.prog-cell { display: flex; align-items: center; gap: 10px; }
|
||||
.prog-cell .p { font-size: 12.5px; font-weight: 600; min-width: 34px; text-align: right; }
|
||||
.cur { font-size: 13px; color: var(--foreground); display: flex; align-items: center; gap: 6px; min-width: 0; }
|
||||
.cur .n { width: 20px; height: 20px; border-radius: 999px; background: color-mix(in oklab, var(--primary) 10%, transparent); color: var(--primary); display: grid; place-items: center; font-size: 11px; font-weight: 600; flex-shrink: 0; }
|
||||
.cur span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.mini { width: 30px; height: 30px; border-radius: var(--radius-md); border: none; background: transparent; display: grid; place-items: center; color: var(--muted-foreground); cursor: pointer; }
|
||||
.mini:hover { background: var(--accent); color: var(--foreground); }
|
||||
.mini svg { width: 15px; height: 15px; stroke-width: 2; }
|
||||
.note-banner { display: flex; align-items: center; gap: 10px; padding: 11px 14px; border-radius: var(--radius-md); background: color-mix(in oklab, var(--primary) 7%, transparent); border: 1px solid color-mix(in oklab, var(--primary) 20%, transparent); font-size: 13px; color: var(--foreground); margin-bottom: 16px; }
|
||||
.note-banner svg { width: 15px; height: 15px; stroke-width: 2; color: var(--primary); flex-shrink: 0; }
|
||||
@media (max-width: 860px) { .thead { display: none; } .trow.grid-cols { grid-template-columns: 1fr auto; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<aside class="sidebar">
|
||||
<a class="back-link" href="teacher-paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>All Learning Paths</a>
|
||||
<div class="path-id">
|
||||
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
|
||||
<div><div class="nm">Frontend Engineering Bootcamp</div><div class="st st-active"><span class="dot"></span>Active</div></div>
|
||||
</div>
|
||||
<a class="nav-item" href="teacher-path-builder.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>Courses<span class="nav-tail tnum">5</span></a>
|
||||
<a class="nav-item active" href="teacher-path-people.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>People<span class="nav-tail tnum">48</span></a>
|
||||
<a class="nav-item" href="teacher-path-analytics.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/></svg>Analytics</a>
|
||||
<a class="nav-item" href="teacher-path-landing-editor.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>Landing page</a>
|
||||
<a class="nav-item" href="teacher-path-certificate.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>Certificate</a>
|
||||
<a class="nav-item" href="teacher-path-settings.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4"/></svg>Settings</a>
|
||||
<div class="sidebar-foot"><div class="avatar">JD</div><div class="who"><div class="nm">Jordan Diallo</div><div class="rl">Admin</div></div></div>
|
||||
</aside>
|
||||
|
||||
<div class="main">
|
||||
<header class="topbar">
|
||||
<nav class="crumbs">
|
||||
<a href="teacher-paths.html">Learning Paths</a><span class="sep">/</span>
|
||||
<a href="teacher-path-builder.html">Frontend Engineering Bootcamp</a><span class="sep">/</span>
|
||||
<span class="here">People</span>
|
||||
</nav>
|
||||
<div class="top-actions">
|
||||
<button class="icon-btn" id="theme" title="Toggle theme" aria-label="Toggle theme"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg></button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="content">
|
||||
<div class="wrap" style="max-width: 980px">
|
||||
<div class="page-head">
|
||||
<div>
|
||||
<h1 class="page-title">People</h1>
|
||||
<p class="page-sub">48 learners enrolled in this path.</p>
|
||||
</div>
|
||||
<a class="btn btn-primary"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M19 8v6M22 11h-6"/></svg>Add learners</a>
|
||||
</div>
|
||||
|
||||
<div class="note-banner">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 8v4M12 16h.01"/></svg>
|
||||
Adding a learner to this path automatically enrolls them in all 5 courses. Removing them preserves their course access and progress.
|
||||
</div>
|
||||
|
||||
<div class="toolbar">
|
||||
<input class="input" placeholder="Search by name or email…" />
|
||||
<select class="select" style="max-width: 180px">
|
||||
<option>All progress</option><option>Not started</option><option>In progress</option><option>Completed</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="card" style="overflow: hidden">
|
||||
<div class="thead grid-cols"><span>Learner</span><span>Path progress</span><span>Current course</span><span>Enrolled</span><span></span></div>
|
||||
|
||||
<div class="trow grid-cols">
|
||||
<div class="person"><span class="avatar">AO</span><div style="min-width: 0"><div class="nm">Ada Okafor</div><div class="em">a•••@gmail.com</div></div></div>
|
||||
<div class="prog-cell"><div class="progress progress-thin"><span style="width: 49%"></span></div><span class="p tnum">49%</span></div>
|
||||
<span class="cur"><span class="n tnum">3</span><span>React</span></span>
|
||||
<span class="text-muted tnum" style="font-size: 13px">May 2</span>
|
||||
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></button>
|
||||
</div>
|
||||
|
||||
<div class="trow grid-cols">
|
||||
<div class="person"><span class="avatar">TB</span><div style="min-width: 0"><div class="nm">Tunde Bello</div><div class="em">t•••@yahoo.com</div></div></div>
|
||||
<div class="prog-cell"><div class="progress progress-thin progress-success"><span style="width: 100%"></span></div><span class="p tnum" style="color: var(--success)">100%</span></div>
|
||||
<span class="badge badge-success-soft"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>Certificate earned</span>
|
||||
<span class="text-muted tnum" style="font-size: 13px">Mar 18</span>
|
||||
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></button>
|
||||
</div>
|
||||
|
||||
<div class="trow grid-cols">
|
||||
<div class="person"><span class="avatar">MK</span><div style="min-width: 0"><div class="nm">Mariam Kone</div><div class="em">m•••@outlook.com</div></div></div>
|
||||
<div class="prog-cell"><div class="progress progress-thin"><span style="width: 74%"></span></div><span class="p tnum">74%</span></div>
|
||||
<span class="cur"><span class="n tnum">4</span><span>State & Data</span></span>
|
||||
<span class="text-muted tnum" style="font-size: 13px">Apr 11</span>
|
||||
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></button>
|
||||
</div>
|
||||
|
||||
<div class="trow grid-cols">
|
||||
<div class="person"><span class="avatar">SD</span><div style="min-width: 0"><div class="nm">Sam Diallo</div><div class="em">s•••@gmail.com</div></div></div>
|
||||
<div class="prog-cell"><div class="progress progress-thin"><span style="width: 12%"></span></div><span class="p tnum">12%</span></div>
|
||||
<span class="cur"><span class="n tnum">1</span><span>HTML & CSS</span></span>
|
||||
<span class="text-muted tnum" style="font-size: 13px">Jul 8</span>
|
||||
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></button>
|
||||
</div>
|
||||
|
||||
<div class="trow grid-cols">
|
||||
<div class="person"><span class="avatar">LN</span><div style="min-width: 0"><div class="nm">Lara Nwosu</div><div class="em">l•••@proton.me</div></div></div>
|
||||
<div class="prog-cell"><div class="progress progress-thin"><span style="width: 0%"></span></div><span class="p tnum">0%</span></div>
|
||||
<span class="badge badge-muted">Not started</span>
|
||||
<span class="text-muted tnum" style="font-size: 13px">Jul 21</span>
|
||||
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('theme').onclick = () => {
|
||||
const dark = document.documentElement.classList.toggle('dark');
|
||||
localStorage.cioTheme = dark ? 'dark' : 'light';
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,216 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Path Settings · ClassroomIO</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="app-theme.css" />
|
||||
<script>
|
||||
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
<style>
|
||||
.fset { margin-top: 16px; }
|
||||
.fset-head { padding: 16px 20px; border-bottom: 1px solid var(--border); }
|
||||
.fset-head h2 { font-size: 14.5px; font-weight: 600; margin: 0; }
|
||||
.fset-head p { font-size: 12.5px; color: var(--muted-foreground); margin: 2px 0 0; }
|
||||
.fset-body { padding: 18px 20px; }
|
||||
.cover-pick { display: flex; gap: 14px; align-items: center; }
|
||||
.cover-prev { width: 150px; height: 84px; border-radius: var(--radius-md); flex-shrink: 0; background: radial-gradient(120% 150% at 10% -20%, oklch(0.623 0.214 259.815) 0%, transparent 55%), linear-gradient(120deg, oklch(0.488 0.243 264.376), oklch(0.546 0.245 262.881)); }
|
||||
.trow2 { display: flex; align-items: center; gap: 14px; padding: 4px 0; }
|
||||
.trow2 .tt { font-size: 14px; font-weight: 500; }
|
||||
.trow2 .td { font-size: 12.5px; color: var(--muted-foreground); margin-top: 2px; }
|
||||
.trow2 .grow { flex: 1; }
|
||||
.sep { height: 1px; background: var(--border); margin: 14px 0; }
|
||||
.price-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
|
||||
.save-note { display: flex; align-items: center; gap: 8px; margin-top: 12px; padding: 10px 12px; border-radius: var(--radius-md); background: var(--success-soft); color: var(--success); font-size: 13px; font-weight: 500; }
|
||||
.save-note svg { width: 15px; height: 15px; stroke-width: 2.2; flex-shrink: 0; }
|
||||
.radio-card { display: flex; align-items: flex-start; gap: 12px; border: 1px solid var(--border); border-radius: var(--radius-md); padding: 12px 14px; cursor: pointer; margin-bottom: 8px; }
|
||||
.radio-card.sel { border-color: var(--primary); background: color-mix(in oklab, var(--primary) 5%, transparent); }
|
||||
.rdot { width: 16px; height: 16px; border-radius: 999px; border: 1.5px solid var(--input); flex-shrink: 0; margin-top: 2px; display: grid; place-items: center; }
|
||||
.radio-card.sel .rdot { border-color: var(--primary); }
|
||||
.radio-card.sel .rdot::after { content: ''; width: 8px; height: 8px; border-radius: 999px; background: var(--primary); }
|
||||
.rt { font-size: 13.5px; font-weight: 500; display: flex; align-items: center; gap: 8px; }
|
||||
.rd { font-size: 12.5px; color: var(--muted-foreground); margin-top: 1px; display: block; }
|
||||
.danger-zone { border-color: color-mix(in oklab, var(--destructive) 35%, transparent); }
|
||||
.danger-zone .fset-head h2 { color: var(--destructive); }
|
||||
.savebar { position: sticky; bottom: 12px; margin-top: 20px; background: color-mix(in oklab, var(--background) 94%, transparent); backdrop-filter: blur(8px); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 10px 14px; display: flex; align-items: center; gap: 12px; box-shadow: var(--shadow-md); }
|
||||
.savebar .msg { font-size: 13px; color: var(--muted-foreground); }
|
||||
.savebar .actions { margin-left: auto; display: flex; gap: 8px; }
|
||||
@media (max-width: 680px) { .price-row { grid-template-columns: 1fr; } .cover-pick { flex-direction: column; align-items: stretch; } .cover-prev { width: 100%; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<aside class="sidebar">
|
||||
<a class="back-link" href="teacher-paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>All Learning Paths</a>
|
||||
<div class="path-id">
|
||||
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
|
||||
<div><div class="nm">Frontend Engineering Bootcamp</div><div class="st st-active"><span class="dot"></span>Active</div></div>
|
||||
</div>
|
||||
<a class="nav-item" href="teacher-path-builder.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>Courses<span class="nav-tail tnum">5</span></a>
|
||||
<a class="nav-item" href="teacher-path-people.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>People<span class="nav-tail tnum">48</span></a>
|
||||
<a class="nav-item" href="teacher-path-analytics.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/></svg>Analytics</a>
|
||||
<a class="nav-item" href="teacher-path-landing-editor.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>Landing page</a>
|
||||
<a class="nav-item" href="teacher-path-certificate.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>Certificate</a>
|
||||
<a class="nav-item active" href="teacher-path-settings.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4"/></svg>Settings</a>
|
||||
<div class="sidebar-foot"><div class="avatar">JD</div><div class="who"><div class="nm">Jordan Diallo</div><div class="rl">Admin</div></div></div>
|
||||
</aside>
|
||||
|
||||
<div class="main">
|
||||
<header class="topbar">
|
||||
<nav class="crumbs">
|
||||
<a href="teacher-paths.html">Learning Paths</a><span class="sep">/</span>
|
||||
<a href="teacher-path-builder.html">Frontend Engineering Bootcamp</a><span class="sep">/</span>
|
||||
<span class="here">Settings</span>
|
||||
</nav>
|
||||
<div class="top-actions">
|
||||
<button class="icon-btn" id="theme" title="Toggle theme" aria-label="Toggle theme"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg></button>
|
||||
<a class="btn btn-outline btn-sm" href="path-detail.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></svg>Preview as student</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="content">
|
||||
<div class="wrap-narrow">
|
||||
<div class="page-head" style="margin-bottom: 6px">
|
||||
<div>
|
||||
<h1 class="page-title">Settings</h1>
|
||||
<p class="page-sub">Manage how this path appears, is priced, and behaves for learners.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- General -->
|
||||
<section class="card fset">
|
||||
<div class="fset-head"><h2>General</h2><p>The name, summary, and cover learners see across the LMS.</p></div>
|
||||
<div class="fset-body">
|
||||
<div class="field">
|
||||
<label class="label" for="nm">Path name</label>
|
||||
<input class="input" id="nm" value="Frontend Engineering Bootcamp" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label" for="ds">Description</label>
|
||||
<textarea class="textarea" id="ds">A guided, five-course track that takes you from markup fundamentals to shipping a production React app. Finish in order to earn your certificate.</textarea>
|
||||
</div>
|
||||
<div class="field">
|
||||
<span class="label">Cover image</span>
|
||||
<div class="cover-pick">
|
||||
<div class="cover-prev"></div>
|
||||
<div style="display: flex; flex-direction: column; gap: 8px; align-items: flex-start">
|
||||
<button class="btn btn-outline btn-sm"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M17 8l-5-5-5 5M12 3v12"/></svg>Upload image</button>
|
||||
<span class="hint">PNG or JPG, at least 1200×480px.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Pricing -->
|
||||
<section class="card fset">
|
||||
<div class="fset-head"><h2>Pricing</h2><p>One bundle price for the whole path. Enrolling unlocks every course.</p></div>
|
||||
<div class="fset-body">
|
||||
<div class="price-row">
|
||||
<div class="field" style="margin-bottom: 0">
|
||||
<label class="label" for="pr">Path price</label>
|
||||
<input class="input tnum" id="pr" value="$199" />
|
||||
</div>
|
||||
<div class="field" style="margin-bottom: 0">
|
||||
<label class="label" for="cur">Currency</label>
|
||||
<select class="select" id="cur"><option>USD</option><option>EUR</option><option>NGN</option></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sep"></div>
|
||||
<div class="trow2">
|
||||
<div class="grow">
|
||||
<div class="tt">Show savings vs individual courses</div>
|
||||
<div class="td tnum">Courses sum to $280 — the page will show "Save $81 (29%)".</div>
|
||||
</div>
|
||||
<label class="switch"><input type="checkbox" checked aria-label="Show savings" /><span class="track"></span><span class="knob"></span></label>
|
||||
</div>
|
||||
<div class="save-note tnum">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>
|
||||
Learners see: $199 <s style="opacity: 0.7">$280</s> · Save $81 vs buying each course
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Enrollment & flow -->
|
||||
<section class="card fset">
|
||||
<div class="fset-head"><h2>Enrollment & flow</h2><p>How learners join and move through the path.</p></div>
|
||||
<div class="fset-body">
|
||||
<div class="trow2">
|
||||
<div class="grow">
|
||||
<div class="tt">Self-enrollment from the landing page</div>
|
||||
<div class="td">Visitors can buy or join this path from your public site. Turn off for admin-managed enrollment only.</div>
|
||||
</div>
|
||||
<label class="switch"><input type="checkbox" checked aria-label="Self-enrollment" /><span class="track"></span><span class="knob"></span></label>
|
||||
</div>
|
||||
<div class="sep"></div>
|
||||
<div class="trow2">
|
||||
<div class="grow">
|
||||
<div class="tt">Unlock courses in order</div>
|
||||
<div class="td">Each course unlocks after the previous one's lessons and exercises are complete.</div>
|
||||
</div>
|
||||
<label class="switch"><input type="checkbox" checked aria-label="Unlock in order" /><span class="track"></span><span class="knob"></span></label>
|
||||
</div>
|
||||
<div class="sep"></div>
|
||||
<div class="trow2">
|
||||
<div class="grow">
|
||||
<div class="tt">Auto-enroll in path courses</div>
|
||||
<div class="td">Joining the path enrolls the learner in every course it contains.</div>
|
||||
</div>
|
||||
<label class="switch"><input type="checkbox" checked aria-label="Auto-enroll" /><span class="track"></span><span class="knob"></span></label>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Status -->
|
||||
<section class="card fset">
|
||||
<div class="fset-head"><h2>Status & visibility</h2><p>Controls whether learners can see and join this path.</p></div>
|
||||
<div class="fset-body">
|
||||
<label class="radio-card sel"><span class="rdot"></span><span><span class="rt">Active <span class="badge badge-success-soft">Visible</span></span><span class="rd">Live on your landing page and in the LMS for enrolled learners.</span></span></label>
|
||||
<label class="radio-card"><span class="rdot"></span><span><span class="rt">Draft <span class="badge badge-muted">Hidden</span></span><span class="rd">Hidden from visitors and learners while you build it.</span></span></label>
|
||||
<label class="radio-card"><span class="rdot"></span><span><span class="rt">Archived <span class="badge badge-muted">Off catalog</span></span><span class="rd">Removed everywhere. Learner progress and course access are preserved.</span></span></label>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Danger -->
|
||||
<section class="card fset danger-zone">
|
||||
<div class="fset-head"><h2>Danger zone</h2></div>
|
||||
<div class="fset-body">
|
||||
<div class="trow2">
|
||||
<div class="grow">
|
||||
<div class="tt">Delete this path</div>
|
||||
<div class="td">Permanently removes the path and its landing page. Courses, enrollments, and learner progress are not deleted.</div>
|
||||
</div>
|
||||
<button class="btn btn-destructive btn-sm"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg>Delete path</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="savebar">
|
||||
<span class="msg">Unsaved changes</span>
|
||||
<div class="actions">
|
||||
<button class="btn btn-ghost btn-sm">Discard</button>
|
||||
<button class="btn btn-primary btn-sm">Save changes</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('theme').onclick = () => {
|
||||
const dark = document.documentElement.classList.toggle('dark');
|
||||
localStorage.cioTheme = dark ? 'dark' : 'light';
|
||||
};
|
||||
document.querySelectorAll('.radio-card').forEach((r) => {
|
||||
r.addEventListener('click', () => {
|
||||
document.querySelector('.radio-card.sel')?.classList.remove('sel');
|
||||
r.classList.add('sel');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,157 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Set up your path · ClassroomIO</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="app-theme.css" />
|
||||
<script>
|
||||
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
<style>
|
||||
.gs-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; margin: 8px 0 20px; }
|
||||
.list { display: flex; flex-direction: column; gap: 8px; }
|
||||
.summary-cnt { display: flex; align-items: center; gap: 10px; }
|
||||
.launch { margin-top: 20px; display: flex; align-items: center; gap: 14px; padding: 16px 18px; flex-wrap: wrap; }
|
||||
.launch .txt { flex: 1; min-width: 220px; }
|
||||
.launch .txt b { font-size: 14px; font-weight: 600; }
|
||||
.launch .txt p { margin: 1px 0 0; font-size: 13px; color: var(--muted-foreground); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<aside class="sidebar">
|
||||
<a class="back-link" href="teacher-paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>All Learning Paths</a>
|
||||
<div class="path-id">
|
||||
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
|
||||
<div><div class="nm">Frontend Engineering Bootcamp</div><div class="st st-draft"><span class="dot"></span>Draft</div></div>
|
||||
</div>
|
||||
<a class="nav-item" href="teacher-path-builder.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>Courses<span class="nav-tail tnum">5</span></a>
|
||||
<a class="nav-item" href="teacher-path-people.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>People<span class="nav-tail tnum">0</span></a>
|
||||
<a class="nav-item" href="teacher-path-analytics.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/></svg>Analytics</a>
|
||||
<a class="nav-item" href="teacher-path-landing-editor.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>Landing page</a>
|
||||
<a class="nav-item" href="teacher-path-certificate.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>Certificate</a>
|
||||
<a class="nav-item" href="teacher-path-settings.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4"/></svg>Settings</a>
|
||||
<div class="sidebar-foot"><div class="avatar">JD</div><div class="who"><div class="nm">Jordan Diallo</div><div class="rl">Admin</div></div></div>
|
||||
</aside>
|
||||
|
||||
<div class="main">
|
||||
<header class="topbar">
|
||||
<nav class="crumbs">
|
||||
<a href="teacher-paths.html">Learning Paths</a><span class="sep">/</span>
|
||||
<a href="teacher-path-builder.html">Frontend Engineering Bootcamp</a><span class="sep">/</span>
|
||||
<span class="here">Set up</span>
|
||||
</nav>
|
||||
<div class="top-actions">
|
||||
<button class="icon-btn" id="theme" title="Toggle theme" aria-label="Toggle theme"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg></button>
|
||||
<a class="btn btn-outline btn-sm" href="path-detail.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></svg>Preview as student</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="content">
|
||||
<div class="wrap-narrow">
|
||||
<div class="gs-head">
|
||||
<div>
|
||||
<h1 class="page-title">Set up your path</h1>
|
||||
<p class="page-sub">Finish these steps to launch <strong style="color: var(--foreground); font-weight: 500">Frontend Engineering Bootcamp</strong> to your learners.</p>
|
||||
</div>
|
||||
<div class="ring">
|
||||
<svg viewBox="0 0 100 100">
|
||||
<circle class="track" cx="50" cy="50" r="45" fill="none" stroke-width="8" />
|
||||
<circle class="arc" cx="50" cy="50" r="45" fill="none" stroke-width="8" stroke-linecap="round" stroke-dasharray="282.7" stroke-dashoffset="188.5" />
|
||||
</svg>
|
||||
<span class="lbl tnum">33%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item item-outline" style="margin-bottom: 16px; cursor: default">
|
||||
<div class="item-content">
|
||||
<span class="item-desc" style="margin-bottom: 10px">A path goes live once its courses are ordered, priced, and set to Active.</span>
|
||||
<div class="summary-cnt">
|
||||
<span class="item-desc tnum" style="color: var(--foreground)">2 of 6 completed</span>
|
||||
<span class="dots"><span class="dot on"></span><span class="dot on"></span><span class="dot"></span><span class="dot"></span><span class="dot"></span><span class="dot"></span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list">
|
||||
<div class="item item-muted item-done">
|
||||
<div class="item-media-icon is-done"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></div>
|
||||
<div class="item-content">
|
||||
<span class="item-title">Name & describe your path</span>
|
||||
<span class="item-desc">Give the path a clear, outcome-based name and a short summary.</span>
|
||||
</div>
|
||||
<div class="item-actions"><span class="btn btn-secondary btn-sm disabled">Done</span></div>
|
||||
</div>
|
||||
|
||||
<div class="item item-muted item-done">
|
||||
<div class="item-media-icon is-done"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></div>
|
||||
<div class="item-content">
|
||||
<span class="item-title">Add courses</span>
|
||||
<span class="item-desc">Pick the courses that make up this learning path.</span>
|
||||
</div>
|
||||
<div class="item-actions"><span class="btn btn-secondary btn-sm disabled">Done</span></div>
|
||||
</div>
|
||||
|
||||
<div class="item item-current">
|
||||
<div class="item-media-icon is-current"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="9" cy="6" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="18" r="1"/></svg></div>
|
||||
<div class="item-content">
|
||||
<span class="item-title">Set the course order</span>
|
||||
<span class="item-desc">Drag courses into the order learners should complete them.</span>
|
||||
</div>
|
||||
<div class="item-actions"><a class="btn btn-primary btn-sm" href="teacher-path-builder.html">Set order<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 18l6-6-6-6"/></svg></a></div>
|
||||
</div>
|
||||
|
||||
<div class="item item-muted">
|
||||
<div class="item-media-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg></div>
|
||||
<div class="item-content">
|
||||
<span class="item-title">Set your price</span>
|
||||
<span class="item-desc">Price the path as a bundle — learners see the savings vs individual courses.</span>
|
||||
</div>
|
||||
<div class="item-actions"><a class="btn btn-outline btn-sm" href="teacher-path-settings.html">Set price<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 18l6-6-6-6"/></svg></a></div>
|
||||
</div>
|
||||
|
||||
<div class="item item-muted">
|
||||
<div class="item-media-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></div>
|
||||
<div class="item-content">
|
||||
<span class="item-title">Customize your landing page</span>
|
||||
<span class="item-desc">Outcomes, skills, instructors, testimonials, and FAQs on the public path page.</span>
|
||||
</div>
|
||||
<div class="item-actions"><a class="btn btn-outline btn-sm" href="teacher-path-landing-editor.html">Customize<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 18l6-6-6-6"/></svg></a></div>
|
||||
</div>
|
||||
|
||||
<div class="item item-muted">
|
||||
<div class="item-media-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><path d="M22 4 12 14.01l-3-3"/></svg></div>
|
||||
<div class="item-content">
|
||||
<span class="item-title">Activate the path</span>
|
||||
<span class="item-desc">Set the status to Active so it appears on your landing page and LMS.</span>
|
||||
</div>
|
||||
<div class="item-actions"><a class="btn btn-outline btn-sm" href="teacher-path-settings.html">Activate<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 18l6-6-6-6"/></svg></a></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card launch">
|
||||
<div class="ring ring-sm">
|
||||
<svg viewBox="0 0 100 100"><circle class="track" cx="50" cy="50" r="45" fill="none" stroke-width="10" /><circle class="arc" cx="50" cy="50" r="45" fill="none" stroke-width="10" stroke-linecap="round" stroke-dasharray="282.7" stroke-dashoffset="188.5" /></svg>
|
||||
</div>
|
||||
<div class="txt">
|
||||
<b>4 steps left to launch</b>
|
||||
<p>Order the courses, set a price, polish the landing page, and activate.</p>
|
||||
</div>
|
||||
<a class="btn btn-primary" href="teacher-path-settings.html">Activate now</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('theme').onclick = () => {
|
||||
const dark = document.documentElement.classList.toggle('dark');
|
||||
localStorage.cioTheme = dark ? 'dark' : 'light';
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,131 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Learning Paths (Admin) · ClassroomIO</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="app-theme.css" />
|
||||
<script>
|
||||
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
|
||||
document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
<style>
|
||||
.stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-bottom: 24px; }
|
||||
.grid-cols { grid-template-columns: 2.4fr 0.8fr 0.9fr 1fr 40px; }
|
||||
.p-ico { width: 38px; height: 38px; border-radius: var(--radius-md); display: grid; place-items: center; color: #fff; flex-shrink: 0; }
|
||||
.p-ico svg { width: 18px; height: 18px; stroke-width: 2; }
|
||||
.p-name { display: flex; align-items: center; gap: 12px; min-width: 0; }
|
||||
.p-name .t { font-size: 14px; font-weight: 500; }
|
||||
.p-name .d { font-size: 12.5px; color: var(--muted-foreground); display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
|
||||
.cell { display: flex; align-items: center; gap: 6px; color: var(--foreground); }
|
||||
.cell svg { width: 14px; height: 14px; stroke-width: 2; color: var(--muted-foreground); }
|
||||
.row-more { color: var(--muted-foreground); display: grid; place-items: center; }
|
||||
.row-more svg { width: 16px; height: 16px; stroke-width: 2; }
|
||||
.org-pill { display: flex; align-items: center; gap: 8px; padding: 7px 10px; border: 1px solid var(--sidebar-border); border-radius: var(--radius-md); margin-bottom: 6px; background: var(--background); }
|
||||
.org-pill .l { width: 22px; height: 22px; border-radius: var(--radius-sm); background: oklch(0.596 0.145 163.225); color: #fff; display: grid; place-items: center; font-size: 11px; font-weight: 600; }
|
||||
.org-pill .n { font-size: 13px; font-weight: 500; }
|
||||
.org-pill svg { margin-left: auto; width: 14px; height: 14px; color: var(--muted-foreground); stroke-width: 2; }
|
||||
@media (max-width: 900px) { .stats { grid-template-columns: 1fr; } .thead { display: none; } .trow.grid-cols { grid-template-columns: 1fr auto; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<aside class="sidebar">
|
||||
<div class="brand"><div class="brand-mark">C</div><div class="brand-name">ClassroomIO</div></div>
|
||||
<div class="org-pill"><span class="l">A</span><span class="n">Acme Academy</span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></div>
|
||||
<div class="nav-label">Workspace</div>
|
||||
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>Dashboard</a>
|
||||
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>Courses</a>
|
||||
<a class="nav-item active" href="teacher-paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Paths</a>
|
||||
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>Audience</a>
|
||||
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M14 9V5a3 3 0 0 0-6 0v4"/><rect x="4" y="9" width="16" height="12" rx="2"/></svg>Community</a>
|
||||
<div class="nav-label">Settings</div>
|
||||
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2"/></svg>Organization</a>
|
||||
<div class="sidebar-foot"><div class="avatar">JD</div><div class="who"><div class="nm">Jordan Diallo</div><div class="rl">Admin</div></div></div>
|
||||
</aside>
|
||||
|
||||
<div class="main">
|
||||
<header class="topbar">
|
||||
<span class="top-title">Learning Paths</span>
|
||||
<div class="top-actions">
|
||||
<button class="icon-btn" id="theme" title="Toggle theme" aria-label="Toggle theme"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg></button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="content">
|
||||
<div class="wrap" style="max-width: 1000px">
|
||||
<div class="page-head">
|
||||
<div>
|
||||
<h1 class="page-title">Learning Paths</h1>
|
||||
<p class="page-sub">Group your courses into ordered tracks your learners complete step by step.</p>
|
||||
</div>
|
||||
<a class="btn btn-primary" href="teacher-path-setup.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 5v14M5 12h14"/></svg>Create path</a>
|
||||
</div>
|
||||
|
||||
<div class="stats">
|
||||
<div class="card stat-card"><div class="k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Active paths</div><div class="v tnum">3</div></div>
|
||||
<div class="card stat-card"><div class="k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>Enrolled learners</div><div class="v tnum">126</div></div>
|
||||
<div class="card stat-card"><div class="k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>Completions</div><div class="v tnum">54</div></div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="overflow: hidden">
|
||||
<div class="thead grid-cols"><span>Path</span><span>Courses</span><span>Learners</span><span>Status</span><span></span></div>
|
||||
|
||||
<a class="trow grid-cols" href="teacher-path-builder.html">
|
||||
<div class="p-name">
|
||||
<span class="p-ico" style="background: linear-gradient(135deg, oklch(0.488 0.243 264.376), oklch(0.623 0.214 259.815))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></span>
|
||||
<div style="min-width: 0"><div class="t">Frontend Engineering Bootcamp</div><div class="d">HTML foundations through shipping a React app.</div></div>
|
||||
</div>
|
||||
<span class="cell tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>5</span>
|
||||
<span class="cell tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>48</span>
|
||||
<span><span class="badge badge-success-soft"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Active</span></span>
|
||||
<span class="row-more"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></span>
|
||||
</a>
|
||||
|
||||
<a class="trow grid-cols" href="teacher-path-builder.html">
|
||||
<div class="p-name">
|
||||
<span class="p-ico" style="background: linear-gradient(135deg, oklch(0.596 0.145 163.225), oklch(0.696 0.17 162.48))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></span>
|
||||
<div style="min-width: 0"><div class="t">Data Science with Python</div><div class="d">Pandas, visualization, and applied ML basics.</div></div>
|
||||
</div>
|
||||
<span class="cell tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>4</span>
|
||||
<span class="cell tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>61</span>
|
||||
<span><span class="badge badge-success-soft"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Active</span></span>
|
||||
<span class="row-more"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></span>
|
||||
</a>
|
||||
|
||||
<a class="trow grid-cols" href="teacher-path-setup.html">
|
||||
<div class="p-name">
|
||||
<span class="p-ico" style="background: linear-gradient(135deg, oklch(0.666 0.179 58.318), oklch(0.769 0.188 70.08))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></span>
|
||||
<div style="min-width: 0"><div class="t">Product Management Fundamentals</div><div class="d">Discovery, prioritization, and roadmap craft.</div></div>
|
||||
</div>
|
||||
<span class="cell tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>5</span>
|
||||
<span class="cell tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>0</span>
|
||||
<span><span class="badge badge-warning" style="background: var(--warning-soft); color: var(--warning)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>Draft</span></span>
|
||||
<span class="row-more"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></span>
|
||||
</a>
|
||||
|
||||
<a class="trow grid-cols" href="teacher-path-builder.html" style="opacity: 0.7">
|
||||
<div class="p-name">
|
||||
<span class="p-ico" style="background: var(--muted); color: var(--muted-foreground)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></span>
|
||||
<div style="min-width: 0"><div class="t">Workplace Compliance 2026</div><div class="d">Security awareness, data handling, code of conduct.</div></div>
|
||||
</div>
|
||||
<span class="cell tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>3</span>
|
||||
<span class="cell tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>17</span>
|
||||
<span><span class="badge badge-muted">Inactive</span></span>
|
||||
<span class="row-more"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('theme').onclick = () => {
|
||||
const dark = document.documentElement.classList.toggle('dark');
|
||||
localStorage.cioTheme = dark ? 'dark' : 'light';
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
name: write-prd
|
||||
description: Write a product PRD for ClassroomIO the house way — clarify all features with the user first, research the codebase, write the PRD under prd/<feature>/, then build clickable HTML prototypes under prototypes/<feature>/ that become the UX source of truth. Use when the user asks to "write a PRD", "spec a feature", "plan a new product/feature", or "prototype a feature end to end".
|
||||
---
|
||||
|
||||
# Write a PRD
|
||||
|
||||
A PRD here is two artifacts that ship together:
|
||||
|
||||
1. `prd/<feature>/README.md` — the written spec.
|
||||
2. `prototypes/<feature>/` — clickable HTML prototypes of every surface, with an `index.html` map. **The prototypes are the UX source of truth**; when prose and prototype disagree on a UI detail, the prototype wins, and the PRD must say so.
|
||||
|
||||
Work in this order. Do not write the PRD before the decisions are locked, and do not build prototypes before the PRD scope is clear.
|
||||
|
||||
## Phase 1 — Get clear on all the features first
|
||||
|
||||
Never start writing from a one-line request. Close every open fork with the user via `AskUserQuestion` (option-based, 3–4 questions per round, 2–3 rounds max):
|
||||
|
||||
- **Relationship to existing features** — new entity vs extension of something shipped? (Check `prd/` for overlapping PRDs first; e.g. "learning paths" nearly collided with the shipped Programs feature.)
|
||||
- **Who touches it** — enumerate the personas and confirm each surface: public visitor (org landing site), learner (LMS), teacher/admin (dashboard). Most features need all three; ask which are in scope.
|
||||
- **The business mechanics** — pricing, enrollment/self-serve vs admin-managed, gating/completion rules, certificates, statuses (Active/Draft/Archived).
|
||||
- **Scope cuts** — what's explicitly v1 vs later. Every "maybe" becomes a Non-Goal or a decision.
|
||||
- **References** — if the user points at a competitor page or screenshot, fetch/read it and mirror its structure deliberately.
|
||||
|
||||
Every answer becomes a numbered entry in the PRD's **Confirmed Decisions** section. If the user answers with a note instead of an option, treat it as a lead to chase (fetch the URL, read the screenshot), not a checkbox.
|
||||
|
||||
## Phase 2 — Research the codebase before writing
|
||||
|
||||
- Read the closest existing PRD in `prd/` and match its format.
|
||||
- Audit current state: what tables, services, routes, and UI patterns already exist that this feature reuses or must not break. Capture it as a **Current-State Audit** table (capability → current state → notes).
|
||||
- Find the real UI patterns to mirror (use an Explore agent for breadth): the component primitives in `packages/ui`, the sibling feature's routes/sidebar/pages, the landing-page theme system. Name the actual files in the PRD.
|
||||
|
||||
## Phase 3 — Write the PRD
|
||||
|
||||
Location: `prd/<feature>/README.md`. House structure (match `prd/programs [DONE]/README.md`):
|
||||
|
||||
1. **Status** — Draft / In review / Done.
|
||||
2. **Prototypes — the UX source of truth** — state that UX comes from the prototype folder, show the start page in a code block (`prototypes/<feature>/index.html`), and include a surface → files table.
|
||||
3. **Purpose** — one paragraph; name the reference experience if there is one.
|
||||
4. **Problem Statement** — bullets of what's impossible or painful today.
|
||||
5. **Confirmed Decisions** — numbered; this is the contract from Phase 1.
|
||||
6. **Current-State Audit** — the table from Phase 2.
|
||||
7. **Product Goals** / **Non-Goals (v1)**.
|
||||
8. **Functional Requirements** — one subsection per surface (public / learner / teacher), each referencing its prototype file and describing states, not just happy paths (locked, empty, draft…).
|
||||
9. **Technical Design** — data model as schema code blocks (follow repo rules: no relational IDs in jsonb, computed values never stored), core logic in pseudocode, an API route table, and a frontend plan that follows CLAUDE.md layering (validation → queries → services → routes → feature types/API classes).
|
||||
10. **Implementation Order** — numbered phases an engineer can execute top to bottom, with build verification commands.
|
||||
11. **Acceptance Criteria** — testable, numbered; always include a "zero regression on existing features" criterion and "all copy uses translation keys".
|
||||
12. **Risks and Mitigations** — each risk paired with a concrete mitigation.
|
||||
|
||||
Keep it scannable: tables for routes and audits, code blocks for schemas, prose only where judgment is needed.
|
||||
|
||||
## Phase 4 — Build the prototypes
|
||||
|
||||
Location: `prototypes/<feature>/` — standalone HTML files, one per screen, plus shared CSS:
|
||||
|
||||
- **Use the real design tokens, not invented ones.** App screens: a shared `app-theme.css` mirroring `packages/ui/src/index.css` (OKLCH vars, Geist, radii, shadows, Button/Badge/Item/Progress recipes, `.dark` class). Public screens: a `landing-theme.css` mirroring the default org-landing theme (`--landing-*` vars). Read the actual component variants (`tv()` blocks) before styling.
|
||||
- **Match shipped UI, don't redesign it.** If a screen wraps an existing view (course page, setup checklist, settings form), replicate that view's real structure — sidebar, header, states — and add only the feature-specific chrome. Screenshots from the user override everything.
|
||||
- **`index.html` is the start page**: a map of every screen grouped by persona/journey, each card linking in. All pages cross-link so each journey clicks through end to end.
|
||||
- Every page: light/dark toggle, realistic data (no lorem), all states shown (done / in progress / locked / empty / draft). Small vanilla-JS interactions (drag reorder, accordions, tabs) are worth the effort — they sell the flow.
|
||||
- Open pages with `open <file>` as you finish them so the user can react early; iterate on their feedback per screen. Expect header/sidebar nitpicks — fidelity to the real app is the bar.
|
||||
|
||||
## Phase 5 — Close the loop
|
||||
|
||||
- Re-check the PRD against the final prototypes (files renamed? screens added/removed? decisions changed mid-build?) and fix drift.
|
||||
- Tell the user the start page path and the PRD path in your summary.
|
||||
- Flag the one or two product calls you made without an explicit answer so they can veto them.
|
||||
Reference in New Issue
Block a user