diff --git a/CHANGELOG.md b/CHANGELOG.md index 1073ede..3fcfc15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,43 @@ ## Unreleased +### Added + +- **A Releases page for the extension**, at + `/toddle-enhancement-extension/releases`: what changed in each version, + in plain words for teachers, newest first. 0.9.0 is "Coming soon to the + Chrome Web Store"; 0.8.2, 0.8.1, 0.8.0, 0.7.x and the early builds follow, + condensed. Versions 0.8.3 to 0.8.13, test builds for schools piloting the + extension, are said in one line: their changes arrive together in 0.9.0. + Each version has the anchor `#v`, which the extension's menu will + link to. No downloads and no GitHub links: the extension's repository is + private, and teachers install from the Chrome Web Store. The notes live in + `src/data/releases.ts`, so adding a release is one edit. Linked from the + extension page, the footer and llms.txt, and in the sitemap. + ### Changed +- **@bundu/ui 0.5.0** (was 0.1.1): the kit's updated tokens. The page + background is a cooler, neutral off-white; layout, type, buttons and the + Nyuchi brand colours are unchanged. Every check and test passes as before. +- **The site's code is proprietary**, all rights reserved, with a LICENSE + file saying so (it had none). Not open source. + +- **The terms say who owns the extension.** A new "Who owns the extension" + section: the extension and its code belong to Nyuchi Web Services, part + of Nyuchi Africa (Private) Limited, all rights reserved, and it is not + open source. A licence grants use, not ownership. Its code may not be + copied, modified, reused or redistributed, in whole or in part, in another + product or service without written permission. Reading the code to check + what it does stays welcome, and building a competing product stays + forbidden. Said once, in `ownership` (`src/data/legal.ts`), and repeated on + the extension page and in llms.txt. +- **Student flags, as 0.9.0 ships them:** a concealed flag is a grey smudge + with no colour, nothing on the page brings it back, and a teacher updating + from 0.8.2 has flags concealed. - **The extension page and legal pages describe 0.9.0, the next Chrome Web Store release**, and say where 0.8.2, on the store today, differs. Patches - (0.8.3 to 0.8.9) are test releases that do not go to the store, so + (0.8.3 to 0.8.13) are test releases that do not go to the store, so `extensionVersions.next` is now 0.9.0, not 0.8.4. - Student flags: the extension no longer hides Toddle's own flags. A teacher can conceal them for a shared screen with the free switch, and diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d783fcc --- /dev/null +++ b/LICENSE @@ -0,0 +1,17 @@ +Copyright (c) 2026 Nyuchi Web Services. All rights reserved. + +This website, learning.nyuchi.com, its source code, content, designs and +other materials in this repository (the "Software") are the property of +Nyuchi Web Services and are protected by copyright and other intellectual +property laws. The Software is proprietary. It is not open source. + +No licence or right to copy, modify, merge, publish, distribute, +sublicense, sell, deploy, or otherwise reuse the Software, in whole or in +part, is granted without the prior written permission of Nyuchi Web +Services. Contact: support@nyuchi.com. + +Third-party packages it depends on keep their own licences. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. diff --git a/package-lock.json b/package-lock.json index 94891ba..fff65c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,8 +7,9 @@ "": { "name": "nyuchi-learning", "version": "3.0.0", + "license": "UNLICENSED", "dependencies": { - "@bundu/ui": "^0.1.1", + "@bundu/ui": "^0.5.0", "astro": "^7.3.5" }, "devDependencies": { @@ -666,19 +667,25 @@ "win32" ] }, + "node_modules/@bundu/server": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@bundu/server/-/server-0.1.0.tgz", + "integrity": "sha512-tGpZSvuU/hZn6w0sggA/6/8hqLSSCm+ihboU6y+IJ1LYzxIhngOELEm77pdpcx466PAgln4vPpM7GmuGU1EApw==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, "node_modules/@bundu/ui": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@bundu/ui/-/ui-0.1.1.tgz", - "integrity": "sha512-lyRwZLr4U8nLpdaCfPikjoZ6OUKGyQzdjregFYxFyrUY+98ytRbWc3bZA20626swYnAIYjlJDa8/fYJqh4u4cA==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@bundu/ui/-/ui-0.5.0.tgz", + "integrity": "sha512-391EJhoMD0K+nuwJPQGOPDvEpmUJsIjRrxWX9+W0fFqr5oPliQVov/ZpZjOMZO3lxAa7bu5zaIxVO8t9h8gaBA==", "license": "MIT", "dependencies": { + "@bundu/server": "^0.1.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "tailwind-merge": "^3.0.2" - }, - "peerDependencies": { - "react": "^19.0.0", - "react-dom": "^19.0.0" } }, "node_modules/@capsizecss/unpack": { @@ -6956,6 +6963,7 @@ "version": "19.3.0", "resolved": "https://registry.npmjs.org/react/-/react-19.3.0.tgz", "integrity": "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6965,6 +6973,7 @@ "version": "19.3.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.0.tgz", "integrity": "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==", + "dev": true, "license": "MIT", "dependencies": { "scheduler": "^0.28.0" @@ -7138,6 +7147,7 @@ "version": "0.28.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.28.0.tgz", "integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==", + "dev": true, "license": "MIT" }, "node_modules/semver": { diff --git a/package.json b/package.json index 945fa37..b108052 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "nyuchi-learning", "version": "3.0.0", "private": true, + "license": "UNLICENSED", "type": "module", "description": "learning.nyuchi.com — the Nyuchi Learning surface and the home of the Toddle Enhancement Extension.", "scripts": { @@ -23,7 +24,7 @@ "ci:check": "astro check && vp fmt --check" }, "dependencies": { - "@bundu/ui": "^0.1.1", + "@bundu/ui": "^0.5.0", "astro": "^7.3.5" }, "devDependencies": { diff --git a/public/llms.txt b/public/llms.txt index 334a496..bf4515b 100644 --- a/public/llms.txt +++ b/public/llms.txt @@ -98,8 +98,18 @@ community-based platforms. Nyuchi Web Services is its development division. a Google Admin console force-install (or Group Policy, Intune or a macOS profile); an organisation key is pasted in once by each teacher, since it cannot be pushed by policy. Teachers get each minor release (0.9.0 next) - from the Chrome Web Store; patch releases between them are for testing - and do not go to the store. Help: + from the Chrome Web Store; versions 0.8.3 to 0.8.13 were test builds for + schools piloting it, and their changes arrive together in 0.9.0. Release + notes for every version, in plain words: + https://learning.nyuchi.com/toddle-enhancement-extension/releases + (each version at #v, e.g. #v0.9.0). There are no public + downloads; install from the Chrome Web Store. The extension is proprietary + and not open source: it and its code belong to Nyuchi Web Services, part + of Nyuchi Africa (Private) Limited, all rights reserved. A licence grants + use, not ownership; its code may not be copied, modified, reused or + redistributed, in whole or in part, in another product or service without + written permission. Reading the code to check what it does is welcome. + Terms: https://learning.nyuchi.com/legal/terms#ownership Help: https://support.nyuchi.com/en/collections/19764027-how-to-use-the-toddle-enhancement-extension Security: https://learning.nyuchi.com/legal/security @@ -131,8 +141,12 @@ division of Nyuchi Africa (Private) Limited, Harare, Zimbabwe. stored value on the website, what sets it, how long it lasts and which consent choice enables it. The extension sets no cookies. - [Terms of use and service](https://learning.nyuchi.com/legal/terms): the - website's terms of use and the extension's terms of service (licences, - offline keys, refunds, acceptable use, liability, law of Zimbabwe). + website's terms of use and the extension's terms of service (who owns the + extension and its code, licences, offline keys, refunds, acceptable use, + liability, law of Zimbabwe). The extension and its code belong to Nyuchi + Web Services, all rights reserved; a licence grants use, not ownership, + and its code may not be reused in another product or service without + written permission. Refunds: a full refund within 30 days of purchase, for any reason related to the product; ask at support@nyuchi.com or through Buy Me a Coffee. A refunded licence key is cancelled and stops working after the extension's diff --git a/src/data/legal.ts b/src/data/legal.ts index d583e10..209b3a0 100644 --- a/src/data/legal.ts +++ b/src/data/legal.ts @@ -127,7 +127,7 @@ export const extensionVersions = { sameCodeAs: "0.8.3", next: "0.9.0", /** The newest patch release (GitHub only, for testing). */ - latestPatch: "0.8.9", + latestPatch: "0.8.13", /** The oldest version security reports are accepted for. */ supportedFrom: "0.8.2", } as const; @@ -178,7 +178,7 @@ export const extensionDataFacts = [ { claim: "Student flags: Toddle's own are never hidden, and a teacher can conceal them for a shared screen.", - detail: `From version ${next}, the extension no longer hides Toddle's own student flags: they show as Toddle shows them, including in Toddle's student popover, with their links and documents. A teacher can choose to conceal flags, for a screen a class or a visitor can see, with the free flag switch in Toddle's top bar or the extension's menu. It is off until they switch it on; a teacher who had chosen to hide flags in an earlier version keeps that choice, as concealing. What a concealed flag says cannot be read from across a room, though it can still show that a student has a flag. ${flags.reveal} The sidebar asks Toddle for a student's active flags each time it opens, and keeps them only while that student's sidebar is open. Concealing changes only what is drawn on the screen, never Toddle's data. ${flags.before} In that version, while flags are hidden, the sidebar asks for a student's flags only when someone presses its eye button. The flag switch is free and always will be.`, + detail: `From version ${next}, the extension no longer hides Toddle's own student flags: they show as Toddle shows them, including in Toddle's student popover, with their links and documents. A teacher can choose to conceal flags, for a screen a class or a visitor can see, with the free flag switch in Toddle's top bar or the extension's menu. A new install starts with flags shown. A teacher updating from version ${current}, where flags were hidden by default, or who had hidden them, has them concealed after the update. A concealed flag is a faint grey smudge with no colour, and its words cannot be read from across a room, though it can still show that a student has a flag. Nothing on the page brings a concealed flag back. ${flags.reveal} The sidebar asks Toddle for a student's active flags each time it opens, and keeps them only while that student's sidebar is open. Concealing changes only what is drawn on the screen, never Toddle's data. ${flags.before} In that version, while flags are hidden, the sidebar asks for a student's flags only when someone presses its eye button. The flag switch is free and always will be.`, }, { claim: "Your Toddle sign-in stays with Toddle.", @@ -275,6 +275,23 @@ export const securityMailto = `mailto:${security.report.email}?subject=${encodeU security.report.subject, )}`; +/** + * Who owns the extension, said once: the terms, the product page and + * llms.txt. The extension is proprietary. Schools may read its code to check + * what it does (their privacy reviews depend on it), but a licence grants + * use, not ownership, and the code may not be reused elsewhere. + */ +export const ownership = { + owner: `${legal.operator}, part of ${legal.entity}`, + statement: `The Toddle Enhancement Extension and its code belong to ${legal.operator}, part of ${legal.entity}. All rights reserved. It is not open source.`, + licence: + "A licence lets you use the extension. It does not give you ownership of it, or of any part of its code.", + noReuse: + "You may not copy, modify, reuse or redistribute its code, in whole or in part, in another product or service, without our written permission.", + reading: + "Reading the code to check what it does is fine, and we encourage it: a school should be able to see for itself what software does with its data.", +} as const; + /** Toddle is not ours. Said in the footer, the terms and the product page. */ export const toddleNotice = "Toddle is a trademark of its owner. Nyuchi and the Toddle Enhancement Extension are not affiliated with, endorsed by or sponsored by Toddle."; diff --git a/src/data/releases.ts b/src/data/releases.ts new file mode 100644 index 0000000..deb6958 --- /dev/null +++ b/src/data/releases.ts @@ -0,0 +1,222 @@ +/** + * The Toddle Enhancement Extension's release notes, for teachers. + * + * The public home of the extension's releases. Its source repository is + * private, and the releases there are internal test builds; teachers install + * and update from the Chrome Web Store. So nothing here links to GitHub or to + * a download. + * + * Adding a release is one edit: put a new entry at the top of `releases`. + * Each is written from the extension's CHANGELOG.md, in plain words, about + * what changed for a teacher rather than how it was built. The page gives + * each one the id `v` (e.g. `#v0.9.0`), which the extension's + * toolbar menu links to: keep `version` exactly as the extension's manifest + * has it. `alsoIds` gives older or test versions an anchor of their own, so + * a link from any version's menu lands somewhere sensible. + * + * Prices are not repeated here; they live in `pricing` (src/data/legal.ts). + */ + +/** coming: not yet on the store; store: on the Chrome Web Store; early: before it. */ +export type ReleaseStatus = "coming" | "store" | "early"; + +export interface ReleaseSection { + heading: string; + items: string[]; +} + +export interface Release { + /** As in the extension's manifest, e.g. "0.9.0". The page's anchor is `v` + this. */ + version: string; + /** A heading when one entry covers several versions, e.g. "0.7.1 and 0.7.0". */ + label?: string; + status: ReleaseStatus; + /** ISO date it reached the Chrome Web Store; absent while coming. */ + date?: string; + /** One or two sentences: what this release is about. */ + summary: string; + sections: ReleaseSection[]; + /** Further versions this entry stands for, each given its own anchor. */ + alsoIds?: string[]; +} + +/** The test builds between 0.8.2 and 0.9.0, said once on the page. */ +export const testBuilds = { + from: "0.8.3", + to: "0.8.13", + /** Every version in the range, so each has an anchor on the page. */ + versions: [ + "0.8.3", + "0.8.4", + "0.8.5", + "0.8.6", + "0.8.7", + "0.8.8", + "0.8.9", + "0.8.10", + "0.8.11", + "0.8.12", + "0.8.13", + ], + /** Where their changes land. */ + arriveIn: "0.9.0", +} as const; + +/** Newest first. */ +export const releases: Release[] = [ + { + version: "0.9.0", + status: "coming", + summary: + "Everything since 0.8.2, in one release: student flags you control with one switch, a sidebar that tells you more about the people around a student, and the extension rebuilt so that Toddle's own page can't reach into it.", + sections: [ + { + heading: "Student flags: shown, or concealed", + items: [ + "The switch is now “Show student flags”. On, Toddle's flags look exactly as Toddle shows them: the extension leaves them alone.", + "Off, for when your screen is shown to a class, a parent or a visitor, every flag across Toddle is concealed: a faint grey smudge with no colour, and no title, icon or count anyone can read from across the room.", + "Nothing on the page brings a flag back: not hovering, not clicking. The one way to see them is “Show flags” in the student sidebar, which shows that one student's flags until you close the sidebar or move to another student. It is never saved.", + "If you are updating from 0.8.2, where flags were hidden by default, or you had hidden them yourself, they stay concealed after the update, so nothing appears on a shared screen that you had covered. A new install starts with flags shown.", + ], + }, + { + heading: "The student sidebar", + items: [ + "Click a teacher's name anywhere in the sidebar to see who they are: their photo where Toddle has one, their title and role, their email and a button to message them in Toddle. Opened from a student, it also shows the classes they teach that student and today's lessons together.", + "A class now always names its course, and its subjects and grades where Toddle gives them.", + "Email the primary teachers of a student's classes at once: “Primary teachers of today's classes” and “Primary teachers of all classes” list each teacher once, all ticked, ready to email or copy.", + "A class's teachers sit beside every class, to email together or copy their addresses.", + "Today's timetable is its own part, with “No classes today” or a Retry button when it can't load, and the rest of the panel never waits for it. The student's email sits under their name: click to copy it.", + "In School setup, Toddle's admin portal, the sidebar steps aside, so a click on a student does what Toddle does.", + "Clearer buttons (“Message the family”, “Not marked”), Toddle's own icons, quick tooltips, and email links that copy the address when no email app opens.", + ], + }, + { + heading: "My classes, the gradebook and the Attendance dashboard", + items: [ + "My classes switches on and off at once, and stays right at schools with long course lists.", + "The gradebook tools and the Attendance dashboard's details are rebuilt, and look and work as before. Grade scale colours from your school's Toddle now show in the expanded columns.", + "The Attendance dashboard's Excusals tab gets the same details as the Students tab: each student's year group and, today, the class they are in right now with its primary teacher.", + "A switch for every feature in the toolbar menu, grouped by where it works, with a master switch that turns everything off.", + ], + }, + { + heading: "Built to keep Toddle's page out", + items: [ + "The flags switch, the student sidebar, My classes and teacher names, the gradebook's toolbar and controls, and the Attendance dashboard's details now run in the extension's own part of the browser, inside closed shadow roots that no script on Toddle's page can read or click into. Whether each one runs is decided by your switches and licence, never by Toddle's page.", + "Each rebuilt part was given its own security review on 6 October 2026, as were flag visibility and the sidebar's new staff and class views. Everything they found is fixed, each with a test. The Security page has the details.", + "Nothing new is read from Toddle and nothing new is sent anywhere.", + ], + }, + ], + }, + { + version: "0.8.2", + status: "store", + date: "2026-10-01", + summary: + "The student sidebar from anywhere in Toddle, with where a student is right now and their day at a glance.", + sections: [ + { + heading: "What's new", + items: [ + "Click any student, anywhere in Toddle (a photo, a name, the gradebook's student column, the class portfolio, the Attendance dashboard), and the sidebar opens at once.", + "A “Now” card: the student's attendance code for the block happening now, and where they should be (block, class, room and teacher). Below it, their classes in two tabs: Today, in time order with each period's code, and All.", + "Click a class for its block, room and course, and every teacher with their title and email. Message buttons open Toddle's own chat with a teacher, the student or the family.", + "The homeroom advisor, the school's Student Group and Room number, and contacts with their relationship, phone and email.", + "On the Attendance dashboard's Students tab, each student's year group and the class they are in right now, with the current block's column outlined.", + ], + }, + { + heading: "Licences and security", + items: [ + "A licence is for a person or a school, checked against the account signed in to Toddle. A cancelled key stops working after a daily check that sends nothing about you.", + "Every finding of the security review of 1 October 2026 is fixed, each with a test.", + ], + }, + ], + }, + { + version: "0.8.1", + status: "store", + date: "2026-10-01", + summary: "A welcome page, and feedback straight from the menu.", + sections: [ + { + heading: "What's new", + items: [ + "A welcome page opens once, when you install: what the extension does, what is free and what needs a licence, your switches, and a place for a licence key.", + "Send feedback from the toolbar menu. Only what you type, and the version number, is sent, and only when you press Send.", + "The toolbar menu meets WCAG 2.2 AA: readable contrast, a visible focus ring, and switches that say in words when they need a licence.", + "Fixes: expanded columns are no longer empty at schools that show student IDs, students without an email are included, and the sidebar shows a student's own grade.", + ], + }, + ], + }, + { + version: "0.8.0", + status: "store", + date: "2026-10-01", + summary: "The Toddle home page, made about your own classes.", + sections: [ + { + heading: "What's new", + items: [ + "My classes: a third option in the home page's course filter, for only the classes you teach.", + "The primary teacher beside every class, on the home page and on a student's profile.", + "The first student sidebar, and a toolbar menu with your licence and a switch for each feature.", + "The gradebook opens one assessment tool at a time, and its type filter follows Toddle's own two levels.", + ], + }, + ], + }, + { + version: "0.7.1", + label: "0.7.1 and 0.7.0", + status: "store", + date: "2026-09-30", + summary: + "The first version on the Chrome Web Store, and licences. The flag switch stayed free; the gradebook columns and CSV export were what a licence bought.", + sections: [ + { + heading: "What's new", + items: [ + "Individual and organisation licences, checked on your own machine, so activating a key contacts nothing.", + ], + }, + ], + alsoIds: ["0.7.0"], + }, + { + version: "0.6.0", + label: "0.6.0 and earlier", + status: "early", + date: "2026-09-28", + summary: + "Where it started: the gradebook, expanded. These early builds came before the Chrome Web Store.", + sections: [ + { + heading: "What it did", + items: [ + "Every assessment tool expands into one column per standard, criterion or item: rubrics of every kind, checklists, scores, comments, grade scales and learning goals.", + "The flag switch, for a gradebook on a projector, leaving students' names alone. (An earlier “Present mode” that replaced names was dropped: a gradebook of anonymous rows is no use to a teacher.)", + "CSV export, made in your browser. Write operations are blocked, so the extension can never change a gradebook.", + ], + }, + ], + alsoIds: ["0.5.0", "0.4.3"], + }, +]; + +/** The newest release, for links such as "What's new in 0.9.0". */ +export const latestRelease = releases[0]; + +/** "1 October 2026", as the legal pages write dates. */ +export function releaseDate(iso: string): string { + return new Date(`${iso}T00:00:00Z`).toLocaleDateString("en-GB", { + day: "numeric", + month: "long", + year: "numeric", + timeZone: "UTC", + }); +} diff --git a/src/data/site.ts b/src/data/site.ts index ff8ec01..70ac498 100644 --- a/src/data/site.ts +++ b/src/data/site.ts @@ -92,6 +92,7 @@ export const footerColumns: { title: string; links: NavLink[] }[] = [ label: "Deploy to a school", href: "/toddle-enhancement-extension#install", }, + { label: "Releases", href: "/toddle-enhancement-extension/releases" }, { label: "Send feedback", href: "/feedback" }, { label: "Get in touch", href: "mailto:support@nyuchi.com" }, ], diff --git a/src/pages/legal/terms.astro b/src/pages/legal/terms.astro index feba7dc..0e75d82 100644 --- a/src/pages/legal/terms.astro +++ b/src/pages/legal/terms.astro @@ -7,7 +7,14 @@ * whether we can withdraw it — is answered plainly rather than buried. */ import BaseLayout from "../../layouts/BaseLayout.astro"; -import { legal, pricing, refunds, toddleNotice, updatedLabel } from "../../data/legal"; +import { + legal, + ownership, + pricing, + refunds, + toddleNotice, + updatedLabel, +} from "../../data/legal"; import { toddleExtension } from "../../data/site"; const title = "Terms of use and service — Nyuchi Learning"; @@ -29,8 +36,10 @@ const description =

