mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-25 03:44:29 +03:00
What's new popup (#20112)
DES-192 We often hear that people are not aware of the new features we ship. Ways in which people can find out are social media/changelog/dashboard – all of these are easy to miss. We'd like to introduce a template for a simple notification in the sidebar that can be used any time a new and noteworthy feature has shipped. The purpose of this is simply to notify and will disappear forever after it's been dismissed.
This commit is contained in:
parent
f01e06153f
commit
5bb945e89b
@ -189,3 +189,4 @@ add|ember-template-lint|require-iframe-title|27|20|27|20|94e58d11848d5613900c218
|
||||
add|ember-template-lint|require-iframe-title|42|16|42|16|a3292b469dc37f2f4791e7f224b0b65c8ecf5d18|1712707200000|1723075200000|1728259200000|app/components/modals/email-preview.hbs
|
||||
add|ember-template-lint|no-autofocus-attribute|21|20|21|20|942419d05c04ded6716f09faecd6b1ab55418121|1712707200000|1723075200000|1728259200000|app/components/modals/new-custom-integration.hbs
|
||||
add|ember-template-lint|no-invalid-interactive|2|37|2|37|e21ba31f54b631a428c28a1c9f88d0dc66f2f5fc|1712707200000|1723075200000|1728259200000|app/components/modals/search.hbs
|
||||
remove|ember-template-lint|no-unknown-arguments-for-builtin-components|93|93|93|93|156670ca427c49c51f0a94f862b286ccc9466d92|1712707200000|1723075200000|1728259200000|app/components/gh-nav-menu/footer.hbs
|
||||
|
@ -4,17 +4,17 @@
|
||||
<h4>{{svg-jar "gift" alt="Gift" class="v-mid"}}What's new</h4>
|
||||
</div>
|
||||
<div class="gh-dashboard-resource-body">
|
||||
<div class="gh-dashboard-list {{if this.whatsNew.hasNew "has-new"}}">
|
||||
<div class="gh-dashboard-list {{if this.whatsNew.hasNew "has-new"}}">
|
||||
{{#if (not (or this.loading this.error))}}
|
||||
<div class="gh-dashboard-list-body">
|
||||
{{#each this.entries as |entry|}}
|
||||
<div class="gh-dashboard-list-item">
|
||||
<LinkTo class="gh-dashboard-list-post" @route="whatsnew" @query={{hash entry=entry.slug}}>
|
||||
<a href={{entry.url}} class="gh-dashboard-list-post" target="_blank" rel="noopener noreferrer">
|
||||
<span class="gh-dashboard-list-link">
|
||||
<span>{{entry.title}}</span>
|
||||
</span>
|
||||
<div class="gh-dashboard-resource-secondary">{{moment-format entry.published_at "D MMM YYYY"}}</div>
|
||||
</LinkTo>
|
||||
</a>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="gh-dashboard-list-empty">
|
||||
@ -26,7 +26,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="gh-dashboard-resource-footer">
|
||||
<LinkTo @route="whatsnew" @query={{hash entry=null}} class="green">View more features →</LinkTo>
|
||||
<a href="https://ghost.org/changelog" class="green" target="_blank" rel="noopener noreferrer">View more features →</a>
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
|
28
ghost/admin/app/components/gh-nav-menu/footer-banner.hbs
Normal file
28
ghost/admin/app/components/gh-nav-menu/footer-banner.hbs
Normal file
@ -0,0 +1,28 @@
|
||||
{{#if this.showReferralInvite}}
|
||||
<div class="gh-sidebar-banner gh-referral-toast">
|
||||
<button class="gh-sidebar-banner-close" type="button" {{on "click" this.dismissReferralInvite}}>×</button>
|
||||
<a href="https://referrals.ghost.org/?ref=admin" target="_blank" rel="noopener noreferrer">
|
||||
<strong>You qualify for our invite-only referral program.</strong>
|
||||
<p class="gh-footer-toast-p">Refer people to Ghost and earn a <strong>30% share</strong> of the subscription revenue, every single month.</p>
|
||||
<div class="gh-btn gh-btn-black gh-sidebar-banner-button" type="button"><span>Find out more →</span></div>
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if (and this.showWhatsNew this.whatsNew.hasNew)}}
|
||||
{{#let (get this.whatsNew.entries "0") as |entry|}}
|
||||
<div class="gh-sidebar-banner gh-whatsnew-toast">
|
||||
<button class="gh-sidebar-banner-close" type="button" {{on "click" this.dismissWhatsNewToast}}>×</button>
|
||||
<a class="gh-sidebar-banner-container" href={{entry.url}} target="_blank" rel="noopener noreferrer" {{on "click" (fn this.openFeaturedWhatsNew entry.url)}}>
|
||||
<div class="gh-sidebar-banner-head">
|
||||
{{svg-jar "sparkle-fill" class="gh-sidebar-banner-icon gh-whatsnew-banner-icon"}}
|
||||
<span class="gh-sidebar-banner-subhead">What's new?</span>
|
||||
</div>
|
||||
<div class="gh-sidebar-banner-msg">{{entry.title}}</div>
|
||||
{{#if entry.custom_excerpt}}
|
||||
<div class="gh-sidebar-banner-details">{{entry.custom_excerpt}}</div>
|
||||
{{/if}}
|
||||
</a>
|
||||
</div>
|
||||
{{/let}}
|
||||
{{/if}}
|
89
ghost/admin/app/components/gh-nav-menu/footer-banner.js
Normal file
89
ghost/admin/app/components/gh-nav-menu/footer-banner.js
Normal file
@ -0,0 +1,89 @@
|
||||
import Component from '@glimmer/component';
|
||||
import envConfig from 'ghost-admin/config/environment';
|
||||
import moment from 'moment-timezone';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
|
||||
export default class FooterBanner extends Component {
|
||||
@service session;
|
||||
@service dashboardStats;
|
||||
@service feature;
|
||||
@service membersUtils;
|
||||
@service modals;
|
||||
@service settings;
|
||||
@service whatsNew;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.loadCurrentMRR.perform();
|
||||
}
|
||||
|
||||
get isAdminOrOwner() {
|
||||
return this.session.user.isAdmin;
|
||||
}
|
||||
|
||||
get isReferralNotificationNotDismissed() {
|
||||
return !this.feature.accessibility.referralInviteDismissed;
|
||||
}
|
||||
|
||||
get stripeLiveModeEnabled() {
|
||||
// allow testing mode when not in a production environment
|
||||
const isDevModeStripeEnabled = envConfig.environment !== 'production' && this.membersUtils.isStripeEnabled;
|
||||
const isLiveEnabled = this.settings.stripeConnectLivemode;
|
||||
return isDevModeStripeEnabled || isLiveEnabled;
|
||||
}
|
||||
|
||||
get hasReachedMRR() {
|
||||
return this.dashboardStats.currentMRR / 100 >= 100;
|
||||
}
|
||||
|
||||
get showReferralInvite() {
|
||||
// Conditions to see the referral invite
|
||||
// 1. Needs to be Owner or Admin
|
||||
// 2. Stripe is setup and enabled in live mode
|
||||
// 3. MRR is > $100
|
||||
// 4. Notification has not yet been dismissed by the user
|
||||
return !this.args.hasThemeErrors && this.isAdminOrOwner && this.isReferralNotificationNotDismissed && this.stripeLiveModeEnabled && this.hasReachedMRR;
|
||||
}
|
||||
|
||||
get showWhatsNew() {
|
||||
return !this.showReferralInvite && this.whatsNew.hasNewFeatured;
|
||||
}
|
||||
|
||||
@task
|
||||
*loadCurrentMRR() {
|
||||
if (this.isAdminOrOwnern) {
|
||||
try {
|
||||
yield this.dashboardStats.loadMrrStats();
|
||||
} catch (error) {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
dismissReferralInvite(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if (!this.feature.referralInviteDismissed) {
|
||||
this.feature.referralInviteDismissed = moment().tz(this.settings.timezone);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
dismissWhatsNewToast(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
// Dismiss
|
||||
this.whatsNew.seen();
|
||||
}
|
||||
|
||||
@action
|
||||
openFeaturedWhatsNew(href) {
|
||||
window.open(href, '_blank');
|
||||
this.whatsNew.seen();
|
||||
}
|
||||
}
|
@ -1,12 +1,19 @@
|
||||
<div class="gh-nav-bottom">
|
||||
{{#if this.hasThemeErrors}}
|
||||
<button type="button" class="gh-footer-toast gh-theme-error-toast" {{on "click" (fn this.openThemeErrors null)}}>
|
||||
<span class="gh-footer-toast-title gh-notification-title">Your theme contains errors</span>
|
||||
<span class="gh-footer-toast-p">Some functionality on your site may be limited →</span>
|
||||
</button>
|
||||
<div class="gh-sidebar-banner gh-error-banner">
|
||||
<button class="gh-sidebar-banner-container" type="button" {{on "click" (fn this.openThemeErrors null)}}>
|
||||
<div>
|
||||
{{svg-jar "warning-fill" class="gh-sidebar-banner-icon"}}
|
||||
</div>
|
||||
<div>
|
||||
<span class="gh-sidebar-banner-subhead">Your theme has errors</span>
|
||||
<p class="gh-sidebar-banner-msg">Some functionality on your site may be limited →</p>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<GhReferralInvite @hasThemeErrors={{this.hasThemeErrors}} />
|
||||
<GhNavMenu::FooterBanner @hasThemeErrors={{this.hasThemeErrors}} />
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="pe-all">
|
||||
@ -14,7 +21,7 @@
|
||||
<dropdown.Trigger class="outline-0 pointer">
|
||||
<div class="flex-auto flex items-center">
|
||||
<div class="gh-user-avatar relative" style={{background-image-style this.session.user.profileImageUrl}}>
|
||||
{{#if this.whatsNew.hasNew}}<span class="absolute dib ba b--white br-100 gh-whats-new-badge-account"></span>{{/if}}
|
||||
{{#if (and this.whatsNew.hasNew (not this.whatsNew.hasNewFeatured))}}<span class="absolute dib ba b--white br-100 gh-whats-new-badge-account"></span>{{/if}}
|
||||
</div>
|
||||
{{svg-jar "arrow-down" class="w3 mr1 fill-darkgrey"}}
|
||||
</div>
|
||||
@ -45,12 +52,12 @@
|
||||
<li class="divider" role="separator"></li>
|
||||
{{else}}
|
||||
<li>
|
||||
<LinkTo @route="whatsnew" @query={{hash entry=null}} class="dropdown-item" @role="menuitem" tabindex="-1" data-test-nav="whatsnew">
|
||||
<button class="dropdown-item" tabindex="-1" data-test-nav="whatsnew" type="button" {{on "click" this.openWhatsNew}}>
|
||||
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>
|
||||
</button>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import Component from '@ember/component';
|
||||
import ThemeErrorsModal from '../modals/design/theme-errors';
|
||||
import WhatsNew from '../modals/whats-new';
|
||||
import calculatePosition from 'ember-basic-dropdown/utils/calculate-position';
|
||||
import classic from 'ember-classic-decorator';
|
||||
import {action} from '@ember/object';
|
||||
@ -43,7 +44,7 @@ export default class Footer extends Component {
|
||||
// filter errors that have other UI to display to users that the functionality is not working
|
||||
const filteredErrors = errors?.filter((error) => {
|
||||
if (error.code === 'GS110-NO-MISSING-PAGE-BUILDER-USAGE' && error?.failures?.[0].message.includes(`show_title_and_feature_image`)) {
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
@ -60,4 +61,9 @@ export default class Footer extends Component {
|
||||
|
||||
return {horizontalPosition, verticalPosition, style};
|
||||
}
|
||||
|
||||
@action
|
||||
openWhatsNew() {
|
||||
return this.modals.open(WhatsNew);
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
<div class="gh-nav-top">
|
||||
<ul class="gh-nav-list gh-nav-main">
|
||||
{{#if (gh-user-can-admin this.session.user)}}
|
||||
<li class="relative">
|
||||
<li class="relative gh-nav-list-home">
|
||||
<LinkTo @route="dashboard" @alt="Dashboard" title="Dashboard" data-test-nav="dashboard">{{svg-jar "house"}} Dashboard</LinkTo>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
@ -23,10 +23,10 @@ export default class Main extends Component.extend(ShortcutsMixin) {
|
||||
@service router;
|
||||
@service session;
|
||||
@service ui;
|
||||
@service whatsNew;
|
||||
@service membersStats;
|
||||
@service settings;
|
||||
@service explore;
|
||||
@service notifications;
|
||||
|
||||
@inject config;
|
||||
|
||||
|
24
ghost/admin/app/components/modals/whats-new.hbs
Normal file
24
ghost/admin/app/components/modals/whats-new.hbs
Normal file
@ -0,0 +1,24 @@
|
||||
<div class="modal-content">
|
||||
<h1 class="gh-whasnew-modal-title">What's new?</h1>
|
||||
<section class="gh-whatsnew-modal-entries" {{did-insert (perform this.whatsNew.updateLastSeen)}}>
|
||||
{{#each this.whatsNew.entries as |entry|}}
|
||||
<a class="gh-whatsnew-modal-entry" href={{entry.url}} target="_blank" rel="noopener noreferrer">
|
||||
{{#if entry.feature_image}}
|
||||
<img class="gh-whatsnew-modal-entry-featureimage" src={{entry.feature_image}} alt={{entry.title}}>
|
||||
{{/if}}
|
||||
<div class="gh-whatsnew-modal-entrycontent">
|
||||
<h2>{{entry.title}}</h2>
|
||||
{{#if entry.custom_excerpt}}
|
||||
<p>{{entry.custom_excerpt}}</p>
|
||||
{{/if}}
|
||||
<span>{{moment-format entry.published_at "DD MMMM YYYY"}}</span>
|
||||
</div>
|
||||
</a>
|
||||
{{/each}}
|
||||
</section>
|
||||
|
||||
<div class="gh-whatsnew-modal-footer">
|
||||
<a href="https://ghost.org/changelog/#/portal/signup" class="gh-btn" type="button" target="_blank" rel="noopener noreferrer"><span>Turn on notifications</span></a>
|
||||
<a class="gh-btn gh-btn-primary" href="https://ghost.org/changelog" target="_blank" rel="noopener noreferrer"><span>All updates →</span></a>
|
||||
</div>
|
||||
</div>
|
15
ghost/admin/app/components/modals/whats-new.js
Normal file
15
ghost/admin/app/components/modals/whats-new.js
Normal file
@ -0,0 +1,15 @@
|
||||
import Component from '@glimmer/component';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class WhatsNewFeatured extends Component {
|
||||
@service whatsNew;
|
||||
|
||||
static modalOptions = {
|
||||
className: 'fullscreen-modal-action fullscreen-modal-wide fullscreen-modal-whatsnew'
|
||||
};
|
||||
|
||||
willDestroy() {
|
||||
super.willDestroy(...arguments);
|
||||
this.whatsNew.seen();
|
||||
}
|
||||
}
|
@ -7,6 +7,8 @@ import {task} from 'ember-concurrency';
|
||||
|
||||
export default Service.extend({
|
||||
session: service(),
|
||||
store: service(),
|
||||
response: null,
|
||||
|
||||
entries: null,
|
||||
changelogUrl: 'https://ghost.org/blog/',
|
||||
@ -39,32 +41,47 @@ export default Service.extend({
|
||||
return latestMoment.isAfter(lastSeenMoment);
|
||||
}),
|
||||
|
||||
showModal: action(function () {
|
||||
hasNewFeatured: computed('entries.[]', function () {
|
||||
if (!this.hasNew) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let [latestEntry] = this.entries;
|
||||
return latestEntry.featured;
|
||||
}),
|
||||
|
||||
seen: action(function () {
|
||||
this.updateLastSeen.perform();
|
||||
}),
|
||||
|
||||
openFeaturedModal: action(function () {
|
||||
this.set('isShowingModal', true);
|
||||
}),
|
||||
|
||||
closeModal: action(function () {
|
||||
closeFeaturedModal: action(function () {
|
||||
this.set('isShowingModal', false);
|
||||
this.updateLastSeen.perform();
|
||||
this.seen();
|
||||
}),
|
||||
|
||||
fetchLatest: task(function* () {
|
||||
try {
|
||||
// we should already be logged in at this point so lets grab the user
|
||||
// record and store it locally so that we don't have to deal with
|
||||
// session.user being a promise and causing issues with CPs
|
||||
let user = yield this.session.user;
|
||||
this.set('_user', user);
|
||||
if (!this.response) {
|
||||
// we should already be logged in at this point so lets grab the user
|
||||
// record and store it locally so that we don't have to deal with
|
||||
// session.user being a promise and causing issues with CPs
|
||||
let user = yield this.session.user;
|
||||
this.set('_user', user);
|
||||
|
||||
let response = yield fetch('https://ghost.org/changelog.json');
|
||||
if (!response.ok) {
|
||||
// eslint-disable-next-line
|
||||
return console.error('Failed to fetch changelog', {response});
|
||||
this.response = yield fetch('https://ghost.org/changelog.json');
|
||||
if (!this.response.ok) {
|
||||
// eslint-disable-next-line
|
||||
return console.error('Failed to fetch changelog', {response});
|
||||
}
|
||||
|
||||
let result = yield this.response.json();
|
||||
this.set('entries', result.posts || []);
|
||||
this.set('changelogUrl', result.changelogUrl);
|
||||
}
|
||||
|
||||
let result = yield response.json();
|
||||
this.set('entries', result.posts || []);
|
||||
this.set('changelogUrl', result.changelogUrl);
|
||||
} catch (e) {
|
||||
console.error(e); // eslint-disable-line
|
||||
}
|
||||
|
@ -54,6 +54,7 @@
|
||||
@import "layouts/content.css";
|
||||
@import "layouts/editor.css";
|
||||
@import "layouts/whatsnew.css";
|
||||
@import "layouts/whatsnew-modal.css";
|
||||
@import "layouts/tags.css";
|
||||
@import "layouts/members.css";
|
||||
@import "layouts/member-activity.css";
|
||||
@ -1426,3 +1427,7 @@ Onboarding checklist: Share publication modal */
|
||||
.gh-share-links li a:hover {
|
||||
background: #394047;
|
||||
}
|
||||
|
||||
.gh-sidebar-banner.gh-error-banner {
|
||||
background: var(--lightgrey-d1);
|
||||
}
|
@ -56,6 +56,7 @@
|
||||
@import "layouts/content.css";
|
||||
@import "layouts/editor.css";
|
||||
@import "layouts/whatsnew.css";
|
||||
@import "layouts/whatsnew-modal.css";
|
||||
@import "layouts/tags.css";
|
||||
@import "layouts/members.css";
|
||||
@import "layouts/posts.css";
|
||||
|
@ -445,6 +445,10 @@
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.gh-nav-list-home svg {
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.gh-nav-list svg.force-fill path {
|
||||
fill: var(--midgrey);
|
||||
}
|
||||
@ -2137,12 +2141,12 @@ section.gh-ds h2 {
|
||||
background: var(--red);
|
||||
}
|
||||
|
||||
/* Ghost Referrals invite toast */
|
||||
.gh-referral-toast {
|
||||
/* Sidebar banners like ghost Referrals invite toast */
|
||||
.gh-sidebar-banner {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 25px;
|
||||
margin-bottom: 50px;
|
||||
padding: 12px 16px 16px;
|
||||
margin: 0 -7px 32px;
|
||||
color: var(--black);
|
||||
text-decoration: none;
|
||||
background: var(--white);
|
||||
@ -2152,38 +2156,38 @@ section.gh-ds h2 {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.gh-referral-toast a {
|
||||
.gh-sidebar-banner a {
|
||||
color: var(--black);
|
||||
}
|
||||
|
||||
.gh-referral-toast:hover {
|
||||
.gh-sidebar-banner:hover {
|
||||
transform: translateY(-2px) scale(1.01);
|
||||
box-shadow: rgb(75 225 226 / 38%) -7px -4px 42px 10px, rgb(202 103 255 / 42%) 7px 8px 42px 10px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.gh-referral-toast-close {
|
||||
.gh-sidebar-banner-close {
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
right: 10px;
|
||||
top: 4px;
|
||||
right: 8px;
|
||||
padding: 5px;
|
||||
color: #ddd;
|
||||
font-size: 2.2rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.gh-referral-toast-close:hover {
|
||||
.gh-sidebar-banner-close:hover {
|
||||
color: #15171A;
|
||||
}
|
||||
|
||||
.gh-referral-toast a > strong {
|
||||
.gh-sidebar-banner a > strong {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
font-size: 1.7rem;
|
||||
line-height: 1.2em;
|
||||
}
|
||||
|
||||
.gh-referral-toast a > p {
|
||||
.gh-sidebar-banner a > p {
|
||||
margin: 0;
|
||||
font-size: 1.5rem;
|
||||
line-height: 1.35em;
|
||||
@ -2192,22 +2196,115 @@ section.gh-ds h2 {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.gh-referral-toast a > p strong {
|
||||
.gh-sidebar-banner a > p strong {
|
||||
color: #ff247d;
|
||||
}
|
||||
|
||||
.gh-referral-toast-button {
|
||||
.gh-sidebar-banner-button {
|
||||
margin-top: 20px;
|
||||
border-radius: 5px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.gh-referral-toast-button span {
|
||||
.gh-sidebar-banner-button span {
|
||||
padding: 0 12px;
|
||||
font-size: 1.4rem;
|
||||
text-align-last: center;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
}
|
||||
|
||||
.gh-sidebar-banner-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.gh-sidebar-banner-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.gh-sidebar-banner-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 6px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.gh-sidebar-banner-subhead {
|
||||
font-size: 13px;
|
||||
color: var(--midgrey);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.gh-sidebar-banner a .gh-sidebar-banner-msg {
|
||||
line-height: 1.4em;
|
||||
font-weight: 600;
|
||||
margin-top: -2px;
|
||||
margin-bottom: 0;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.gh-sidebar-banner-details {
|
||||
line-height: 1.4em;
|
||||
font-size: 1.35rem;
|
||||
margin: 5px 0 0;
|
||||
color: var(--darkgrey);
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.gh-sidebar-banner-msg + .gh-sidebar-banner-button {
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.gh-referral-toast {
|
||||
padding: 25px;
|
||||
margin: 0 0 50px;
|
||||
}
|
||||
|
||||
.gh-referral-toast .gh-sidebar-banner-close {
|
||||
top: 7px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.gh-sidebar-banner.gh-error-banner {
|
||||
box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.1), 0px 3px 8px 0px rgba(0, 0, 0, 0.06);
|
||||
margin-bottom: 32px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.gh-sidebar-banner.gh-error-banner .gh-sidebar-banner-container {
|
||||
flex-direction: row;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.gh-sidebar-banner.gh-error-banner .gh-sidebar-banner-icon {
|
||||
color: var(--red);
|
||||
}
|
||||
|
||||
.gh-sidebar-banner.gh-error-banner .gh-sidebar-banner-subhead {
|
||||
color: var(--red);
|
||||
font-size: 1.4rem;
|
||||
font-weight: 600;
|
||||
display: block;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.gh-sidebar-banner.gh-error-banner .gh-sidebar-banner-msg {
|
||||
font-weight: 400;
|
||||
font-size: 1.3rem;
|
||||
margin-top: 4px;
|
||||
color: var(--darkgrey);
|
||||
}
|
||||
|
||||
.gh-sidebar-banner.gh-error-banner .gh-sidebar-banner-button {
|
||||
color: var(--white);
|
||||
background-color: var(--red);
|
||||
}
|
||||
|
||||
.admin-x-container-error {
|
||||
|
150
ghost/admin/app/styles/layouts/whatsnew-modal.css
Normal file
150
ghost/admin/app/styles/layouts/whatsnew-modal.css
Normal file
@ -0,0 +1,150 @@
|
||||
/* What's new modal */
|
||||
/* ---------------------------------------------------------- */
|
||||
.fullscreen-modal-whatsnew,
|
||||
.fullscreen-modal-whatsnew-featured {
|
||||
max-height: calc(100vh - 12vw);
|
||||
overflow-y: auto;
|
||||
border-radius: 8px !important;
|
||||
}
|
||||
|
||||
@media (max-height: 960px) {
|
||||
.fullscreen-modal-whatsnew,
|
||||
.fullscreen-modal-whatsnew-featured {
|
||||
max-height: calc(100vh - 80px);
|
||||
}
|
||||
}
|
||||
|
||||
.fullscreen-modal-whatsnew {
|
||||
max-width: 640px !important;
|
||||
}
|
||||
|
||||
.fullscreen-modal-whatsnew a:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.gh-whatsnew-modal-entries {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.fullscreen-modal-whatsnew .modal-content,
|
||||
.fullscreen-modal-whatsnew-featured .modal-content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.gh-whatsnew-featured-container,
|
||||
.gh-whatsnew-modal-entries {
|
||||
padding: 0 32px;
|
||||
}
|
||||
|
||||
.gh-whatsnew-featured-subhead {
|
||||
margin-bottom: 12px;
|
||||
font-size: 1.3rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.gh-whatsnew-featured-date {
|
||||
font-weight: 500;
|
||||
color: var(--midgrey);
|
||||
}
|
||||
|
||||
.gh-whasnew-featured-title {
|
||||
font-size: 2.8rem;
|
||||
}
|
||||
|
||||
.gh-whatsnew-featured-excerpt {
|
||||
margin: 0 0 24px;
|
||||
font-size: 1.6rem;
|
||||
line-height: 1.35em;
|
||||
}
|
||||
|
||||
.gh-whatsnew-modal-footer {
|
||||
z-index: 999;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: sticky;
|
||||
bottom: 0px;
|
||||
background: #fff;
|
||||
padding: 32px;
|
||||
margin-bottom: -32px;
|
||||
box-shadow: 0px -7px 15px -10px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.gh-whatsnew-modal-footer {
|
||||
bottom: -10px;
|
||||
}
|
||||
}
|
||||
|
||||
.gh-whatsnew-modal {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.gh-whasnew-modal-title {
|
||||
font-size: 2.5rem;
|
||||
padding: 32px 32px 28px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.gh-whatsnew-modal-entry {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 24px;
|
||||
color: var(--black);
|
||||
margin: -8px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.gh-whatsnew-modal-entry:hover {
|
||||
background: var(--whitegrey-l2);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.gh-whatsnew-modal-entry-featureimage {
|
||||
max-width: 160px;
|
||||
height: 110px;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.gh-whatsnew-modal-entrycontent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.gh-whatsnew-modal-entrycontent h2 {
|
||||
font-size: 1.7rem;
|
||||
margin: 6px 0 0;
|
||||
}
|
||||
|
||||
.gh-whatsnew-modal-entrycontent p {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
line-height: 1.45em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.gh-whatsnew-modal-entrycontent span {
|
||||
color: var(--midgrey);
|
||||
}
|
||||
|
||||
.gh-whatsnew-modal-entrycontent img {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.gh-whatsnew-banner-icon {
|
||||
color: var(--yellow);
|
||||
}
|
||||
|
||||
.dropdown-item .gh-whatsnew-banner-icon {
|
||||
margin-right: 0 !important;
|
||||
}
|
@ -1925,4 +1925,4 @@
|
||||
.gh-whats-new .kg-header-card.kg-style-accent a.kg-header-card-button {
|
||||
background: #fff;
|
||||
color: #151515;
|
||||
}
|
||||
}
|
1
ghost/admin/public/assets/icons/sparkle-fill.svg
Normal file
1
ghost/admin/public/assets/icons/sparkle-fill.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" id="Reward-Stars-3--Streamline-Ultimate" height="24" width="24"><desc>Reward Stars 3 Streamline Icon: https://streamlinehq.com</desc><path fill="currentColor" fill-rule="evenodd" d="M17.66 1.143a0.75 0.75 0 0 1 1.451 0c0.33 1.262 0.693 2.037 1.235 2.61 0.546 0.577 1.344 1.027 2.705 1.484a0.75 0.75 0 0 1 0 1.422c-1.36 0.457 -2.16 0.907 -2.705 1.484 -0.542 0.574 -0.904 1.348 -1.235 2.61a0.75 0.75 0 0 1 -1.45 0c-0.331 -1.262 -0.694 -2.036 -1.236 -2.61 -0.545 -0.577 -1.344 -1.027 -2.705 -1.484a0.75 0.75 0 0 1 0 -1.422c1.361 -0.457 2.16 -0.907 2.705 -1.483 0.542 -0.574 0.905 -1.35 1.235 -2.61ZM8.052 5.322a0.75 0.75 0 0 1 1.451 0c0.595 2.283 1.27 3.774 2.33 4.9 1.062 1.129 2.584 1.967 5.031 2.792a0.75 0.75 0 0 1 0 1.422c-2.447 0.824 -3.969 1.663 -5.031 2.792 -1.06 1.126 -1.735 2.617 -2.33 4.9a0.75 0.75 0 0 1 -1.451 0c-0.596 -2.283 -1.27 -3.774 -2.33 -4.9C4.659 16.099 3.138 15.26 0.69 14.436a0.75 0.75 0 0 1 0 -1.422c2.448 -0.825 3.97 -1.663 5.032 -2.792 1.06 -1.126 1.734 -2.617 2.33 -4.9Zm11.85 10.147a0.75 0.75 0 0 0 -0.725 0.556c-0.24 0.9 -0.497 1.421 -0.863 1.8 -0.37 0.384 -0.926 0.698 -1.923 1.026a0.75 0.75 0 0 0 0 1.425c0.997 0.327 1.553 0.641 1.923 1.025 0.366 0.38 0.623 0.9 0.863 1.8a0.75 0.75 0 0 0 1.45 0c0.24 -0.9 0.496 -1.42 0.862 -1.8 0.37 -0.384 0.926 -0.698 1.923 -1.025a0.75 0.75 0 0 0 0 -1.425c-0.997 -0.328 -1.553 -0.642 -1.923 -1.026 -0.366 -0.379 -0.622 -0.9 -0.863 -1.8a0.75 0.75 0 0 0 -0.724 -0.556Z" clip-rule="evenodd" stroke-width="1"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
1
ghost/admin/public/assets/icons/warning-fill.svg
Normal file
1
ghost/admin/public/assets/icons/warning-fill.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="Road-Sign-Warning--Streamline-Ultimate" height="24" width="24"><desc>Road Sign Warning Streamline Icon: https://streamlinehq.com</desc><path d="M23.25 23.23a0.75 0.75 0 0 0 0.66 -1.1l-11.25 -21a0.78 0.78 0 0 0 -1.32 0l-11.25 21a0.73 0.73 0 0 0 0 0.74 0.73 0.73 0 0 0 0.64 0.36ZM12 20.48A1.5 1.5 0 1 1 13.5 19a1.5 1.5 0 0 1 -1.5 1.48Zm0 -12.25a1 1 0 0 1 1 1v5.47a1 1 0 0 1 -2 0V9.23a1 1 0 0 1 1 -1Z" fill="currentColor" stroke-width="1"></path></svg>
|
After Width: | Height: | Size: 513 B |
Loading…
Reference in New Issue
Block a user