diff --git a/README.md b/README.md index 5c0d820..086869a 100644 --- a/README.md +++ b/README.md @@ -1,60 +1,151 @@ -# GCI +# GCI Student Launch Portal + +A lightweight student onboarding website for Genesee Career Institute Computer Science and technology courses. + +Students can use one URL to: + +- choose their course +- open required sign-in systems +- open their LMS +- access course tools +- review orientation expectations +- complete a setup check +- report problems +- start a first activity while others finish setup + +The site is built for GitHub Pages with only HTML, CSS, and vanilla JavaScript. + +## Project structure + +```text +/ +├── index.html +├── orientation.html +├── help.html +├── css/ +│ └── styles.css +├── js/ +│ ├── config.js +│ └── app.js +├── assets/ +│ └── README.md +└── README.md +``` -Tools Built for the Genesee Career Institute +## Preview locally -## Project Hub (Recommended Start) +Because this is a static site, you can preview it in either of these ways: -- Open `index.html` in a browser to access all projects, guides, scripts, and tests from one page. +1. Open `index.html` directly in a browser. +2. Or run a simple local server from the repository root: -## App status +```bash +python3 -m http.server 8000 +``` -- Production - - `OOOReview` (Python Order of operations) — interactive practice app with badge cabinet, mastery tracking, and PNG export. Path: `OOOReview.html` - - `AgileReview` — instructor review tools - - `No_School_Viewer` — schedule viewer - - `wordguide1` — MOS Word Project 1 step-by-step guide. Path: `wordguide1.html` - - `wordguide2` — MOS Word Project 2 step-by-step guide. Path: `wordguide2.html` +Then open `http://localhost:8000/`. - - `Lab Manual Generator` (Python) — Teacher edition DOCX generator (production). Script: `HArdware Lab Manual.py`. Output: `GCI_Computer_Hardware_Labs_Teacher_Edition_updated.docx` +## Enable GitHub Pages -- Alpha Testing - - `GCI_Communications` — communications utilities (Alpha) - -## In Development +1. Push the repository to GitHub. +2. Open **Settings → Pages**. +3. Under **Build and deployment**, choose **Deploy from a branch**. +4. Select the branch you want to publish and the `/ (root)` folder. +5. Save the settings. +6. Wait for GitHub Pages to publish the site. -- `AgileVocab` — vocabulary practice (In Development) -- `GCI3Dorder` — 3D order demo (In Development) -- `mathquest` — interactive math exercises (In Development) -- `ProgReview` — programming review (In Development) +All site links use relative paths so the portal also works from GitHub Pages project URLs such as `https://username.github.io/gci-student-launch/`. -## Quick start (OOOReview) +## Course configuration -- Open `OOOReview.html` in a browser to run the production app locally. +All course data and editable external links live in: -## Quick start (MOS Word Guides) +- `js/config.js` -- Open `wordguide1.html` in a browser for Project 1 guided walkthrough -- Open `wordguide2.html` in a browser for Project 2 guided walkthrough -- Required project files are located in the `wordprojectfiles` folder -- Progress is automatically saved in your browser +This includes: -Contributions welcome — please open an issue describing proposed changes and test steps. +- course names +- course descriptions +- LMS links +- tool links +- syllabus links +- orientation links +- setup check link +- help/reporting link +- first mission links -## Quick start (Lab Manual Generator) +## Change links -- Requirements: Python 3.8+ and the `python-docx` package. -- Install dependency (PowerShell): +Open `js/config.js` and update the URL strings. -```powershell -python -m pip install --user python-docx -``` +Examples of values you will likely replace: -- Generate the teacher edition (PowerShell): +- `setupCheckUrl` +- `helpFormUrl` +- `firstMissionDefaultUrl` +- each course's `syllabusUrl` +- each course's `orientationUrl` +- each course's LMS and tool URLs -```powershell -python "c:\github\GCI\HArdware Lab Manual.py" -``` +Temporary links are intentionally labeled with obvious `REPLACE-WITH-...` placeholders. + +## Add another course + +1. Open `js/config.js`. +2. Add a new item inside `SITE_CONFIG.courses`. +3. Give the new course a unique key. +4. Provide its name, description, LMS items, tool items, syllabus URL, orientation URL, and first mission URL. +5. Save the file and reload the site. + +The homepage course cards and dashboard content are generated from that configuration. + +## Logo placement + +Put the official GCI logo in: + +- `assets/` + +A placeholder logo area is already built into the interface so the site still looks polished before the final logo is available. + +## Placeholder URLs still to update + +The following values are still placeholders by default: + +- district Canvas URL +- setup check form URL +- help/report problem form URL +- course syllabi URLs +- course orientation URLs +- first mission URLs +- district/internal course tools +- certification and hardware resource links +- student help desk URL + +Public services already use real public URLs where appropriate: + +- Gmail +- Google Drive +- Google Classroom +- GitHub +- CodeHS +- Google account sign-in + +## Privacy and security notes + +- The site does not collect student names. +- The site does not collect student email addresses. +- The site stores only course choice and step completion in local browser storage. +- No databases, authentication systems, API keys, or private credentials are used. +- Assume the site is publicly accessible when hosted on GitHub Pages. + +## Before launch checklist -- Notes: - - The script writes `GCI_Computer_Hardware_Labs_Teacher_Edition_updated.docx` by default to avoid write errors if an earlier document is open. Close any open copies of the DOCX to allow overwriting the primary filename. - - After opening the DOCX in Microsoft Word, update the Table of Contents by selecting the TOC page and pressing F9 (or References → Update Table) so page numbers and hyperlinks populate. +- [ ] Replace every `REPLACE-WITH-...` URL in `js/config.js` +- [ ] Add the official GCI logo if available +- [ ] Verify each course shows the correct LMS buttons +- [ ] Verify each course shows the correct tools +- [ ] Test course selection and change course behavior +- [ ] Test onboarding progress save/reset behavior +- [ ] Test the setup check and help form destinations +- [ ] Test the site on a phone and a Chromebook +- [ ] Confirm all external links open safely in a new tab diff --git a/assets/README.md b/assets/README.md new file mode 100644 index 0000000..446d01f --- /dev/null +++ b/assets/README.md @@ -0,0 +1,9 @@ +# Assets + +Place the official GCI logo in this folder when it is available. + +Suggested path: + +- `assets/gci-logo.svg` + +This project currently uses a styled placeholder area so the site still looks complete before the logo is added. diff --git a/css/styles.css b/css/styles.css new file mode 100644 index 0000000..079054e --- /dev/null +++ b/css/styles.css @@ -0,0 +1,586 @@ +:root { + --primary-color: #1d4ed8; + --secondary-color: #0f172a; + --accent-color: #f59e0b; + --background-color: #f4f7fb; + --text-color: #0f172a; + --surface-color: #ffffff; + --border-color: #dbe4f0; + --muted-color: #526176; + --success-color: #12763d; + --warning-color: #9a5c00; + --danger-color: #9f1239; + --shadow: 0 12px 30px rgba(15, 23, 42, 0.08); + --shadow-strong: 0 20px 40px rgba(15, 23, 42, 0.12); + --radius: 1rem; + --radius-sm: 0.75rem; + --max-width: 1120px; +} + +* { + box-sizing: border-box; +} + +html { + color-scheme: light; +} + +body { + margin: 0; + font-family: Inter, "Segoe UI", Roboto, Arial, sans-serif; + color: var(--text-color); + background: linear-gradient(180deg, #eef4ff 0%, var(--background-color) 24rem); + line-height: 1.6; +} + +img { + max-width: 100%; + display: block; +} + +a { + color: var(--primary-color); +} + +button, +input, +textarea, +select { + font: inherit; +} + +button { + cursor: pointer; +} + +:focus-visible { + outline: 3px solid var(--accent-color); + outline-offset: 3px; +} + +[hidden] { + display: none !important; +} + +.skip-link { + position: absolute; + left: 1rem; + top: -4rem; + background: var(--secondary-color); + color: #fff; + padding: 0.75rem 1rem; + border-radius: var(--radius-sm); + z-index: 1000; + text-decoration: none; +} + +.skip-link:focus { + top: 1rem; +} + +.container { + width: min(calc(100% - 2rem), var(--max-width)); + margin: 0 auto; +} + +.stack-lg > * + * { + margin-top: 1.5rem; +} + +.stack-md > * + * { + margin-top: 1rem; +} + +.site-header { + position: sticky; + top: 0; + z-index: 100; + background: rgba(255, 255, 255, 0.94); + border-bottom: 1px solid rgba(219, 228, 240, 0.9); + backdrop-filter: blur(10px); +} + +.topbar { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + padding: 1rem 0; +} + +.brand { + display: inline-flex; + align-items: center; + gap: 0.875rem; + text-decoration: none; + color: inherit; +} + +.brand strong, +.brand small { + display: block; +} + +.brand strong { + font-size: 1rem; +} + +.brand small { + color: var(--muted-color); +} + +.brand-mark { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 3rem; + min-height: 3rem; + padding: 0.5rem; + border-radius: 0.9rem; + background: var(--secondary-color); + color: #fff; + font-weight: 800; + letter-spacing: 0.04em; +} + +.topbar-actions { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} + +.text-link { + text-decoration: none; + font-weight: 700; +} + +.text-link:hover, +.text-link:focus-visible { + text-decoration: underline; +} + +.hero { + padding: 3rem 0 2rem; +} + +.hero-layout { + display: grid; + grid-template-columns: minmax(0, 2fr) minmax(18rem, 1fr); + gap: 1.5rem; + align-items: stretch; +} + +.hero-copy, +.logo-placeholder, +.card { + background: var(--surface-color); + border: 1px solid var(--border-color); + border-radius: 1.5rem; + box-shadow: var(--shadow); +} + +.hero-copy { + padding: 2rem; +} + +.eyebrow, +.section-label { + display: inline-block; + margin: 0 0 0.75rem; + font-size: 0.8rem; + font-weight: 800; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--primary-color); +} + +.hero h1, +.page-intro h1, +.daily-routine h2, +.section-heading h2, +.dashboard-header h2 { + margin: 0; + line-height: 1.05; + letter-spacing: -0.03em; +} + +.hero h1 { + font-size: clamp(2.5rem, 8vw, 4.5rem); +} + +.hero-text { + margin: 1rem 0 0; + font-size: clamp(1.125rem, 3vw, 1.6rem); + font-weight: 700; +} + +.hero-subtext, +.muted, +.section-heading p, +.page-intro p, +.card p, +.card li { + color: var(--muted-color); +} + +.hero-subtext { + max-width: 42rem; +} + +.logo-placeholder { + display: grid; + place-items: center; + padding: 2rem; + min-height: 14rem; + background: linear-gradient(135deg, var(--secondary-color), #1f3a7a); + color: #fff; + text-align: center; + font-weight: 700; +} + +.section { + padding: 0 0 5rem; +} + +.section-heading { + max-width: 40rem; +} + +.card { + padding: 1.5rem; +} + +.small { + font-size: 0.95rem; +} + +.course-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 1rem; +} + +.course-card { + width: 100%; + text-align: left; + padding: 1.5rem; + border: 2px solid var(--border-color); + border-radius: 1.25rem; + background: var(--surface-color); + box-shadow: var(--shadow); + transition: transform 150ms ease, border-color 150ms ease, box-shadow 150ms ease; +} + +.course-card:hover, +.course-card:focus-visible { + transform: translateY(-2px); + border-color: var(--primary-color); + box-shadow: var(--shadow-strong); +} + +.course-card h3, +.step-card h3, +.progress-card h3, +.page-intro h1, +.card h2 { + margin: 0; +} + +.course-card p { + margin: 0.75rem 0 0; + color: var(--muted-color); +} + +.course-card .course-code { + margin-top: 1rem; + font-size: 0.9rem; + font-weight: 700; + color: var(--primary-color); +} + +.dashboard { + scroll-margin-top: 5rem; +} + +.dashboard-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 1rem; +} + +.dashboard-actions, +.button-row, +.link-grid, +.status-grid { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} + +.button, +.resource-link { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 3.5rem; + padding: 0.9rem 1.2rem; + border-radius: 0.95rem; + border: 2px solid transparent; + font-weight: 800; + text-decoration: none; + text-align: center; + transition: transform 150ms ease, box-shadow 150ms ease, background 150ms ease, color 150ms ease, border-color 150ms ease; +} + +.button:hover, +.button:focus-visible, +.resource-link:hover, +.resource-link:focus-visible { + transform: translateY(-1px); +} + +.button-primary, +.resource-link { + background: var(--primary-color); + color: #fff; + box-shadow: var(--shadow); +} + +.button-secondary { + background: #eef4ff; + color: var(--secondary-color); + border-color: #c8dafb; +} + +.button-ghost { + background: transparent; + color: var(--primary-color); + border-color: var(--border-color); +} + +.button-large { + width: 100%; + max-width: 22rem; +} + +.button-uppercase { + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.progress-header { + display: flex; + align-items: end; + justify-content: space-between; + gap: 1rem; + margin-bottom: 1rem; +} + +.progress-text { + margin: 0; + font-size: 1.1rem; + font-weight: 800; +} + +.progress-bar { + height: 1rem; + border-radius: 999px; + background: #dce8f8; + overflow: hidden; +} + +.progress-bar-fill { + width: 0; + height: 100%; + border-radius: inherit; + background: linear-gradient(90deg, var(--primary-color), #60a5fa); + transition: width 180ms ease; +} + +.steps-list { + display: grid; + gap: 1rem; +} + +.step-card { + padding: 1.5rem; +} + +.step-header { + display: flex; + align-items: start; + justify-content: space-between; + gap: 1rem; + margin-bottom: 1rem; +} + +.step-number { + display: inline-flex; + align-items: center; + justify-content: center; + width: 2.4rem; + height: 2.4rem; + border-radius: 999px; + background: #e8f0ff; + color: var(--primary-color); + font-weight: 800; +} + +.step-body > * + * { + margin-top: 1rem; +} + +.link-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); +} + +.resource-link { + min-height: 4rem; +} + +.note-box, +.inline-banner { + padding: 1rem; + border-radius: 1rem; + background: #f7f9fc; + border: 1px solid var(--border-color); +} + +.checklist, +.help-list, +.orientation-list, +.daily-routine ol { + padding-left: 1.25rem; +} + +.status-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); +} + +.status-card { + padding: 1rem; + border-radius: 1rem; + border: 1px solid var(--border-color); + background: #fff; +} + +.status-card strong { + display: block; + margin-bottom: 0.35rem; +} + +.status-emoji { + margin-right: 0.35rem; +} + +.status-ready strong { + color: var(--success-color); +} + +.status-almost strong { + color: var(--warning-color); +} + +.status-help strong { + color: var(--danger-color); +} + +.completion-control { + display: inline-flex; + align-items: center; + gap: 0.75rem; + padding: 0.85rem 1rem; + border: 1px solid var(--border-color); + border-radius: 1rem; + background: #f8fbff; + font-weight: 700; +} + +.completion-control input { + width: 1.2rem; + height: 1.2rem; +} + +.help-fab { + position: fixed; + right: 1rem; + bottom: 1rem; + z-index: 90; + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 3.5rem; + padding: 0.9rem 1.25rem; + border-radius: 999px; + background: var(--accent-color); + color: #1f1300; + text-decoration: none; + font-weight: 900; + box-shadow: var(--shadow-strong); +} + +@media (max-width: 780px) { + .topbar, + .dashboard-header, + .progress-header, + .step-header { + flex-direction: column; + align-items: stretch; + } + + .hero-layout { + grid-template-columns: 1fr; + } + + .button-large, + .dashboard-actions .button, + .button-row .button { + max-width: none; + width: 100%; + } +} + +@media (max-width: 560px) { + .container { + width: min(calc(100% - 1rem), var(--max-width)); + } + + .hero { + padding-top: 1.5rem; + } + + .hero-copy, + .logo-placeholder, + .card, + .course-card, + .step-card { + padding: 1.15rem; + border-radius: 1rem; + } + + .topbar-actions { + width: 100%; + } + + .text-link { + padding: 0.4rem 0; + } + + .help-fab { + left: 0.75rem; + right: 0.75rem; + bottom: 0.75rem; + } +} + +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } +} diff --git a/help.html b/help.html new file mode 100644 index 0000000..277ef5e --- /dev/null +++ b/help.html @@ -0,0 +1,56 @@ + + + + + + Need Help? — GCI Computer Science + + + + + + + + + + + +
+
+
+ +

