Bringing mini charts up to the right and other style tweaks

refs: https://github.com/TryGhost/Team/issues/1531
This commit is contained in:
James Morris 2022-04-26 14:52:46 +01:00
parent ac23f3cdae
commit 118aae2820
11 changed files with 245 additions and 136 deletions

View File

@ -14,22 +14,6 @@
{{/if}}
<Dashboard::V5::Charts::Recents />
{{!-- <div class="gh-dashboard5-split"> --}}
{{!-- <Dashboard::V5::Resources::Multi /> --}}
{{!-- <Dashboard::V5::Resources::Community /> --}}
{{!-- </div> --}}
{{!-- <Dashboard::V5::Resources::Triple /> --}}
{{!-- <div class="gh-dashboard5-split"> --}}
{{!-- <Dashboard::V5::Resources::Community /> --}}
{{!-- <Dashboard::V5::Reso÷urces::WhatsNew /> --}}
{{!-- </div> --}}
{{!-- <Dashboard::V5::Resources::WhatsNew /> --}}
{{!-- <Dashboard::V5::Resources::StaffPicks /> --}}
{{!-- <Dashboard::V5::Resources::Newsletter /> --}}
{{/if}}
</section>

View File

@ -45,16 +45,10 @@
</div>
{{#if this.hasPaidTiers}}
<article class="gh-dashboard5-columns">
<div class="gh-dashboard5-column gh-dashboard5-mrr">
<Dashboard::v5::Charts::Mrr />
</div>
<div class="gh-dashboard5-column gh-dashboard5-breakdown">
<Dashboard::v5::Charts::PaidBreakdown />
</div>
<div class="gh-dashboard5-column gh-dashboard5-mix">
<Dashboard::v5::Charts::PaidMix />
</div>
<article class="gh-dashboard5-minicharts">
<Dashboard::v5::Charts::Mrr />
<Dashboard::v5::Charts::PaidBreakdown />
<Dashboard::v5::Charts::PaidMix />
</article>
{{/if}}
</div>

View File

@ -139,6 +139,20 @@ export default class Anchor extends Component {
data = stats.map(stat => stat.paid + stat.free + stat.comped);
}
// gradient for line
const canvasLine = document.createElement('canvas');
const ctxLine = canvasLine.getContext('2d');
const gradientLine = ctxLine.createLinearGradient(0, 0, 1000, 0);
gradientLine.addColorStop(0, 'rgba(250, 45, 142, 1');
gradientLine.addColorStop(1, 'rgba(143, 66, 255, 1');
// gradient for fill
const canvasFill = document.createElement('canvas');
const ctxFill = canvasFill.getContext('2d');
const gradientFill = ctxFill.createLinearGradient(0, 0, 1000, 0);
gradientFill.addColorStop(0, 'rgba(250, 45, 142, 0.2');
gradientFill.addColorStop(1, 'rgba(143, 66, 255, 0.02');
return {
labels: labels,
datasets: [{
@ -146,8 +160,8 @@ export default class Anchor extends Component {
tension: 0,
cubicInterpolationMode: 'monotone',
fill: true,
fillColor: 'rgba(142, 66, 255, 0.05)',
backgroundColor: 'rgba(142, 66, 255, 0.05)',
fillColor: gradientFill,
backgroundColor: gradientFill,
pointRadius: 0,
pointHitRadius: 10,
pointBorderColor: '#8E42FF',
@ -155,7 +169,7 @@ export default class Anchor extends Component {
pointHoverBackgroundColor: '#8E42FF',
pointHoverBorderColor: '#8E42FF',
pointHoverRadius: 0,
borderColor: '#8E42FF',
borderColor: gradientLine,
borderJoinStyle: 'miter'
}]
};
@ -172,7 +186,7 @@ export default class Anchor extends Component {
get chartOptions() {
let barColor = this.feature.nightShift ? 'rgba(200, 204, 217, 0.25)' : 'rgba(200, 204, 217, 0.65)';
return {
responsive: true,
maintainAspectRatio: false,

View File

@ -1,17 +1,20 @@
<Dashboard::v5::Parts::Metric
@label={{this.chartTitle}}
@value="{{this.currentMRRFormatted}}"
@trends={{this.hasTrends}}
@percentage={{this.mrrTrend}} />
<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}}
<EmberChart
@type={{this.chartType}}
@data={{this.chartData}}
@options={{this.chartOptions}}
@height={{this.chartHeight}} />
{{/if}}
<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>
{{/if}}
</div>
</div>

View File

@ -58,6 +58,13 @@ export default class Mrr extends Component {
const labels = stats.map(stat => stat.date);
const data = stats.map(stat => stat.mrr);
// gradient for fill
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const gradient = ctx.createLinearGradient(0, 0, 0, 120);
gradient.addColorStop(0, 'rgba(143, 66, 255, 0.15');
gradient.addColorStop(1, 'rgba(143, 66, 255, 0.0');
return {
labels: labels,
datasets: [{
@ -65,8 +72,8 @@ export default class Mrr extends Component {
tension: 0,
cubicInterpolationMode: 'monotone',
fill: true,
fillColor: 'rgba(142, 66, 255, 0.02)',
backgroundColor: 'rgba(142, 66, 255, 0.02)',
fillColor: gradient,
backgroundColor: gradient,
pointRadius: 0,
pointHitRadius: 10,
pointBorderColor: '#8E42FF',
@ -105,6 +112,10 @@ export default class Mrr extends Component {
e.target.style.cursor = 'pointer';
}
},
animation: {
duration: 0
},
responsiveAnimationDuration: 0,
tooltips: {
intersect: false,
mode: 'index',
@ -170,10 +181,6 @@ export default class Mrr extends Component {
};
}
get chartHeight() {
return 90;
}
calculatePercentage(from, to) {
if (from === 0) {
if (to > 0) {

View File

@ -1,15 +1,24 @@
<Dashboard::v5::Parts::Metric
@label={{this.chartTitle}} />
<div class="gh-dashboard5-minichart gh-dashboard5-breakdown">
<div class="gh-dashboard5-data">
<Dashboard::v5::Parts::Metric
@label={{this.chartTitle}} />
<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}}
<EmberChart
@type={{this.chartType}}
@data={{this.chartData}}
@options={{this.chartOptions}}
@height={{this.chartHeight}} />
{{/if}}
<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>
{{/if}}
</div>
</div>

View File

@ -96,6 +96,10 @@ export default class PaidBreakdown extends Component {
e.target.style.cursor = 'pointer';
}
},
animation: {
duration: 0
},
responsiveAnimationDuration: 0,
tooltips: {
intersect: false,
mode: 'index',
@ -173,8 +177,4 @@ export default class PaidBreakdown extends Component {
}
};
}
get chartHeight() {
return 120;
}
}

View File

@ -1,34 +1,44 @@
{{#if this.hasMultipleTiers }}
<div class="gh-dashboard5-select">
<PowerSelect
@selected={{this.selectedModeOption}}
@options={{this.modeOptions}}
@searchEnabled={{false}}
@onChange={{this.onSwitchMode}}
@triggerComponent="gh-power-select/trigger"
@triggerClass="gh-contentfilter-menu-trigger"
@dropdownClass="gh-contentfilter-menu-dropdown"
@matchTriggerWidth={{false}}
as |option|
>
{{#if option.name}}{{option.name}}{{else}}<span class="red">Unknown option</span>{{/if}}
</PowerSelect>
<div class="gh-dashboard5-minichart gh-dashboard5-mix {{if this.isChartTiers 'is-tiers'}}">
<div class="gh-dashboard5-data">
<Dashboard::v5::Parts::Metric
@label="Paid mix" />
{{#if this.isChartCadence}}
<div class="gh-dashboard5-legend">
<div class="gh-dashboard5-legend-item">Monthly</div>
<div class="gh-dashboard5-legend-item">Annual</div>
</div>
{{/if}}
</div>
{{/if}}
<Dashboard::v5::Parts::Metric
@label="Paid mix" />
<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>
{{/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}}
@height={{this.chartHeight}} />
{{#if this.hasMultipleTiers }}
<div class="gh-dashboard5-select">
<PowerSelect
@selected={{this.selectedModeOption}}
@options={{this.modeOptions}}
@searchEnabled={{false}}
@onChange={{this.onSwitchMode}}
@triggerComponent="gh-power-select/trigger"
@triggerClass="gh-contentfilter-menu-trigger"
@dropdownClass="gh-contentfilter-menu-dropdown"
@matchTriggerWidth={{false}}
as |option|
>
{{#if option.name}}{{option.name}}{{else}}<span class="red">Unknown option</span>{{/if}}
</PowerSelect>
</div>
{{/if}}
</div>

View File

@ -116,30 +116,24 @@ export default class PaidMix extends Component {
responsive: true,
maintainAspectRatio: false,
legend: {
display: (this.mode === 'cadence' ? true : false),
position: 'left',
labels: {
boxWidth: 13,
fontFamily: '-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Droid Sans,Helvetica Neue,sans-serif',
fontColor: '#626d79',
fontSize: 13
},
onClick: null
display: false
},
layout: {
padding: (this.mode === 'cadence' ? {
left: 7,
left: 0,
right: 21,
top: 10
top: 30
} : {
top: 10,
left: 23,
right: 40
top: 30,
left: 21,
right: 21,
bottom: 30
})
},
animation: {
duration: 0
},
responsiveAnimationDuration: 0,
hover: {
onHover: function (e) {
e.target.style.cursor = 'pointer';
@ -196,7 +190,11 @@ export default class PaidMix extends Component {
};
}
get chartHeight() {
return 130;
get isChartCadence() {
return (this.mode === 'cadence');
}
get isChartTiers() {
return (this.mode === 'tiers');
}
}

View File

@ -9,19 +9,9 @@
<div class="gh-dashboard5-resource-smallarticles">
{{#each this.newsletters as |entry|}}
<a class="gh-dashboard5-resource-smallarticle" href={{set-query-params entry.url utm_source='admin'}} target="_blank" rel="noopener noreferrer">
{{!-- {{#if entry.feature_image}}
<div class="gh-dashboard5-newsletter-thumbnail" style={{background-image-style entry.feature_image}}></div>
{{/if}} --}}
<img class="gh-dashboard5-resource-thumbnail" src="assets/img/newsletter-1.jpg" alt="{{entry.title}}" />
<div class="gh-dashboard5-resource-text">
<h5>{{entry.title}}</h5>
{{!-- {{#if entry.custom_excerpt}}
<p>{{entry.custom_excerpt}}</p>
{{else if entry.excerpt}}
<p>{{entry.excerpt}}</p>
{{/if}} --}}
<div class="gh-dashboard5-resource-secondary">{{moment-format entry.published_at "D MMM YYYY"}}</div>
</div>
</a>
@ -31,7 +21,7 @@
</div>
<div class="gh-dashboard5-resource-footer">
<a href="https://ghost.org/resources/" target="_blank" rel="noopener noreferrer">Sign up to the newsletter &rarr;</a>
<a href="https://ghost.org/resources/newsletter/" target="_blank" rel="noopener noreferrer">Sign up to the newsletter &rarr;</a>
</div>
</article>
</section>

View File

@ -203,6 +203,90 @@ Dashboard v5 Layout */
padding-right: 0;
}
.gh-dashboard5-minicharts {
flex: 1;
padding: 0;
display: flex;
flex-direction: row;
position: relative;
align-items: stretch;
background: transparent;
}
.gh-dashboard5-minichart {
flex: 1;
display: flex;
flex-direction: row;
border-left: 1px solid var(--whitegrey);
padding: 4px 24px;
position: relative;
height: 130px;
}
.gh-dashboard5-minichart .gh-dashboard5-data {
flex: 40%;
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 {
padding-left: 0;
border-left: 0 none;
}
.gh-dashboard5-minichart:last-child {
padding-right: 0;
}
.gh-dashboard5-minichart.is-tiers {
flex-direction: column;
}
.gh-dashboard5-minichart.is-tiers .gh-dashboard5-data {
flex: auto;
}
.gh-dashboard5-minichart.is-tiers .gh-dashboard5-chart {
flex: 1;
}
.gh-dashboard5-legend {
flex: 1;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center
}
.gh-dashboard5-legend-item {
font-size: 1.3rem;
font-weight: 600;
color: #626d79;
padding: 0 0 0 18px;
position: relative;
}
.gh-dashboard5-legend-item::after {
content: '';
width: 9px;
height: 9px;
border-radius: 8px;
background: #8E42FF;
position: absolute;
top: 6px;
left: 0;
}
.gh-dashboard5-legend-item:last-child::after {
background: #FB76B4;
}
.gh-dashboard5-tabs {
display: flex;
flex-direction: row;
@ -255,7 +339,7 @@ Dashboard v5 Layout */
.gh-dashboard5-select-title {
display: flex;
justify-content: flex-start;
margin: -10px 0 -12px -12px;
margin: -12px 0 -12px -12px;
}
.gh-dashboard5-select-title .ember-power-select-selected-item {
@ -478,7 +562,7 @@ Dashboard v5 List */
padding: 14px 0;
display: grid;
grid-template-columns: 55% 15% 30%;
padding: 8px 0;
padding: 4px 0;
}
.gh-dashboard5-list-item:nth-child(3) {
@ -652,29 +736,41 @@ Dashboard v5 Section Anchor */
color: var(--midlightgrey);
}
.gh-dashboard5-anchor .gh-dashboard5-columns {
.gh-dashboard5-anchor .gh-dashboard5-minicharts {
margin-top: 48px;
}
.gh-dashboard5-anchor .gh-dashboard5-mrr .gh-dashboard5-chart {
.gh-dashboard5-mrr .gh-dashboard5-chart {
margin-top: 0;
margin-left: -16px;
margin-right: -16px;
margin-right: -24px;
}
.gh-dashboard5-anchor .gh-dashboard5-breakdown .gh-dashboard5-chart {
.gh-dashboard5-mrr .gh-dashboard5-chart-container {
width: 99%;
}
.gh-dashboard5-breakdown .gh-dashboard5-chart {
margin-top: 8px;
margin-left: -16px;
margin-right: -16px;
margin-right: -24px;
}
.gh-dashboard5-anchor .gh-dashboard5-mix .gh-dashboard5-chart {
.gh-dashboard5-breakdown .gh-dashboard5-chart-container {
width: 99%;
}
.gh-dashboard5-mix .gh-dashboard5-chart {
margin-top: 0;
margin-left: -16px;
margin-right: -16px;
margin-left: -24px;
margin-right: -24px;
}
.gh-dashboard5-anchor .gh-dashboard5-mix .gh-dashboard5-select {
.gh-dashboard5-mix .gh-dashboard5-chart-container {
width: 99%;
}
.gh-dashboard5-mix .gh-dashboard5-select {
top: -8px;
right: -18px;
}
@ -688,7 +784,7 @@ Dashboard v5 Section Engagement */
}
.gh-dashboard5-engagement .gh-dashboard5-columns {
padding-top: 32px;
padding-top: 24px;
}
.gh-dashboard5-engagement .gh-dashboard5-select {
@ -874,7 +970,7 @@ Dashboard v5 Section Recents */
}
.gh-dashboard5-recents .gh-dashboard5-list-loading {
min-height: 240px;
min-height: 200px;
display: flex;
align-items: center;
justify-content: center;
@ -911,6 +1007,7 @@ Dashboard v5 Section What's New */
.gh-dashboard5-whats-new {
position: relative;
margin-left: -12px; /* layout adjustment */
}
.gh-dashboard5-whats-new .gh-dashboard5-list-header,
@ -954,6 +1051,7 @@ Dashboard v5 Section Resources */
.gh-dashboard5-resources {
position: relative;
margin-right: 12px; /* layout adjustment */
}
.gh-dashboard5-resources .gh-dashboard5-articles {
@ -1059,6 +1157,7 @@ Dashboard v5 Section Staff Picks */
.gh-dashboard5-staff-picks {
position: relative;
margin-left: -12px; /* layout adjustment */
}
.gh-dashboard5-staff-picks .gh-dashboard5-list-header,
@ -1107,6 +1206,7 @@ Dashboard v5 Section Latest Newsletters */
.gh-dashboard5-newsletter {
position: relative;
margin-right: 12px; /* layout adjustment */
}
.gh-dashboard5-newsletter .gh-dashboard5-newsletter-items {