From 724bad18164dca106135c8fb2ed6d3795cb7ab0c Mon Sep 17 00:00:00 2001
From: Holly Cummins
Date: Wed, 13 Nov 2024 19:50:15 +0000
Subject: [PATCH] Make pie charts render nicely on mobile and be responsive in
general
---
src/components/charts/contributions-chart.js | 130 ++++++++++++++-----
src/templates/extension-detail.js | 14 +-
2 files changed, 98 insertions(+), 46 deletions(-)
diff --git a/src/components/charts/contributions-chart.js b/src/components/charts/contributions-chart.js
index 436b69ef5d95..803989b1a19d 100644
--- a/src/components/charts/contributions-chart.js
+++ b/src/components/charts/contributions-chart.js
@@ -3,21 +3,56 @@ import { getPalette } from "../util/styles/style"
import { LabelList, Legend, Pie, PieChart, ResponsiveContainer, Text, Tooltip } from "recharts"
import PropTypes from "prop-types"
import styled from "styled-components"
+import { useMediaQuery } from "react-responsive"
+import { device } from "../util/styles/breakpoints"
const RADIAN = Math.PI / 180
+const bigHeight = "520px"
+const mediumHeight = "340px"
+const smallHeight = "260px"
+
+// We need to set an explicit height for the charts, or the contents don't render at all
+const ChartHolder = styled.div`
+ height: ${bigHeight};
+
+ // noinspection CssUnknownProperty
+ @media ${device.sm} {
+ height: ${mediumHeight};
+ }
+
+ // noinspection CssUnknownProperty
+ @media ${device.xs} {
+ height: ${smallHeight};
+ }
+`
+
+const LegendHolder = styled.div`
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+`
+
const LegendSwatch = styled.div`
height: var(--font-size-10);
width: var(--font-size-10);
border-radius: 3px;
background-color: ${(props) => props.color};
+ border: 0.5px lightgray solid;
`
const ContributorList = styled.ul`
overflow: scroll;
- height: 400px;
background-color: var(--main-background-color); // this very slightly reduces quite how awful it is if the content overflows to the right-hand side
padding-inline-start: 0;
+
+ height: calc(${bigHeight} - var(--a-generous-space));
+
+ // noinspection CssUnknownProperty
+ @media ${device.sm} {
+ height: auto;
+ }
`
const ContributorInformation = styled.li`
@@ -29,7 +64,7 @@ const ContributorInformation = styled.li`
column-gap: 0.75rem;
font-size: var(--font-size-10);
padding: 2px;
-
+ max-width: 200px;
`
const Contributor = styled.div`
@@ -59,6 +94,9 @@ const ContributionsChart = (props) => {
const uncolouredContributors = props.contributors
const uncolouredCompanies = props.companies
+ const isMobile = useMediaQuery({ query: device.xs })
+ const isSmallScreen = useMediaQuery({ query: device.sm })
+
if (uncolouredContributors?.length > 0) {
const palette = getPalette(uncolouredContributors.length, props.baseColour)
@@ -80,40 +118,60 @@ const ContributionsChart = (props) => {
const contributors = ungroupedContributors.sort((a, b) => a.company === b.company ? (b.contributions - a.contributions) : companyComparator(a.company, b.company))
const lotsOfContributors = contributors.length > 8
+ const shouldRenderLabels = !lotsOfContributors && !isSmallScreen
+ const shouldRenderExternalLegend = isSmallScreen
+
+ // These have to be convincingly smaller than the size of the chartholder, or a ring will go missing
+ const innerRadius = isMobile ? 40 : 70
+ const companyRingWidth = isMobile ? 15 : 25
- const innerRadius = 70
- const companyRingWidth = 25
+ const width = "100%"
// we set a blank label if there are a small number of contributors, so we get the line, but we define our own
// text so we can make it black. the offset in the label list is hand-tuned to put the text near the end of the line
return (
-
-
-
-
-
- ""}
- >
-
- {lotsOfContributors ||
- p} />}
- }
-
-
- {lotsOfContributors && }
-
- [`${value} commits`, name])} />
-
-
- )
+
+
+
+
+
+
+
+
+ "" : false}
+ >
+
+ {shouldRenderLabels &&
+ p} />}
+ }
+
+
+ {(shouldRenderExternalLegend) || }
+
+ [`${value} commits`, name])} />
+
+
+
+
+ {shouldRenderExternalLegend &&
+ renderLegend({
+ payload: contributors.map(entry => {
+ return { payload: { ...entry, value: entry.contributions } }
+ })
+ })
+
+ }
+
)
+
+
}
}
@@ -150,7 +208,7 @@ const renderLegend = (props) => {
const { payload } = props
return (
-
+
Commits
{
@@ -158,24 +216,24 @@ const renderLegend = (props) => {
.sort((a, b) =>
b.payload.contributions - a.payload.contributions
).map((entry, index) => {
- const { payload: { name, value }, color } = entry
+ const { payload: { name, value, fill } } = entry
return (
-
+
{name}
{value}
)
})
}
-
+
)
}
diff --git a/src/templates/extension-detail.js b/src/templates/extension-detail.js
index 86d909b55df9..c9d9c435e183 100644
--- a/src/templates/extension-detail.js
+++ b/src/templates/extension-detail.js
@@ -109,6 +109,7 @@ const Metadata = styled.div`
const MainContent = styled.div`
width: 70%;
+ min-width: 70%;
display: flex;
flex-direction: column;
@@ -174,11 +175,6 @@ const DocumentationHeading = styled.h2`
padding-bottom: 10px;
`
-// I wish this wasn't here, but we need to set an explicit height for the charts, or the contents don't render at all
-const ChartHolder = styled.div`
- height: 480px; // For now, an arbitrary height, but we should tune
-`
-
const Logo = ({ extension, isMobile }) => {
// Size here doesn't matter that much because display size is set in css, but getting smaller makes page load quicker
return isMobile ?
@@ -368,11 +364,9 @@ const ExtensionDetailTemplate = ({
past {numMonthsWithUnit}{" "}
(excluding merge commits).
)}
-
-
-
+
{metadata?.sourceControl?.companies && (
Company affiliations are derived from GitHub user profiles. Want your company's name to be