Keep going if you can.

+

After reporting the problem, continue with anything else you can complete.

+ REPORT A PROBLEM +
+ +
+

Try these steps first:

+
    +
  1. Read the error message.
  2. +
  3. Verify you are using your school account.
  4. +
  5. Ask someone at your table.
  6. +
  7. Refresh or sign in again.
  8. +
  9. If still stuck, report the problem.
  10. +
+
+
+
+ + Back Home + + diff --git a/index.html b/index.html index be3a716..56742d1 100644 --- a/index.html +++ b/index.html @@ -1,539 +1,103 @@ - + - - - - - - - - - - - - - - - - - Genesee Learning Lab — Building the Future of CS in Genesee County - - - - - - + + + GCI Computer Science — Start Here + + + + + - - + - - - -
- - -
-
- -

- Building the Future of
- Computer Science
- in Genesee County -

-

- Hands-on learning in programming, hardware, cybersecurity, AI, and emerging technologies - designed to prepare students for real careers. -

-
- Explore Programs - View Projects - Get Involved + + +
+
+
+
+
GCI Computer Science
+

START HERE

+

Welcome. Let's make sure you're ready.

+

Pick your course to open your onboarding dashboard, essential links, orientation steps, and first mission.

+
+
- -
-
-
-
-

About Us

