0
Fork 0
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:
Peter Zimon 2022-02-01 18:59:20 +01:00 committed by GitHub
parent 9760e67b3d
commit 6fa8dafa79
20 changed files with 385 additions and 278 deletions

View file

@ -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

View file

@ -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}}

View file

@ -7,6 +7,7 @@ import {tracked} from '@glimmer/tracking';
export default class GhNavMenuComponent extends Component {
@service settings;
@service ui;
@service session;
@tracked firstRender = true;

View file

@ -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}}

View file

@ -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 />

View file

@ -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>

View file

@ -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}}

View file

@ -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);

View file

@ -12,6 +12,9 @@ export default class PostsLoadingController extends Controller {
@service session;
@service ui;
@service
config;
@readOnly('postsController.availableTypes')
availableTypes;

View file

@ -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'];

View file

@ -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;
}

View file

@ -6,7 +6,7 @@
.settings-menu-toggle {
position: absolute;
top: 30px;
top: 31px;
right: 24px;
z-index: 9999;
margin-right: 0 !important;

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -21,7 +21,9 @@
<GhContentCover />
<GhMobileNavBar />
{{#if (not this.session.user.isContributor)}}
<GhMobileNavBar />
{{/if}}
</div>
{{#if this.settings.accentColor}}

View file

@ -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

View file

@ -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}}

View file

@ -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>

View file

@ -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;
});
});
});