Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 81 additions & 20 deletions src/components/community-report-next/CommunityReportNext.scss
Original file line number Diff line number Diff line change
Expand Up @@ -192,44 +192,105 @@
margin-top: 12px;
}

.community-report__select-wrap::after {
// Custom chevron (native arrow is hidden via appearance:none).
.community-report__select-button {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
min-height: 44px;
padding: 10px 38px 10px 14px;
cursor: pointer;
font-family: var(--font-family-base);
font-size: 14px;
line-height: 1.35;
color: var(--cr-ink);
text-align: left;
background: #fff;
border: 1px solid #dfe5f0;
border-radius: 8px;
transition: border-color 0.18s ease, box-shadow 0.18s ease, background 0.18s ease;
}

.community-report__select-button::after {
content: '';
position: absolute;
right: 14px;
top: 50%;
width: 10px;
height: 10px;
transform: translateY(-60%) rotate(45deg);
border-right: 2px solid var(--cr-muted);
border-bottom: 2px solid var(--cr-muted);
transform: translateY(-62%) rotate(45deg);
border-right: 2px solid #4c576c;
border-bottom: 2px solid #4c576c;
pointer-events: none;
transition: transform 0.18s ease, border-color 0.18s ease;
}

.community-report__select-button:hover,
.community-report__select-button--open {
border-color: var(--cr-green);
}

.community-report__select-button:focus-visible {
outline: none;
border-color: var(--cr-green);
box-shadow: 0 0 0 3px rgba(6, 128, 95, 0.14);
}

.community-report__select-button--open {
box-shadow: 0 2px 8px 0 rgba(49, 77, 136, 0.16);
}

.community-report__select-button--open::after {
transform: translateY(-38%) rotate(225deg);
border-color: var(--cr-green);
}

.community-report__select-button--placeholder {
color: #8592a6;
}

.community-report__select {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
.community-report__select-menu {
position: absolute;
z-index: 30;
top: calc(100% + 6px);
left: 0;
width: 100%;
max-height: 260px;
overflow-y: auto;
padding: 6px 0;
background: #fff;
border: 1px solid #dfe5f0;
border-radius: 8px;
box-shadow: 0 2px 8px 0 rgba(49, 77, 136, 0.16);
}

.community-report__select-option {
display: block;
width: 100%;
min-height: 36px;
padding: 8px 14px;
cursor: pointer;
padding: 11px 36px 11px 14px;
font-family: var(--font-family-base);
font-size: 14px;
line-height: 1.4;
color: var(--cr-ink);
background: #fff;
border: 1px solid var(--cr-line);
border-radius: 10px;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
text-align: left;
background: transparent;
border: 0;
transition: background 0.16s ease, color 0.16s ease;
}

.community-report__select:hover {
border-color: rgba(6, 128, 95, 0.4);
.community-report__select-option:hover,
.community-report__select-option:focus-visible {
outline: none;
background: #f7fafc;
}

.community-report__select:focus-visible {
outline: none;
border-color: var(--cr-green);
box-shadow: 0 0 0 3px rgba(6, 128, 95, 0.15);
.community-report__select-option--selected {
color: var(--cr-green);
font-weight: 500;
background: transparent;
}

/* ---------------- Content ---------------- */
Expand Down
93 changes: 77 additions & 16 deletions src/components/community-report-next/CommunityReportNext.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { JSX, useEffect, useState } from 'react';
import React, { JSX, useEffect, useRef, useState } from 'react';
import { LayoutNext } from '../home-next/LayoutNext';
import './CommunityReportNext.scss';
import './WeeklyReport.scss';
Expand Down Expand Up @@ -111,6 +111,8 @@ export default function CommunityReportNext({ reports }: CommunityReportNextProp
const latest = reports[0];
const historical = reports.slice(1);
const [selectedId, setSelectedId] = useState<string>(latest?.id ?? '');
const [isPastMenuOpen, setIsPastMenuOpen] = useState(false);
const pastMenuRef = useRef<HTMLDivElement>(null);

// Allow deep-linking to a specific report via URL hash, e.g.
// /community-report#2026-06-22. Read on mount (client-only; window is
Expand All @@ -122,15 +124,43 @@ export default function CommunityReportNext({ reports }: CommunityReportNextProp
}
}, [reports]);

useEffect(() => {
if (!isPastMenuOpen) {
return;
}

const closeOnOutsideClick = (event: MouseEvent) => {
if (!pastMenuRef.current?.contains(event.target as Node)) {
setIsPastMenuOpen(false);
}
};

const closeOnEscape = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
setIsPastMenuOpen(false);
}
};

document.addEventListener('mousedown', closeOnOutsideClick);
document.addEventListener('keydown', closeOnEscape);

return () => {
document.removeEventListener('mousedown', closeOnOutsideClick);
document.removeEventListener('keydown', closeOnEscape);
};
}, [isPastMenuOpen]);

const select = (id: string) => {
setSelectedId(id);
setIsPastMenuOpen(false);
if (typeof window !== 'undefined') {
window.history.replaceState(null, '', `#${id}`);
}
};

const selected = reports.find(r => r.id === selectedId) ?? latest;
const isHistoricalSelected = historical.some(r => r.id === selectedId);
const selectedHistoricalLabel = isHistoricalSelected ? selected?.label : 'Past reports...';
const SelectedReport = selected?.Component;

return (
Expand Down Expand Up @@ -159,22 +189,53 @@ export default function CommunityReportNext({ reports }: CommunityReportNextProp
)}

{historical.length > 0 && (
<div className="community-report__select-wrap">
<select
className="community-report__select"
aria-label="Browse past weekly reports"
value={isHistoricalSelected ? selectedId : ''}
onChange={e => select(e.target.value)}
<div className="community-report__select-wrap" ref={pastMenuRef}>
<button
type="button"
className={
'community-report__select-button' +
(isPastMenuOpen ? ' community-report__select-button--open' : '') +
(!isHistoricalSelected ? ' community-report__select-button--placeholder' : '')
}
aria-haspopup="listbox"
aria-expanded={isPastMenuOpen}
aria-controls="community-report-past-menu"
onClick={() => setIsPastMenuOpen(open => !open)}
onKeyDown={event => {
if (event.key === 'ArrowDown') {
event.preventDefault();
setIsPastMenuOpen(true);
}
}}
>
<option value="" disabled>
Past reports…
</option>
{historical.map(r => (
<option key={r.id} value={r.id}>
{r.label}
</option>
))}
</select>
<span>{selectedHistoricalLabel}</span>
</button>
{isPastMenuOpen && (
<div
id="community-report-past-menu"
className="community-report__select-menu"
role="listbox"
aria-label="Browse past weekly reports"
>
{historical.map(r => (
<button
key={r.id}
type="button"
role="option"
aria-selected={selectedId === r.id}
className={
'community-report__select-option' +
(selectedId === r.id
? ' community-report__select-option--selected'
: '')
}
onClick={() => select(r.id)}
>
{r.label}
</button>
))}
</div>
)}
</div>
)}
</div>
Expand Down
Loading
Loading