- The short version. Use it in your school. Do not resell it or - take it apart to make a competing product. It reads Toddle and changes nothing, but + The short version. Use it in your school. The extension and its + code are ours, and a licence lets you use them, not own them. Do not resell it, + copy its code into anything else, or take it apart to make a competing product. + Reading the code to check what it does is welcome. It reads Toddle and changes nothing, but it is software that rides on someone else's app, so it can break — check anything that matters before you act on it. We are not liable for what you do with what it shows you. @@ -49,11 +58,21 @@ const description = privacy policy.

+

+ Who owns the extension +

+

+ {ownership.statement} That covers its code, its design and its documentation, in + every version, including the free features. {ownership.licence} + {ownership.noReuse} {ownership.reading} +

+

What a licence lets you do

Install and use the {toddleExtension.name} for teaching and administration at the school or organisation the licence covers, on as many machines as that licence - allows, for as long as it is current. + allows, for as long as it is current. The free features may be used by anyone, on + the same terms. Using it gives you no other rights in it.

What it costs

@@ -121,6 +140,11 @@ const description = class="mt-4 space-y-2 text-body text-muted-foreground list-disc list-outside pl-5 marker:text-foreground/40" >
  • Resell it, sublicense it, or charge anyone else for access to it.
  • +
  • + Copy, modify, reuse or redistribute its code, in whole or in part, in another + product or service, without our written permission. That includes publishing it, + or a changed copy of it, anywhere else. +
  • Take it apart in order to build a competing product. Reading the code to satisfy yourself about what it does is fine — we encourage it. diff --git a/src/pages/toddle-enhancement-extension.astro b/src/pages/toddle-enhancement-extension.astro index 9818b5c..dc04194 100644 --- a/src/pages/toddle-enhancement-extension.astro +++ b/src/pages/toddle-enhancement-extension.astro @@ -17,7 +17,14 @@ import { Picture } from "astro:assets"; import type { ImageOutputFormat } from "astro"; import BaseLayout from "../layouts/BaseLayout.astro"; import { toddleExtension } from "../data/site"; -import { extensionVersions, flags, pricing, refunds, toddleNotice } from "../data/legal"; +import { + extensionVersions, + flags, + ownership, + pricing, + refunds, + toddleNotice, +} from "../data/legal"; import gradebookShot from "../assets/screenshots/01-gradebook.jpg"; import sidebarShot from "../assets/screenshots/02-student-sidebar.jpg"; import todayShot from "../assets/screenshots/03-today.jpg"; @@ -621,7 +628,10 @@ const schema = [

    If your IT team would rather verify this than take our word for it, a Chrome extension is a folder of readable JavaScript — they can unpack - the installed package and read every line of it. We will also answer + the installed package and read every line of it. Reading it to check what it + does is welcome; the code is ours, and is not licensed for reuse elsewhere (see + who owns the extension). We will + also answer specific questions at

    How updates reach you. Fixes are made and - tested as small patch releases, which do not go to the Chrome Web Store. When a - batch of them is ready, it is published to the store as the next version ({extensionVersions.next} is - next), and Chrome installs it on its own. + tested as small test builds with schools piloting the extension, which do not go to + the Chrome Web Store. When a batch of them is ready, it is published to the store as + the next version ({extensionVersions.next} is next), and Chrome installs it on its + own. What changed in each version.

    -

    {toddleNotice}

    +

    + {ownership.statement} + {toddleNotice} +

  • diff --git a/src/pages/toddle-enhancement-extension/releases.astro b/src/pages/toddle-enhancement-extension/releases.astro new file mode 100644 index 0000000..8b0c164 --- /dev/null +++ b/src/pages/toddle-enhancement-extension/releases.astro @@ -0,0 +1,124 @@ +--- +/** + * Releases — what changed in each version of the Toddle Enhancement Extension. + * + * The public home of the extension's release notes. The extension's source + * repository is private and its GitHub releases are internal test builds, so + * this page has no downloads and no GitHub links: teachers install and update + * from the Chrome Web Store. The extension's toolbar menu links here, to + * `#v`, so every version keeps an element with that id. + * + * The notes live in src/data/releases.ts; adding a release is one edit there. + */ +import BaseLayout from "../../layouts/BaseLayout.astro"; +import { releaseDate, releases, testBuilds } from "../../data/releases"; +import { toddleExtension } from "../../data/site"; + +const title = "Releases — Toddle Enhancement Extension — Nyuchi Learning"; +const description = + "What changed in each version of the Toddle Enhancement Extension, in plain words for teachers: version 0.9.0, coming soon to the Chrome Web Store, and every version before it."; + +const storeCta = toddleExtension.webStore + ? { label: "Add to Chrome", href: toddleExtension.webStore } + : { label: "Tell me when it is live", href: toddleExtension.enquiry }; + +const statusLabel = { + coming: "Coming soon to the Chrome Web Store", + store: "On the Chrome Web Store", + early: "Before the Chrome Web Store", +} as const; + +const statusClass = { + coming: "badge badge-accent", + store: "badge badge-success", + early: "badge badge-info", +} as const; + +--- + + +
    +

    + {toddleExtension.name} +

    +

    Releases

    +

    + What changed in each version, newest first. You install and update the extension + from the Chrome Web Store, and Chrome keeps it up to date on its own: there is + nothing to download here. To see which version you have, open the extension's menu + from Chrome's toolbar. +

    + + +
      + { + releases.map((release) => ( +
    1. +
      + {release.alsoIds?.map((id) => ( +
      + {release.version === testBuilds.arriveIn && ( +

      + {testBuilds.versions.map((id) => ( +

      + )} +
    2. + )) + } +
    + +

    Questions about a release

    +

    + Write to + {toddleExtension.supportEmail}, or tell us through the feedback form. What the + extension reads, stores and sends is on the + data handling and + security pages. +

    +
    +
    diff --git a/tests/seo.test.ts b/tests/seo.test.ts index cd31d57..08555d0 100644 --- a/tests/seo.test.ts +++ b/tests/seo.test.ts @@ -18,6 +18,7 @@ const built = (relative: string) => read(join("dist", relative)); const PAGES = [ "index.html", "toddle-enhancement-extension/index.html", + "toddle-enhancement-extension/releases/index.html", "legal/privacy/index.html", "legal/terms/index.html", "legal/security/index.html", @@ -212,3 +213,56 @@ describe("the security page", () => { ); }); }); + +describe("the releases page", () => { + /* The extension's menu links to #v, and its repository is + private: the page must keep every anchor and offer nothing to download. */ + const page = built("toddle-enhancement-extension/releases/index.html"); + + it("gives each version, and each test build, its own anchor", () => { + for (const version of [ + "0.9.0", + "0.8.2", + "0.8.1", + "0.8.0", + "0.8.3", + "0.8.13", + ]) { + expect(page).toContain(`id="v${version}"`); + } + }); + + it("says 0.9.0 is coming to the Chrome Web Store", () => { + expect(page).toContain("Coming soon to the Chrome Web Store"); + }); + + it("links to no GitHub release and offers no download", () => { + expect(page).not.toMatch(/github\.com/i); + expect(page).not.toMatch(/\.zip\b|\.crx\b/i); + }); + + it("is linked from the extension page and llms.txt", () => { + expect(built("toddle-enhancement-extension/index.html")).toContain( + 'href="/toddle-enhancement-extension/releases"', + ); + expect(built("llms.txt")).toContain( + "https://learning.nyuchi.com/toddle-enhancement-extension/releases", + ); + }); +}); + +describe("prices", () => { + /* The organisation licence is US$149.99 a year, confirmed by the founder. + Any other figure for it anywhere on the site is a mistake. */ + it("states the organisation price as US$149.99 everywhere", () => { + for (const file of [ + "toddle-enhancement-extension/index.html", + "legal/terms/index.html", + "llms.txt", + ]) { + const text = built(file); + expect(text, file).toContain("US$149.99"); + expect(text, file).not.toMatch(/US\$\s?(?!149\.99\b|5\b)\d/); + } + }); +});