diff --git a/docs/design/specs/2026-05-20-index-page-redesign.md b/docs/design/specs/2026-05-20-index-page-redesign.md new file mode 100644 index 00000000..6ab135af --- /dev/null +++ b/docs/design/specs/2026-05-20-index-page-redesign.md @@ -0,0 +1,116 @@ +# Index Page Redesign + +**Date:** 2026-05-20 +**Status:** Approved + +## Goals + +1. Make the index page hero background truly full-viewport-width. +2. Align hero text and list content to the same horizontal position. +3. Match the list content max-width to idea-post pages (1200px via `contentWrapper`). +4. Replace the deprecated `antd/List` component with native HTML. +5. Redesign list items in an editorial style — bold typographic, no avatars, no placeholder counts. +6. Introduce a shared CSS token so hero text and list content are guaranteed to stay aligned. + +## Layout Structure + +The index page will set `fullWidthPage: true` via `useSetLayoutConfig()`. This removes the `max-width: 1200px` cap and side borders from `contentWrapper`, allowing the hero background to bleed edge-to-edge. + +Within the now-unconstrained page, both the hero text and the IdeaRoll use the same inner wrapper: + +``` +max-width: 1200px +margin: 0 auto +padding: 32px var(--content-padding-x) +``` + +This guarantees horizontal alignment regardless of viewport width. + +### Shared token + +Add to `src/style/colors.css`: + +```css +/* Layout */ +--content-padding-x: 48px; +--content-padding-x-sm: 24px; +``` + +Used in `index-page.module.css` for both `.heroInner` and `.listWrapper`. `--content-padding-x-sm` replaces `--content-padding-x` at `@media (max-width: 768px)`. + +### Hero restructure + +The `
` gets a full-width background only. Text moves into a new `
` that provides the constrained, centered inner wrapper. + +Before: +``` +
← background + max-width + padding +

breadcrumb

+

Idea Board

+

subtitle

+
+``` + +After: +``` +
← background only, full-width +
← max-width: 1200px, centered, padded +

breadcrumb

+

Idea Board

+

subtitle

