More layout tweaks to new dashboard

refs: https://github.com/TryGhost/Team/issues/1462
This commit is contained in:
James Morris 2022-04-11 17:17:31 +01:00
parent 7e499573e5
commit f046e5e118
12 changed files with 691 additions and 255 deletions

View File

@ -22,37 +22,39 @@
{{#if option.name}}{{option.name}}{{else}}<span class="red">Unknown option</span>{{/if}}
</PowerSelect>
</div>
<div id="gh-dashboard5-anchor-globaldate">
March 31, 2022
</div>
</section>
{{!-- {{#if this.hasPaidTiers}}
{{!--
{{#if this.hasPaidTiers}}
<div class="gh-dashboard5-paid">
<section class="gh-dashboard5-section">
<div class="gh-dashboard5-growth">
<article class="gh-dashboard5-box">
<Dashboard::V5::ChartPaidMembers @days={{this.days}}/>
</article>
<article class="gh-dashboard5-box">
<Dashboard::V5::ChartPaidMix />
</article>
</div>
</section>
</div>
{{/if}} --}}
{{/if}}
--}}
{{#if this.areNewslettersEnabled}}
<section class="gh-dashboard5-split is-third">
<section class="gh-dashboard5-section gh-dashboard5-engagement">
<Dashboard::V5::ChartEngagement />
</section>
<section class="gh-dashboard5-split">
<section class="gh-dashboard5-split">
<section class="gh-dashboard5-section gh-dashboard5-engagement">
<Dashboard::V5::ChartEngagement />
</section>
<section class="gh-dashboard5-section gh-dashboard5-email">
<article class="gh-dashboard5-box">
<section class="gh-dashboard5-section gh-dashboard5-email">
<Dashboard::V5::ChartEmail />
</article>
</section>
</section>
<section class="gh-dashboard5-section gh-dashboard5-rate">
<Dashboard::V5::ChartOpenRate />
</section>
</section>
{{else}}
@ -63,33 +65,42 @@
{{else}}
{{#if this.areNewslettersEnabled}}
<section class="gh-dashboard5-section gh-dashboard5-email">
<article class="gh-dashboard5-box">
<Dashboard::V5::ChartEmail />
</article>
</section>
<section class="gh-dashboard5-split">
<section class="gh-dashboard5-split">
<section class="gh-dashboard5-section gh-dashboard5-engagement">
<Dashboard::V5::ChartEngagement />
</section>
<section class="gh-dashboard5-section gh-dashboard5-email">
<Dashboard::V5::ChartEmail />
</section>
</section>
<section class="gh-dashboard5-section gh-dashboard5-rate">
<Dashboard::V5::ChartOpenRate />
</section>
</section>
{{/if}}
{{/if}}
<section class="gh-dashboard5-split">
<section class="gh-dashboard5-section gh-dashboard5-posts">
<article class="gh-dashboard5-box">
<Dashboard::V5::RecentPosts />
</article>
</section>
<section class="gh-dashboard5-section gh-dashboard5-activity">
<article class="gh-dashboard5-box">
<Dashboard::V5::RecentActivity />
</article>
</section>
<section class="gh-dashboard5-section gh-dashboard5-resource">
<Dashboard::V5::Resources::Help />
</section>
{{!-- <section class="gh-dashboard-section gh-dashboard5-resource">
<Dashboard::V5::ResourceGeneral />
</section> --}}
</section>
{{!-- <Dashboard::V5::Resources::WhatsNew />
{{!--
<Dashboard::V5::Resources::WhatsNew />
<Dashboard::V5::Resources::LatestNewsletters />
<Dashboard::V5::Resources::StaffPicks /> --}}
<Dashboard::V5::Resources::StaffPicks />
--}}
{{/if}}
<Dashboard::V5::PrototypeControlPanel />
</section>

View File

@ -1,5 +1,38 @@
<div class="gh-dashboard5-title">
<h4>{{this.chartTitle}}</h4>
<div class="gh-dashboard5-stats{{unless this.hasPaidTiers ' is-solo'}}" {{did-insert this.loadCharts}}>
<button class="gh-dashboard5-stats-button {{if this.chartShowingTotal 'is-selected'}}" type="button" {{on "click" (fn this.changeChartDisplay "total")}}>
<Dashboard::v5::parts::ChartMetric
@label={{gh-pluralize this.totalMembers "Total member" without-count=true}}
@value={{format-number this.totalMembers}}
@trends={{this.hasTrends}}
@percentage={{this.totalMembersTrend}}
@large={{true}} />
</button>
{{#if this.hasPaidTiers}}
<button class="gh-dashboard5-stats-button {{if this.chartShowingPaid 'is-selected'}}" type="button" {{on "click" (fn this.changeChartDisplay "paid")}}>
<Dashboard::v5::parts::ChartMetric
@label={{gh-pluralize this.paidMembers "Paid member" without-count=true}}
@value={{format-number this.paidMembers}}
@trends={{this.hasTrends}}
@percentage={{this.paidMembersTrend}}
@large={{true}} />
</button>
<button class="gh-dashboard5-stats-button {{if this.chartShowingBreakdown 'is-selected'}}" type="button" {{on "click" (fn this.changeChartDisplay "breakdown")}}>
<Dashboard::v5::parts::ChartMetric
@label="Paid breakdown"
@value={{format-number this.paidBreakdown}}
@trends={{this.hasTrends}}
@percentage={{this.paidBreakdownTrend}}
@large={{true}} />
</button>
<button class="gh-dashboard5-stats-button {{if this.chartShowingMonthly 'is-selected'}}" type="button" {{on "click" (fn this.changeChartDisplay "monthly")}}>
<Dashboard::v5::parts::ChartMetric
@label="MRR"
@value="${{gh-price-amount this.currentMRR}}"
@trends={{this.hasTrends}}
@percentage={{this.mrrTrend}}
@large={{true}} />
</button>
{{/if}}
</div>
<div class="gh-dashboard5-chart">
@ -13,48 +46,5 @@
@options={{this.chartOptions}}
@height={{this.chartHeight}} />
</div>
<div class="gh-dashboard5-chart-ticks">
<span>Mar 1</span>
<span>Mar 6</span>
<span>Mar 12</span>
<span>Mar 18</span>
<span>Mar 24</span>
<span>Mar 30</span>
</div>
{{/if}}
</div>
<div class="gh-dashboard5-stats" {{did-insert this.loadCharts}}>
<button class="gh-dashboard5-stats-button {{if this.chartShowingTotal 'is-selected'}}" type="button" {{on "click" (fn this.changeChartDisplay "total")}}>
<Dashboard::v5::parts::ChartMetric
@label={{gh-pluralize this.totalMembers "Total member" without-count=true}}
@value={{format-number this.totalMembers}}
@trends={{this.hasTrends}}
@percentage={{this.totalMembersTrend}}
@large={{true}}
@center={{true}}
@reverse={{true}} />
</button>
{{#if this.hasPaidTiers}}
<button class="gh-dashboard5-stats-button {{if this.chartShowingPaid 'is-selected'}}" type="button" {{on "click" (fn this.changeChartDisplay "paid")}}>
<Dashboard::v5::parts::ChartMetric
@label={{gh-pluralize this.paidMembers "Paid member" without-count=true}}
@value={{format-number this.paidMembers}}
@trends={{this.hasTrends}}
@percentage={{this.paidMembersTrend}}
@large={{true}}
@center={{true}}
@reverse={{true}} />
</button>
<button class="gh-dashboard5-stats-button {{if this.chartShowingMonthly 'is-selected'}}" type="button" {{on "click" (fn this.changeChartDisplay "monthly")}}>
<Dashboard::v5::parts::ChartMetric
@label="MRR"
@value="${{gh-price-amount this.currentMRR}}"
@trends={{this.hasTrends}}
@percentage={{this.mrrTrend}}
@large={{true}}
@center={{true}}
@reverse={{true}} />
</button>
{{/if}}
</div>

View File

@ -19,8 +19,7 @@ export default class ChartAnchor extends Component {
@action
changeChartDisplay(type) {
this.chartDisplay = type;
document.querySelector('#gh-dashboard5-bar').classList.remove('is-show');
document.querySelector('#gh-dashboard5-anchor-tooltip').classList.remove('is-show');
this.loadCharts();
}
get chartShowingTotal() {
@ -31,6 +30,10 @@ export default class ChartAnchor extends Component {
return (this.chartDisplay === 'paid');
}
get chartShowingBreakdown() {
return (this.chartDisplay === 'breakdown');
}
get chartShowingMonthly() {
return (this.chartDisplay === 'monthly');
}
@ -40,6 +43,8 @@ export default class ChartAnchor extends Component {
return this.dashboardStats.memberCountStats === null;
} else if (this.chartDisplay === 'paid') {
return this.dashboardStats.memberCountStats === null;
} else if (this.chartDisplay === 'breakdown') {
return this.dashboardStats.memberCountStats === null;
} else if (this.chartDisplay === 'monthly') {
return this.dashboardStats.mrrStats === null;
}
@ -54,6 +59,10 @@ export default class ChartAnchor extends Component {
return this.dashboardStats.memberCounts?.paid ?? 0;
}
get paidBreakdown() {
return this.dashboardStats.memberCounts?.breakdown ?? 0;
}
get freeMembers() {
return this.dashboardStats.memberCounts?.free ?? 0;
}
@ -74,6 +83,10 @@ export default class ChartAnchor extends Component {
return this.calculatePercentage(this.dashboardStats.memberCountsTrend.paid, this.dashboardStats.memberCounts.paid);
}
get paidBreakdownTrend() {
return '40%';
}
get freeMembersTrend() {
return this.calculatePercentage(this.dashboardStats.memberCountsTrend.free, this.dashboardStats.memberCounts.free);
}
@ -86,30 +99,45 @@ export default class ChartAnchor extends Component {
return this.dashboardStats.siteStatus?.hasPaidTiers;
}
get chartTitle() {
if (this.chartDisplay === 'total') {
return 'Total members';
} else if (this.chartDisplay === 'paid') {
return 'Paid members';
} else if (this.chartDisplay === 'monthly') {
return 'MRR';
}
}
get chartType() {
if (this.chartDisplay === 'total') {
return 'line';
} else if (this.chartDisplay === 'paid') {
if (this.chartDisplay === 'breakdown') {
return 'bar';
} else if (this.chartDisplay === 'monthly') {
return 'line';
}
return 'line';
}
get chartData() {
let stats = [];
let labels = [];
let data = [];
let newData;
let canceledData;
if (this.chartDisplay === 'breakdown') {
stats = this.dashboardStats.filledMemberCountStats;
labels = stats.map(stat => stat.date);
newData = stats.map(stat => stat.paidSubscribed);
canceledData = stats.map(stat => -stat.paidCanceled);
return {
labels: labels,
datasets: [
{
data: newData,
fill: false,
backgroundColor: '#BD96F6',
cubicInterpolationMode: 'monotone',
barThickness: 18
},{
data: canceledData,
fill: false,
backgroundColor: '#FB76B4',
cubicInterpolationMode: 'monotone',
barThickness: 18
}]
};
}
if (this.chartDisplay === 'total') {
stats = this.dashboardStats.filledMemberCountStats;
@ -152,6 +180,102 @@ export default class ChartAnchor extends Component {
}
get chartOptions() {
if (this.chartDisplay === 'breakdown') {
return {
responsive: true,
maintainAspectRatio: false,
title: {
display: false
},
legend: {
display: false
},
hover: {
onHover: function (e) {
e.target.style.cursor = 'pointer';
}
},
tooltips: {
intersect: false,
mode: 'index',
displayColors: false,
backgroundColor: '#15171A',
xPadding: 7,
yPadding: 7,
cornerRadius: 5,
caretSize: 7,
caretPadding: 5,
bodyFontSize: 12.5,
titleFontSize: 12,
titleFontStyle: 'normal',
titleFontColor: 'rgba(255, 255, 255, 0.7)',
titleMarginBottom: 3,
callbacks: {
title: (tooltipItems) => {
return moment(tooltipItems[0].xLabel).format(DATE_FORMAT);
}
}
},
scales: {
yAxes: [{
offset: true,
gridLines: {
drawTicks: false,
display: true,
drawBorder: false,
color: 'rgba(255, 255, 255, 0.1)',
lineWidth: 0,
zeroLineColor: 'rgba(200, 204, 217, 0.75)',
zeroLineWidth: 1
},
ticks: {
display: true,
maxTicksLimit: 5,
fontColor: '#7C8B9A',
padding: 8,
precision: 0
}
}],
xAxes: [{
offset: true,
stacked: true,
gridLines: {
color: 'rgba(200, 204, 217, 0.75)',
borderDash: [4,4],
display: true,
drawBorder: true,
drawTicks: false,
zeroLineWidth: 1,
zeroLineColor: 'rgba(200, 204, 217, 0.75)',
zeroLineBorderDash: [4,4]
},
ticks: {
display: true,
maxRotation: 0,
minRotation: 0,
padding: 8,
autoSkip: true,
maxTicksLimit: 7
},
type: 'time',
time: {
displayFormats: {
millisecond: 'MMM DD',
second: 'MMM DD',
minute: 'MMM DD',
hour: 'MMM DD',
day: 'MMM DD',
week: 'MMM DD',
month: 'MMM DD',
quarter: 'MMM DD',
year: 'MMM DD'
}
}
}]
}
};
}
return {
responsive: true,
maintainAspectRatio: false,
@ -209,8 +333,11 @@ export default class ChartAnchor extends Component {
yAxes: [{
gridLines: {
drawTicks: false,
display: false,
drawBorder: false
display: true,
drawBorder: false,
color: 'transparent',
zeroLineColor: 'rgba(200, 204, 217, 0.75)',
zeroLineWidth: 1
},
ticks: {
display: false,
@ -218,26 +345,31 @@ export default class ChartAnchor extends Component {
fontColor: '#7C8B9A',
padding: 8,
precision: 0,
beginAtZero: false
stepSize: 1
},
display: true
}],
xAxes: [{
gridLines: {
color: '#DDE1E5',
color: 'rgba(200, 204, 217, 0.75)',
borderDash: [4,4],
display: true,
drawBorder: true,
drawTicks: false,
zeroLineWidth: 1,
zeroLineColor: '#DDE1E5',
zeroLineColor: 'rgba(200, 204, 217, 0.75)',
zeroLineBorderDash: [4,4]
},
ticks: {
display: false,
display: true,
maxRotation: 0,
minRotation: 0,
beginAtZero: false
padding: 14,
autoSkip: true,
maxTicksLimit: 8,
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Droid Sans", "Helvetica Neue", sans-serif',
fontSize: 11,
fontColor: '#7c8b9a'
},
type: 'time',
time: {
@ -260,7 +392,7 @@ export default class ChartAnchor extends Component {
}
get chartHeight() {
return 275;
return 300;
}
calculatePercentage(from, to) {

View File

@ -1,48 +1,15 @@
<div class="gh-dashboard5-title">
<h4>Email</h4>
</div>
<div {{did-insert this.loadCharts}} class="gh-dashboard5-insert">
<div class="gh-dashboard5-insert-item">
<Dashboard::v5::parts::ChartMetric
@label="Newsletter subscribers"
@value={{format-number this.dataSubscribers.total}}
@reverse={true}
/>
</div>
<div class="gh-dashboard5-insert-item">
<Dashboard::v5::parts::ChartMetric
@label="Emails sent over last 30 days"
@value={{format-number this.dataEmailsSent}}
@reverse={true}
/>
</div>
<div class="gh-dashboard5-insert-item">
<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-ticks">
<span>100%</span>
<span>75%</span>
<span>50%</span>
<span>25%</span>
</div>
<div class="gh-dashboard5-chart-container">
<EmberChart
@type={{this.chartType}}
@data={{this.chartData}}
@options={{this.chartOptions}}
@height={{this.chartHeight}} />
</div>
{{/if}}
<article class="gh-dashboard5-box">
<div {{did-insert this.loadCharts}} class="gh-dashboard5-insert">
<div class="gh-dashboard5-insert-item">
<Dashboard::v5::parts::ChartMetric
@label="Newsletter subscribers"
@value={{format-number this.dataSubscribers.total}} />
</div>
<div class="gh-dashboard5-insert-item">
<Dashboard::v5::parts::ChartMetric
@label="Emails sent over last 30 days"
@value={{format-number this.dataEmailsSent}} />
</div>
<Dashboard::v5::parts::ChartMetric
@label="Open rate"
@value="{{this.currentOpenRate}}%"
@reverse={true}
/>
</div>
</div>
</article>

View File

@ -1,22 +1,15 @@
<article {{did-insert this.loadCharts}} class="gh-dashboard5-box">
<div class="gh-dashboard5-title">
<h4>Engagement</h4>
</div>
<div class="gh-dashboard5-insert">
<div class="gh-dashboard5-insert-item">
<Dashboard::v5::parts::ChartMetric
@label="Engaged over 30 days"
@value={{this.data30Days}}
@reverse={true}
/>
</div>
<div class="gh-dashboard5-insert-item">
<Dashboard::v5::parts::ChartMetric
@label="Engaged over 7 days"
@value={{this.data7Days}}
@reverse={true}
/>
</div>
</div>

View File

@ -0,0 +1,27 @@
<article class="gh-dashboard5-box">
<div class="gh-dashboard5-insert">
<Dashboard::v5::parts::ChartMetric
@label="Open rate"
@value="{{this.currentOpenRate}}%" />
<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-ticks">
<span>100%</span>
<span>75%</span>
<span>50%</span>
<span>25%</span>
</div>
<div class="gh-dashboard5-chart-container">
<EmberChart
@type={{this.chartType}}
@data={{this.chartData}}
@options={{this.chartOptions}}
@height={{this.chartHeight}} />
</div>
{{/if}}
</div>
</div>
</article>

View File

@ -0,0 +1,137 @@
import Component from '@glimmer/component';
import {action} from '@ember/object';
import {inject as service} from '@ember/service';
export default class ChartOpenRate extends Component {
@service dashboardStats;
/**
* Call this method when you need to fetch new data from the server.
*/
@action
loadCharts() {
// The dashboard stats service will take care or reusing and limiting API-requests between charts
this.dashboardStats.loadNewsletterSubscribers();
this.dashboardStats.loadEmailsSent();
this.dashboardStats.loadEmailOpenRateStats();
}
get dataSubscribers() {
// @todo: show paid, free, total together
return this.dashboardStats.newsletterSubscribers ?? {
total: 0,
free: 0,
paid: 0
};
}
get currentOpenRate() {
if (this.dashboardStats.emailOpenRateStats === null || this.dashboardStats.emailOpenRateStats.length === 0) {
return '-';
}
return this.dashboardStats.emailOpenRateStats[this.dashboardStats.emailOpenRateStats.length - 1].openRate;
}
get dataEmailsSent() {
return this.dashboardStats.emailsSent30d ?? 0;
}
get loading() {
return this.dashboardStats.emailOpenRateStats === null;
}
get chartType() {
return 'bar';
}
get chartData() {
const stats = this.dashboardStats.emailOpenRateStats;
const labels = stats.map(stat => stat.subject);
const data = stats.map(stat => stat.openRate);
return {
labels,
datasets: [{
data,
fill: false,
backgroundColor: '#14B8FF',
cubicInterpolationMode: 'monotone',
barThickness: 18
}]
};
}
get chartOptions() {
return {
responsive: true,
maintainAspectRatio: false,
title: {
display: false
},
legend: {
display: false
},
hover: {
onHover: function (e) {
e.target.style.cursor = 'pointer';
}
},
tooltips: {
intersect: false,
mode: 'index',
displayColors: false,
backgroundColor: '#15171A',
xPadding: 7,
yPadding: 7,
cornerRadius: 5,
caretSize: 7,
caretPadding: 5,
bodyFontSize: 12.5,
titleFontSize: 12,
titleFontStyle: 'normal',
titleFontColor: 'rgba(255, 255, 255, 0.7)',
titleMarginBottom: 3
},
scales: {
yAxes: [{
gridLines: {
drawTicks: false,
display: false,
drawBorder: false
},
ticks: {
display: false,
maxTicksLimit: 5,
fontColor: '#7C8B9A',
padding: 8,
precision: 0
}
}],
xAxes: [{
gridLines: {
color: 'rgba(200, 204, 217, 0.75)',
borderDash: [4,4],
display: true,
drawBorder: true,
drawTicks: false,
zeroLineWidth: 1,
zeroLineColor: 'rgba(200, 204, 217, 0.75)',
zeroLineBorderDash: [4,4]
},
ticks: {
display: false,
maxTicksLimit: 5,
autoSkip: true,
maxRotation: 0,
minRotation: 0
}
}]
}
};
}
get chartHeight() {
return 125;
}
}

View File

@ -1,13 +1,13 @@
<div class="gh-dashboard5-metric {{if @center "is-center"}} {{if @reverse "is-reverse"}}">
<div class="gh-dashboard5-metric {{if @center "is-center"}} {{if @reverse "is-reverse"}} {{if @large "is-large"}}">
<div class="gh-dashboard5-metric-data">
{{#if @reverse}}
{{#if @value}}
<div class="gh-dashboard5-metric-value {{if @large "is-large"}}">
<div class="gh-dashboard5-metric-value">
{{@value}}
</div>
{{!-- {{#if @trends}}
{{#if @trends}}
<Dashboard::v5::parts::ChartPercentage @percentage={{@percentage}}/>
{{/if}} --}}
{{/if}}
</div>
{{/if}}
<h5 class="gh-dashboard5-metric-label">
{{@label}}
@ -17,12 +17,12 @@
{{@label}}
</h5>
{{#if @value}}
<div class="gh-dashboard5-metric-value {{if @large "is-large"}}">
<div class="gh-dashboard5-metric-value">
{{@value}}
{{#if @trends}}
<Dashboard::v5::parts::ChartPercentage @percentage={{@percentage}}/>
{{/if}}
</div>
{{#if @trends}}
<Dashboard::v5::parts::ChartPercentage @percentage={{@percentage}}/>
{{/if}}
{{/if}}
{{/if}}
</div>

View File

@ -1,6 +1,6 @@
<div class="gh-dashboard5-list" data-test-dashboard-member-activity>
<div class="gh-dashboard5-title">
<h4>Recent activity</h4><h4>Recent posts</h4>
<div class="gh-dashboard5-list-header">
<div class="gh-dashboard5-list-title">Recent activity</div>
</div>
<div class="gh-dashboard5-list-body">
@ -23,16 +23,15 @@
{{#let (parse-member-event event) as |parsedEvent|}}
<div class="gh-dashboard5-list-item" data-test-dashboard-member-activity-item>
<LinkTo class="member-details" @route="member" @model="{{parsedEvent.memberId}}">
{{!-- {{svg-jar parsedEvent.icon}} --}}
{{!-- {{parsedEvent.subject}} --}}
John
<GhMemberAvatar @member={{parsedEvent.member}} @containerClass="w8 h8 mr3 flex-shrink-0" />
{{parsedEvent.subject}}
<span>
{{parsedEvent.action}}
{{parsedEvent.object}}
{{parsedEvent.info}}
</span>
</LinkTo>
{{!-- <span class="gh-dashboard-activity-time">{{moment-from-now parsedEvent.timestamp}}</span> --}}
<span class="gh-dashboard-activity-time">{{moment-from-now parsedEvent.timestamp}}</span>
</div>
{{/let}}
{{/each}}

View File

@ -1,6 +1,8 @@
<div class="gh-dashboard5-list" {{did-insert this.loadPosts}}>
<div class="gh-dashboard5-title">
<h4>Recent posts</h4>
<div class="gh-dashboard5-list-header">
<div class="gh-dashboard5-list-title">Recent posts</div>
<div class="gh-dashboard5-list-title">Sends</div>
<div class="gh-dashboard5-list-title">Opens</div>
</div>
<div class="gh-dashboard5-list-body">
@ -9,6 +11,8 @@
<LinkTo class="gh-dashboard5-list-post permalink" @route="editor.edit" @models={{array post.displayName post.id}}>
{{post.title}}
</LinkTo>
<span>231</span>
<span>65%</span>
</div>
{{else}}
<div class="gh-dashboard5-list-empty">

View File

@ -1098,3 +1098,9 @@ kbd {
.gh-done {
background: #15171A;
}
/* Dashboard v5 */
.gh-dashboard5-anchor .gh-dashboard5-stats-button.is-selected {
border-color: #394047;
}

View File

@ -974,10 +974,12 @@ a.gh-dashboard-container {
}
/* Temporary section for prototype convenience */
/* ---------------------------------
Dashboard v5 Prototype */
.prototype-panel {
/* Keep it out of view */
margin-top: 50vh;
margin-top: 50vh; /* Keep it out of view */
}
.prototype-states-buttons {
@ -1037,6 +1039,10 @@ a.gh-dashboard-container {
font-size: 24px;
}
/* ---------------------------------
Dashboard v5 Misc */
.gh-dashboard5-number {
display: flex;
align-items: flex-end;
@ -1129,7 +1135,6 @@ a.gh-dashboard-container {
.gh-dashboard5-overview > .gh-dashboard5-box {
padding: 0;
/* min-height: 346px; */
}
.gh-dashboard5-overview .gh-dashboard5-insert {
@ -1171,13 +1176,13 @@ a.gh-dashboard-container {
.gh-dashboard5-section .ember-power-select-selected-item {
font-size: 1.2rem;
text-transform: none;
text-transform: uppercase;
font-weight: 500;
letter-spacing: .2px;
font-size: 1.1rem;
letter-spacing: .2px;
color: var(--midgrey);
letter-spacing: .3px;
line-height: 1em;
padding: 0;
color: var(--midlightgrey);
white-space: nowrap;
}
.gh-dashboard5 .gh-list-header {
@ -1314,8 +1319,13 @@ Dashboard v5 Layout */
.gh-dashboard5-split {
display: grid;
gap: 24px;
gap: 32px;
grid-template-columns: 1fr 1fr;
position: relative;
}
.gh-dashboard5-split.is-four {
grid-template-columns: 1fr 1fr 1fr 1fr;
}
.gh-dashboard5-split.is-solo {
@ -1326,11 +1336,33 @@ Dashboard v5 Layout */
grid-template-columns: 1fr 3fr;
}
.gh-dashboard5-split.is-three {
grid-template-columns: 1fr 1fr 2fr;
}
.gh-dashboard5-split.is-fourth {
grid-template-columns: 3fr 1fr;
}
.gh-dashboard5-split.is-fifth {
grid-template-columns: 2fr 1fr;
}
.gh-dashboard5-split.is-triple {
grid-template-columns: 2fr 1fr 1fr;
}
.gh-dashboard5-split .prototype-selection {
position: absolute;
top: -20px;
right: 0;
}
.gh-dashboard5-section {
flex: 1;
display: flex;
flex-direction: column;
margin-bottom: 24px;
margin-bottom: 32px;
}
.gh-dashboard5-container {
@ -1348,8 +1380,10 @@ Dashboard v5 Layout */
.gh-dashboard5-title h4 {
margin: 0 16px 0 0;
font-weight: 700;
color: var(--darkgrey);
font-size: 1.65rem;
font-weight: 600;
line-height: 1.4em;
color: #15171a;
}
.gh-dashboard5-title h4:nth-child(2) {
@ -1370,8 +1404,6 @@ Dashboard v5 Layout */
.gh-dashboard5-area {
background: rgb(252,252,252);
background: linear-gradient(180deg, rgba(252,252,252,1) 0%, rgba(249,250,254,1) 100%);
/* background: rgb(255,249,226);
background: linear-gradient(180deg, rgba(255,249,226,1) 0%, rgba(220,242,255,1) 100%); */
background: #fafbfc;
border: 1px solid rgb(235, 238, 240);
padding: 24px;
@ -1392,6 +1424,10 @@ Dashboard v5 Layout */
border-width: 1px;
}
.gh-dashboard5-main-selection {
margin-top: -24px;
}
/* ---------------------------------
Dashboard v5 Chart */
@ -1487,15 +1523,23 @@ Dashboard v5 Metric */
align-items: center;
font-size: 1.2rem;
text-transform: uppercase;
font-weight: 500;
font-weight: 600;
letter-spacing: .3px;
line-height: 1em;
margin: 2px 0 0;
margin: 0 0 14px;
padding: 0;
color: var(--midgrey);
white-space: nowrap;
}
.gh-dashboard5-metric.is-large .gh-dashboard5-metric-label {
margin-bottom: 10px;
}
.gh-dashboard5-metric.is-reverse .gh-dashboard5-metric-label {
margin: 2px 0 0;
}
.gh-dashboard5-metric.is-center .gh-dashboard5-metric-label {
text-align: center;
margin-top: 4px;
@ -1504,10 +1548,8 @@ Dashboard v5 Metric */
.gh-dashboard5-metric-value {
display: flex;
align-items: flex-end;
font-size: 2.4rem;
line-height: 4rem;
font-weight: 700;
color: var(--black);
font-size: 2.8rem;
font-weight: 600;
letter-spacing: -.1px;
line-height: 1em;
white-space: nowrap;
@ -1515,15 +1557,20 @@ Dashboard v5 Metric */
gap: 10px;
}
.gh-dashboard5-metric-value.is-large {
font-size: 3.2rem;
margin-bottom: 6px;
.gh-dashboard5-metric.is-large .gh-dashboard5-metric-value {
font-size: 3.4rem;
font-weight: 600;
margin-bottom: 0;
}
.gh-dashboard5-metric.is-center .gh-dashboard5-metric-value {
justify-content: center;
}
.gh-dashboard5-metric.is-reverse.is-large .gh-dashboard5-metric-value {
margin-bottom: 6px;
}
.gh-dashboard5-metric-extra {
text-transform: none;
font-weight: 500;
@ -1546,19 +1593,50 @@ Dashboard v5 List */
}
.gh-dashboard5-list-header {
padding: 0 0 8px;
display: grid;
grid-template-columns: 65% 20% 15%;
padding: 0 0 20px;
border-bottom: 1px solid var(--whitegrey);
}
.gh-dashboard5-list-title {
align-items: center;
font-size: 1.2rem;
text-transform: uppercase;
font-weight: 500;
letter-spacing: .3px;
line-height: 1em;
padding: 0;
color: #7c8b9a;
white-space: nowrap;
padding: 0 24px 0 0;
}
.gh-dashboard5-list-body {
flex: 1;
display: flex;
flex-direction: column;
padding: 0 0 8px;
padding: 8px 0;
}
.gh-dashboard5-list-item {
padding: 14px 0;
border-bottom: 1px solid #efefef;
display: grid;
grid-template-columns: 65% 20% 15%;
padding: 8px 0;
border-bottom: 1px solid var(--whitegrey);
}
.gh-dashboard5-activity .gh-dashboard5-list-item {
grid-template-columns: 80% 20%;
}
.gh-dashboard5-list-item:nth-child(3) {
border-bottom: 0 none;
}
.gh-dashboard5-list-item > span {
padding: 0 24px 4px 0;
}
.gh-dashboard5-list-item:last-child {
@ -1566,13 +1644,19 @@ Dashboard v5 List */
}
.gh-dashboard5-list-item a {
font-weight: 600;
font-weight: 500;
font-size: 1.5rem;
color: var(--black);
color: var(--darkgrey);
display: inline-block;
padding: 3px 64px 0 0;
}
.gh-dashboard5-list-item > span {
font-size: 2rem;
font-weight: 600;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
align-items: center;
}
.gh-dashboard5-list-item svg {
@ -1581,9 +1665,10 @@ Dashboard v5 List */
margin: 0 0.75rem 0 0;
}
.gh-dashboard5-list-item a span {
.gh-dashboard5-list-item > a > span {
color: var(--midgrey);
padding: 0 0 0 0.5rem
padding: 0 0 0 0.5rem;
white-space: nowrap;
}
.gh-dashboard5-list-footer {
@ -1601,6 +1686,9 @@ Dashboard v5 Section Anchor */
.gh-dashboard5-anchor .gh-dashboard5-box {
align-items: stretch;
padding-top: 8px;
padding-bottom: 12px;
height: 431px;
}
.gh-dashboard5-anchor.is-top .gh-dashboard5-box {
@ -1611,12 +1699,8 @@ Dashboard v5 Section Anchor */
display: flex;
flex-direction: row;
width: calc(100% + 48px);
padding: 4px;
margin: 16px -24px -24px;
border-radius: 3px;
border: 1px solid var(--whitegrey);
border-width: 1px 0 0;
background: #fafbfc;
padding: 0 8px 8px;
margin: 0 -24px 0;
}
.gh-dashboard5-anchor .gh-dashboard5-title {
@ -1633,17 +1717,25 @@ Dashboard v5 Section Anchor */
cursor: pointer;
position: relative;
flex: 1;
padding: 16px 16px 20px;
margin: 2px;
padding: 16px 16px 20px 12px;
margin: 2px 4px 2px 2px;
text-align: left;
background: transparent;
border-radius: 2px;
border: 1px solid transparent;
border-radius: 5px;
}
.gh-dashboard5-anchor .gh-dashboard5-stats-button.is-selected {
color: #15171a;
background: #fff!important;
box-shadow: 0 2px 4px rgb(0 0 0 / 8%);
color: var(--black);
background: var(--white) !important;
box-shadow: 0 0 12px rgb(0 0 0 / 3%);
border: 1px solid var(--whitegrey);
}
.gh-dashboard5-anchor .gh-dashboard5-stats.is-solo .gh-dashboard5-stats-button.is-selected {
background: transparent;
box-shadow: 0 none;
border: 0 none;
}
.gh-dashboard5-anchor .gh-dashboard5-stats-highlight {
@ -1664,6 +1756,8 @@ Dashboard v5 Section Anchor */
.gh-dashboard5-anchor .gh-dashboard5-chart {
flex-direction: column;
margin-left: -16px;
margin-right: -16px;
}
.gh-dashboard5-anchor .gh-dashboard5-chart-ticks {
@ -1682,8 +1776,8 @@ Dashboard v5 Section Anchor */
}
.gh-dashboard5-anchor .prototype-selection {
top: 18px;
right: 6px;
top: 16px;
right: 8px;
}
@ -1748,50 +1842,51 @@ Dashboard v5 Section Email */
}
.gh-dashboard5-email .gh-dashboard5-insert {
display: grid;
grid-template-columns: 1fr 2fr;
grid-template-rows: 1fr 1fr;
gap: 0;
display: flex;
flex-direction: row;
flex: 1;
}
.gh-dashboard5-email .gh-dashboard5-insert-item {
flex: 1;
display: flex;
flex-direction: column;
justify-content: flex-end;
flex-direction: row;
justify-content: flex-start;
min-height: 80px;
}
.gh-dashboard5-email .gh-dashboard5-insert-item:nth-child(1) {
/* --- Newsletter Subscribers */
grid-column: 1;
grid-row: 1;
padding: 4px 16px 16px 0;
border: 1px solid var(--whitegrey);
border-width: 0 1px 1px 0;
/* --- Engaged Over 30 Days */
padding: 4px 16px 0 0;
}
.gh-dashboard5-email .gh-dashboard5-insert-item:nth-child(2) {
/* --- Emails Sent */
grid-column: 1;
grid-row: 2;
/* --- Engaged Over 7 Days */
padding: 4px 16px 0 16px;
}
.gh-dashboard5-split .gh-dashboard5-email .gh-dashboard5-insert {
flex-direction: column;
}
.gh-dashboard5-split .gh-dashboard5-email .gh-dashboard5-insert-item {
border-radius: 0;
border-width: 0 0 1px;
padding: 8px 16px 16px 0;
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.gh-dashboard5-split .gh-dashboard5-email .gh-dashboard5-insert-item:nth-child(1) {
/* --- Engaged Over 30 Days */
padding: 4px 16px 16px 0;
}
.gh-dashboard5-split .gh-dashboard5-email .gh-dashboard5-insert-item:nth-child(2) {
/* --- Engaged Over 7 Days */
flex: 1;
padding: 16px 16px 0 0;
border-right: 1px solid var(--whitegrey);
}
.gh-dashboard5-email .gh-dashboard5-insert-item:nth-child(3) {
/* --- Open Rate */
grid-column: 2;
grid-row: 1 / span 2;
justify-content: space-between;
align-items: stretch;
padding: 4px 0 0 24px;
}
.gh-dashboard5-email .gh-dashboard5-chart {
margin: 0 0 24px;
}
.gh-dashboard5-email .gh-dashboard5-chart-ticks {
padding: 0 16px 0 0;
}
@ -1803,7 +1898,7 @@ Dashboard v5 Section Engagement */
}
.gh-dashboard5-engagement .prototype-selection {
top: 18px;
top: 16px;
}
.gh-dashboard5-engagement .gh-dashboard5-insert {
@ -1823,7 +1918,6 @@ Dashboard v5 Section Engagement */
.gh-dashboard5-engagement .gh-dashboard5-insert-item:nth-child(1) {
/* --- Engaged Over 30 Days */
padding: 4px 16px 0 0;
border-right: 1px solid var(--whitegrey);
}
.gh-dashboard5-engagement .gh-dashboard5-insert-item:nth-child(2) {
@ -1841,13 +1935,12 @@ Dashboard v5 Section Engagement */
padding: 8px 16px 16px 0;
display: flex;
flex-direction: column;
justify-content: flex-end;
justify-content: flex-start;
}
.gh-dashboard5-split .gh-dashboard5-engagement .gh-dashboard5-insert-item:nth-child(1) {
/* --- Engaged Over 30 Days */
padding: 4px 16px 16px 0;
border-bottom: 1px solid var(--whitegrey);
}
.gh-dashboard5-split .gh-dashboard5-engagement .gh-dashboard5-insert-item:nth-child(2) {
@ -1861,25 +1954,102 @@ Dashboard v5 Section Engagement */
Dashboard v5 Section Posts */
.gh-dashboard5-posts .gh-dashboard5-box {
padding: 24px;
padding: 28px 24px 24px;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: stretch;
}
.gh-dashboard5-posts .gh-dashboard5-title {
margin-bottom: 24px;
}
.gh-dashboard5-posts .gh-dashboard5-list-item {
padding-top: 16px;
padding-bottom: 16px;
}
.gh-dashboard5-posts .gh-dashboard5-list-item:nth-child(1) {
padding-top: 8px;
}
.gh-dashboard5-posts .gh-dashboard5-list-item:nth-child(4),
.gh-dashboard5-posts .gh-dashboard5-list-item:nth-child(5) {
display: none;
}
.gh-dashboard5-posts .gh-dashboard5-list-item a {
width: 80%;
height: 57px;
overflow: hidden;
color: var(--darkgrey);
}
/* ---------------------------------
Dashboard v5 Section Activity */
.gh-dashboard5-activity .gh-dashboard5-box {
padding: 24px;
padding: 28px 24px 24px;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: stretch;
}
.gh-dashboard5-activity .gh-dashboard5-title {
margin-bottom: 20px;
}
.gh-dashboard5-activity .gh-dashboard5-list-item {
display: flex;
flex-direction: row;
padding: 10px 0;
border-bottom: 0 none;
}
.gh-dashboard5-activity .gh-dashboard5-list-item .member-details {
flex: 1;
display: flex;
justify-content: flex-start;
align-items: center;
padding: 0;
}
.gh-dashboard5-activity .gh-dashboard5-list-item .member-avatar {
width: 28px;
height: 28px;
background: #70DEB1;
border-radius: 24px;
margin: 0 12px 0 0;
}
.gh-dashboard5-activity .gh-dashboard5-list-item > span.gh-dashboard-activity-time {
font-size: 1.2rem;
color: var(--midlightgrey);
text-align: right;
padding-right: 0;
padding-top: 6px;
}
/* ---------------------------------
Dashboard v5 Section Email Open Rate */
.gh-dashboard5-rate .gh-dashboard5-chart {
margin: 24px 0 0;
}
.gh-dashboard5-rate .gh-dashboard5-chart-ticks {
padding: 0 16px 0 0;
}
.gh-dashboard5-rate .gh-dashboard5-metric-label {
padding-top: 4px;
}
/* ---------------------------------
Dashboard v5 Section Resource */
@ -1946,4 +2116,4 @@ Dashboard v5 Section Resource */
.gh-dashboard5-area-dot.is-selected {
background: var(--midgrey);
}
}