Fixed layout bugs with new dashboard charts

refs: https://github.com/TryGhost/Team/issues/1531

- investigated how to make the layout not break on resize
- using a width 99% hack to make chartjs react properly
- redid the markup for the minicharts for more stable loading
- added in a subtle gradient for the mrr minichart
This commit is contained in:
James Morris 2022-04-27 14:40:38 +01:00
parent ccd722a5f7
commit e5d5e359d7
10 changed files with 137 additions and 159 deletions

View File

@ -26,16 +26,18 @@
{{/if}}
<div class="gh-dashboard5-hero {{unless this.hasPaidTiers 'is-solo'}}">
<div class="gh-dashboard5-chart">
<div class="gh-dashboard5-chart gh-dashboard5-totals">
{{#if this.loading}}
<div class="gh-dashboard5-chart-loading" style={{html-safe (concat "height: " this.chartHeight "px;")}}/>
{{else}}
<div class="gh-dashboard5-chart-container">
<EmberChart
@type="line"
@data={{this.chartData}}
@options={{this.chartOptions}}
@height={{if this.hasPaidTiers this.chartHeight this.chartHeightSmall}} />
<div class="gh-dashboard5-chart-box">
<EmberChart
@type="line"
@data={{this.chartData}}
@options={{this.chartOptions}}
@height={{200}} />
</div>
<div id="gh-dashboard5-anchor-tooltip" class="gh-dashboard5-tooltip">
<div class="gh-dashboard5-tooltip-label">

View File

@ -199,8 +199,9 @@ export default class Anchor extends Component {
let barColor = this.feature.nightShift ? 'rgba(200, 204, 217, 0.25)' : 'rgba(200, 204, 217, 0.65)';
return {
responsive: true,
maintainAspectRatio: false,
responsiveAnimationDuration: 1,
animation: false,
title: {
display: false
},
@ -211,8 +212,8 @@ export default class Anchor extends Component {
padding: {
top: 2,
bottom: 2,
left: 16,
right: 16
left: 0,
right: 0
}
},
hover: {

View File

@ -1,19 +1,18 @@
<div class="gh-dashboard5-minichart gh-dashboard5-mrr">
<Dashboard::v5::Parts::Metric
@label={{this.chartTitle}}
@value="{{this.currentMRRFormatted}}"
@trends={{this.hasTrends}}
@percentage={{this.mrrTrend}} />
<div class="gh-dashboard5-chart">
{{#if this.loading}}
<div class="gh-dashboard5-chart-loading" style={{html-safe (concat "height: " this.chartHeight "px;")}}/>
{{else}}
<div class="gh-dashboard5-chart-container">
<EmberChart
@type={{this.chartType}}
@data={{this.chartData}}
@options={{this.chartOptions}} />
<div class="gh-dashboard5-chart-box">
<EmberChart
@type={{this.chartType}}
@data={{this.chartData}}
@options={{this.chartOptions}}
@height={{130}} />
</div>
<div class="gh-dashboard5-chart-gradient"></div>
<div id="gh-dashboard5-mrr-tooltip" class="gh-dashboard5-tooltip">
<div class="gh-dashboard5-tooltip-label">
@ -26,4 +25,12 @@
</div>
{{/if}}
</div>
<div class="gh-dashboard5-data">
<Dashboard::v5::Parts::Metric
@label={{this.chartTitle}}
@value="{{this.currentMRRFormatted}}"
@trends={{this.hasTrends}}
@percentage={{this.mrrTrend}} />
</div>
</div>

View File

@ -102,10 +102,10 @@ export default class Mrr extends Component {
},
layout: {
padding: {
top: 4,
top: 2,
bottom: 2,
left: 16,
right: 16
left: 0,
right: 0
}
},
hover: {

View File

@ -1,23 +1,16 @@
<div class="gh-dashboard5-minichart gh-dashboard5-breakdown">
<div class="gh-dashboard5-data">
<Dashboard::v5::Parts::Metric
@label={{this.chartTitle}} />
<div class="gh-dashboard5-legend">
<div class="gh-dashboard5-legend-item">New</div>
<div class="gh-dashboard5-legend-item">Canceled</div>
</div>
</div>
<div class="gh-dashboard5-chart" {{did-insert this.loadCharts}}>
{{#if this.loading}}
<div class="gh-dashboard5-chart-loading" style={{html-safe (concat "height: " this.chartHeight "px;")}}/>
{{else}}
<div class="gh-dashboard5-chart-container">
<EmberChart
@type={{this.chartType}}
@data={{this.chartData}}
@options={{this.chartOptions}} />
<div class="gh-dashboard5-chart-box">
<EmberChart
@type={{this.chartType}}
@data={{this.chartData}}
@options={{this.chartOptions}}
@height={{130}} />
</div>
<div id="gh-dashboard5-breakdown-tooltip" class="gh-dashboard5-tooltip">
<div class="gh-dashboard5-tooltip-label">
@ -32,4 +25,14 @@
</div>
{{/if}}
</div>
<div class="gh-dashboard5-data">
<Dashboard::v5::Parts::Metric
@label={{this.chartTitle}} />
<div class="gh-dashboard5-legend">
<div class="gh-dashboard5-legend-item">New</div>
<div class="gh-dashboard5-legend-item">Canceled</div>
</div>
</div>
</div>

View File

@ -85,10 +85,10 @@ export default class PaidBreakdown extends Component {
},
layout: {
padding: {
top: 8,
top: 24,
bottom: 0,
left: 16,
right: 16
left: 0,
right: 0
}
},
hover: {

View File

@ -1,4 +1,26 @@
<div class="gh-dashboard5-minichart gh-dashboard5-mix {{if this.isChartTiers 'is-tiers'}}">
<div class="gh-dashboard5-chart" {{did-insert this.loadCharts}}>
{{#if this.loading}}
<div class="gh-dashboard5-chart-loading" style={{html-safe (concat "height: " this.chartHeight "px;")}}/>
{{else}}
<div class="gh-dashboard5-chart-container">
<div class="gh-dashboard5-chart-box">
<EmberChart
@type={{this.chartType}}
@data={{this.chartData}}
@options={{this.chartOptions}}
@height={{130}} />
</div>
<div id="gh-dashboard5-mix-tooltip" class="gh-dashboard5-tooltip">
<div class="gh-dashboard5-tooltip-value">
-
</div>
</div>
</div>
{{/if}}
</div>
<div class="gh-dashboard5-data">
<Dashboard::v5::Parts::Metric
@label="Paid mix" />
@ -11,25 +33,6 @@
{{/if}}
</div>
<div class="gh-dashboard5-chart" {{did-insert this.loadCharts}}>
{{#if this.loading}}
<div class="gh-dashboard5-chart-loading" style={{html-safe (concat "height: " this.chartHeight "px;")}}/>
{{else}}
<div class="gh-dashboard5-chart-container">
<EmberChart
@type={{this.chartType}}
@data={{this.chartData}}
@options={{this.chartOptions}} />
<div id="gh-dashboard5-mix-tooltip" class="gh-dashboard5-tooltip">
<div class="gh-dashboard5-tooltip-value">
-
</div>
</div>
</div>
{{/if}}
</div>
{{#if this.hasMultipleTiers }}
<div class="gh-dashboard5-select">
<PowerSelect

View File

@ -63,6 +63,7 @@ export default class PaidMix extends Component {
const totalCadence = this.dashboardStats.paidMembersByCadence.monthly + this.dashboardStats.paidMembersByCadence.annual;
const monthlyPercentage = Math.round(this.dashboardStats.paidMembersByCadence.monthly / totalCadence * 100);
const annualPercentage = Math.round(this.dashboardStats.paidMembersByCadence.annual / totalCadence * 100);
const barThickness = 5;
if (this.mode === 'cadence') {
return {
@ -70,15 +71,13 @@ export default class PaidMix extends Component {
datasets: [{
label: 'Monthly',
data: [monthlyPercentage],
fill: true,
backgroundColor: '#8E42FF',
barThickness: 7
barThickness
}, {
label: 'Annual',
data: [annualPercentage],
fill: true,
backgroundColor: '#FB76B4',
barThickness: 7
barThickness
}]
};
}
@ -99,9 +98,7 @@ export default class PaidMix extends Component {
data: [tierPercentage],
label: labels[i],
backgroundColor: colors[i],
fill: true,
borderRadius: 15,
barThickness: 7
barThickness
});
}
@ -119,16 +116,12 @@ export default class PaidMix extends Component {
display: false
},
layout: {
padding: (this.mode === 'cadence' ? {
left: 0,
right: 21,
top: 30
} : {
padding: {
top: 30,
left: 21,
right: 21,
bottom: 30
})
bottom: 0,
left: 0,
right: 0
}
},
animation: {
duration: 0

View File

@ -1,5 +1,5 @@
<section class="gh-dashboard5-resource gh-dashboard5-staff-picks" {{did-insert this.load}}>
<article class="gh-dashboard5-resource-box">
<article class="gh-dashboard5-resource-box is-secondary">
<div class="gh-dashboard5-resource-title">
<h4>Staff Picks</h4>
</div>

View File

@ -67,6 +67,7 @@ Dashboard v5 Layout */
.gh-dashboard5-layout {
max-width: 1230px;
min-width: 850px;
margin: 0 auto;
}
@ -168,7 +169,7 @@ Dashboard v5 Layout */
}
.gh-dashboard5-box.is-secondary {
background: #f5f6f6;
background: var(--main-color-content-greybg);
border: transparent;
}
@ -215,8 +216,6 @@ Dashboard v5 Layout */
.gh-dashboard5-minichart {
flex: 1;
display: flex;
flex-direction: row;
border-left: 1px solid var(--whitegrey);
padding: 4px 24px;
position: relative;
@ -224,15 +223,20 @@ Dashboard v5 Layout */
}
.gh-dashboard5-minichart .gh-dashboard5-data {
flex: 40%;
pointer-events: none;
position: absolute;
top: 0;
left: 24px;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
}
.gh-dashboard5-minichart .gh-dashboard5-chart {
flex: 60%;
.gh-dashboard5-minichart:first-child .gh-dashboard5-data {
left: 0;
}
.gh-dashboard5-minichart:first-child {
@ -248,12 +252,8 @@ Dashboard v5 Layout */
flex-direction: column;
}
.gh-dashboard5-minichart.is-tiers .gh-dashboard5-data {
flex: auto;
}
.gh-dashboard5-minichart.is-tiers .gh-dashboard5-chart {
flex: 1;
padding: 0;
}
.gh-dashboard5-legend {
@ -378,6 +378,7 @@ Dashboard v5 Layout */
.gh-dashboard5-inner {
max-width: 1230px;
min-width: 850px;
margin: 0 auto;
}
@ -422,8 +423,37 @@ Dashboard v5 Chart */
.gh-dashboard5-chart-container {
flex: 1;
position: relative;
width: 100%; /* hack for ChartJS responsive resizing */
}
.gh-dashboard5-chart-box {
position: relative;
height: 200px;
width: 99%; /* ChartJS hack to resize with window */
}
.gh-dashboard5-chart-gradient {
pointer-events: none;
position: absolute;
top: 0;
left: 0;
width: 32px;
height: 100%;
background: rgb(21,23,25);
background: linear-gradient(270deg, rgba(21,23,25,0) 0%, rgba(21,23,25,1) 100%);
}
.gh-dashboard5-chart-box canvas {
height: 100% !important;
}
.gh-dashboard5-minicharts .gh-dashboard5-chart {
width: 100%;
height: 100%;
padding: 0 0 0 30%;
}
.gh-dashboard5-minicharts .gh-dashboard5-chart-box {
height: 130px;
}
@ -761,14 +791,11 @@ Dashboard v5 Anchor */
.gh-dashboard5-anchor .gh-dashboard5-chart {
flex-direction: column;
margin-top: 24px;
margin-left: -16px;
margin-right: -16px;
}
.gh-dashboard5-anchor .gh-dashboard5-chart-ticks {
flex-direction: row;
padding: 10px 16px;
padding: 10px 0;
font-size: 1.2rem;
color: var(--midlightgrey);
}
@ -777,36 +804,6 @@ Dashboard v5 Anchor */
margin-top: 48px;
}
.gh-dashboard5-mrr .gh-dashboard5-chart {
margin-top: 0;
margin-left: -16px;
margin-right: -24px;
}
.gh-dashboard5-mrr .gh-dashboard5-chart-container {
width: 99%;
}
.gh-dashboard5-breakdown .gh-dashboard5-chart {
margin-top: 8px;
margin-left: -16px;
margin-right: -24px;
}
.gh-dashboard5-breakdown .gh-dashboard5-chart-container {
width: 99%;
}
.gh-dashboard5-mix .gh-dashboard5-chart {
margin-top: 0;
margin-left: -24px;
margin-right: -24px;
}
.gh-dashboard5-mix .gh-dashboard5-chart-container {
width: 99%;
}
.gh-dashboard5-mix .gh-dashboard5-select {
top: -8px;
right: -18px;
@ -1316,44 +1313,6 @@ Dashboard v5 Misc */
font-weight: 600;
}
.gh-dashboard5-rate-bar {
flex: 1;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
}
.gh-dashboard5-rate-amount {
height: 6px;
border-radius: 2.5px;
background: var(--whitegrey);
overflow: hidden;
position: relative;
display: block;
flex-grow: 1;
margin-left: 20px;
}
.gh-dashboard5-rate-amount + span {
flex-shrink: 0;
padding-left: 15px;
}
.gh-dashboard5-rate-amount > span {
/* background: var(--purple); */
background: rgb(213,184,255);
background: linear-gradient(90deg, rgba(213,184,255,1) 0%, rgba(142,66,255,1) 100%);
border-top-right-radius: 2.5px;
border-bottom-right-radius: 2.5px;
position: absolute;
left: 0;
top: 0;
bottom: 0;
}
/* ---------------------------------
Dashboard v5 Resources */
@ -1384,6 +1343,12 @@ Dashboard v5 Resources */
box-shadow: 0px 2px 16px 0px rgba(0, 0, 0, 0.02);
}
.gh-dashboard5-resource-box.is-secondary {
background: var(--main-color-content-greybg);
border-color: transparent;
box-shadow: none;
}
.gh-dashboard5-resource-title {
display: flex;
flex-direction: row;
@ -1530,3 +1495,7 @@ Dashboard v5 Tooltips */
.gh-dashboard5-mix .gh-dashboard5-tooltip-value {
font-size: 1.4rem;
}
.gh-dashboard5-totals {
margin-top: 24px;
}