+
+
+``` + +## IdeaRoll: Editorial Item Design + +Replace `antd/List` + `List.Item` + `List.Item.Meta` with a native `
- ) : ( - "" - ) - } - renderItem={(item) => ( - , - , - ...item.tags.map((tag) => ( - - )), - ]} - > - {item.title}} - avatar={ - - {item.authors.map((author) => ( - - {author.name[0].toUpperCase()} - + <> + + {count !== undefined && ( +
+ + See more + +
)} - /> + ); }; diff --git a/src/style/idea-roll.module.css b/src/style/idea-roll.module.css index 398ec0b0..5919b1ed 100644 --- a/src/style/idea-roll.module.css +++ b/src/style/idea-roll.module.css @@ -1,18 +1,66 @@ .container { - margin: auto; + list-style: none; + padding: 0; + margin: 0; background-color: var(--bg-base-color); +} + +.listItem { + padding: 22px 0; + border-bottom: 1px solid var(--border-color); +} - :global(.ant-list-item) { - border-left: 3px solid var(--primary-color); - padding-left: 20px; - } +.listItem:last-child { + border-bottom: none; +} - :global(.ant-list-item-meta-title a) { - color: var(--primary-color) !important; - font-weight: 600; - } +.tagEyebrow { + display: flex; + align-items: center; + flex-wrap: wrap; + margin-bottom: 6px; +} + +/* Overrides antd Tag's scoped styles, which win without !important */ +.eyebrowTag { + font-size: 10px !important; + font-weight: 700 !important; + letter-spacing: 0.15em !important; + text-transform: uppercase !important; + color: var(--primary-color) !important; + background: transparent !important; + border: none !important; + padding: 0 !important; + margin: 0 !important; + line-height: inherit !important; + cursor: pointer; +} + +.tagSeparator { + font-size: 10px; + font-weight: 400; + color: var(--border-color); + margin: 0 5px; + user-select: none; +} + +.title { + display: block; + font-size: 19px; + font-weight: 800; + color: var(--primary-color); + text-decoration: none; + letter-spacing: -0.02em; + line-height: 1.25; + margin-bottom: 6px; +} + +.title:hover { + text-decoration: underline; +} - :global(.ant-list-item-meta-title a:hover) { - color: var(--primary-color); - } +.byline { + font-size: 11px; + font-weight: 400; + color: var(--text-secondary-color); } diff --git a/src/style/index-page.module.css b/src/style/index-page.module.css index 33f06c2b..d589e09b 100644 --- a/src/style/index-page.module.css +++ b/src/style/index-page.module.css @@ -1,46 +1,13 @@ -.container { -} - -.header { - max-width: var(--page-max-width); - margin: auto; - padding: 32px 96px; - @media (max-width: 768px) { - padding: 16px 24px; - } -} - -.info { - background-color: var(--surface-color); - border: 1px solid var(--primary-color); - border-radius: 2px; - padding: 20px 32px; - @media (max-width: 768px) { - padding: 16px 24px; - } -} - -.list-wrapper { - max-width: var(--page-max-width); - margin: auto; - padding: 32px 96px; - @media (max-width: 768px) { - padding: 16px 24px; - } - li:global(.ant-list-item) { - @media (max-width: 768px) { - padding: 6px 12px; - } - } -} - .hero { background-color: var(--primary-color); - max-width: var(--page-max-width); +} + +.heroInner { + max-width: var(--content-max-width); margin: 0 auto; - padding: 32px 96px; + padding: 32px var(--content-padding-x); @media (max-width: 768px) { - padding: 24px 24px; + padding: 24px var(--content-padding-x-sm); } } @@ -75,3 +42,12 @@ margin: 0; max-width: 640px; } + +.listWrapper { + max-width: var(--content-max-width); + margin: 0 auto; + padding: 32px var(--content-padding-x); + @media (max-width: 768px) { + padding: 16px var(--content-padding-x-sm); + } +} diff --git a/src/style/layout.module.css b/src/style/layout.module.css index a2c5527f..972fb360 100644 --- a/src/style/layout.module.css +++ b/src/style/layout.module.css @@ -65,4 +65,7 @@ max-width: none; border-left: none; border-right: none; + background-color: var( + --bg-base-color + ); /* full page layouts should not have a gutter that is colored differently from the page background than the container */ } diff --git a/src/style/sider.module.css b/src/style/sider.module.css index f78e244f..592f3e84 100644 --- a/src/style/sider.module.css +++ b/src/style/sider.module.css @@ -1,7 +1,7 @@ .sider { padding: 24px 0px 0px 0px; border-left: 1px solid var(--border-color); - background-color: var(--bg-secondary-color); + background-color: var(--bg-base-color); position: sticky; top: 64px; align-self: flex-start; @@ -12,5 +12,5 @@ .siderMenu { color: var(--text-secondary-color); - background-color: var(--bg-secondary-color); + background-color: var(--bg-base-color); } diff --git a/src/style/theme.ts b/src/style/theme.ts index 6c20cd20..96cebd33 100644 --- a/src/style/theme.ts +++ b/src/style/theme.ts @@ -54,7 +54,7 @@ export default { colorBgLayout: BG_LAYOUT, colorLink: ALLEN_VIOLET, colorLinkActive: ALLEN_GREEN, - colorLinkHover: ALLEN_GREEN, + colorLinkHover: ALLEN_VIOLET, borderRadius: 2, colorBorder: BORDER_COLOR, fontFamily: "Instrument Sans", diff --git a/src/templates/index-page.tsx b/src/templates/index-page.tsx index 1ee2e8e2..59ad0dde 100644 --- a/src/templates/index-page.tsx +++ b/src/templates/index-page.tsx @@ -1,14 +1,16 @@ -import React from "react"; +import React, { useEffect } from "react"; import { graphql } from "gatsby"; import PropTypes from "prop-types"; +import { useSetLayoutConfig } from "../LayoutContext"; import IdeaRoll from "../components/IdeaRoll"; const { hero, heroBreadcrumb, + heroInner, heroSubtitle, heroTitle, listWrapper, @@ -23,17 +25,26 @@ interface QueryResult { } export const IndexPageTemplate: React.FC = () => { + const setLayout = useSetLayoutConfig(); + + useEffect(() => { + setLayout({ fullWidthPage: true }); + return () => setLayout({ fullWidthPage: undefined }); + }, [setLayout]); + return (
-

- allen institute / cell science / open ideas/ -

-

Idea Board

-

- A living collection of early-stage ideas, proposals, and - open questions from Allen Institute scientists. -

+
+

+ allen institute / cell science / open ideas/ +

+

Idea Board

+

+ A living collection of early-stage ideas, proposals, and + open questions from Allen Institute scientists. +

+