diff --git a/README.md b/README.md index 5e24075..9f3fc8f 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ CI rejects JavaScript or CSS growth beyond the limits in the current production build and should be raised only with an explanation in the pull request. -Lighthouse runs three times against both generated pages. Accessibility, SEO, +Lighthouse runs three times against all five generated pages. Accessibility, SEO, layout stability, blocking time, and best-practice regressions fail CI; performance-score and largest-contentful-paint regressions initially warn while the project establishes a stable baseline. @@ -72,3 +72,13 @@ The Cloudflare Pages project should use: Do not set `SKIP_DEPENDENCY_INSTALL`. Cloudflare copies `public/_headers` into the production build and applies those response headers to static assets. + +## Competition editions + +The homepage is the current 2026 competition. Past editions live at +`/competitions/2024/` and `/competitions/2025/`; organization content lives at +`/about/`. Competition-specific sponsors, photos, and results are assigned in +`src/data/competitions.ts`, with shared logo definitions in `src/data/sponsors.ts`. +Archives only display available historical content, never current registration +information. New editions need a static HTML entry, Vite input, sitemap entry, +and Lighthouse URL in addition to their competition data. diff --git a/about/index.html b/about/index.html new file mode 100644 index 0000000..ec26ede --- /dev/null +++ b/about/index.html @@ -0,0 +1,112 @@ + + + + + + About MACSO | Massachusetts Computer Science Olympiad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/competitions/2024/index.html b/competitions/2024/index.html new file mode 100644 index 0000000..742b062 --- /dev/null +++ b/competitions/2024/index.html @@ -0,0 +1,112 @@ + + + + + + MACSO 2024 Archive | Massachusetts Computer Science Olympiad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/competitions/2025/index.html b/competitions/2025/index.html new file mode 100644 index 0000000..de750e8 --- /dev/null +++ b/competitions/2025/index.html @@ -0,0 +1,114 @@ + + + + + + + MACSO Fall 2025 Archive | Massachusetts Computer Science Olympiad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/config/lighthouserc.json b/config/lighthouserc.json index 5d1255e..50a9254 100644 --- a/config/lighthouserc.json +++ b/config/lighthouserc.json @@ -2,18 +2,59 @@ "ci": { "collect": { "staticDistDir": "./dist", - "url": ["http://localhost/", "http://localhost/careers/"], + "url": [ + "http://localhost/", + "http://localhost/careers/", + "http://localhost/about/", + "http://localhost/competitions/2024/", + "http://localhost/competitions/2025/" + ], "numberOfRuns": 3 }, "assert": { "assertions": { - "categories:performance": ["warn", { "minScore": 0.9 }], - "categories:accessibility": ["error", { "minScore": 0.95 }], - "categories:best-practices": ["error", { "minScore": 0.9 }], - "categories:seo": ["error", { "minScore": 0.95 }], - "cumulative-layout-shift": ["error", { "maxNumericValue": 0.1 }], - "total-blocking-time": ["error", { "maxNumericValue": 300 }], - "largest-contentful-paint": ["warn", { "maxNumericValue": 2500 }] + "categories:performance": [ + "warn", + { + "minScore": 0.9 + } + ], + "categories:accessibility": [ + "error", + { + "minScore": 0.95 + } + ], + "categories:best-practices": [ + "error", + { + "minScore": 0.9 + } + ], + "categories:seo": [ + "error", + { + "minScore": 0.95 + } + ], + "cumulative-layout-shift": [ + "error", + { + "maxNumericValue": 0.1 + } + ], + "total-blocking-time": [ + "error", + { + "maxNumericValue": 300 + } + ], + "largest-contentful-paint": [ + "warn", + { + "maxNumericValue": 2500 + } + ] } } } diff --git a/index.html b/index.html index ae81620..ae44992 100644 --- a/index.html +++ b/index.html @@ -6,7 +6,7 @@ Massachusetts Computer Science Olympiad | MACSO @@ -60,7 +60,7 @@ /> + + + logo_webTop + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/sitemap.xml b/public/sitemap.xml index 6b0e860..15984a0 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -2,7 +2,7 @@ https://macso.org/ - 2026-09-14 + 2026-10-11 monthly 1.0 @@ -12,4 +12,7 @@ monthly 0.8 + https://macso.org/about/yearly0.6 + https://macso.org/competitions/2024/yearly0.6 + https://macso.org/competitions/2025/yearly0.6 diff --git a/src/components/layout/Footer.module.css b/src/components/layout/Footer.module.css index 94929ee..4a89287 100644 --- a/src/components/layout/Footer.module.css +++ b/src/components/layout/Footer.module.css @@ -47,3 +47,14 @@ transition: none; } } + +.links { + display: flex; + justify-content: center; + flex-wrap: wrap; + gap: 12px 24px; + margin: 16px 0; +} +.links a { + color: var(--accent-text); +} diff --git a/src/components/layout/Footer.tsx b/src/components/layout/Footer.tsx index c5acd75..555c696 100644 --- a/src/components/layout/Footer.tsx +++ b/src/components/layout/Footer.tsx @@ -17,16 +17,12 @@ export function Footer({ page }: FooterProps) { Brookline Computer Science Initiative (BCSI), a 501(c)(3) non-profit organization.

-

- Directed by{' '} - - Mikhail Zhernevskii - - , Jun 2024 - October 2024 -

+

Website is made by{' '} diff --git a/src/components/layout/Header.module.css b/src/components/layout/Header.module.css index f7d11c4..ac03133 100644 --- a/src/components/layout/Header.module.css +++ b/src/components/layout/Header.module.css @@ -143,7 +143,9 @@ } @media (prefers-reduced-motion: reduce) { - .nav a.hire, + .nav a.hire { + transition: none; + } .themeButton, .themeButton svg, .brand, @@ -152,3 +154,57 @@ transition: none; } } + +.archives { + position: relative; + font-size: 0.88rem; + font-weight: 700; +} +.archives summary { + cursor: pointer; + padding: 8px 0; +} +.archives summary:focus-visible { + outline: 3px solid var(--blue-deep); + outline-offset: 3px; +} +.archiveLinks { + position: absolute; + top: 100%; + left: 0; + min-width: 180px; + display: grid; + gap: 4px; + padding: 10px; + background: var(--paper); + border: 1px solid var(--rule-strong); + border-radius: 8px; + box-shadow: var(--shadow); +} +.archiveLinks a { + padding: 10px; +} +.nav a[aria-current='page'] { + color: var(--blue-deep); + text-decoration: underline; + text-underline-offset: 5px; +} +@media (max-width: 520px) { + .header { + gap: 8px; + padding: 10px 18px; + } + .nav { + width: 100%; + gap: 4px 14px; + } + .nav a, + .archives { + font-size: 0.8rem; + } + .themeButton { + margin-left: auto; + width: 30px; + height: 30px; + } +} diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index adf3694..003fcd4 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react' -import { navLinks } from '~/data/site' +import { pastCompetitions } from '~/data/competitions' import { applyTheme, getPreferredTheme, saveTheme } from '~/lib/theme' import { type PageId, pageMeta } from './pages' import styles from './Header.module.css' @@ -12,7 +12,6 @@ export function Header({ page }: HeaderProps) { const [theme, setTheme] = useState(getPreferredTheme) const { topId } = pageMeta[page] const isHome = page === 'home' - const hashBase = isHome ? '' : '/' useEffect(() => { applyTheme(theme) @@ -30,11 +29,36 @@ export function Header({ page }: HeaderProps) { macso.