-

Real Skills. Real Projects. Real Futures.

-

- Genesee Learning Lab is a hands-on computer science and technology initiative focused on helping - students build real-world skills through authentic, career-connected projects. We believe every - student deserves access to meaningful technology education — regardless of background or prior experience. -

-

- Our curriculum spans programming, computer hardware, cybersecurity, artificial intelligence, data science, - 3D printing, and emerging technologies — giving students a broad and deep foundation for the careers of tomorrow. -

- Explore Our Programs +
+
+
+
+

Select your course

+

Choose the class your instructor told you to use today.

-
-
- -
- Authentic Project Work - Students build, code, design, and solve real problems — not just worksheets. -
+
+
+ + + +
+
+ +
+ +

Start independently.

+
    +
  1. Log in.
  2. +
  3. Open your course.
  4. +
  5. Check today's instructions.
  6. +
  7. Begin working.
  8. +
+
- - -
-
-
- What We Teach -

Learning Areas

-

Explore five interconnected disciplines that together cover the breadth of modern technology careers.

-
-
-
- -

Programming & Software Development

-

From Python and web development to app design and software engineering, students learn to think like developers and build real applications from scratch.

-
-
- -

Computer Hardware & IT Systems

-

Students build, upgrade, and troubleshoot computers. They explore networking, operating systems, and the physical infrastructure that powers the digital world.

