mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-25 09:03:12 +03:00
Added static result table for members filtering
- Added horizontal scrolling, fullscreen table component. - Mocked multiple columns in the members result list. Alpha feature.
This commit is contained in:
parent
3e82a19791
commit
d356f5451a
@ -1,61 +1,188 @@
|
||||
<li class="gh-list-row gh-members-list-item {{if @member.is_loading "loading"}}" data-test-member={{@member.id}} ...attributes>
|
||||
{{#if @member.is_loading}}
|
||||
<div class="gh-list-data gh-members-list-basic gh-list-loadingcell">
|
||||
<div class="gh-list-loading-title"></div>
|
||||
<div class="gh-list-loading-detail"></div>
|
||||
</div>
|
||||
<div class="gh-list-data gh-members-list-open-rate gh-list-cellwidth-10"></div>
|
||||
<div class="gh-list-data gh-members-list-geolocation gh-list-cellwidth-10"></div>
|
||||
<div class="gh-list-data gh-members-list-subscribed-at gh-list-cellwidth-10"></div>
|
||||
<div class="gh-list-data gh-members-list-chevron gh-list-cellwidth-chevron"></div>
|
||||
{{else}}
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data gh-members-list-basic">
|
||||
<div class="flex items-center">
|
||||
<GhMemberAvatar @member={{@member}} @containerClass="w9 h9 mr3 flex-shrink-0" />
|
||||
<div class="w-80">
|
||||
<h3 class="ma0 pa0 gh-members-list-name {{if (not @member.name) "gh-members-name-noname"}}">{{or @member.name @member.email}}</h3>
|
||||
{{#if @member.name}}
|
||||
<p class="ma0 pa0 middarkgrey f8 gh-members-list-email">{{@member.email}}</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if (feature "membersFiltering")}}
|
||||
<tr>
|
||||
{{#if @member.is_loading}}
|
||||
<div class="gh-list-data gh-members-list-basic gh-list-loadingcell">
|
||||
<div class="gh-list-loading-title"></div>
|
||||
<div class="gh-list-loading-detail"></div>
|
||||
</div>
|
||||
</LinkTo>
|
||||
<div class="gh-list-data"></div>
|
||||
<div class="gh-list-data"></div>
|
||||
<div class="gh-list-data"></div>
|
||||
<div class="gh-list-data"></div>
|
||||
<div class="gh-list-data"></div>
|
||||
<div class="gh-list-data"></div>
|
||||
<div class="gh-list-data"></div>
|
||||
<div class="gh-list-data"></div>
|
||||
<div class="gh-list-data"></div>
|
||||
{{else}}
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data">
|
||||
<div class="flex items-center">
|
||||
<GhMemberAvatar @member={{@member}} @containerClass="w9 h9 mr3 flex-shrink-0" />
|
||||
<div class="w-80">
|
||||
<h3 class="ma0 pa0 gh-members-list-name {{if (not @member.name) "gh-members-name-noname"}}">{{or @member.name @member.email}}</h3>
|
||||
{{#if @member.name}}
|
||||
<p class="ma0 pa0 middarkgrey f8 gh-members-list-email">{{@member.email}}</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</LinkTo>
|
||||
|
||||
{{#if (feature "emailAnalytics")}}
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data gh-members-list-open-rate middarkgrey f8 {{if (not @member.name) "gh-members-list-open-rate-noname"}}">
|
||||
{{#if (not (is-empty @member.emailOpenRate))}}
|
||||
<span class="gh-members-list-open-rate-mobile">{{@member.emailOpenRate}}%</span>
|
||||
{{#if (feature "emailAnalytics")}}
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data middarkgrey f8 {{if (not @member.name) "gh-members-list-open-rate-noname"}}">
|
||||
{{#if (not (is-empty @member.emailOpenRate))}}
|
||||
<span class="gh-members-list-open-rate-mobile">{{@member.emailOpenRate}}%</span>
|
||||
{{else}}
|
||||
<span class="midlightgrey">N/A</span>
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data middarkgrey f8 {{if (not @member.name) "gh-members-geolocation-noname"}}">
|
||||
{{#if (and @member.geolocation @member.geolocation.country)}}
|
||||
{{#if (and (eq @member.geolocation.country_code "US") @member.geolocation.region)}}
|
||||
{{@member.geolocation.region}}, US
|
||||
{{else}}
|
||||
{{#if @member.geolocation.country}}
|
||||
{{@member.geolocation.country}}
|
||||
{{else}}
|
||||
<span class="midlightgrey">Unknown</span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<span class="midlightgrey">Unknown</span>
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data middarkgrey f8">
|
||||
{{#if @member.createdAtUTC}}
|
||||
<div>{{moment-format @member.createdAtUTC "D MMM YYYY"}}</div>
|
||||
<div class="midlightgrey gh-members-list-subscribed-moment">{{moment-from-now @member.createdAtUTC}}</div>
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
|
||||
{{#if (feature "emailAnalytics")}}
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data middarkgrey f8">
|
||||
{{#if (not (is-empty @member.emailOpenRate))}}
|
||||
<span class="gh-members-list-open-rate-mobile">{{@member.emailOpenRate}}%</span>
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data middarkgrey f8">
|
||||
{{#if (and @member.geolocation @member.geolocation.country)}}
|
||||
{{#if (and (eq @member.geolocation.country_code "US") @member.geolocation.region)}}
|
||||
{{@member.geolocation.region}}, US
|
||||
{{else}}
|
||||
{{#if @member.geolocation.country}}
|
||||
{{@member.geolocation.country}}
|
||||
{{else}}
|
||||
<span class="midlightgrey">Unknown</span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<span class="midlightgrey">Unknown</span>
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data middarkgrey f8">
|
||||
{{#if @member.createdAtUTC}}
|
||||
<div>{{moment-format @member.createdAtUTC "D MMM YYYY"}}</div>
|
||||
<div class="midlightgrey gh-members-list-subscribed-moment">{{moment-from-now @member.createdAtUTC}}</div>
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
|
||||
{{#if (feature "emailAnalytics")}}
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data middarkgrey f8">
|
||||
{{#if (not (is-empty @member.emailOpenRate))}}
|
||||
<span class="gh-members-list-open-rate-mobile">{{@member.emailOpenRate}}%</span>
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data middarkgrey f8">
|
||||
{{#if (and @member.geolocation @member.geolocation.country)}}
|
||||
{{#if (and (eq @member.geolocation.country_code "US") @member.geolocation.region)}}
|
||||
{{@member.geolocation.region}}, US
|
||||
{{else}}
|
||||
{{#if @member.geolocation.country}}
|
||||
{{@member.geolocation.country}}
|
||||
{{else}}
|
||||
<span class="midlightgrey">Unknown</span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<span class="midlightgrey">Unknown</span>
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data middarkgrey f8">
|
||||
{{#if @member.createdAtUTC}}
|
||||
<div>{{moment-format @member.createdAtUTC "D MMM YYYY"}}</div>
|
||||
<div class="midlightgrey gh-members-list-subscribed-moment">{{moment-from-now @member.createdAtUTC}}</div>
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data gh-members-list-geolocation middarkgrey f8 {{if (not @member.name) "gh-members-geolocation-noname"}}">
|
||||
{{#if (and @member.geolocation @member.geolocation.country)}}
|
||||
{{#if (and (eq @member.geolocation.country_code "US") @member.geolocation.region)}}
|
||||
{{@member.geolocation.region}}, US
|
||||
{{else}}
|
||||
{{#if @member.geolocation.country}}
|
||||
{{@member.geolocation.country}}
|
||||
{{else}}
|
||||
<span class="midlightgrey">Unknown</span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<span class="midlightgrey">Unknown</span>
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data gh-members-list-subscribed-at middarkgrey f8 {{if (not @member.name) "gh-members-subscribed-noname"}}">
|
||||
{{#if @member.createdAtUTC}}
|
||||
<div>{{moment-format @member.createdAtUTC "D MMM YYYY"}}</div>
|
||||
<div class="midlightgrey gh-members-list-subscribed-moment">{{moment-from-now @member.createdAtUTC}}</div>
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data gh-list-cellwidth-chevron gh-members-list-chevron">
|
||||
<div class="flex items-center justify-end w-100 h-100">
|
||||
<span class="nr2">{{svg-jar "arrow-right" class="w6 h6 fill-midgrey pa1"}}</span>
|
||||
</tr>
|
||||
{{else}}
|
||||
<li class="gh-list-row gh-members-list-item {{if @member.is_loading "loading"}}" data-test-member={{@member.id}} ...attributes>
|
||||
{{#if @member.is_loading}}
|
||||
<div class="gh-list-data gh-members-list-basic gh-list-loadingcell">
|
||||
<div class="gh-list-loading-title"></div>
|
||||
<div class="gh-list-loading-detail"></div>
|
||||
</div>
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
</li>
|
||||
<div class="gh-list-data gh-members-list-open-rate gh-list-cellwidth-10"></div>
|
||||
<div class="gh-list-data gh-members-list-geolocation gh-list-cellwidth-10"></div>
|
||||
<div class="gh-list-data gh-members-list-subscribed-at gh-list-cellwidth-10"></div>
|
||||
<div class="gh-list-data gh-members-list-chevron gh-list-cellwidth-chevron"></div>
|
||||
{{else}}
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data gh-members-list-basic">
|
||||
<div class="flex items-center">
|
||||
<GhMemberAvatar @member={{@member}} @containerClass="w9 h9 mr3 flex-shrink-0" />
|
||||
<div class="w-80">
|
||||
<h3 class="ma0 pa0 gh-members-list-name {{if (not @member.name) "gh-members-name-noname"}}">{{or @member.name @member.email}}</h3>
|
||||
{{#if @member.name}}
|
||||
<p class="ma0 pa0 middarkgrey f8 gh-members-list-email">{{@member.email}}</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</LinkTo>
|
||||
|
||||
{{#if (feature "emailAnalytics")}}
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data gh-members-list-open-rate middarkgrey f8 {{if (not @member.name) "gh-members-list-open-rate-noname"}}">
|
||||
{{#if (not (is-empty @member.emailOpenRate))}}
|
||||
<span class="gh-members-list-open-rate-mobile">{{@member.emailOpenRate}}%</span>
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data gh-members-list-geolocation middarkgrey f8 {{if (not @member.name) "gh-members-geolocation-noname"}}">
|
||||
{{#if (and @member.geolocation @member.geolocation.country)}}
|
||||
{{#if (and (eq @member.geolocation.country_code "US") @member.geolocation.region)}}
|
||||
{{@member.geolocation.region}}, US
|
||||
{{else}}
|
||||
{{#if @member.geolocation.country}}
|
||||
{{@member.geolocation.country}}
|
||||
{{else}}
|
||||
<span class="midlightgrey">Unknown</span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<span class="midlightgrey">Unknown</span>
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data gh-members-list-subscribed-at middarkgrey f8 {{if (not @member.name) "gh-members-subscribed-noname"}}">
|
||||
{{#if @member.createdAtUTC}}
|
||||
<div>{{moment-format @member.createdAtUTC "D MMM YYYY"}}</div>
|
||||
<div class="midlightgrey gh-members-list-subscribed-moment">{{moment-from-now @member.createdAtUTC}}</div>
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
|
||||
<LinkTo @route="member" @model={{@member}} title="Member details" class="gh-list-data gh-list-cellwidth-chevron gh-members-list-chevron">
|
||||
<div class="flex items-center justify-end w-100 h-100">
|
||||
<span class="nr2">{{svg-jar "arrow-right" class="w6 h6 fill-midgrey pa1"}}</span>
|
||||
</div>
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/if}}
|
@ -295,4 +295,79 @@ ul.nostyle li {
|
||||
max-width: 320px;
|
||||
height: 9px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/* Horizontally scrolling list */
|
||||
.gh-list-scrolling {
|
||||
position: relative;
|
||||
overflow: scroll;
|
||||
max-width: calc(100% + 96px);
|
||||
height: calc(100vh - 96px);
|
||||
margin: 0 -48px -81px;
|
||||
padding: 0 48px 0 0;
|
||||
}
|
||||
|
||||
.gh-list-scrolling table {
|
||||
position: relative;
|
||||
border-collapse: inherit;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.gh-list-scrolling thead th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
vertical-align: middle;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.1px;
|
||||
color: var(--black);
|
||||
background: var(--main-bg-color);
|
||||
background: linear-gradient(90deg, rgba(255,255,255,1) 90%, rgba(255,255,255,0) 100%);
|
||||
border-bottom: var(--whitegrey) 1px solid;
|
||||
padding: 10px 20px;
|
||||
text-transform: uppercase;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.gh-list-scrolling thead th:first-child {
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
border-bottom: none;
|
||||
padding: 0 60px 0 48px;
|
||||
}
|
||||
|
||||
.gh-list-scrolling tbody .gh-list-data:first-child {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
border-bottom: none;
|
||||
background: var(--main-bg-color);
|
||||
background: linear-gradient(90deg, rgba(255,255,255,1) 90%, rgba(255,255,255,0) 100%);
|
||||
padding: 0 60px 0 48px;
|
||||
}
|
||||
|
||||
.gh-list-scrolling thead th:first-child::before,
|
||||
.gh-list-scrolling tbody .gh-list-data:first-child::before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 48px;
|
||||
height: 1px;
|
||||
background: var(--whitegrey);
|
||||
}
|
||||
|
||||
.gh-list-scrolling td,
|
||||
.gh-list-scrolling th,
|
||||
.gh-list-scrolling a {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.gh-list-scrolling tbody th{
|
||||
position: sticky;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.gh-list-scrolling tbody .gh-list-data {
|
||||
border-top: none;
|
||||
border-bottom: var(--whitegrey) 1px solid;
|
||||
}
|
@ -66,6 +66,10 @@
|
||||
max-width: 1600px;
|
||||
}
|
||||
|
||||
.gh-main-fullwidth .gh-canvas {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* Flexbox fix. https://github.com/TryGhost/Ghost/issues/5804#issuecomment-141416812 */
|
||||
.gh-main > section {
|
||||
width: 100%;
|
||||
|
@ -68,35 +68,13 @@
|
||||
|
||||
.members-list .gh-list-header {
|
||||
position: sticky;
|
||||
top: 84px;
|
||||
top: 96px;
|
||||
z-index: 1;
|
||||
background: var(--white);
|
||||
}
|
||||
|
||||
.members-list-header-overlay {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
position: sticky;
|
||||
height: 40px;
|
||||
top: calc(84px - 40px); /* match gh-list-header sticky top */
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-top: -40px;
|
||||
transform: translateY(40px);
|
||||
z-index: 2;
|
||||
|
||||
border-radius: 5px 5px 0 0;
|
||||
|
||||
border-bottom: 1px solid #e5eff5;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 500;
|
||||
letter-spacing: .1px;
|
||||
color: #738a94;
|
||||
text-transform: uppercase;
|
||||
padding: 10px 16px;
|
||||
white-space: nowrap;
|
||||
background: #f8fafc;
|
||||
.gh-list-scrolling-h .members-list .gh-list-header {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.members-header .view-actions input.gh-members-list-searchfield {
|
||||
|
@ -8,7 +8,7 @@
|
||||
<GhNavMenu />
|
||||
{{/if}}
|
||||
|
||||
<main class="gh-main {{this.ui.mainClass}}" role="main">
|
||||
<main class="gh-main {{this.ui.mainClass}} {{if (and (feature "membersFiltering") (or (eq this.router.currentURL "/members") (eq this.router.currentURL "/members/import"))) "gh-main-fullwidth"}}" role="main">
|
||||
{{outlet}}
|
||||
|
||||
{{#if this.showBilling}}
|
||||
|
@ -80,6 +80,32 @@
|
||||
|
||||
{{#unless this.members.loading}}
|
||||
<section class="view-container">
|
||||
{{#if (feature "membersFiltering")}}
|
||||
<div class="gh-list-scrolling">
|
||||
<table class="gh-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{this.listHeader}}</th>
|
||||
<th>Open rate</th>
|
||||
<th>Location</th>
|
||||
<th>Created</th>
|
||||
<th>Open rate</th>
|
||||
<th>Location</th>
|
||||
<th>Created</th>
|
||||
<th>Open rate</th>
|
||||
<th>Location</th>
|
||||
<th>Created</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<VerticalCollection @tagName="tbody" @items={{this.members}} @key="id" @containerSelector=".gh-main" @estimateHeight={{69}} @staticHeight={{true}} @bufferSize={{20}} as |member|>
|
||||
<GhMembersListItem
|
||||
@member={{member}}
|
||||
data-test-member={{member.id}}
|
||||
/>
|
||||
</VerticalCollection>
|
||||
</table>
|
||||
</div>
|
||||
{{else}}
|
||||
<section class="content-list">
|
||||
<ol class="members-list gh-list {{unless this.members "no-posts"}}">
|
||||
{{#if this.members}}
|
||||
@ -113,6 +139,7 @@
|
||||
{{/if}}
|
||||
</ol>
|
||||
</section>
|
||||
{{/if}}
|
||||
</section>
|
||||
{{else}}
|
||||
<div class="gh-content">
|
||||
|
Loading…
Reference in New Issue
Block a user