Add password-protected NCERT workshop pages
This commit is contained in:
parent
3f53d3c289
commit
3c694517fc
12 changed files with 871 additions and 16 deletions
|
|
@ -41,7 +41,9 @@ const shouldRenderBody = !isOverview || showOverviewContent || showScheduleBlock
|
||||||
const shouldUseWideBody = Boolean(isOverview && event.showScheduleOnOverview);
|
const shouldUseWideBody = Boolean(isOverview && event.showScheduleOnOverview);
|
||||||
const scheduleAsTabs =
|
const scheduleAsTabs =
|
||||||
showScheduleBlock && event.scheduleDisplay === "tabs" && (event.schedule?.length ?? 0) > 1;
|
showScheduleBlock && event.scheduleDisplay === "tabs" && (event.schedule?.length ?? 0) > 1;
|
||||||
const showHeroScheduleLink = Boolean(schedulePage && !event.showScheduleOnOverview);
|
const showHeroScheduleLink = Boolean(
|
||||||
|
schedulePage && !event.showScheduleOnOverview && event.showScheduleLinkInHero !== false,
|
||||||
|
);
|
||||||
const hasHeroActions = Boolean(event.sourceUrl || showHeroScheduleLink);
|
const hasHeroActions = Boolean(event.sourceUrl || showHeroScheduleLink);
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -54,9 +56,10 @@ const hasHeroActions = Boolean(event.sourceUrl || showHeroScheduleLink);
|
||||||
brandTitle={eventTitle}
|
brandTitle={eventTitle}
|
||||||
brandSubtitle="Event home"
|
brandSubtitle="Event home"
|
||||||
navItems={navItems}
|
navItems={navItems}
|
||||||
|
accessPassword={event.accessPassword}
|
||||||
>
|
>
|
||||||
{isOverview ? (
|
{isOverview ? (
|
||||||
<section class:list={["event-hero", `event-hero--${theme}`]}>
|
<section class:list={["event-hero", `event-hero--${theme}`, event.slug === "ncert" && "event-hero--narrow"]}>
|
||||||
<div class="event-hero__content">
|
<div class="event-hero__content">
|
||||||
<p class="eyebrow">{event.kind} / {event.year}</p>
|
<p class="eyebrow">{event.kind} / {event.year}</p>
|
||||||
<h1>{event.title}</h1>
|
<h1>{event.title}</h1>
|
||||||
|
|
@ -123,9 +126,24 @@ const hasHeroActions = Boolean(event.sourceUrl || showHeroScheduleLink);
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isOverview && showOverviewContent && event.links && (
|
{isOverview && showOverviewContent && event.links && (
|
||||||
<section class="link-strip" aria-label="Related links">
|
event.slug === "ncert" ? (
|
||||||
{event.links.map((link) => <a href={link.href}>{link.label}</a>)}
|
<section class="content-section quick-links" aria-labelledby="quick-links-title">
|
||||||
</section>
|
<p class="eyebrow">Quick links</p>
|
||||||
|
<h2 id="quick-links-title">Working documents and handbooks</h2>
|
||||||
|
<div class="quick-link-grid">
|
||||||
|
{event.links.map((link) => (
|
||||||
|
<a href={link.href} target="_blank" rel="noreferrer">
|
||||||
|
<span>{link.label}</span>
|
||||||
|
<strong aria-hidden="true">Open ↗</strong>
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
) : (
|
||||||
|
<section class="link-strip" aria-label="Related links">
|
||||||
|
{event.links.map((link) => <a href={link.href}>{link.label}</a>)}
|
||||||
|
</section>
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isOverview && showOverviewContent && overviewSections.map((section) => (
|
{isOverview && showOverviewContent && overviewSections.map((section) => (
|
||||||
|
|
@ -143,6 +161,35 @@ const hasHeroActions = Boolean(event.sourceUrl || showHeroScheduleLink);
|
||||||
{section.bullets.map((bullet) => <li>{bullet}</li>)}
|
{section.bullets.map((bullet) => <li>{bullet}</li>)}
|
||||||
</ul>
|
</ul>
|
||||||
)}
|
)}
|
||||||
|
{section.links && (
|
||||||
|
<div class="resource-grid">
|
||||||
|
{section.links.map((link) => (
|
||||||
|
<a href={link.href} target="_blank" rel="noreferrer">
|
||||||
|
<span>{link.label}</span>
|
||||||
|
{link.description && <small>{link.description}</small>}
|
||||||
|
<strong aria-hidden="true">Open PDF ↗</strong>
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{section.entries && (
|
||||||
|
<div class="minutes-list">
|
||||||
|
{section.entries.map((entry) => (
|
||||||
|
<article class="minutes-entry">
|
||||||
|
<header>
|
||||||
|
{entry.meta && <p>{entry.meta}</p>}
|
||||||
|
<h3>{entry.title}</h3>
|
||||||
|
</header>
|
||||||
|
{entry.body.map((paragraph) => <p>{paragraph}</p>)}
|
||||||
|
{entry.bullets && (
|
||||||
|
<ul>
|
||||||
|
{entry.bullets.map((bullet) => <li>{bullet}</li>)}
|
||||||
|
</ul>
|
||||||
|
)}
|
||||||
|
</article>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{section.table && (
|
{section.table && (
|
||||||
<div class="table-wrap">
|
<div class="table-wrap">
|
||||||
<table>
|
<table>
|
||||||
|
|
@ -196,6 +243,35 @@ const hasHeroActions = Boolean(event.sourceUrl || showHeroScheduleLink);
|
||||||
{currentSection.bullets.map((bullet) => <li>{bullet}</li>)}
|
{currentSection.bullets.map((bullet) => <li>{bullet}</li>)}
|
||||||
</ul>
|
</ul>
|
||||||
)}
|
)}
|
||||||
|
{currentSection.links && (
|
||||||
|
<div class="resource-grid">
|
||||||
|
{currentSection.links.map((link) => (
|
||||||
|
<a href={link.href} target="_blank" rel="noreferrer">
|
||||||
|
<span>{link.label}</span>
|
||||||
|
{link.description && <small>{link.description}</small>}
|
||||||
|
<strong aria-hidden="true">Open PDF ↗</strong>
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{currentSection.entries && (
|
||||||
|
<div class="minutes-list">
|
||||||
|
{currentSection.entries.map((entry) => (
|
||||||
|
<article class="minutes-entry">
|
||||||
|
<header>
|
||||||
|
{entry.meta && <p>{entry.meta}</p>}
|
||||||
|
<h3>{entry.title}</h3>
|
||||||
|
</header>
|
||||||
|
{entry.body.map((paragraph) => <p>{paragraph}</p>)}
|
||||||
|
{entry.bullets && (
|
||||||
|
<ul>
|
||||||
|
{entry.bullets.map((bullet) => <li>{bullet}</li>)}
|
||||||
|
</ul>
|
||||||
|
)}
|
||||||
|
</article>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{currentSection.table && (
|
{currentSection.table && (
|
||||||
<div class="table-wrap">
|
<div class="table-wrap">
|
||||||
<table>
|
<table>
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,12 @@ const { schedule, asTabs = false } = Astro.props;
|
||||||
<h2>Schedule</h2>
|
<h2>Schedule</h2>
|
||||||
{asTabs ? (
|
{asTabs ? (
|
||||||
<div class="schedule-tabs" data-schedule-tabs>
|
<div class="schedule-tabs" data-schedule-tabs>
|
||||||
<div class="schedule-tablist" role="tablist" aria-label="Schedule days">
|
<div
|
||||||
|
class="schedule-tablist"
|
||||||
|
role="tablist"
|
||||||
|
aria-label="Schedule days"
|
||||||
|
style={`--schedule-tab-count: ${Math.min(schedule.length, 4)}`}
|
||||||
|
>
|
||||||
{schedule.map((day, index) => (
|
{schedule.map((day, index) => (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,26 @@ export function getEventNavItems(event: Event) {
|
||||||
const peoplePage = eventPages.find((page) => page.type === "people");
|
const peoplePage = eventPages.find((page) => page.type === "people");
|
||||||
const visualPage = eventPages.find((page) => page.type === "visual");
|
const visualPage = eventPages.find((page) => page.type === "visual");
|
||||||
|
|
||||||
|
if (event.slug === "ncert") {
|
||||||
|
const directSectionIds = ["participants", "summary-minutes"];
|
||||||
|
|
||||||
|
return [
|
||||||
|
...(!event.hideOverviewNav ? [{ label: "Overview", href: basePath }] : []),
|
||||||
|
...directSectionIds.flatMap((id) => {
|
||||||
|
const page = sectionPages.find((entry) => entry.id === id);
|
||||||
|
return page ? [{ label: page.label, href: page.href }] : [];
|
||||||
|
}),
|
||||||
|
...(schedulePage ? [{ label: "Schedule", href: schedulePage.href }] : []),
|
||||||
|
{
|
||||||
|
label: "Information",
|
||||||
|
items: infoPages.map((page) => ({
|
||||||
|
label: page.title,
|
||||||
|
href: `${basePath}info/${page.slug}/`,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
if (event.slug === "barcamp") {
|
if (event.slug === "barcamp") {
|
||||||
return [
|
return [
|
||||||
...(!event.hideOverviewNav ? [{ label: "Overview", href: basePath }] : []),
|
...(!event.hideOverviewNav ? [{ label: "Overview", href: basePath }] : []),
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,17 @@ export type EventSection = {
|
||||||
body?: string[];
|
body?: string[];
|
||||||
numbered?: string[];
|
numbered?: string[];
|
||||||
bullets?: string[];
|
bullets?: string[];
|
||||||
|
links?: {
|
||||||
|
label: string;
|
||||||
|
href: string;
|
||||||
|
description?: string;
|
||||||
|
}[];
|
||||||
|
entries?: {
|
||||||
|
title: string;
|
||||||
|
meta?: string;
|
||||||
|
body: string[];
|
||||||
|
bullets?: string[];
|
||||||
|
}[];
|
||||||
table?: InfoTable;
|
table?: InfoTable;
|
||||||
tables?: InfoTable[];
|
tables?: InfoTable[];
|
||||||
};
|
};
|
||||||
|
|
@ -47,11 +58,13 @@ export type Event = {
|
||||||
status?: string;
|
status?: string;
|
||||||
summary: string;
|
summary: string;
|
||||||
href?: string;
|
href?: string;
|
||||||
|
accessPassword?: string;
|
||||||
sourceUrl?: string;
|
sourceUrl?: string;
|
||||||
showRoleInHero?: boolean;
|
showRoleInHero?: boolean;
|
||||||
showOverviewContent?: boolean;
|
showOverviewContent?: boolean;
|
||||||
hideOverviewNav?: boolean;
|
hideOverviewNav?: boolean;
|
||||||
showScheduleOnOverview?: boolean;
|
showScheduleOnOverview?: boolean;
|
||||||
|
showScheduleLinkInHero?: boolean;
|
||||||
scheduleDisplay?: "grid" | "tabs";
|
scheduleDisplay?: "grid" | "tabs";
|
||||||
featured?: boolean;
|
featured?: boolean;
|
||||||
highlight?: boolean;
|
highlight?: boolean;
|
||||||
|
|
@ -114,6 +127,297 @@ export const events: Event[] = [
|
||||||
schedule: [],
|
schedule: [],
|
||||||
people: [],
|
people: [],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
year: "2026",
|
||||||
|
slug: "ncert",
|
||||||
|
href: "/ncert/",
|
||||||
|
title: "Workshop on Development of Computer Science Textbooks",
|
||||||
|
shortTitle: "NCERT Textbook Workshop",
|
||||||
|
subtitle: "Four days of collaborative curriculum and textbook development",
|
||||||
|
date: "July 16-19, 2026",
|
||||||
|
location: "IIT Gandhinagar",
|
||||||
|
kind: "Workshop",
|
||||||
|
role: "Host",
|
||||||
|
status: "July 16-19",
|
||||||
|
theme: "sage",
|
||||||
|
accessPassword: "NCERT2026",
|
||||||
|
showRoleInHero: false,
|
||||||
|
showOverviewContent: true,
|
||||||
|
showScheduleOnOverview: false,
|
||||||
|
showScheduleLinkInHero: false,
|
||||||
|
scheduleDisplay: "tabs",
|
||||||
|
summary:
|
||||||
|
"A four-day NCERT workshop at IIT Gandhinagar focused on developing Computer Science textbooks and turning the committee's curriculum work into a coherent chapter plan.",
|
||||||
|
tags: ["NCERT", "computer science education", "textbook development"],
|
||||||
|
facts: [
|
||||||
|
{ label: "Format", value: "Four-day working workshop" },
|
||||||
|
],
|
||||||
|
links: [
|
||||||
|
{
|
||||||
|
label: "Current overview document",
|
||||||
|
href: "https://docs.google.com/document/d/1a15lxJ2sCReA499Rl4ZZzLBUkvSLZrB2nug1n53ITjI/edit?tab=t.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Current textbooks and materials",
|
||||||
|
href: "https://drive.google.com/drive/u/2/folders/1G1EU5tvUDi-VWYQL5u9LxkBbtcf7kcM0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Overleaf project",
|
||||||
|
href: "https://www.overleaf.com/project/69b97fe6efd17e1e47ce833f",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "GitHub: csncert/grade11",
|
||||||
|
href: "https://github.com/csncert/grade11",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Class III CT&AI handbook",
|
||||||
|
href: "https://cbseacademic.nic.in/web_material/CurriculumMain27/CTAI_Pri3SH_2026-27.pdf",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Class IV CT&AI handbook",
|
||||||
|
href: "https://cbseacademic.nic.in/web_material/CurriculumMain27/CTAI_Pri4SH_2026-27.pdf",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Class V CT&AI handbook",
|
||||||
|
href: "https://cbseacademic.nic.in/web_material/CurriculumMain27/CTAI_Pri5SH_2026-27.pdf",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
title: "Overview",
|
||||||
|
body: [
|
||||||
|
"Members of the Computer Science Textbook Development Team are meeting at IIT Gandhinagar for four focused days of syllabus refinement, chapter planning, writing, and review.",
|
||||||
|
"The workshop builds on a sequence of online committee meetings held since November 2025. Those discussions established the curricular goals and competencies, explored the relationship between computational thinking and programming, and developed a working structure for the textbooks.",
|
||||||
|
"The Schedule page contains the first day's programme. Plans for the remaining days will be added there as the workshop progresses.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Participants",
|
||||||
|
body: [
|
||||||
|
"Participants in the four-day workshop on the development of Computer Science textbooks, held at IIT Gandhinagar from July 16-19, 2026.",
|
||||||
|
],
|
||||||
|
table: {
|
||||||
|
headers: ["S. No.", "Name", "Designation / Affiliation"],
|
||||||
|
rows: [
|
||||||
|
["1", "Prof. Chandrasekaran Pandurangan", "Chairperson, CS-TDT"],
|
||||||
|
["2", "Prof. Madhavan Mukund", "Chennai Mathematical Institute"],
|
||||||
|
["3", "Shri Vipul Shah", "Principal Scientist, Founder of ACM India's CS Pathshala"],
|
||||||
|
["4", "Dr. Angel Rathnabai", "CIET, NCERT"],
|
||||||
|
["5", "Smt. Mamta Manaktala", "Senior Learning Manager (India), Raspberry Pi Foundation, Gurgaon"],
|
||||||
|
["6", "Smt. Preyashi Agarwal", "Software Industry Professional and Researcher (Microservices & Cloud)"],
|
||||||
|
["7", "Smt. Shweta", "iTech Creations / Freelance Technology Writer"],
|
||||||
|
["8", "Dr. Chandni Agarwal", "PGT Computer Science, Maharaja Agrasen Model School, Delhi"],
|
||||||
|
["9", "Shri Naveen Gupta", "PGT-CS, St. Mark's Sr. Sec. Public School, Delhi"],
|
||||||
|
["10", "Smt. Mohini Arora", "HOD Computer Science, Air Force Golden Jubilee Institute, Delhi"],
|
||||||
|
["11", "Smt. Chetna Khanna", "Freelance educationist (Ex. PGT CS), Delhi"],
|
||||||
|
["12", "Smt. Rajeshwari Lakshmanan", "PGT-CS, SNDJA Vivekananda Vidyalaya Sr Secondary School, Chennai"],
|
||||||
|
["13", "Shri Shravan S K", "Member, NSTC, Programme Office"],
|
||||||
|
["14", "Dr. Neeldhara Mishra", "Faculty member, Deptt of CS, IIT Gandhinagar"],
|
||||||
|
["15", "Prof. K Vijayan", "Member co-coordinator, CS-TDT, DCS&D, NCERT"],
|
||||||
|
["16", "Dr. Rejaul Karim Barbhuiya", "Member coordinator, CS-TDT, DESM, NCERT"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Summary Minutes",
|
||||||
|
body: [
|
||||||
|
"The summaries below were prepared from the supplied automatic transcripts. Repeated recordings of the same meetings have been consolidated, and minor transcription errors may remain in names or technical terms.",
|
||||||
|
],
|
||||||
|
entries: [
|
||||||
|
{
|
||||||
|
title: "Committee orientation and scope",
|
||||||
|
meta: "November 25, 2025",
|
||||||
|
body: [
|
||||||
|
"The committee introduced its members and reviewed the task of developing the Computer Science curriculum and textbooks for Classes XI and XII. The discussion emphasized beginning with curricular goals and competencies, while keeping computational thinking, abstraction, puzzles, and progression from the existing curriculum in view.",
|
||||||
|
],
|
||||||
|
bullets: [
|
||||||
|
"Use a shared Drive for recordings, source documents, profiles, and committee material.",
|
||||||
|
"Seek a broader NSTC orientation before freezing curricular goals and the syllabus.",
|
||||||
|
"Collect missing contact details and circulate the Drive link separately by email.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Goals, competencies, and a route to chapterization",
|
||||||
|
meta: "November 29, 2025",
|
||||||
|
body: [
|
||||||
|
"The committee reviewed its mandate, acknowledged the compressed timeline, and discussed how much freedom it had to revise existing curricular goals. Members agreed that the work should move in sequence from goals to competencies, syllabus, chapterization, and writing, with room for iteration between stages.",
|
||||||
|
],
|
||||||
|
bullets: [
|
||||||
|
"Collect structured feedback on curricular goals through the shared Google form.",
|
||||||
|
"Map the existing curriculum under broad headings such as systems, networks, databases, programming, data, trends, and ethics.",
|
||||||
|
"Aim to reach chapterization in roughly three weeks and use an in-person meeting for intensive content decisions.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Balancing ambition with the delivery timeline",
|
||||||
|
meta: "December 6, 2025",
|
||||||
|
body: [
|
||||||
|
"Members discussed the tension between a philosophically ambitious curriculum and what Class XI-XII students can realistically learn within the available hours. A short foundational bridge at the start of Class XI was considered, along with a faster shift from broad goals to concrete textbook content.",
|
||||||
|
],
|
||||||
|
bullets: [
|
||||||
|
"Develop curricular goals and the minimum viable core of the textbook in parallel.",
|
||||||
|
"Prepare a consolidated summary and a pointed agenda for the next meeting.",
|
||||||
|
"Plan an in-person meeting, with online participation available for members who cannot travel.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Programming choices and curricular balance",
|
||||||
|
meta: "December 16, 2025",
|
||||||
|
body: [
|
||||||
|
"The committee refined curricular goals and competencies and debated whether visual programming in Snap should precede Python. Members also asked whether the emerging framework over-emphasized AI while giving too little space to databases, complexity, independent problem solving, and computing systems in India.",
|
||||||
|
],
|
||||||
|
bullets: [
|
||||||
|
"Revise the wording and balance of the curricular goals where needed.",
|
||||||
|
"Identify major content areas before the December 19 meeting.",
|
||||||
|
"Form topic-based groups in preparation for the planned end-of-December in-person meeting.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Pseudocode, Snap, and Python",
|
||||||
|
meta: "December 19, 2025",
|
||||||
|
body: [
|
||||||
|
"The meeting compared pseudocode, block-based programming, and Python as bridges from algorithmic thinking to executable programs. Snap was valued for reducing syntax and providing immediate visual feedback, while Python benefited from existing teacher experience and wider familiarity.",
|
||||||
|
],
|
||||||
|
bullets: [
|
||||||
|
"Keep the programming-language choice open while evaluating teacher readiness and pedagogical value.",
|
||||||
|
"Use the agreed curricular goals as the structure for members to indicate preferred areas of work.",
|
||||||
|
"Finalize content areas and subgroup participation at the December 23 meeting.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "From curricular goals to chapters",
|
||||||
|
meta: "December 23, 2025",
|
||||||
|
body: [
|
||||||
|
"Members continued the programming-language discussion and stressed that students should encounter both clear algorithmic representations and runnable programs. The group agreed that chapterization and sequencing needed more detail before writing groups could work effectively.",
|
||||||
|
],
|
||||||
|
bullets: [
|
||||||
|
"Enter the in-person meeting with a stable set of curricular goals and competencies.",
|
||||||
|
"Use the meeting to draft the syllabus outline, decide chapter order, and then form writing subcommittees.",
|
||||||
|
"Build projects and practical work into the progression rather than treating them as an afterthought.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "First-cut chapter plan and writing groups",
|
||||||
|
meta: "January 9, 2026",
|
||||||
|
body: [
|
||||||
|
"A first chapter structure and proposed writing-review groups were presented. Members favored introducing problem solving, pseudocode, and executable visual programming together, rather than keeping learners away from the computer through a long theory-only opening.",
|
||||||
|
],
|
||||||
|
bullets: [
|
||||||
|
"Connect early algorithms to later Snap implementations and practical exercises.",
|
||||||
|
"Plan teacher orientation and hand-holding if Snap is adopted.",
|
||||||
|
"Let groups propose agenda items and clarify whether the current large blocks are units, chapters, or chapters with subchapters.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Chapter outlines before full drafting",
|
||||||
|
meta: "January 13, 2026",
|
||||||
|
body: [
|
||||||
|
"The committee reviewed subgroup responsibilities and the need for a coherent picture of both Class XI and Class XII. To avoid extensive rewrites, each group was asked to agree on a concise chapter outline before investing in full prose.",
|
||||||
|
],
|
||||||
|
bullets: [
|
||||||
|
"Treat the chapter outline as the first checkpoint, followed by syllabus drafting and chapter writing.",
|
||||||
|
"Nominate one point of contact for each subgroup.",
|
||||||
|
"Develop enough of the Class XII structure to validate the progression from Class XI.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Draft milestones and syllabus completeness",
|
||||||
|
meta: "February 17, 2026",
|
||||||
|
body: [
|
||||||
|
"Members set a working sequence for draft submission, review, and revision. The Class XI syllabus needed unit-wise topics, learning outcomes, marks, practical work, and suggested resources, while the Class XII outline had to be developed in parallel so students could see the full two-year offering.",
|
||||||
|
],
|
||||||
|
bullets: [
|
||||||
|
"Hold an overall syllabus-draft meeting the following week.",
|
||||||
|
"Target a first chapter draft in mid-March, followed by review and revision.",
|
||||||
|
"Close the Class XII outline by the end of February or early March if possible.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "NCERT delivery dates and review plan",
|
||||||
|
meta: "February 25, 2026",
|
||||||
|
body: [
|
||||||
|
"The committee noted that the Class XI textbook rollout had moved to the 2027-28 academic year and worked backward from NCERT's delivery dates. The discussion distinguished the first submitted draft from the later reviewed manuscript.",
|
||||||
|
],
|
||||||
|
bullets: [
|
||||||
|
"March 20: first drafts of all Part I chapters and the complete Class XI syllabus.",
|
||||||
|
"April 20: final draft manuscript of Part I after review.",
|
||||||
|
"May 30: first draft of Part II; use March 10 as the next progress-review meeting.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Progress review ahead of the March deadline",
|
||||||
|
meta: "March 10, 2026",
|
||||||
|
body: [
|
||||||
|
"Writing was under way on the introductory, algorithms and pseudocode, data-centric computing, historical perspective, and Snap material. The chapter drafts were progressing, but the complete Class XI syllabus was not yet in a form ready for submission.",
|
||||||
|
],
|
||||||
|
bullets: [
|
||||||
|
"Derive the full syllabus outline from the chapter work already completed.",
|
||||||
|
"Hold chapter-wise slide presentations on March 17 at 9:00 pm.",
|
||||||
|
"Use that review to prepare for the March 20 submission milestone.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Replanning after changes in the writing team",
|
||||||
|
meta: "July 5, 2026",
|
||||||
|
body: [
|
||||||
|
"The committee reported that the curriculum had advanced substantially, but textbook implementation had stalled after two key contributors withdrew. Members discussed whether to preserve usable fragments, simplify the plan, or restart the programming portion with new contributors.",
|
||||||
|
],
|
||||||
|
bullets: [
|
||||||
|
"Identify special invitees or replacement contributors with the needed programming and pedagogy expertise.",
|
||||||
|
"Review the existing programming drafts before choosing what can be retained.",
|
||||||
|
"Prepare for the IIT Gandhinagar working meeting and reconvene as a full committee on July 9.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Urgent syllabus reset before the workshop",
|
||||||
|
meta: "July 9, 2026",
|
||||||
|
body: [
|
||||||
|
"The committee reviewed a chapter-wise Class XI plan spanning computational thinking, puzzles, algorithms, pseudocode and flowcharts, programming, and later applications. The largest unresolved issue remained whether to begin with Python, retain Snap, or compare Snap and Scratch through a small prototype before deciding.",
|
||||||
|
],
|
||||||
|
bullets: [
|
||||||
|
"Keep the already agreed curricular goals and competencies as the foundation for the revised syllabus.",
|
||||||
|
"Prepare a small comparative block-programming example to support the Snap-versus-Scratch decision.",
|
||||||
|
"Use a technical subset meeting followed by a full committee meeting to arrive at a defensible chapter plan before the in-person workshop.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
schedule: [
|
||||||
|
{
|
||||||
|
label: "Day 1",
|
||||||
|
date: "July 16, 2026",
|
||||||
|
items: [
|
||||||
|
{ time: "09:30", title: "Settle in and configure screen sharing on the 'smart' TV 😬", kind: "note" },
|
||||||
|
{ time: "10:00", title: "Opening remarks", kind: "session" },
|
||||||
|
{ time: "10:30", title: "Review and recap of what we have so far", kind: "session" },
|
||||||
|
{ time: "11:00", title: "Coffee at Nescafe", kind: "break" },
|
||||||
|
{ time: "11:30", title: "Anup's presentation on flowcharts", kind: "session" },
|
||||||
|
{ time: "12:30", title: "Discussion: finalizing the plan ahead", kind: "session" },
|
||||||
|
{ time: "13:00", title: "Lunch back at the guest house", kind: "break" },
|
||||||
|
{ time: "14:30", title: "Small-group discussions / breakout rooms", kind: "session" },
|
||||||
|
{ time: "16:00", title: "Coffee at Nescafe", kind: "break" },
|
||||||
|
{ time: "16:30", title: "Small-group discussions continue", kind: "session" },
|
||||||
|
{ time: "18:00", title: "Consolidate, review, and plan for tomorrow", kind: "session" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Day 2",
|
||||||
|
date: "July 17, 2026",
|
||||||
|
items: [{ time: "To be announced", title: "Schedule to be confirmed", kind: "note" }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Day 3",
|
||||||
|
date: "July 18, 2026",
|
||||||
|
items: [{ time: "To be announced", title: "Schedule to be confirmed", kind: "note" }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Day 4",
|
||||||
|
date: "July 19, 2026",
|
||||||
|
items: [{ time: "To be announced", title: "Schedule to be confirmed", kind: "note" }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
year: "2026",
|
year: "2026",
|
||||||
slug: "history-of-science",
|
slug: "history-of-science",
|
||||||
|
|
@ -931,10 +1235,15 @@ export const internalEvents = events.filter((event) => event.slug);
|
||||||
export const organizedEvents = events;
|
export const organizedEvents = events;
|
||||||
|
|
||||||
export function getEventPath(event: Event) {
|
export function getEventPath(event: Event) {
|
||||||
|
if (event.href?.startsWith("/")) return event.href;
|
||||||
if (event.slug) return `/${event.year}/${event.slug}/`;
|
if (event.slug) return `/${event.year}/${event.slug}/`;
|
||||||
return event.href ?? "#";
|
return event.href ?? "#";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const yearPathEvents = internalEvents.filter(
|
||||||
|
(event) => getEventPath(event) === `/${event.year}/${event.slug}/`,
|
||||||
|
);
|
||||||
|
|
||||||
export function getEventBasePath(event: Event) {
|
export function getEventBasePath(event: Event) {
|
||||||
return getEventPath(event);
|
return getEventPath(event);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
---
|
---
|
||||||
import "../styles/global.css";
|
import "../styles/global.css";
|
||||||
|
import { createHash } from "node:crypto";
|
||||||
|
|
||||||
type NavLink = {
|
type NavLink = {
|
||||||
label: string;
|
label: string;
|
||||||
|
|
@ -24,6 +25,7 @@ type Props = {
|
||||||
brandTitle?: string;
|
brandTitle?: string;
|
||||||
brandSubtitle?: string;
|
brandSubtitle?: string;
|
||||||
navItems?: NavItem[];
|
navItems?: NavItem[];
|
||||||
|
accessPassword?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
|
@ -34,6 +36,7 @@ const {
|
||||||
brandTitle = "Events",
|
brandTitle = "Events",
|
||||||
brandSubtitle = "organized events and local guides",
|
brandSubtitle = "organized events and local guides",
|
||||||
navItems: suppliedNavItems,
|
navItems: suppliedNavItems,
|
||||||
|
accessPassword,
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
|
|
||||||
const pageTitle = title === "Events" ? "Events" : `${title} - Events`;
|
const pageTitle = title === "Events" ? "Events" : `${title} - Events`;
|
||||||
|
|
@ -44,6 +47,10 @@ const defaultNavItems: NavItem[] = [
|
||||||
const navItems = suppliedNavItems ?? defaultNavItems;
|
const navItems = suppliedNavItems ?? defaultNavItems;
|
||||||
const navVariant = suppliedNavItems ? "standard" : "toggle";
|
const navVariant = suppliedNavItems ? "standard" : "toggle";
|
||||||
const pathname = Astro.url.pathname;
|
const pathname = Astro.url.pathname;
|
||||||
|
const accessPasswordHash = accessPassword
|
||||||
|
? createHash("sha256").update(accessPassword).digest("hex")
|
||||||
|
: undefined;
|
||||||
|
const accessKey = `event-access:${brandHref}`;
|
||||||
const rybbitScriptSrc = "https://analytics.neeldhara.cloud/api/script.js";
|
const rybbitScriptSrc = "https://analytics.neeldhara.cloud/api/script.js";
|
||||||
const rybbitSiteId = "12";
|
const rybbitSiteId = "12";
|
||||||
const isMenu = (item: NavItem): item is Extract<NavItem, { items: NavLink[] }> => "items" in item;
|
const isMenu = (item: NavItem): item is Extract<NavItem, { items: NavLink[] }> => "items" in item;
|
||||||
|
|
@ -94,7 +101,40 @@ const getMenuLayout = (item: Extract<NavItem, { items: NavLink[] }>) => {
|
||||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||||
{import.meta.env.PROD && <script is:inline src={rybbitScriptSrc} data-site-id={rybbitSiteId} defer></script>}
|
{import.meta.env.PROD && <script is:inline src={rybbitScriptSrc} data-site-id={rybbitSiteId} defer></script>}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body class:list={[accessPassword && "is-locked"]}>
|
||||||
|
{accessPassword && (
|
||||||
|
<section
|
||||||
|
class="access-gate"
|
||||||
|
data-access-gate
|
||||||
|
data-access-hash={accessPasswordHash}
|
||||||
|
data-access-key={accessKey}
|
||||||
|
aria-labelledby="access-title"
|
||||||
|
>
|
||||||
|
<div class="access-gate__card">
|
||||||
|
<p class="eyebrow">Private event page</p>
|
||||||
|
<h1 id="access-title">Enter the workshop password</h1>
|
||||||
|
<p>This event information is shared with workshop participants.</p>
|
||||||
|
<form data-access-form>
|
||||||
|
<label for="event-password">Password</label>
|
||||||
|
<div class="access-gate__controls">
|
||||||
|
<input
|
||||||
|
id="event-password"
|
||||||
|
name="password"
|
||||||
|
type="password"
|
||||||
|
required
|
||||||
|
autocomplete="off"
|
||||||
|
spellcheck="false"
|
||||||
|
aria-describedby="access-error"
|
||||||
|
data-access-input
|
||||||
|
/>
|
||||||
|
<button type="submit" data-access-submit>Unlock</button>
|
||||||
|
</div>
|
||||||
|
<p class="access-gate__error" id="access-error" aria-live="polite" data-access-error></p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
|
<div data-protected-shell hidden={Boolean(accessPassword)}>
|
||||||
<a class="skip-link" href="#content">Skip to content</a>
|
<a class="skip-link" href="#content">Skip to content</a>
|
||||||
<header class="site-header">
|
<header class="site-header">
|
||||||
<div class="site-header__inner">
|
<div class="site-header__inner">
|
||||||
|
|
@ -177,7 +217,7 @@ const getMenuLayout = (item: Extract<NavItem, { items: NavLink[] }>) => {
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<main id="content">
|
<main id="content" tabindex="-1">
|
||||||
<slot />
|
<slot />
|
||||||
</main>
|
</main>
|
||||||
<footer class="site-footer">
|
<footer class="site-footer">
|
||||||
|
|
@ -190,5 +230,84 @@ const getMenuLayout = (item: Extract<NavItem, { items: NavLink[] }>) => {
|
||||||
<a href="https://github.com/neeldhara">GitHub</a>
|
<a href="https://github.com/neeldhara">GitHub</a>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
</div>
|
||||||
|
{accessPassword && (
|
||||||
|
<script is:inline>
|
||||||
|
const accessGate = document.querySelector("[data-access-gate]");
|
||||||
|
|
||||||
|
if (accessGate) {
|
||||||
|
const protectedShell = document.querySelector("[data-protected-shell]");
|
||||||
|
const accessForm = accessGate.querySelector("[data-access-form]");
|
||||||
|
const passwordInput = accessGate.querySelector("[data-access-input]");
|
||||||
|
const submitButton = accessGate.querySelector("[data-access-submit]");
|
||||||
|
const errorMessage = accessGate.querySelector("[data-access-error]");
|
||||||
|
const expectedHash = accessGate.getAttribute("data-access-hash");
|
||||||
|
const storageKey = accessGate.getAttribute("data-access-key");
|
||||||
|
|
||||||
|
const readAccess = () => {
|
||||||
|
try {
|
||||||
|
return storageKey && sessionStorage.getItem(storageKey) === expectedHash;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const rememberAccess = () => {
|
||||||
|
try {
|
||||||
|
if (storageKey && expectedHash) sessionStorage.setItem(storageKey, expectedHash);
|
||||||
|
} catch {
|
||||||
|
// Access still works for this page even when storage is unavailable.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const hashPassword = async (value) => {
|
||||||
|
const bytes = new TextEncoder().encode(value);
|
||||||
|
const digest = await crypto.subtle.digest("SHA-256", bytes);
|
||||||
|
return Array.from(new Uint8Array(digest))
|
||||||
|
.map((byte) => byte.toString(16).padStart(2, "0"))
|
||||||
|
.join("");
|
||||||
|
};
|
||||||
|
|
||||||
|
const unlock = (moveFocus = false) => {
|
||||||
|
accessGate.hidden = true;
|
||||||
|
if (protectedShell) protectedShell.hidden = false;
|
||||||
|
document.body.classList.remove("is-locked");
|
||||||
|
if (moveFocus) document.querySelector("#content")?.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (readAccess()) {
|
||||||
|
unlock();
|
||||||
|
} else {
|
||||||
|
accessGate.hidden = false;
|
||||||
|
if (protectedShell) protectedShell.hidden = true;
|
||||||
|
|
||||||
|
if (window.matchMedia("(hover: hover) and (pointer: fine)").matches) {
|
||||||
|
passwordInput?.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
accessForm?.addEventListener("submit", async (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (!passwordInput || !submitButton || !expectedHash) return;
|
||||||
|
|
||||||
|
submitButton.disabled = true;
|
||||||
|
errorMessage.textContent = "";
|
||||||
|
passwordInput.setAttribute("aria-invalid", "false");
|
||||||
|
|
||||||
|
const submittedHash = await hashPassword(passwordInput.value);
|
||||||
|
|
||||||
|
if (submittedHash === expectedHash) {
|
||||||
|
rememberAccess();
|
||||||
|
unlock(true);
|
||||||
|
} else {
|
||||||
|
errorMessage.textContent = "That password is not correct. Please try again.";
|
||||||
|
passwordInput.setAttribute("aria-invalid", "true");
|
||||||
|
passwordInput.select();
|
||||||
|
submitButton.disabled = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
)}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
---
|
---
|
||||||
import BarcampPage from "../../components/BarcampPage.astro";
|
import BarcampPage from "../../components/BarcampPage.astro";
|
||||||
import EventPage from "../../components/EventPage.astro";
|
import EventPage from "../../components/EventPage.astro";
|
||||||
import { getEventByParams, getEventPageEntry, internalEvents } from "../../data/events";
|
import { getEventByParams, getEventPageEntry, yearPathEvents } from "../../data/events";
|
||||||
|
|
||||||
export function getStaticPaths() {
|
export function getStaticPaths() {
|
||||||
return internalEvents.map((event) => ({
|
return yearPathEvents.map((event) => ({
|
||||||
params: { year: event.year, slug: event.slug },
|
params: { year: event.year, slug: event.slug },
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
---
|
---
|
||||||
import BarcampPage from "../../../components/BarcampPage.astro";
|
import BarcampPage from "../../../components/BarcampPage.astro";
|
||||||
import EventPage from "../../../components/EventPage.astro";
|
import EventPage from "../../../components/EventPage.astro";
|
||||||
import { getEventByParams, getEventPageEntries, internalEvents } from "../../../data/events";
|
import { getEventByParams, getEventPageEntries, yearPathEvents } from "../../../data/events";
|
||||||
|
|
||||||
export function getStaticPaths() {
|
export function getStaticPaths() {
|
||||||
return internalEvents.flatMap((event) =>
|
return yearPathEvents.flatMap((event) =>
|
||||||
getEventPageEntries(event)
|
getEventPageEntries(event)
|
||||||
.filter((pageEntry) => pageEntry.type !== "overview")
|
.filter((pageEntry) => pageEntry.type !== "overview")
|
||||||
.map((pageEntry) => ({
|
.map((pageEntry) => ({
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ import { getEventNavItems } from "../../../../data/eventNav";
|
||||||
import {
|
import {
|
||||||
getEventBasePath,
|
getEventBasePath,
|
||||||
getEventByParams,
|
getEventByParams,
|
||||||
internalEvents,
|
yearPathEvents,
|
||||||
} from "../../../../data/events";
|
} from "../../../../data/events";
|
||||||
import { getInfoPage, infoPages } from "../../../../data/info";
|
import { getInfoPage, infoPages } from "../../../../data/info";
|
||||||
|
|
||||||
export function getStaticPaths() {
|
export function getStaticPaths() {
|
||||||
return internalEvents.flatMap((event) =>
|
return yearPathEvents.flatMap((event) =>
|
||||||
infoPages.map((page) => ({
|
infoPages.map((page) => ({
|
||||||
params: {
|
params: {
|
||||||
year: event.year,
|
year: event.year,
|
||||||
|
|
@ -47,6 +47,7 @@ const infoNavLabel = event.slug === "barcamp" ? "Venue" : "Information";
|
||||||
brandTitle={eventTitle}
|
brandTitle={eventTitle}
|
||||||
brandSubtitle="Event home"
|
brandSubtitle="Event home"
|
||||||
navItems={getEventNavItems(event)}
|
navItems={getEventNavItems(event)}
|
||||||
|
accessPassword={event.accessPassword}
|
||||||
>
|
>
|
||||||
<section class="event-page-heading">
|
<section class="event-page-heading">
|
||||||
<nav class="event-breadcrumb" aria-label="Event breadcrumb">
|
<nav class="event-breadcrumb" aria-label="Event breadcrumb">
|
||||||
|
|
|
||||||
25
src/pages/ncert/[page].astro
Normal file
25
src/pages/ncert/[page].astro
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
import EventPage from "../../components/EventPage.astro";
|
||||||
|
import { getEventByParams, getEventPageEntries } from "../../data/events";
|
||||||
|
|
||||||
|
export function getStaticPaths() {
|
||||||
|
const event = getEventByParams("2026", "ncert");
|
||||||
|
|
||||||
|
if (!event) return [];
|
||||||
|
|
||||||
|
return getEventPageEntries(event)
|
||||||
|
.filter((pageEntry) => pageEntry.type !== "overview")
|
||||||
|
.map((pageEntry) => ({
|
||||||
|
params: { page: pageEntry.id },
|
||||||
|
props: { event, pageEntry },
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const { event, pageEntry } = Astro.props;
|
||||||
|
|
||||||
|
if (!event || !pageEntry) {
|
||||||
|
return Astro.redirect("/ncert/");
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
<EventPage event={event} pageEntry={pageEntry} />
|
||||||
14
src/pages/ncert/index.astro
Normal file
14
src/pages/ncert/index.astro
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
import EventPage from "../../components/EventPage.astro";
|
||||||
|
import { getEventByParams, getEventPageEntry } from "../../data/events";
|
||||||
|
|
||||||
|
const event = getEventByParams("2026", "ncert");
|
||||||
|
|
||||||
|
if (!event) {
|
||||||
|
return Astro.redirect("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageEntry = getEventPageEntry(event);
|
||||||
|
---
|
||||||
|
|
||||||
|
<EventPage event={event} pageEntry={pageEntry} />
|
||||||
56
src/pages/ncert/info/[infoSlug].astro
Normal file
56
src/pages/ncert/info/[infoSlug].astro
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
---
|
||||||
|
import InfoPageSections from "../../../components/InfoPageSections.astro";
|
||||||
|
import SiteLayout from "../../../layouts/SiteLayout.astro";
|
||||||
|
import { getEventNavItems } from "../../../data/eventNav";
|
||||||
|
import { getEventBasePath, getEventByParams } from "../../../data/events";
|
||||||
|
import { infoPages } from "../../../data/info";
|
||||||
|
|
||||||
|
export function getStaticPaths() {
|
||||||
|
const event = getEventByParams("2026", "ncert");
|
||||||
|
|
||||||
|
if (!event) return [];
|
||||||
|
|
||||||
|
return infoPages.map((page) => ({
|
||||||
|
params: { infoSlug: page.slug },
|
||||||
|
props: { event, page },
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const { event, page } = Astro.props;
|
||||||
|
|
||||||
|
if (!event || !page) {
|
||||||
|
return Astro.redirect("/ncert/");
|
||||||
|
}
|
||||||
|
|
||||||
|
const eventTitle = event.shortTitle ?? event.title;
|
||||||
|
const basePath = getEventBasePath(event);
|
||||||
|
---
|
||||||
|
|
||||||
|
<SiteLayout
|
||||||
|
title={`${page.title} - ${eventTitle}`}
|
||||||
|
description={page.title}
|
||||||
|
theme={event.theme ?? "default"}
|
||||||
|
brandHref={basePath}
|
||||||
|
brandTitle={eventTitle}
|
||||||
|
brandSubtitle="Event home"
|
||||||
|
navItems={getEventNavItems(event)}
|
||||||
|
accessPassword={event.accessPassword}
|
||||||
|
>
|
||||||
|
<section class="event-page-heading">
|
||||||
|
<nav class="event-breadcrumb" aria-label="Event breadcrumb">
|
||||||
|
<a href={basePath}>{eventTitle}</a>
|
||||||
|
<span aria-hidden="true">/</span>
|
||||||
|
<span>Information</span>
|
||||||
|
<span aria-hidden="true">/</span>
|
||||||
|
<span>{page.title}</span>
|
||||||
|
</nav>
|
||||||
|
<p class="eyebrow">Information</p>
|
||||||
|
<h1>{page.title}</h1>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="event-shell event-shell--single">
|
||||||
|
<div class="event-content">
|
||||||
|
<InfoPageSections page={page} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</SiteLayout>
|
||||||
|
|
@ -131,7 +131,8 @@ a {
|
||||||
}
|
}
|
||||||
|
|
||||||
a:focus-visible,
|
a:focus-visible,
|
||||||
button:focus-visible {
|
button:focus-visible,
|
||||||
|
input:focus-visible {
|
||||||
outline: 2px solid var(--ring);
|
outline: 2px solid var(--ring);
|
||||||
outline-offset: 3px;
|
outline-offset: 3px;
|
||||||
}
|
}
|
||||||
|
|
@ -207,6 +208,111 @@ th {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body.is-locked {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-gate[hidden],
|
||||||
|
[data-protected-shell][hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-gate {
|
||||||
|
display: grid;
|
||||||
|
min-height: 100svh;
|
||||||
|
place-items: center;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 15% 20%, rgba(240, 214, 141, 0.28), transparent 28rem),
|
||||||
|
radial-gradient(circle at 85% 80%, rgba(49, 91, 75, 0.16), transparent 30rem),
|
||||||
|
var(--background);
|
||||||
|
padding: max(1rem, env(safe-area-inset-top)) max(1rem, env(safe-area-inset-right))
|
||||||
|
max(1rem, env(safe-area-inset-bottom)) max(1rem, env(safe-area-inset-left));
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-gate__card {
|
||||||
|
display: grid;
|
||||||
|
width: min(100%, 34rem);
|
||||||
|
gap: 1rem;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: color-mix(in oklch, var(--card) 96%, white);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
padding: clamp(1.35rem, 4vw, 2.5rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-gate__card h1 {
|
||||||
|
font-size: clamp(2rem, 7vw, 3.1rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-gate__card > p:not(.eyebrow) {
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-gate__card form,
|
||||||
|
.access-gate__card label {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-gate__card form {
|
||||||
|
gap: 0.55rem;
|
||||||
|
padding-top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-gate__card label {
|
||||||
|
color: var(--foreground);
|
||||||
|
font-size: 0.88rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-gate__controls {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) auto;
|
||||||
|
gap: 0.55rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-gate__controls input,
|
||||||
|
.access-gate__controls button {
|
||||||
|
min-height: 48px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 8px;
|
||||||
|
font: inherit;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-gate__controls input {
|
||||||
|
min-width: 0;
|
||||||
|
background: var(--card);
|
||||||
|
box-shadow: 0 0 0 1px color-mix(in oklch, var(--border) 82%, var(--foreground));
|
||||||
|
color: var(--foreground);
|
||||||
|
padding: 0.7rem 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-gate__controls input[aria-invalid="true"] {
|
||||||
|
box-shadow: 0 0 0 1px #8e3f3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-gate__controls button {
|
||||||
|
cursor: pointer;
|
||||||
|
background: var(--primary);
|
||||||
|
color: var(--primary-foreground);
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 0.7rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-gate__controls button:active {
|
||||||
|
transform: scale(0.97);
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-gate__controls button:disabled {
|
||||||
|
cursor: wait;
|
||||||
|
opacity: 0.68;
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-gate__error {
|
||||||
|
min-height: 1.5em;
|
||||||
|
color: #8e3f3f;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
.skip-link {
|
.skip-link {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 1rem;
|
left: 1rem;
|
||||||
|
|
@ -816,6 +922,10 @@ button.event-badge::before {
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.event-hero--narrow {
|
||||||
|
width: min(940px, calc(100% - 2rem));
|
||||||
|
}
|
||||||
|
|
||||||
.event-hero__content {
|
.event-hero__content {
|
||||||
display: grid;
|
display: grid;
|
||||||
align-content: center;
|
align-content: center;
|
||||||
|
|
@ -982,6 +1092,36 @@ button.event-badge::before {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.quick-link-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 0.65rem;
|
||||||
|
padding-top: 0.15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-link-grid a {
|
||||||
|
display: flex;
|
||||||
|
min-height: 64px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 0.8rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: color-mix(in oklch, var(--muted-2) 58%, white);
|
||||||
|
box-shadow: 0 0 0 1px var(--border);
|
||||||
|
padding: 0.8rem 0.9rem;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-link-grid span {
|
||||||
|
line-height: 1.35;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-link-grid strong {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
color: var(--primary);
|
||||||
|
font-size: 0.82rem;
|
||||||
|
}
|
||||||
|
|
||||||
.check-list {
|
.check-list {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.65rem;
|
gap: 0.65rem;
|
||||||
|
|
@ -1020,6 +1160,80 @@ button.event-badge::before {
|
||||||
box-shadow: 0 0 0 1px var(--border);
|
box-shadow: 0 0 0 1px var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.resource-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 0.75rem;
|
||||||
|
padding-top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-grid a {
|
||||||
|
display: grid;
|
||||||
|
min-height: 168px;
|
||||||
|
align-content: space-between;
|
||||||
|
gap: 0.7rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: color-mix(in oklch, var(--muted-2) 58%, white);
|
||||||
|
box-shadow: 0 0 0 1px var(--border);
|
||||||
|
padding: 1rem;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-grid span {
|
||||||
|
font-family: var(--font-heading);
|
||||||
|
font-size: 1.35rem;
|
||||||
|
line-height: 1.15;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-grid small {
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.86rem;
|
||||||
|
line-height: 1.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-grid strong {
|
||||||
|
color: var(--primary);
|
||||||
|
font-size: 0.86rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.minutes-list {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.75rem;
|
||||||
|
padding-top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.minutes-entry {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.75rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: color-mix(in oklch, var(--muted-2) 42%, white);
|
||||||
|
box-shadow: 0 0 0 1px var(--border);
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.minutes-entry header {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.minutes-entry header p {
|
||||||
|
color: var(--primary);
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.minutes-entry > p,
|
||||||
|
.minutes-entry li {
|
||||||
|
color: color-mix(in oklch, var(--foreground) 78%, white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.minutes-entry ul {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.4rem;
|
||||||
|
padding-left: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.image-section img {
|
.image-section img {
|
||||||
width: min(100%, 760px);
|
width: min(100%, 760px);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
|
@ -1055,7 +1269,7 @@ button.event-badge::before {
|
||||||
|
|
||||||
.schedule-tablist {
|
.schedule-tablist {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(var(--schedule-tab-count, 2), minmax(0, 1fr));
|
||||||
gap: 0.35rem;
|
gap: 0.35rem;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: color-mix(in oklch, var(--muted-2) 70%, white);
|
background: color-mix(in oklch, var(--muted-2) 70%, white);
|
||||||
|
|
@ -2067,6 +2281,22 @@ button.event-badge::before {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.schedule-tablist {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-link-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-gate__controls {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
.schedule-item {
|
.schedule-item {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue