Skip to content

Commit

Permalink
feat(community): new community page design (#11653)
Browse files Browse the repository at this point in the history
Co-authored-by: Claas Augner <[email protected]>
Co-authored-by: Florian Dieminger <[email protected]>
  • Loading branch information
3 people authored Oct 15, 2024
1 parent b37a6e1 commit 75a3f2f
Show file tree
Hide file tree
Showing 27 changed files with 1,380 additions and 227 deletions.
31 changes: 13 additions & 18 deletions build/spas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,6 @@ export async function buildSPAs(options: {
noIndexing: true,
},
{ prefix: "about", pageTitle: "About MDN" },
{ prefix: "community", pageTitle: "Contribute to MDN" },
{
prefix: "advertising",
pageTitle: "Advertise with us",
Expand Down Expand Up @@ -269,16 +268,9 @@ export async function buildSPAs(options: {
}

// Building the MDN Plus pages.

/**
*
* @param {string} dirpath
* @param {string} slug
* @param {string} title
*/
async function buildStaticPages(
dirpath: string,
slug: string,
slugPrefix?: string,
title = "MDN"
) {
const crawler = new fdir()
Expand All @@ -299,13 +291,14 @@ export async function buildSPAs(options: {
const frontMatter = frontmatter<DocFrontmatter>(markdown);
const rawHTML = await m2h(frontMatter.body, { locale });

const url = `/${locale}/${slug}/${page}`;
const slug = slugPrefix ? `${slugPrefix}/${page}` : `${page}`;
const url = `/${locale}/${slug}`;
const d = {
url,
rawBody: rawHTML,
metadata: {
locale: DEFAULT_LOCALE,
slug: `${slug}/${page}`,
slug,
url,
},

Expand All @@ -327,16 +320,13 @@ export async function buildSPAs(options: {
};
const context: HydrationData = {
hyData,
pageTitle: `${frontMatter.attributes.title || ""} | ${title}`,
pageTitle: frontMatter.attributes.title
? `${frontMatter.attributes.title} | ${title}`
: title,
url,
};

const outPath = path.join(
BUILD_OUT_ROOT,
pathLocale,
...slug.split("/"),
page
);
const outPath = path.join(BUILD_OUT_ROOT, pathLocale, ...slug.split("/"));
fs.mkdirSync(outPath, { recursive: true });
const jsonFilePath = path.join(outPath, "index.json");
fs.writeFileSync(jsonFilePath, JSON.stringify(context));
Expand All @@ -363,6 +353,11 @@ export async function buildSPAs(options: {
"observatory/docs",
OBSERVATORY_TITLE
);
await buildStaticPages(
fileURLToPath(new URL("../copy/community/", import.meta.url)),
"",
"Contribute to MDN"
);

// Build all the home pages in all locales.
// Fetch merged content PRs for the latest contribution section.
Expand Down
4 changes: 2 additions & 2 deletions client/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { PageNotFound } from "./page-not-found";
import { Plus } from "./plus";
import { About } from "./about";
import { getCategoryByPathname } from "./utils";
import { Contribute } from "./community";
import { Community } from "./community";
import { ContributorSpotlight } from "./contributor-spotlight";
import { useIsServer, usePing } from "./hooks";

Expand Down Expand Up @@ -330,7 +330,7 @@ export function App(appProps: HydrationData) {
path="/community/*"
element={
<StandardLayout>
<Contribute />
<Community {...appProps} />
</StandardLayout>
}
/>
Expand Down
1 change: 1 addition & 0 deletions client/src/assets/community/community-calls-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions client/src/assets/community/community-calls.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions client/src/assets/community/discord-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions client/src/assets/community/discord.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions client/src/assets/community/people-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions client/src/assets/community/people.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions client/src/assets/community/quote-end-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions client/src/assets/community/quote-end.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions client/src/assets/community/quote-start-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions client/src/assets/community/quote-start.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions client/src/assets/community/video-bg-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions client/src/assets/community/video-bg.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added client/src/assets/community/video-thumbnail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions client/src/assets/community/youtube-play.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
144 changes: 144 additions & 0 deletions client/src/community/contributor-list.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
@use "../ui/vars" as *;

* {
box-sizing: border-box;
}

.wrap {
--img-size: 3.75em;
--li-size: calc(var(--img-size) * 2.5);
}

ul {
--circle-border-size: 0.375em;
align-content: start;
display: grid;
gap: 2rem 1rem;
grid-template-columns: repeat(auto-fit, minmax(var(--li-size), 1fr));
justify-items: center;
margin: 0;
padding: 0;

@media (max-width: $screen-md) {
display: flex;
margin-top: 2rem;
overflow-x: auto;
}
}

li,
a {
align-items: center;
display: flex;
flex-direction: column;
flex-shrink: 0;
text-align: center;
}

li {
color: var(--community-text-primary);
width: var(--li-size);
}

img {
background: var(--community-circle-img-border);
border: var(--circle-border-size) var(--community-circle-img-border) solid;
border-radius: 50%;
flex-shrink: 0;
height: var(--img-size);
width: var(--img-size);
}

a {
color: unset;
font-weight: 500;
}

svg {
display: none;
}

@supports (offset-path: ellipse(100% 50% at 100% 50%)) {
@media (min-width: $screen-md) {
.wrap {
container-type: size;
height: 100%;
width: 100%;
}

.inner {
font-size: min(1rem, 3.5cqmin);
padding: calc(var(--img-size) / 2) calc(var(--li-size) / 2);
}

ul {
aspect-ratio: 1 / 2;
display: block;
margin-left: auto;
max-height: var(--community-circle-height);
min-height: 0;
min-width: 0;
position: relative;
}

svg {
display: block;
fill: none;
height: 100%;
overflow: visible;
position: absolute;
stroke: var(--community-circle-img-border);
stroke-width: var(--circle-border-size);
width: 100%;
}

li {
$outer-elements: 5;
$inner-elements: 3;

// necessary because Firefox seems to have a bug where the links aren't
// clickable until we force some kind of re-render which an animation does:
animation: community-circle 0.1ms forwards;
offset-anchor: center calc(0.5 * var(--img-size));
offset-distance: var(--offset-distance);
offset-path: ellipse(100% 50% at 100% 50%);
offset-rotate: 0deg;

&:nth-of-type(n + #{$outer-elements + 1}) {
--img-size: 5em;
offset-path: ellipse(50% 25% at 100% 50%);
}

@keyframes community-circle {
from {
offset-distance: calc(var(--offset-distance) - 0.1%);
}
}

@for $i from 1 through $outer-elements {
&:nth-of-type(#{$i}) {
--offset-distance: #{calc(
75% - (($i - 1) * 50% / ($outer-elements - 1))
)};
}
}

@for $i from 1 through $inner-elements {
&:nth-of-type(#{$outer-elements + $i}) {
--offset-distance: #{calc(
75% - (($i - 1) * 50% / ($inner-elements - 1))
)};
}
}
}

.org {
-webkit-box-orient: vertical;
/* stylelint-disable-next-line value-no-vendor-prefix */
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
overflow: hidden;
}
}
}
109 changes: 109 additions & 0 deletions client/src/community/contributor-list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { LitElement, html } from "lit";
import { customElement } from "lit/decorators.js";

import styles from "./contributor-list.scss?css" with { type: "css" };

interface ContributorData {
name: string;
github: string;
org?: string;
}

@customElement("contributor-list")
export class ContributorList extends LitElement {
_contributors: ContributorData[] = [];

static properties = {
_contributors: { state: true },
};

static styles = styles;

constructor() {
super();
const contributorList = this.querySelector("ul");
const randomContributors: ContributorData[] = [];
if (contributorList) {
const contributors = [...contributorList.querySelectorAll("li")];
for (let index = 0; index < 8; index++) {
const contributor = popRandom(contributors);
if (!contributor) {
break;
}
const [name, github, org] = [...contributor.childNodes].map(
(node) => node?.textContent?.trim() || undefined
);
if (!name || !github) {
index--;
continue;
}
randomContributors.push({
name,
github,
org,
});
}
this._contributors = randomContributors;
}
}

render() {
return html`<div class="wrap">
<div class="inner">
<ul>
<svg>
<defs>
<mask id="hide-half">
<rect
x="0%"
y="0%"
width="100%"
height="100%"
fill="#fff"
stroke="#fff"
/>
</mask>
</defs>
<ellipse
rx="100%"
ry="50%"
cx="100%"
cy="50%"
mask="url(#hide-half)"
/>
<ellipse
rx="50%"
ry="25%"
cx="100%"
cy="50%"
mask="url(#hide-half)"
/>
</svg>
${this._contributors.map(({ name, github, org }) => {
const imgSrc = `https://avatars.githubusercontent.com/${github
?.split("/")
.slice(-1)}`;
return html`<li>
<a href="${github}" target="_blank" rel="nofollow noreferrer">
<img
src="${imgSrc}?size=80"
srcset="${imgSrc}?size=160 2x"
loading="lazy"
referrerpolicy="no-referrer"
/>
${name}
</a>
<span class="org">${org}</span>
</li>`;
})}
</ul>
</div>
</div>`;
}
}

function popRandom<T>(array: Array<T>) {
const i = Math.floor(Math.random() * array.length);
// mutate the array:
return array.splice(i, 1)[0];
}
Loading

0 comments on commit 75a3f2f

Please sign in to comment.