mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
Contributors updates (#2235)
Updates Admin UX for Contributors When logged in as a Contributor: - removes sidebar, added floating account menu and dark-mode switch to right side. Updated mobile menu accordingly - all post by the given user is listed in the Post list - changed post filtering - hides email columns in post list - removes publishmenu for Contributors in Post preview modal - visual tweaks
This commit is contained in:
parent
9760e67b3d
commit
6fa8dafa79
20 changed files with 385 additions and 278 deletions
|
@ -1,38 +1,39 @@
|
|||
<div class="gh-contentfilter view-actions-bottom-row" ...attributes>
|
||||
{{#unless @currentUser.isContributor}}
|
||||
<div class="gh-contentfilter-menu gh-contentfilter-type {{if @selectedType.value "gh-contentfilter-selected"}}" data-test-type-select="true">
|
||||
<PowerSelect
|
||||
@selected={{@selectedType}}
|
||||
@options={{@availableTypes}}
|
||||
@searchEnabled={{false}}
|
||||
@onChange={{@onTypeChange}}
|
||||
@triggerComponent="gh-power-select/trigger"
|
||||
@triggerClass="gh-contentfilter-menu-trigger"
|
||||
@dropdownClass="gh-contentfilter-menu-dropdown"
|
||||
@matchTriggerWidth={{false}}
|
||||
as |type|
|
||||
>
|
||||
{{#if type.name}}{{type.name}}{{else}}<span class="red">Unknown type</span>{{/if}}
|
||||
</PowerSelect>
|
||||
</div>
|
||||
{{/unless}}
|
||||
|
||||
<div class="gh-contentfilter-menu gh-contentfilter-visibility {{if @selectedVisibility.value "gh-contentfilter-selected"}}" data-test-visibility-select="true">
|
||||
<div class="gh-contentfilter-menu gh-contentfilter-type {{if @selectedType.value "gh-contentfilter-selected"}}" data-test-type-select="true">
|
||||
<PowerSelect
|
||||
@selected={{@selectedVisibility}}
|
||||
@options={{@availableVisibilities}}
|
||||
@selected={{@selectedType}}
|
||||
@options={{@availableTypes}}
|
||||
@searchEnabled={{false}}
|
||||
@onChange={{@onVisibilityChange}}
|
||||
@onChange={{@onTypeChange}}
|
||||
@triggerComponent="gh-power-select/trigger"
|
||||
@triggerClass="gh-contentfilter-menu-trigger"
|
||||
@dropdownClass="gh-contentfilter-menu-dropdown"
|
||||
@matchTriggerWidth={{false}}
|
||||
as |visibility|
|
||||
as |type|
|
||||
>
|
||||
{{#if visibility.name}}{{visibility.name}}{{else}}<span class="red">Unknown visibility</span>{{/if}}
|
||||
{{#if type.name}}{{type.name}}{{else}}<span class="red">Unknown type</span>{{/if}}
|
||||
</PowerSelect>
|
||||
</div>
|
||||
|
||||
{{#unless @currentUser.isContributor}}
|
||||
<div class="gh-contentfilter-menu gh-contentfilter-visibility {{if @selectedVisibility.value "gh-contentfilter-selected"}}" data-test-visibility-select="true">
|
||||
<PowerSelect
|
||||
@selected={{@selectedVisibility}}
|
||||
@options={{@availableVisibilities}}
|
||||
@searchEnabled={{false}}
|
||||
@onChange={{@onVisibilityChange}}
|
||||
@triggerComponent="gh-power-select/trigger"
|
||||
@triggerClass="gh-contentfilter-menu-trigger"
|
||||
@dropdownClass="gh-contentfilter-menu-dropdown"
|
||||
@matchTriggerWidth={{false}}
|
||||
as |visibility|
|
||||
>
|
||||
{{#if visibility.name}}{{visibility.name}}{{else}}<span class="red">Unknown visibility</span>{{/if}}
|
||||
</PowerSelect>
|
||||
</div>
|
||||
{{/unless}}
|
||||
|
||||
{{#unless @currentUser.isAuthorOrContributor}}
|
||||
<div class="gh-contentfilter-menu gh-contentfilter-author {{if @selectedAuthor.slug "gh-contentfilter-selected"}}" data-test-author-select="true">
|
||||
<PowerSelect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<nav class="gh-nav {{if this.ui.contextualNavMenu "gh-nav-contextual"}}" {{did-insert this.updateFirstRender}} ...attributes>
|
||||
<nav class="gh-nav {{if this.ui.contextualNavMenu "gh-nav-contextual"}} {{if this.session.user.isContributor "gh-nav-contributor"}}" {{did-insert this.updateFirstRender}} ...attributes>
|
||||
{{#if this.ui.contextualNavMenu}}
|
||||
{{component (concat "gh-nav-menu/" ui.contextualNavMenu)}}
|
||||
{{else}}
|
||||
|
|
|
@ -7,6 +7,7 @@ import {tracked} from '@glimmer/tracking';
|
|||
export default class GhNavMenuComponent extends Component {
|
||||
@service settings;
|
||||
@service ui;
|
||||
@service session;
|
||||
|
||||
@tracked firstRender = true;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div class="gh-nav-bottom">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<div class="pe-all">
|
||||
<GhBasicDropdown @horizontalPosition="left" @verticalPosition="above" @calculatePosition={{this.userDropdownPosition}} as |dropdown|>
|
||||
<dropdown.Trigger class="outline-0 pointer">
|
||||
<div class="flex-auto flex items-center">
|
||||
|
@ -11,7 +11,7 @@
|
|||
</div>
|
||||
</dropdown.Trigger>
|
||||
|
||||
<dropdown.Content class="gh-nav-menu-dropdown">
|
||||
<dropdown.Content class="gh-nav-menu-dropdown {{if this.session.user.isContributor "gh-nav-menu-dropdown-contributor"}}">
|
||||
<ul class="dropdown-menu dropdown-triangle-top" role="menu">
|
||||
<li role="presentation">
|
||||
<div class="gh-account-menu-header">
|
||||
|
@ -23,54 +23,63 @@
|
|||
</div>
|
||||
</li>
|
||||
<li class="divider" role="separator"></li>
|
||||
<li role="presentation">
|
||||
<LinkTo @route="whatsnew" @query={{hash entry=null}} @classNames="dropdown-item" @role="menuitem" @tabindex="-1" data-test-nav="whatsnew">
|
||||
What's new?
|
||||
{{#if this.whatsNew.hasNew}}
|
||||
<div class="flex-grow-1 flex justify-end"><span class="dib w2 h2 top-0 right-0 bg-green br-100"></span></div>
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
</li>
|
||||
|
||||
{{#if this.session.user.isContributor}}
|
||||
<li role="presentation">
|
||||
<LinkTo @route="posts" @query={{hash entry=null}} @classNames="dropdown-item" @role="menuitem" @tabindex="-1" data-test-nav="posts">
|
||||
Posts
|
||||
</LinkTo>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<a href="{{this.config.blogUrl}}/" class="dropdown-item" role="menuitem" tabindex="-1" title="Open site in new tab" target="_blank">View site</a>
|
||||
</li>
|
||||
<li class="divider" role="separator"></li>
|
||||
{{else}}
|
||||
<li role="presentation">
|
||||
<LinkTo @route="whatsnew" @query={{hash entry=null}} @classNames="dropdown-item" @role="menuitem" @tabindex="-1" data-test-nav="whatsnew">
|
||||
What's new?
|
||||
{{#if this.whatsNew.hasNew}}
|
||||
<div class="flex-grow-1 flex justify-end"><span class="dib w2 h2 top-0 right-0 bg-green br-100"></span></div>
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
<li role="presentation">
|
||||
<LinkTo @route="settings.staff.user" @model={{this.session.user.slug}} @classNames="dropdown-item" @role="menuitem" @tabindex="-1" data-test-nav="user-profile">
|
||||
Your profile
|
||||
</LinkTo>
|
||||
</li>
|
||||
<li class="divider" role="separator"></li>
|
||||
<li role="presentation">
|
||||
<a class="dropdown-item" role="menuitem" tabindex="-1" href="https://ghost.org/docs/" target="_blank">
|
||||
Support center
|
||||
</a>
|
||||
</li>
|
||||
{{!-- <li role="presentation">
|
||||
<a class="dropdown-item" role="menuitem" tabindex="-1" target="_blank"
|
||||
href="https://twitter.com/intent/tweet?text=%40Ghost+Hi%21+Can+you+help+me+with+&related=Ghost"
|
||||
onclick="window.open(this.href, 'twitter-share', 'width=550,height=235');return false;"
|
||||
>
|
||||
Tweet @Ghost!
|
||||
</a>
|
||||
</li> --}}
|
||||
<li role="presentation">
|
||||
<a class="dropdown-item" role="menuitem" tabindex="-1" href="https://ghost.org/help/topic/setting-up/" target="_blank">
|
||||
How to use Ghost
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{{#if this.showDropdownExtension}}
|
||||
{{#each this.config.clientExtensions.dropdown.items as |menuItem| }}
|
||||
{{#if menuItem.divider}}
|
||||
<li class="divider" role="separator"></li>
|
||||
{{else}}
|
||||
<li role="presentation">
|
||||
<a href="{{menuItem.href}}" target="_blank" class="dropdown-item {{menuItem.classes}}" role="menuitem" tabindex="-1">
|
||||
{{menuItem.text}}
|
||||
</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#unless this.session.user.isContributor}}
|
||||
<li class="divider" role="separator"></li>
|
||||
<li role="presentation">
|
||||
<a class="dropdown-item" role="menuitem" tabindex="-1" href="https://ghost.org/docs/" target="_blank">
|
||||
Support center
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<a class="dropdown-item" role="menuitem" tabindex="-1" href="https://ghost.org/help/topic/setting-up/" target="_blank">
|
||||
How to use Ghost
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{{#if this.showDropdownExtension}}
|
||||
{{#each this.config.clientExtensions.dropdown.items as |menuItem| }}
|
||||
{{#if menuItem.divider}}
|
||||
<li class="divider" role="separator"></li>
|
||||
{{else}}
|
||||
<li role="presentation">
|
||||
<a href="{{menuItem.href}}" target="_blank" class="dropdown-item {{menuItem.classes}}" role="menuitem" tabindex="-1">
|
||||
{{menuItem.text}}
|
||||
</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
<li class="divider" role="separator"></li>
|
||||
{{/unless}}
|
||||
|
||||
<li role="presentation">
|
||||
<LinkTo @route="signout" @classNames="dropdown-item user-menu-signout" @role="menuitem" @tabindex="-1">
|
||||
Sign out
|
||||
|
@ -80,7 +89,7 @@
|
|||
</dropdown.Content>
|
||||
</GhBasicDropdown>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<div class="flex items-center pe-all">
|
||||
{{#if (gh-user-can-admin this.session.user)}}
|
||||
<LinkTo class="gh-nav-bottom-tabicon" @route="settings" @current-when={{this.isSettingsRoute}} data-test-nav="settings">{{svg-jar "settings"}}</LinkTo>
|
||||
{{/if}}
|
||||
|
|
|
@ -1,60 +1,44 @@
|
|||
<div class="flex flex-column h-100" {{css-transition (unless @firstRender "gh-nav-main")}} data-test-nav-menu="main" ...attributes>
|
||||
<header class="gh-nav-menu">
|
||||
<div class="gh-nav-menu-details">
|
||||
<div class="gh-nav-menu-icon {{this.iconClass}}" style={{this.iconStyle}}></div>
|
||||
<div class="gh-nav-menu-details-sitetitle">{{this.config.blogTitle}}</div>
|
||||
</div>
|
||||
<div class="gh-nav-menu-search">
|
||||
<button class="gh-nav-btn-search" {{on "click" (action "openSearchModal")}} title="Search site (Ctrl/⌘ + K)"><span>{{svg-jar "search"}}</span></button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{{#unless this.session.user.isContributor}}
|
||||
<header class="gh-nav-menu">
|
||||
<div class="gh-nav-menu-details">
|
||||
<div class="gh-nav-menu-icon {{this.iconClass}}" style={{this.iconStyle}}></div>
|
||||
<div class="gh-nav-menu-details-sitetitle">{{this.config.blogTitle}}</div>
|
||||
</div>
|
||||
<div class="gh-nav-menu-search">
|
||||
<button class="gh-nav-btn-search" {{on "click" (action "openSearchModal")}} title="Search site (Ctrl/⌘ + K)"><span>{{svg-jar "search"}}</span></button>
|
||||
</div>
|
||||
</header>
|
||||
{{/unless}}
|
||||
|
||||
<section class="gh-nav-body">
|
||||
<div class="gh-nav-top">
|
||||
<ul class="gh-nav-list gh-nav-main">
|
||||
{{#if (gh-user-can-admin this.session.user)}}
|
||||
<li class="relative">
|
||||
<LinkTo @route="dashboard" @alt="Dashboard" @title="Dashboard" data-test-nav="dashboard">{{svg-jar "house"}} Dashboard</LinkTo>
|
||||
</li>
|
||||
{{/if}}
|
||||
<li class="relative">
|
||||
<span {{action "transitionToOrRefreshSite" on="click"}}>
|
||||
<LinkTo @route="site" data-test-nav="site" @current-when={{this.isOnSite}} @preventDefault={{false}}>
|
||||
{{svg-jar "view-site"}} View site
|
||||
</LinkTo>
|
||||
</span>
|
||||
<a href="{{this.config.blogUrl}}/" class="gh-secondary-action" title="Open site in new tab" target="_blank">
|
||||
<span>{{svg-jar "external"}}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="gh-nav-list gh-nav-manage">
|
||||
<li class="gh-nav-list-new relative">
|
||||
<GhLinkToCustomViewsIndex @route="posts" @query={{reset-query-params "posts"}} data-test-nav="posts">{{svg-jar "posts"}}Posts</GhLinkToCustomViewsIndex>
|
||||
<LinkTo @route="editor.new" @model="post" @classNames="gh-secondary-action gh-nav-new-post" @alt="New post" @title="New post" data-test-nav="new-story"><span>{{svg-jar "add-stroke"}}</span></LinkTo>
|
||||
{{#if this.session.user.isAuthorOrContributor}}
|
||||
{{#if this.customViews.forPosts}}
|
||||
<ul class="gh-nav-view-list">
|
||||
{{#each this.customViews.forPosts as |view|}}
|
||||
<li>
|
||||
<LinkTo @route="posts" @query={{reset-query-params "posts" view.filter}} data-test-nav-custom="{{view.route}}-{{view.name}}" title="{{view.name}}">
|
||||
<span class="gh-nav-viewname">{{view.name}}</span>
|
||||
<span class="flex items-center svg-{{view.color}}">
|
||||
{{#unless view.icon}}
|
||||
<span class="absolute circle"></span>
|
||||
{{/unless}}
|
||||
</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{#if this.customViews.forPosts}}
|
||||
<button type="button" class="gh-nav-button-expand {{if this.navigation.settings.expanded.posts "expanded"}}" {{on "click" (fn this.navigation.toggleExpansion "posts")}} aria-label="{{if this.navigation.settings.expanded.posts "Collapse custom post types" "Expand custom post types"}}">
|
||||
{{svg-jar (if this.navigation.settings.expanded.posts "arrow-down-stroke" "arrow-right-stroke")}}
|
||||
</button>
|
||||
{{#liquid-if this.navigation.settings.expanded.posts}}
|
||||
|
||||
{{#unless this.session.user.isContributor}}
|
||||
<div class="gh-nav-top">
|
||||
<ul class="gh-nav-list gh-nav-main">
|
||||
{{#if (gh-user-can-admin this.session.user)}}
|
||||
<li class="relative">
|
||||
<LinkTo @route="dashboard" @alt="Dashboard" @title="Dashboard" data-test-nav="dashboard">{{svg-jar "house"}} Dashboard</LinkTo>
|
||||
</li>
|
||||
{{/if}}
|
||||
<li class="relative">
|
||||
<span {{action "transitionToOrRefreshSite" on="click"}}>
|
||||
<LinkTo @route="site" data-test-nav="site" @current-when={{this.isOnSite}} @preventDefault={{false}}>
|
||||
{{svg-jar "view-site"}} View site
|
||||
</LinkTo>
|
||||
</span>
|
||||
<a href="{{this.config.blogUrl}}/" class="gh-secondary-action" title="Open site in new tab" target="_blank">
|
||||
<span>{{svg-jar "external"}}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="gh-nav-list gh-nav-manage">
|
||||
<li class="gh-nav-list-new relative">
|
||||
<GhLinkToCustomViewsIndex @route="posts" @query={{reset-query-params "posts"}} data-test-nav="posts">{{svg-jar "posts"}}Posts</GhLinkToCustomViewsIndex>
|
||||
<LinkTo @route="editor.new" @model="post" @classNames="gh-secondary-action gh-nav-new-post" @alt="New post" @title="New post" data-test-nav="new-story"><span>{{svg-jar "add-stroke"}}</span></LinkTo>
|
||||
{{#if this.session.user.isAuthorOrContributor}}
|
||||
{{#if this.customViews.forPosts}}
|
||||
<ul class="gh-nav-view-list">
|
||||
{{#each this.customViews.forPosts as |view|}}
|
||||
<li>
|
||||
|
@ -69,79 +53,101 @@
|
|||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{/liquid-if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</li>
|
||||
<li>
|
||||
{{!-- clicking the Content link whilst on the content screen should reset the filter --}}
|
||||
{{#if (eq this.router.currentRouteName "pages")}}
|
||||
<LinkTo @route="pages" @query={{reset-query-params "pages"}} @classNames="active" data-test-nav="pages">{{svg-jar "page"}}Pages</LinkTo>
|
||||
{{else}}
|
||||
<LinkTo @route="pages" data-test-nav="pages">{{svg-jar "page"}}Pages</LinkTo>
|
||||
{{/if}}
|
||||
</li>
|
||||
{{#if this.showTagsNavigation}}
|
||||
<li><LinkTo @route="tags" data-test-nav="tags">{{svg-jar "tag"}}Tags</LinkTo></li>
|
||||
{{/if}}
|
||||
{{#if (gh-user-can-admin this.session.user)}}
|
||||
<li class="relative">
|
||||
{{#if (eq this.router.currentRouteName "members.index")}}
|
||||
<LinkTo @route="members" @current-when="members member" @query={{reset-query-params "members.index"}} data-test-nav="members">{{svg-jar "members"}}Members
|
||||
{{#unless this.memberCountLoading}}
|
||||
<span class="gh-nav-member-count">{{format-number this.memberCount}}</span>
|
||||
{{/unless}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<LinkTo @route="members" @current-when="members member" data-test-nav="members">{{svg-jar "members"}}Members
|
||||
{{#unless this.memberCountLoading}}
|
||||
<span class="gh-nav-member-count">{{format-number this.memberCount}}</span>
|
||||
{{/unless}}
|
||||
</LinkTo>
|
||||
{{#if this.customViews.forPosts}}
|
||||
<button type="button" class="gh-nav-button-expand {{if this.navigation.settings.expanded.posts "expanded"}}" {{on "click" (fn this.navigation.toggleExpansion "posts")}} aria-label="{{if this.navigation.settings.expanded.posts "Collapse custom post types" "Expand custom post types"}}">
|
||||
{{svg-jar (if this.navigation.settings.expanded.posts "arrow-down-stroke" "arrow-right-stroke")}}
|
||||
</button>
|
||||
{{#liquid-if this.navigation.settings.expanded.posts}}
|
||||
<ul class="gh-nav-view-list">
|
||||
{{#each this.customViews.forPosts as |view|}}
|
||||
<li>
|
||||
<LinkTo @route="posts" @query={{reset-query-params "posts" view.filter}} data-test-nav-custom="{{view.route}}-{{view.name}}" title="{{view.name}}">
|
||||
<span class="gh-nav-viewname">{{view.name}}</span>
|
||||
<span class="flex items-center svg-{{view.color}}">
|
||||
{{#unless view.icon}}
|
||||
<span class="absolute circle"></span>
|
||||
{{/unless}}
|
||||
</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{/liquid-if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</li>
|
||||
|
||||
{{#if this.isStripeConnected}}
|
||||
<li>
|
||||
<LinkTo @route="offers" @alt="Offers">{{svg-jar "percentage"}}Offers</LinkTo>
|
||||
{{!-- clicking the Content link whilst on the content screen should reset the filter --}}
|
||||
{{#if (eq this.router.currentRouteName "pages")}}
|
||||
<LinkTo @route="pages" @query={{reset-query-params "pages"}} @classNames="active" data-test-nav="pages">{{svg-jar "page"}}Pages</LinkTo>
|
||||
{{else}}
|
||||
<LinkTo @route="pages" data-test-nav="pages">{{svg-jar "page"}}Pages</LinkTo>
|
||||
{{/if}}
|
||||
</li>
|
||||
{{#if this.showTagsNavigation}}
|
||||
<li><LinkTo @route="tags" data-test-nav="tags">{{svg-jar "tag"}}Tags</LinkTo></li>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</ul>
|
||||
|
||||
{{#if this.session.user.isOwnerOnly}}
|
||||
<ul class="gh-nav-list">
|
||||
{{#if this.showBilling}}
|
||||
<li class="relative">
|
||||
<a href="javascript:void(0)" class={{if this.billing.billingWindowOpen "active"}} {{action "toggleBillingModal" }} data-test-nav="billing">
|
||||
{{svg-jar "credit-card"}} Ghost(Pro)
|
||||
</a>
|
||||
</li>
|
||||
<li class="relative gh-nav-pro">
|
||||
<GhBillingUpdateButton />
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.showMenuExtension}}
|
||||
<ul class="gh-nav-list gh-nav-settings">
|
||||
{{#if this.config.clientExtensions.menu.title}}
|
||||
<li class="gh-nav-list-h">{{this.config.clientExtensions.menu.title}}</li>
|
||||
{{/if}}
|
||||
{{#each this.config.clientExtensions.menu.items as |menuItem| }}
|
||||
<li>
|
||||
<a href="{{menuItem.href}}" target="_blank">{{svg-jar menuItem.icon}}{{menuItem.text}}</a>
|
||||
{{#if (gh-user-can-admin this.session.user)}}
|
||||
<li class="relative">
|
||||
{{#if (eq this.router.currentRouteName "members.index")}}
|
||||
<LinkTo @route="members" @current-when="members member" @query={{reset-query-params "members.index"}} data-test-nav="members">{{svg-jar "members"}}Members
|
||||
{{#unless this.memberCountLoading}}
|
||||
<span class="gh-nav-member-count">{{format-number this.memberCount}}</span>
|
||||
{{/unless}}
|
||||
</LinkTo>
|
||||
{{else}}
|
||||
<LinkTo @route="members" @current-when="members member" data-test-nav="members">{{svg-jar "members"}}Members
|
||||
{{#unless this.memberCountLoading}}
|
||||
<span class="gh-nav-member-count">{{format-number this.memberCount}}</span>
|
||||
{{/unless}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.showScriptExtension}}
|
||||
{{{this.config.clientExtensions.script.container}}}
|
||||
<script src="{{this.config.clientExtensions.script.src}}"></script>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if this.isStripeConnected}}
|
||||
<li>
|
||||
<LinkTo @route="offers" @alt="Offers">{{svg-jar "percentage"}}Offers</LinkTo>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</ul>
|
||||
|
||||
{{#if this.session.user.isOwnerOnly}}
|
||||
<ul class="gh-nav-list">
|
||||
{{#if this.showBilling}}
|
||||
<li class="relative">
|
||||
<a href="javascript:void(0)" class={{if this.billing.billingWindowOpen "active"}} {{action "toggleBillingModal" }} data-test-nav="billing">
|
||||
{{svg-jar "credit-card"}} Ghost(Pro)
|
||||
</a>
|
||||
</li>
|
||||
<li class="relative gh-nav-pro">
|
||||
<GhBillingUpdateButton />
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.showMenuExtension}}
|
||||
<ul class="gh-nav-list gh-nav-settings">
|
||||
{{#if this.config.clientExtensions.menu.title}}
|
||||
<li class="gh-nav-list-h">{{this.config.clientExtensions.menu.title}}</li>
|
||||
{{/if}}
|
||||
{{#each this.config.clientExtensions.menu.items as |menuItem| }}
|
||||
<li>
|
||||
<a href="{{menuItem.href}}" target="_blank">{{svg-jar menuItem.icon}}{{menuItem.text}}</a>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.showScriptExtension}}
|
||||
{{{this.config.clientExtensions.script.container}}}
|
||||
<script src="{{this.config.clientExtensions.script.src}}"></script>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/unless}}
|
||||
|
||||
<GhNavMenu::Footer />
|
||||
|
||||
|
|
|
@ -3,25 +3,46 @@
|
|||
{{on "mouseleave" this.mouseLeave}}
|
||||
...attributes
|
||||
>
|
||||
<LinkTo @route="editor.edit" @models={{array @post.displayName @post.id}} class="permalink gh-list-data gh-post-list-title">
|
||||
<h3 class="gh-content-entry-title">
|
||||
{{@post.title}}
|
||||
</h3>
|
||||
<p>
|
||||
<span class="gh-content-entry-meta">
|
||||
By <span class="midgrey-l2 fw5">{{this.authorNames}}</span>
|
||||
|
||||
{{#if @post.primaryTag}}
|
||||
in <span class="midgrey-l2 fw5">{{@post.primaryTag.name}}</span>
|
||||
{{/if}}
|
||||
{{#if (and this.session.user.isContributor @post.isPublished)}}
|
||||
<a href={{@post.url}} class="permalink gh-list-data gh-post-list-title" target="_blank">
|
||||
<h3 class="gh-content-entry-title">
|
||||
{{@post.title}} {{svg-jar "external" class="gh-post-list-external"}}
|
||||
</h3>
|
||||
<p>
|
||||
<span class="gh-content-entry-meta">
|
||||
By <span class="midgrey-l2 fw5">{{this.authorNames}}</span>
|
||||
|
||||
• <span data-tooltip="{{gh-format-post-time @post.updatedAtUTC "D MMM YYYY"}}">{{gh-format-post-time @post.updatedAtUTC draft=true}}</span>
|
||||
{{#if @post.primaryTag}}
|
||||
in <span class="midgrey-l2 fw5">{{@post.primaryTag.name}}</span>
|
||||
{{/if}}
|
||||
|
||||
</span>
|
||||
</p>
|
||||
</LinkTo>
|
||||
• <span data-tooltip="{{gh-format-post-time @post.updatedAtUTC "D MMM YYYY"}}">{{gh-format-post-time @post.updatedAtUTC draft=true}}</span>
|
||||
|
||||
{{#if (not-eq this.settings.editorDefaultEmailRecipients "disabled")}}
|
||||
</span>
|
||||
</p>
|
||||
</a>
|
||||
{{else}}
|
||||
<LinkTo @route="editor.edit" @models={{array @post.displayName @post.id}} class="permalink gh-list-data gh-post-list-title">
|
||||
<h3 class="gh-content-entry-title">
|
||||
{{@post.title}}
|
||||
</h3>
|
||||
<p>
|
||||
<span class="gh-content-entry-meta">
|
||||
By <span class="midgrey-l2 fw5">{{this.authorNames}}</span>
|
||||
|
||||
{{#if @post.primaryTag}}
|
||||
in <span class="midgrey-l2 fw5">{{@post.primaryTag.name}}</span>
|
||||
{{/if}}
|
||||
|
||||
• <span data-tooltip="{{gh-format-post-time @post.updatedAtUTC "D MMM YYYY"}}">{{gh-format-post-time @post.updatedAtUTC draft=true}}</span>
|
||||
|
||||
</span>
|
||||
</p>
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
|
||||
{{#if (and (not-eq this.settings.editorDefaultEmailRecipients "disabled") (not this.session.user.isContributor))}}
|
||||
{{#if (and this.feature.emailAnalytics (eq @post.displayName "post"))}}
|
||||
<LinkTo @route="editor.edit" @models={{array @post.displayName @post.id}} class="permalink gh-list-data gh-post-list-recipients">
|
||||
<div class="flex fw4">
|
||||
|
@ -53,37 +74,73 @@
|
|||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
<LinkTo @route="editor.edit" @models={{array @post.displayName @post.id}} class="permalink gh-list-data gh-post-list-status">
|
||||
<div class="flex items-center">
|
||||
{{#if @post.isScheduled}}
|
||||
<span class="gh-content-status-scheduled gh-badge nowrap" title="Scheduled" data-tooltip="{{capitalize this.scheduledText}} to {{@post.emailRecipientFilter}} members">
|
||||
Scheduled
|
||||
{{#if @post.emailRecipientFilter}}
|
||||
{{svg-jar "email-stroke"}}
|
||||
{{#if (and this.session.user.isContributor @post.isPublished)}}
|
||||
<a href={{@post.url}} class="permalink gh-list-data gh-post-list-status" target="_blank">
|
||||
<div class="flex items-center">
|
||||
{{#if @post.isScheduled}}
|
||||
<span class="gh-content-status-scheduled gh-badge nowrap" title="Scheduled" data-tooltip="{{capitalize this.scheduledText}} to {{@post.emailRecipientFilter}} members">
|
||||
Scheduled
|
||||
{{#if @post.emailRecipientFilter}}
|
||||
{{svg-jar "email-stroke"}}
|
||||
{{/if}}
|
||||
</span>
|
||||
{{/if}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if @post.isDraft}}
|
||||
<span class="gh-content-status-draft gh-badge gh-badge-pink nowrap">
|
||||
Draft
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if @post.isPublished}}
|
||||
<span class="gh-content-status-published nowrap">
|
||||
Published
|
||||
{{#if @post.hasEmail}}
|
||||
{{svg-jar "email-stroke"}}
|
||||
{{#if @post.isDraft}}
|
||||
<span class="gh-content-status-draft gh-badge gh-badge-pink nowrap">
|
||||
Draft
|
||||
</span>
|
||||
{{/if}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if @post.isSent}}
|
||||
<span class="gh-content-status-emailed nowrap">
|
||||
{{svg-jar "email-stroke"}}
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</LinkTo>
|
||||
{{#if @post.isPublished}}
|
||||
<span class="gh-content-status-published nowrap">
|
||||
Published
|
||||
{{#if @post.hasEmail}}
|
||||
{{svg-jar "email-stroke"}}
|
||||
{{/if}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if @post.isSent}}
|
||||
<span class="gh-content-status-emailed nowrap">
|
||||
{{svg-jar "email-stroke"}}
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</a>
|
||||
{{else}}
|
||||
<LinkTo @route="editor.edit" @models={{array @post.displayName @post.id}} class="permalink gh-list-data gh-post-list-status">
|
||||
<div class="flex items-center">
|
||||
{{#if @post.isScheduled}}
|
||||
<span class="gh-content-status-scheduled gh-badge nowrap" title="Scheduled" data-tooltip="{{capitalize this.scheduledText}} to {{@post.emailRecipientFilter}} members">
|
||||
Scheduled
|
||||
{{#if @post.emailRecipientFilter}}
|
||||
{{svg-jar "email-stroke"}}
|
||||
{{/if}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if @post.isDraft}}
|
||||
<span class="gh-content-status-draft gh-badge gh-badge-pink nowrap">
|
||||
Draft
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if @post.isPublished}}
|
||||
<span class="gh-content-status-published nowrap">
|
||||
Published
|
||||
{{#if @post.hasEmail}}
|
||||
{{svg-jar "email-stroke"}}
|
||||
{{/if}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if @post.isSent}}
|
||||
<span class="gh-content-status-emailed nowrap">
|
||||
{{svg-jar "email-stroke"}}
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
</li>
|
|
@ -19,13 +19,15 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<GhPublishmenu
|
||||
@post={{@data.post}}
|
||||
@postStatus={{@data.post.status}}
|
||||
@saveTask={{@data.saveTask}}
|
||||
@setSaveType={{@data.setEditorSaveType}}
|
||||
@memberCount={{@data.memberCount}}
|
||||
@uiContext="preview" />
|
||||
{{#if (not this.session.user.isContributor)}}
|
||||
<GhPublishmenu
|
||||
@post={{@data.post}}
|
||||
@postStatus={{@data.post.status}}
|
||||
@saveTask={{@data.saveTask}}
|
||||
@setSaveType={{@data.setEditorSaveType}}
|
||||
@memberCount={{@data.memberCount}}
|
||||
@uiContext="preview" />
|
||||
{{/if}}
|
||||
</header>
|
||||
|
||||
{{#if this.saveFirstTask.isRunning}}
|
||||
|
|
|
@ -7,6 +7,7 @@ import {tracked} from '@glimmer/tracking';
|
|||
export default class ModalPostPreviewComponent extends Component {
|
||||
@tracked tab = 'browser';
|
||||
@service settings;
|
||||
@service session;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
|
|
@ -12,6 +12,9 @@ export default class PostsLoadingController extends Controller {
|
|||
@service session;
|
||||
@service ui;
|
||||
|
||||
@service
|
||||
config;
|
||||
|
||||
@readOnly('postsController.availableTypes')
|
||||
availableTypes;
|
||||
|
||||
|
|
|
@ -54,6 +54,9 @@ export default class PostsController extends Controller {
|
|||
@service store;
|
||||
@service settings;
|
||||
|
||||
@service
|
||||
config;
|
||||
|
||||
// default values for these are set in `init` and defined in `helpers/reset-query-params`
|
||||
queryParams = ['type', 'access', 'author', 'tag', 'order'];
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ export default class PostsRoute extends AuthenticatedRoute {
|
|||
} else if (user.isContributor) {
|
||||
// Contributors can only view their own draft posts
|
||||
filterParams.authors = user.slug;
|
||||
filterParams.status = 'draft';
|
||||
// filterParams.status = 'draft';
|
||||
} else if (params.author) {
|
||||
filterParams.authors = params.author;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
.settings-menu-toggle {
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
top: 31px;
|
||||
right: 24px;
|
||||
z-index: 9999;
|
||||
margin-right: 0 !important;
|
||||
|
|
|
@ -180,6 +180,21 @@
|
|||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.gh-post-list-external {
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
margin-left: 6px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.gh-post-list-external path {
|
||||
fill: var(--midgrey);
|
||||
}
|
||||
|
||||
.gh-list-row:hover .gh-post-list-external {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.gh-post-list-featured {
|
||||
padding: 15px 0px 20px 10px;
|
||||
width: 1px;
|
||||
|
@ -195,6 +210,8 @@
|
|||
}
|
||||
|
||||
.gh-content-entry-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 0 3px 0;
|
||||
font-size: 1.6rem !important;
|
||||
font-weight: 600;
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
.contributor-save-button {
|
||||
position: relative;
|
||||
z-index: 1000;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.post-settings {
|
||||
|
@ -609,7 +610,7 @@ body[data-user-is-dragging] .gh-editor-feature-image-dropzone {
|
|||
height: 33px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 5px 12px 6px;
|
||||
padding: 0 12px;
|
||||
font-size: 1.35rem;
|
||||
font-weight: 400;
|
||||
color: var(--midgrey-l2);
|
||||
|
@ -622,7 +623,7 @@ body[data-user-is-dragging] .gh-editor-feature-image-dropzone {
|
|||
background: var(--white);
|
||||
font-size: 1.35rem;
|
||||
font-weight: 500;
|
||||
color: var(--green-d1);
|
||||
color: var(--green-d1) !important;
|
||||
margin-right: 8px;
|
||||
outline: none;
|
||||
border: none;
|
||||
|
|
|
@ -107,6 +107,15 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
.gh-nav-contributor {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
border-right: none;
|
||||
background: unset;
|
||||
width: 100%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.gh-nav-menu {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
|
@ -124,6 +133,10 @@
|
|||
padding: 6px 0;
|
||||
}
|
||||
|
||||
.gh-nav-menu-dropdown-contributor .dropdown-menu {
|
||||
top: -272px;
|
||||
}
|
||||
|
||||
.gh-nav-menu-dropdown .dropdown-menu>li>a,
|
||||
.gh-nav-menu-dropdown .dropdown-menu>li>button {
|
||||
font-size: 1.4rem;
|
||||
|
@ -708,11 +721,27 @@
|
|||
.gh-nav-bottom .ember-basic-dropdown-trigger {
|
||||
padding: 4px 8px 4px 4px;
|
||||
margin: -4px -8px -4px -4px;
|
||||
border-radius: 999px;
|
||||
background: var(--main-bg-color);
|
||||
}
|
||||
|
||||
.gh-nav-bottom .ember-basic-dropdown-trigger:hover {
|
||||
background: var(--whitegrey);
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.gh-nav-contributor .gh-nav-bottom .ember-basic-dropdown-trigger {
|
||||
padding: 8px 12px 8px 8px;
|
||||
margin: -4px 0px -4px 0px;
|
||||
/* background: var(--main-bg-color); */
|
||||
/* box-shadow:
|
||||
0px -1px 10px rgba(0, 0, 0, 0.08),
|
||||
0px 2.8px 2.2px rgba(0, 0, 0, 0.014),
|
||||
0px 6.7px 5.3px rgba(0, 0, 0, 0.02),
|
||||
0px 12.5px 10px rgba(0, 0, 0, 0.025),
|
||||
0px 22.3px 17.9px rgba(0, 0, 0, 0.03),
|
||||
0px 41.8px 33.4px rgba(0, 0, 0, 0.036),
|
||||
0px 100px 80px rgba(0, 0, 0, 0.05)
|
||||
; */
|
||||
}
|
||||
|
||||
.gh-nav-bottom-tabicon {
|
||||
|
@ -861,7 +890,7 @@
|
|||
}
|
||||
|
||||
/* Hide the nav */
|
||||
.gh-nav {
|
||||
.gh-nav:not(.gh-nav-contributor) {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
@ -871,6 +900,7 @@
|
|||
transition: transform 0.4s cubic-bezier(0.1, 0.7, 0.1, 1);
|
||||
transform: translate3d(-260px, 0px, 0px);
|
||||
}
|
||||
|
||||
.mobile-menu-expanded .gh-nav {
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
|
@ -892,7 +922,7 @@
|
|||
padding: 24px 15px 24px 16px;
|
||||
}
|
||||
|
||||
.gh-nav {
|
||||
.gh-nav:not(.gh-nav-contributor) {
|
||||
width: 80vw;
|
||||
transform: translate3d(-80vw, 0px, 0px);
|
||||
}
|
||||
|
@ -940,7 +970,7 @@
|
|||
padding-bottom: 55px;
|
||||
}
|
||||
|
||||
.gh-nav-body {
|
||||
.gh-nav:not(.gh-nav-contributor) .gh-nav-body {
|
||||
padding-bottom: 64px;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,9 @@
|
|||
|
||||
<GhContentCover />
|
||||
|
||||
<GhMobileNavBar />
|
||||
{{#if (not this.session.user.isContributor)}}
|
||||
<GhMobileNavBar />
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if this.settings.accentColor}}
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
<GhTaskButton @buttonText="Save"
|
||||
@task={{this.save}}
|
||||
@runningText="Saving"
|
||||
@class="gh-btn gh-btn-blue gh-btn-icon contributor-save-button"
|
||||
@class="gh-btn gh-btn-icon gh-btn-editor contributor-save-button"
|
||||
data-test-contributor-save=true />
|
||||
{{else}}
|
||||
<GhPublishmenu
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<section class="gh-canvas" {{did-insert (action "setMainClass" "gh-main-primarybg" target=this.ui)}}>
|
||||
<GhCanvasHeader class="gh-canvas-header break tablet post-header">
|
||||
<GhCustomViewTitle @title="Posts" @query={{reset-query-params "posts"}} />
|
||||
<GhCustomViewTitle @title={{if this.session.user.isContributor (concat this.config.blogTitle " posts") "Posts"}} @query={{reset-query-params "posts"}} />
|
||||
<section class="view-actions">
|
||||
<GhContentfilter
|
||||
@currentUser={{this.session.user}}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<section class="gh-canvas">
|
||||
<GhCanvasHeader class="gh-canvas-header break tablet post-header">
|
||||
<GhCustomViewTitle @title="Posts" @query={{reset-query-params "posts"}} />
|
||||
<GhCustomViewTitle @title={{if this.session.user.isContributor (concat this.config.blogTitle " posts") "Posts"}} @query={{reset-query-params "posts"}} />
|
||||
|
||||
<section class="view-actions">
|
||||
<GhContentfilter
|
||||
|
@ -31,7 +31,7 @@
|
|||
{{#if this.postsInfinityModel}}
|
||||
<li class="gh-list-row header">
|
||||
<div class="gh-list-header gh-posts-title-header">Title</div>
|
||||
{{#if (not-eq this.settings.editorDefaultEmailRecipients "disabled")}}
|
||||
{{#if (and (not-eq this.settings.editorDefaultEmailRecipients "disabled") (not this.session.user.isContributor))}}
|
||||
{{#if this.feature.emailAnalytics}}
|
||||
<div class="gh-list-header gh-posts-sends-header">Sends</div>
|
||||
<div class="gh-list-header gh-posts-opens-header">Opens</div>
|
||||
|
|
|
@ -246,40 +246,14 @@ describe('Acceptance: Content', function () {
|
|||
});
|
||||
|
||||
describe('as contributor', function () {
|
||||
let contributor, contributorPost;
|
||||
|
||||
beforeEach(async function () {
|
||||
let contributorRole = this.server.create('role', {name: 'Contributor'});
|
||||
contributor = this.server.create('user', {roles: [contributorRole]});
|
||||
let adminRole = this.server.create('role', {name: 'Administrator'});
|
||||
let admin = this.server.create('user', {roles: [adminRole]});
|
||||
|
||||
// Create posts
|
||||
contributorPost = this.server.create('post', {authors: [contributor], status: 'draft', title: 'Contributor Post Draft'});
|
||||
this.server.create('post', {authors: [contributor], status: 'published', title: 'Contributor Published Post'});
|
||||
this.server.create('post', {authors: [admin], status: 'scheduled', title: 'Admin Post'});
|
||||
|
||||
return await authenticateSession();
|
||||
});
|
||||
|
||||
it('only fetches the contributor\'s draft posts', async function () {
|
||||
await visit('/posts');
|
||||
|
||||
// Ensure the type, tag, and author selectors don't exist
|
||||
expect(find('[data-test-type-select]'), 'type selector').to.not.exist;
|
||||
expect(find('[data-test-tag-select]'), 'tag selector').to.not.exist;
|
||||
expect(find('[data-test-author-select]'), 'author selector').to.not.exist;
|
||||
|
||||
// Trigger a sort request
|
||||
await selectChoose('[data-test-order-select]', 'Oldest');
|
||||
|
||||
// API request includes author filter
|
||||
let [lastRequest] = this.server.pretender.handledRequests.slice(-1);
|
||||
expect(lastRequest.queryParams.filter).to.have.string(`authors:${contributor.slug}`);
|
||||
|
||||
// only contributor's post is shown
|
||||
expect(findAll('[data-test-post-id]').length, 'post count').to.equal(1);
|
||||
expect(find(`[data-test-post-id="${contributorPost.id}"]`), 'author post').to.exist;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue