Code, design and documents 5 files
src/components/CountryArticle.astro +2 −2
@@ -2,5 +2,5 @@
// Full write-up for one country. Rendered on its own page, and fetched into the
// drawer on the home page — so there is a single template for both views.
-import { SEGMENTS, REC_LABEL, REC_HELP, MED_LABEL, countries, changes, segAvg, segmentPoints, segmentMax, subunitsOf, formatDate } from "../lib/countries.js";
+import { SEGMENTS, REC_LABEL, REC_HELP, MED_LABEL, MED_HELP, countries, changes, segAvg, segmentPoints, segmentMax, subunitsOf, formatDate } from "../lib/countries.js";
import { tierOf, tierColor } from "../lib/tiers.js";
import CountryChanges from "./CountryChanges.astro";
@@ -86,5 +86,5 @@ const circ = 2 * Math.PI * r;
<div class="d-chips">
<span class={`chip s-${v.rec}`} title={REC_HELP[v.rec]}>Recreational: {REC_LABEL[v.rec]}</span>
- <span class={`chip s-${v.med}`}>Medical: {MED_LABEL[v.med]}</span>
+ <span class={`chip s-${v.med}`} title={MED_HELP[v.med]}>Medical: {MED_LABEL[v.med]}</span>
</div>
{d && d.context.some((x) => x && (x.status || x.seeds)) && (
src/content.config.ts +6 −2
@@ -22,4 +22,8 @@ const status = {
// "death": illegal, and the law allows the death penalty for cannabis offences, in practice trafficking.
recreational: z.enum(["legal", "partial", "decriminalised", "illegal", "death"]),
+ // "legal": an established patient route for cannabis or cannabis-based medicine.
+ // "limited": case-specific or pharmaceutical-only access, or legal authority limited to a pilot,
+ // one region, research/production, or a framework that is not yet operational.
+ // "none": no legal medical use; a proposal, CBD/hemp alone, or a future programme does not qualify.
medical: z.enum(["legal", "limited", "none"]),
};
@@ -79,6 +83,6 @@ const countries = defineCollection({
.superRefine((data, ctx) => {
// Every source key cited by a segment must be defined under `sources`.
- if ((data.recreational === "death") !== Boolean(data.context.death_penalty)) {
- ctx.addIssue({ code: "custom", message: 'a country marked "recreational: death" needs a context.death_penalty section, and only such a country may have one' });
+ if (data.recreational === "death" && !data.context.death_penalty) {
+ ctx.addIssue({ code: "custom", message: 'a country marked "recreational: death" needs a context.death_penalty section' });
}
const blocks = { ...data.segments, ...data.context } as Record<string, { sources: string[] }>;
src/lib/countries.js +5 −0
@@ -17,4 +17,9 @@ export const REC_HELP = {
};
export const MED_LABEL = { yes: "Legal", limited: "Limited", no: "None" };
+export const MED_HELP = {
+ yes: "Patients have an established legal route to cannabis or cannabis-based medicine",
+ limited: "Access is case-specific, pharmaceutical-only, regional, a pilot, production-only or not yet operational",
+ no: "No legal medical use; proposals and CBD or industrial hemp alone do not qualify",
+};
// Explanations that exist for each country but are not part of the score.
// "Death penalty" comes first and exists only for countries whose law provides for it;
src/pages/history/[id].astro +2 −2
@@ -2,5 +2,5 @@
import Base from "../../layouts/Base.astro";
import ScoreChange from "../../components/ScoreChange.astro";
-import { changes, countries, changeDate, REC_LABEL, REC_HELP, MED_LABEL } from "../../lib/countries.js";
+import { changes, countries, changeDate, REC_LABEL, REC_HELP, MED_LABEL, MED_HELP } from "../../lib/countries.js";
import { tierOf, tierColor } from "../../lib/tiers.js";
@@ -89,5 +89,5 @@ const circ = 2 * Math.PI * r;
<div class="d-chips">
<span class={`chip s-${c.rec}`} title={REC_HELP[c.rec]}>Recreational: {REC_LABEL[c.rec]}</span>
- <span class={`chip s-${c.med}`}>Medical: {MED_LABEL[c.med]}</span>
+ <span class={`chip s-${c.med}`} title={MED_HELP[c.med]}>Medical: {MED_LABEL[c.med]}</span>
</div>
<p class="ca-note">{c.note}</p>
src/pages/index.astro +3 −3
@@ -3,5 +3,5 @@ import Base from "../layouts/Base.astro";
import DidYouKnow from "../components/DidYouKnow.astro";
import Changes from "../components/Changes.astro";
-import { SEGMENTS, DATA_SNAPSHOT, REC_LABEL, REC_ORDER, REC_HELP, MED_LABEL, countries, regions, worldAvg, lastUpdated, formatDate, subunitsOf, places } from "../lib/countries.js";
+import { SEGMENTS, DATA_SNAPSHOT, REC_LABEL, REC_ORDER, REC_HELP, MED_LABEL, MED_HELP, countries, regions, worldAvg, lastUpdated, formatDate, subunitsOf, places } from "../lib/countries.js";
import { TIERS, tierColor } from "../lib/tiers.js";
import { PLANTING_STATUS, PLANTING_TRADE, STATUS_SECTIONS } from "../lib/segment-ids.js";
@@ -67,5 +67,5 @@ const LAW_SECTIONS = {
sub: "Green means adults may legally have cannabis, yellow that small amounts bring at most a fine, red that it is a crime; the darkest red marks laws with a death penalty.",
note: "The legal status of cannabis for adults. The index score measures much more than this one label." },
- med: { name: "Medical status", complete: true, statuses: Object.fromEntries(MED_ORDER.map((k) => [k, { label: MED_LABEL[k], help: "" }])),
+ med: { name: "Medical status", complete: true, statuses: Object.fromEntries(MED_ORDER.map((k) => [k, { label: MED_LABEL[k], help: MED_HELP[k] }])),
tiers: { yes: 5, limited: 3, no: 0 },
sub: "Green means a medical cannabis programme is legal, yellow that access is limited, red that there is none.",
@@ -257,5 +257,5 @@ const columnGroups = [["Shown by default", BASE_COLUMNS], ...["Score segments",
{SHOW_PRICES && <td class="num-col hide-md" data-col="price">{streetFlower(c) ? `$${streetFlower(c).usd.toFixed(2)}` : "—"}</td>}
<td class="hide-sm" data-col="rec"><span class={`chip s-${c.rec}`} title={REC_HELP[c.rec]}>{REC_LABEL[c.rec]}</span></td>
- <td class="hide-md" data-col="med"><span class={`chip s-${c.med}`}>{MED_LABEL[c.med]}</span></td>
+ <td class="hide-md" data-col="med"><span class={`chip s-${c.med}`} title={MED_HELP[c.med]}>{MED_LABEL[c.med]}</span></td>
{EXTRA_COLUMNS.map((col) => {
const chip = col.chip?.(c);