-
-
- -

Cybersecurity

-

Students explore how to protect systems and data, practice with real-world security scenarios, and build skills aligned to CompTIA and industry security standards.

-
-
- -

Artificial Intelligence & Data Science

-

Students work with AI tools, explore machine learning concepts, and use real data to answer meaningful questions — preparing for the most in-demand field in tech.

-
-
- -

Engineering & Emerging Technology

-

From 3D printing and Raspberry Pi to autonomous drones and maker projects, students design and build physical-digital solutions to real engineering challenges.

-
-
-
-
- - -
-
-
- Student Experiences -

What Students Are Doing

-

Hands-on, energizing, and career-ready — here's a sample of the work happening in the lab.

-
-
-
- -

Building & Troubleshooting PCs

-

Students disassemble and reassemble computers, diagnose hardware failures, and configure operating systems from scratch.

-
-
- -

Programming Games & Software

-

From text-based Python games to interactive web applications, students write real code that does real things.

-
-
- -

Designing & 3D Printing Products

-

Using Tinkercad and Bambu A1 printers, students design, slice, and print original products solving real design challenges.

-
-
- -

Working with Raspberry Pi Systems

-

Students program microcomputers for real applications — from media centers to environmental sensors to physical computing projects.

-
-
- -

Exploring Cybersecurity Scenarios

-

Students navigate ethical hacking challenges, practice defense strategies, and learn to think like security professionals.

-
-
- -

Using AI & Data Tools

-

Students analyze real datasets, build models, and work with modern AI platforms to solve data-driven problems.

-
-
- -

Autonomous Drone Development

-

Students program and deploy autonomous drone systems, exploring the intersection of hardware, software, and real-world navigation.

-
-
-
-
- - -
-
-
- Credentials & Careers -

Certifications & Pathways

-

Students leave Genesee Learning Lab with recognized credentials and a clear path toward real careers.

-
-
-
-

Industry Certifications

-
    -
  • CompTIA Tech+
  • -
  • CompTIA A+
  • -
  • IT Specialist Certifications
  • -
  • Microsoft Office Specialist (MOS)
  • -
  • Additional credentials in progress
  • -
-
-
-

Career Pathways

-
    -
  • Software Development
  • -
  • IT Support & Systems Administration
  • -
  • Cybersecurity
  • -
  • Data & AI Careers
  • -
  • Engineering & Emerging Technology
  • -
-
-
-
-
- - -
-
-
- Community -

Built With Our Community

-

Genesee Learning Lab thrives on partnerships. We welcome collaboration from everyone who believes in the power of quality technology education.

