diff --git a/src/pages/community/index.tsx b/src/pages/community/index.tsx index fad4b41a..99c9bc0f 100644 --- a/src/pages/community/index.tsx +++ b/src/pages/community/index.tsx @@ -57,6 +57,105 @@ const channels = [ }, ]; +function IssueIcon() { + return ( + + ); +} + +function CallIcon() { + return ( + + ); +} + +function GroupIcon() { + return ( + + ); +} + +const contributeActions = [ + { + title: 'Good first issues', + description: 'Curated, beginner-friendly issues to make your first PR.', + cta: 'Browse issues', + href: 'https://github.com/openchoreo/openchoreo/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22', + icon: IssueIcon, + }, + { + title: 'Community call', + description: 'Monthly call to hear project updates and engage with the community.', + cta: 'See schedule', + href: 'https://zoom-lfx.platform.linuxfoundation.org/meetings/openchoreo?view=list', + icon: CallIcon, + }, + { + title: 'Working group', + description: 'Help shape direction on a focused area of the project.', + cta: 'Join a group', + href: 'https://github.com/openchoreo/openchoreo/tree/main/working-groups/observability-plane-architecture', + icon: GroupIcon, + }, +]; + export default function Community(): React.JSX.Element { const now = useNow(); const { upcoming, past } = useMemo(() => splitEvents(events, now), [now]); @@ -278,6 +377,37 @@ export default function Community(): React.JSX.Element { */} +
+
+

How to contribute

+

+ Contribute through code, discussion, or planning, every path is + open to you. +

+ +
+ {contributeActions.map((action) => { + const Icon = action.icon; + + return ( +
+ +

{action.title}

+

{action.description}

+ + {action.cta} + +
+ ); + })} +
+
+

Join the community

diff --git a/src/pages/community/styles.module.css b/src/pages/community/styles.module.css index acb612df..0f27186c 100644 --- a/src/pages/community/styles.module.css +++ b/src/pages/community/styles.module.css @@ -30,7 +30,7 @@ } .section { - padding: 56px 0; + padding: 45px 0; } .section h2 { @@ -410,8 +410,57 @@ text-decoration: none; } +.contributeGrid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 16px; +} + +.contributeCard { + padding: 24px; + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 10px; + background: var(--ifm-card-background-color); + text-align: center; +} + +.contributeIcon { + display: grid; + place-items: center; + width: 44px; + height: 44px; + margin: 0 auto 16px; + border-radius: 10px; + background: rgba(47, 129, 247, 0.12); + color: var(--ifm-color-primary); +} + +.contributeIcon svg { + width: 22px; + height: 22px; +} + +.contributeCard h3 { + margin: 0 0 6px; + font-size: 1.05rem; +} + +.contributeCard p { + min-height: 44px; + margin: 0 0 16px; + color: var(--ifm-color-emphasis-700); + font-size: 0.9rem; + line-height: 1.5; +} + +.contributeButton { + padding: 0.35rem 0.9rem; + font-size: 0.85rem; +} + @media (max-width: 900px) { - .eventGrid { + .eventGrid, + .contributeGrid { grid-template-columns: 1fr; } } @@ -473,4 +522,18 @@ .channelGrid { grid-template-columns: 1fr; } + + .contributeGrid { + grid-template-columns: 1fr; + } + + .contributeCard { + padding: 20px; + text-align: center; + } + + .contributeIcon { + margin-left: auto; + margin-right: auto; + } }