-
-
-
- -

Schools

-

Partnering with schools and districts to bring hands-on CS education to more classrooms across Genesee County.

-
-
- -

Families

-

Supporting students and parents through transparent communication, learning events, and shared celebrations of student work.

-
-
- -

Industry Partners

-

Connecting students with professionals for guest speakers, mentorship, internships, and authentic project challenges.

-
-
- -

Community Organizations

-

Collaborating with local nonprofits, libraries, and community groups to extend learning beyond the classroom.

-
-
-
-

Interested in Collaborating?

-

Whether you can offer guest presentations, advisory support, project partnerships, or authentic learning opportunities — we want to hear from you.

- Get In Touch -
-
-
- - -
-
- -

- Explore our programs, see what students are building, or reach out to connect with the Genesee Learning Lab community. -

- -
-
-
- - - - - + Need Help? diff --git a/js/app.js b/js/app.js new file mode 100644 index 0000000..d32db05 --- /dev/null +++ b/js/app.js @@ -0,0 +1,490 @@ +(function () { + const config = window.SITE_CONFIG; + + if (!config) { + return; + } + + const page = document.body.dataset.page; + let homePageControlsInitialized = false; + + function getSelectedCourseId() { + return localStorage.getItem(config.storageKeys.selectedCourse) || ''; + } + + function setSelectedCourseId(courseId) { + localStorage.setItem(config.storageKeys.selectedCourse, courseId); + } + + function getProgressState() { + try { + const raw = localStorage.getItem(config.storageKeys.progress); + return raw ? JSON.parse(raw) : {}; + } catch (error) { + return {}; + } + } + + function setProgressState(progressState) { + localStorage.setItem(config.storageKeys.progress, JSON.stringify(progressState)); + } + + function getCourseProgress(courseId) { + const progressState = getProgressState(); + return progressState[courseId] || {}; + } + + function setStepComplete(courseId, stepId, isComplete) { + const progressState = getProgressState(); + const courseProgress = progressState[courseId] || {}; + courseProgress[stepId] = Boolean(isComplete); + progressState[courseId] = courseProgress; + setProgressState(progressState); + } + + function resetCourseProgress(courseId) { + const progressState = getProgressState(); + progressState[courseId] = {}; + setProgressState(progressState); + } + + function createExternalLink(link) { + const anchor = document.createElement('a'); + anchor.className = link.className || 'resource-link'; + anchor.href = link.url; + anchor.target = '_blank'; + anchor.rel = 'noopener noreferrer'; + anchor.textContent = link.label; + anchor.setAttribute('aria-label', `${link.label} (opens in a new tab)`); + return anchor; + } + + function createStepCard(step, courseId, course, steps) { + const stepCard = document.createElement('section'); + stepCard.className = 'card step-card'; + stepCard.setAttribute('aria-labelledby', `step-${step.id}-heading`); + + const stepHeader = document.createElement('div'); + stepHeader.className = 'step-header'; + + const stepHeadingWrap = document.createElement('div'); + const stepNumber = document.createElement('span'); + stepNumber.className = 'step-number'; + stepNumber.textContent = step.number; + stepNumber.setAttribute('aria-hidden', 'true'); + + const heading = document.createElement('h3'); + heading.id = `step-${step.id}-heading`; + heading.textContent = step.title; + + const description = document.createElement('p'); + description.className = 'muted'; + description.textContent = step.description; + + stepHeadingWrap.append(stepNumber, heading, description); + + const completionLabel = document.createElement('label'); + completionLabel.className = 'completion-control'; + completionLabel.setAttribute('for', `step-complete-${step.id}`); + + const completionInput = document.createElement('input'); + completionInput.type = 'checkbox'; + completionInput.id = `step-complete-${step.id}`; + completionInput.checked = Boolean(getCourseProgress(courseId)[step.id]); + completionInput.addEventListener('change', function () { + setStepComplete(courseId, step.id, completionInput.checked); + updateProgress(courseId, steps); + }); + + const completionText = document.createElement('span'); + completionText.textContent = 'Mark complete'; + + completionLabel.append(completionInput, completionText); + stepHeader.append(stepHeadingWrap, completionLabel); + + const stepBody = document.createElement('div'); + stepBody.className = 'step-body'; + stepBody.append(step.content(course)); + + stepCard.append(stepHeader, stepBody); + return stepCard; + } + + function buildSteps(courseId) { + return [ + { + id: 'sign-in', + number: 1, + title: 'Sign In', + description: 'Verify that your school account and basic Google tools work.', + content: function () { + const fragment = document.createDocumentFragment(); + const note = document.createElement('div'); + note.className = 'note-box'; + note.textContent = 'Use your school Google account for every service in this portal.'; + const links = document.createElement('div'); + links.className = 'link-grid'; + + config.schoolSystems.forEach(function (system) { + const wrap = document.createElement('div'); + wrap.className = 'stack-md'; + wrap.append(createExternalLink(system)); + const detail = document.createElement('p'); + detail.className = 'small muted'; + detail.textContent = system.note; + wrap.append(detail); + links.append(wrap); + }); + + fragment.append(note, links); + return fragment; + } + }, + { + id: 'open-class', + number: 2, + title: 'Open Your Class', + description: 'Open only the course space your instructor tells you to use.', + content: function (activeCourse) { + const fragment = document.createDocumentFragment(); + const note = document.createElement('div'); + note.className = 'inline-banner'; + note.textContent = 'Only open or join the course your instructor tells you to use.'; + const links = document.createElement('div'); + links.className = 'link-grid'; + + activeCourse.lms.forEach(function (item) { + links.append(createExternalLink(item)); + }); + + fragment.append(note, links); + return fragment; + } + }, + { + id: 'tools', + number: 3, + title: 'Check Your Tools', + description: 'Open the tools used in your course and make sure they load.', + content: function (activeCourse) { + const links = document.createElement('div'); + links.className = 'link-grid'; + + activeCourse.tools.forEach(function (tool) { + links.append(createExternalLink(tool)); + }); + + return links; + } + }, + { + id: 'orientation', + number: 4, + title: 'Course Orientation', + description: 'Review how your class works before you begin assignments.', + content: function (activeCourse) { + const fragment = document.createDocumentFragment(); + const buttonRow = document.createElement('div'); + buttonRow.className = 'button-row'; + + const syllabusLink = createExternalLink({ + label: 'View Course Syllabus', + url: activeCourse.syllabusUrl, + className: 'button button-secondary' + }); + const orientationLink = document.createElement('a'); + orientationLink.className = 'button button-secondary'; + orientationLink.href = `./orientation.html?course=${encodeURIComponent(courseId)}`; + orientationLink.textContent = 'Start Course Orientation'; + + buttonRow.append(syllabusLink, orientationLink); + + const list = document.createElement('ul'); + list.className = 'checklist'; + config.orientationTopics.forEach(function (topic) { + const item = document.createElement('li'); + item.textContent = topic; + list.append(item); + }); + + fragment.append(buttonRow, list); + return fragment; + } + }, + { + id: 'setup-check', + number: 5, + title: 'Setup Check', + description: 'Use the setup check to report whether you are ready to continue.', + content: function () { + const fragment = document.createDocumentFragment(); + const buttonRow = document.createElement('div'); + buttonRow.className = 'button-row'; + const setupCheck = createExternalLink({ + label: 'Complete my setup check', + url: config.setupCheckUrl, + className: 'button button-primary button-large button-uppercase' + }); + buttonRow.append(setupCheck); + + const statusGrid = document.createElement('div'); + statusGrid.className = 'status-grid'; + + [ + ['status-ready', '🟢', 'READY', 'Everything works.'], + ['status-almost', '🟡', 'ALMOST READY', 'Something needs attention, but you can continue.'], + ['status-help', '🔴', 'HELP NEEDED', 'A problem is preventing you from continuing.'] + ].forEach(function ([className, emoji, label, description]) { + const statusCard = document.createElement('div'); + statusCard.className = `status-card ${className}`; + + const statusLabel = document.createElement('strong'); + const emojiSpan = document.createElement('span'); + emojiSpan.className = 'status-emoji'; + emojiSpan.setAttribute('aria-hidden', 'true'); + emojiSpan.textContent = emoji; + + const labelSpan = document.createElement('span'); + labelSpan.textContent = label; + + statusLabel.append(emojiSpan, labelSpan); + + const statusDescription = document.createElement('span'); + statusDescription.textContent = description; + + statusCard.append(statusLabel, statusDescription); + statusGrid.append(statusCard); + }); + + fragment.append(buttonRow, statusGrid); + return fragment; + } + }, + { + id: 'first-mission', + number: 6, + title: 'First Mission', + description: "Everything working? Don't wait.", + content: function (activeCourse) { + const fragment = document.createDocumentFragment(); + const heading = document.createElement('p'); + const headingStrong = document.createElement('strong'); + headingStrong.textContent = 'Meet Your Computer'; + heading.append(headingStrong); + + const promptList = document.createElement('ol'); + promptList.className = 'orientation-list'; + [ + 'Operating system', + 'Processor', + 'Installed RAM', + 'Total storage', + 'Available storage', + 'One specification you do not understand', + 'Your best explanation of what that specification means' + ].forEach(function (prompt) { + const item = document.createElement('li'); + item.textContent = prompt; + promptList.append(item); + }); + + const buttonRow = document.createElement('div'); + buttonRow.className = 'button-row'; + const missionLink = createExternalLink({ + label: 'Start First Mission', + url: activeCourse.firstMissionUrl || config.firstMissionDefaultUrl, + className: 'button button-primary button-large' + }); + buttonRow.append(missionLink); + + fragment.append(heading, promptList, buttonRow); + return fragment; + } + } + ]; + } + + function renderCoursePicker() { + const courseGrid = document.getElementById('course-grid'); + if (!courseGrid) { + return; + } + + courseGrid.innerHTML = ''; + Object.entries(config.courses).forEach(function ([courseId, course]) { + const button = document.createElement('button'); + button.type = 'button'; + button.className = 'course-card'; + button.addEventListener('click', function () { + setSelectedCourseId(courseId); + renderHomePage(); + }); + const title = document.createElement('h3'); + title.textContent = course.name; + + const description = document.createElement('p'); + description.textContent = course.description; + + const courseCode = document.createElement('div'); + courseCode.className = 'course-code'; + courseCode.textContent = `Open ${course.shortLabel}`; + + button.append(title, description, courseCode); + courseGrid.append(button); + }); + } + + function updateProgress(courseId, steps) { + const progressText = document.getElementById('progress-text'); + const progressBarFill = document.getElementById('progress-bar-fill'); + if (!progressText || !progressBarFill) { + return; + } + + const progress = getCourseProgress(courseId); + const completedCount = steps.filter(function (step) { + return Boolean(progress[step.id]); + }).length; + const totalSteps = steps.length; + const percent = totalSteps ? (completedCount / totalSteps) * 100 : 0; + + progressText.textContent = `${completedCount} of ${totalSteps} steps complete`; + progressBarFill.style.width = `${percent}%`; + } + + function initializeHomePageControls() { + if (page !== 'home' || homePageControlsInitialized) { + return; + } + + const changeCourseButton = document.getElementById('change-course-button'); + const resetProgressButton = document.getElementById('reset-progress-button'); + + if (!changeCourseButton || !resetProgressButton) { + return; + } + + changeCourseButton.addEventListener('click', function () { + localStorage.removeItem(config.storageKeys.selectedCourse); + renderHomePage(); + document.getElementById('course-picker')?.scrollIntoView({ behavior: 'smooth', block: 'start' }); + }); + + resetProgressButton.addEventListener('click', function () { + const activeCourseId = getSelectedCourseId(); + if (!activeCourseId) { + return; + } + resetCourseProgress(activeCourseId); + renderHomePage(); + }); + + homePageControlsInitialized = true; + } + + function renderHomePage() { + if (page !== 'home') { + return; + } + + renderCoursePicker(); + initializeHomePageControls(); + + const selectedCourseId = getSelectedCourseId(); + const selectedCourse = Object.prototype.hasOwnProperty.call(config.courses, selectedCourseId) + ? config.courses[selectedCourseId] + : undefined; + const picker = document.getElementById('course-picker'); + const dashboard = document.getElementById('dashboard'); + const courseName = document.getElementById('selected-course-name'); + const courseDescription = document.getElementById('selected-course-description'); + const stepsContainer = document.getElementById('steps-container'); + const changeCourseButton = document.getElementById('change-course-button'); + const resetProgressButton = document.getElementById('reset-progress-button'); + + if (!picker || !dashboard || !courseName || !courseDescription || !stepsContainer || !changeCourseButton || !resetProgressButton) { + return; + } + + if (!selectedCourse) { + picker.hidden = false; + dashboard.hidden = true; + return; + } + + picker.hidden = true; + dashboard.hidden = false; + courseName.textContent = selectedCourse.name; + courseDescription.textContent = selectedCourse.description; + stepsContainer.innerHTML = ''; + + const steps = buildSteps(selectedCourseId); + steps.forEach(function (step) { + stepsContainer.append(createStepCard(step, selectedCourseId, selectedCourse, steps)); + }); + + updateProgress(selectedCourseId, steps); + } + + function renderOrientationPage() { + if (page !== 'orientation') { + return; + } + + const courseIdFromQuery = new URLSearchParams(window.location.search).get('course'); + const selectedCourseId = courseIdFromQuery || getSelectedCourseId(); + const course = Object.prototype.hasOwnProperty.call(config.courses, selectedCourseId) + ? config.courses[selectedCourseId] + : undefined; + const banner = document.getElementById('orientation-course-banner'); + const launchButton = document.getElementById('orientation-launch-button'); + const syllabusButton = document.getElementById('orientation-syllabus-button'); + const topicsList = document.getElementById('orientation-topics-list'); + + if (topicsList) { + topicsList.innerHTML = ''; + config.orientationTopics.forEach(function (topic) { + const item = document.createElement('li'); + item.textContent = topic; + topicsList.append(item); + }); + } + + if (!banner || !launchButton || !syllabusButton || !course) { + return; + } + + banner.textContent = `Selected course: ${course.name}`; + launchButton.href = course.orientationUrl; + launchButton.target = '_blank'; + launchButton.rel = 'noopener noreferrer'; + launchButton.textContent = 'Launch Orientation Activity'; + launchButton.setAttribute('aria-label', 'Launch Orientation Activity (opens in a new tab)'); + + syllabusButton.href = course.syllabusUrl; + syllabusButton.target = '_blank'; + syllabusButton.rel = 'noopener noreferrer'; + syllabusButton.textContent = 'View Course Syllabus'; + syllabusButton.setAttribute('aria-label', 'View Course Syllabus (opens in a new tab)'); + } + + function renderHelpPage() { + if (page !== 'help') { + return; + } + + const reportProblemButton = document.getElementById('report-problem-button'); + if (!reportProblemButton) { + return; + } + + reportProblemButton.href = config.helpFormUrl; + reportProblemButton.target = '_blank'; + reportProblemButton.rel = 'noopener noreferrer'; + reportProblemButton.setAttribute('aria-label', 'Report a problem (opens in a new tab)'); + } + + renderHomePage(); + renderOrientationPage(); + renderHelpPage(); +}()); diff --git a/js/config.js b/js/config.js new file mode 100644 index 0000000..36b4118 --- /dev/null +++ b/js/config.js @@ -0,0 +1,106 @@ +const SITE_CONFIG = { + storageKeys: { + selectedCourse: 'gci-launch-selected-course', + progress: 'gci-launch-progress' + }, + schoolSystems: [ + { + label: 'School Google Account', + url: 'https://accounts.google.com/', + note: 'Use your school account only.' + }, + { + label: 'Gmail', + url: 'https://mail.google.com/', + note: 'Check for school messages and announcements.' + }, + { + label: 'Google Drive', + url: 'https://drive.google.com/', + note: 'Open your school files and shared resources.' + } + ], + setupCheckUrl: 'https://example.com/REPLACE-WITH-GCI-SETUP-CHECK-FORM', + helpFormUrl: 'https://example.com/REPLACE-WITH-GCI-HELP-FORM', + firstMissionDefaultUrl: 'https://example.com/REPLACE-WITH-FIRST-MISSION-ACTIVITY', + orientationTopics: [ + 'Where assignments are posted', + 'How assignments are submitted', + 'What to do when absent', + 'How to ask for help', + 'Equipment expectations', + 'What to do when technology fails', + 'Appropriate AI use', + 'How grades work' + ], + courses: { + cs: { + name: 'Computer Science', + shortLabel: 'Computer Science', + description: 'Coding foundations, digital problem solving, and course systems setup.', + lms: [ + { label: 'Google Classroom', url: 'https://classroom.google.com/' } + ], + tools: [ + { label: 'CodeHS', url: 'https://codehs.com/' }, + { label: 'GitHub', url: 'https://github.com/' }, + { label: 'Course Coding Environment', url: 'https://example.com/REPLACE-WITH-CS-CODING-ENVIRONMENT' }, + { label: 'Student Help Desk', url: 'https://example.com/REPLACE-WITH-STUDENT-HELP-DESK' } + ], + syllabusUrl: 'https://example.com/REPLACE-WITH-COMPUTER-SCIENCE-SYLLABUS', + orientationUrl: 'https://example.com/REPLACE-WITH-COMPUTER-SCIENCE-ORIENTATION', + firstMissionUrl: 'https://example.com/REPLACE-WITH-COMPUTER-SCIENCE-FIRST-MISSION' + }, + hardware: { + name: 'Computer Hardware', + shortLabel: 'Computer Hardware', + description: 'Hardware, systems, troubleshooting, and certification-oriented course startup.', + lms: [ + { label: 'Canvas', url: 'https://example.com/REPLACE-WITH-DISTRICT-CANVAS-URL' } + ], + tools: [ + { label: 'Certification Resources', url: 'https://example.com/REPLACE-WITH-CERTIFICATION-RESOURCES' }, + { label: 'Hardware Resources', url: 'https://example.com/REPLACE-WITH-HARDWARE-RESOURCES' }, + { label: 'Student Help Desk', url: 'https://example.com/REPLACE-WITH-STUDENT-HELP-DESK' } + ], + syllabusUrl: 'https://example.com/REPLACE-WITH-COMPUTER-HARDWARE-SYLLABUS', + orientationUrl: 'https://example.com/REPLACE-WITH-COMPUTER-HARDWARE-ORIENTATION', + firstMissionUrl: 'https://example.com/REPLACE-WITH-COMPUTER-HARDWARE-FIRST-MISSION' + }, + apcsa_game: { + name: 'AP CSA / Game Design', + shortLabel: 'AP CSA / Game Design', + description: 'Advanced programming workflow, class systems, and creative development tools.', + lms: [ + { label: 'Google Classroom', url: 'https://classroom.google.com/' }, + { label: 'Canvas', url: 'https://example.com/REPLACE-WITH-DISTRICT-CANVAS-URL' } + ], + tools: [ + { label: 'GitHub', url: 'https://github.com/' }, + { label: 'Course Coding Environment', url: 'https://example.com/REPLACE-WITH-APCSA-CODING-ENVIRONMENT' }, + { label: 'CodeHS', url: 'https://codehs.com/' } + ], + syllabusUrl: 'https://example.com/REPLACE-WITH-APCSA-GAME-DESIGN-SYLLABUS', + orientationUrl: 'https://example.com/REPLACE-WITH-APCSA-GAME-DESIGN-ORIENTATION', + firstMissionUrl: 'https://example.com/REPLACE-WITH-APCSA-GAME-DESIGN-FIRST-MISSION' + }, + career: { + name: 'Career Essentials', + shortLabel: 'Career Essentials', + description: 'Career readiness tools, class systems, and onboarding for professional habits.', + lms: [ + { label: 'Canvas', url: 'https://example.com/REPLACE-WITH-DISTRICT-CANVAS-URL' } + ], + tools: [ + { label: 'Certification Resources', url: 'https://example.com/REPLACE-WITH-CAREER-CERTIFICATION-RESOURCES' }, + { label: 'Student Help Desk', url: 'https://example.com/REPLACE-WITH-STUDENT-HELP-DESK' }, + { label: 'Course Tool Workspace', url: 'https://example.com/REPLACE-WITH-CAREER-ESSENTIALS-TOOL' } + ], + syllabusUrl: 'https://example.com/REPLACE-WITH-CAREER-ESSENTIALS-SYLLABUS', + orientationUrl: 'https://example.com/REPLACE-WITH-CAREER-ESSENTIALS-ORIENTATION', + firstMissionUrl: 'https://example.com/REPLACE-WITH-CAREER-ESSENTIALS-FIRST-MISSION' + } + } +}; + +window.SITE_CONFIG = SITE_CONFIG; diff --git a/orientation.html b/orientation.html new file mode 100644 index 0000000..224086d --- /dev/null +++ b/orientation.html @@ -0,0 +1,63 @@ + + + + + + Course Orientation — GCI Computer Science + + + + + + + + + + + +
+
+
+ +

Know how class works before you begin.

+

Use this page to review the essentials, then launch the orientation activity for your class.

+
No course selected yet. Choose a course on the home page for course-specific links.
+ +
+ +
+

During orientation, make sure you learn:

+
    +
    + +
    +

    After orientation

    +
      +
    1. Return to the dashboard.
    2. +
    3. Complete the setup check.
    4. +
    5. Start the first mission if everything works.
    6. +
    +
    +
    +
    + + Need Help? + +