Skip to content
This repository has been archived by the owner on Nov 28, 2022. It is now read-only.

Commit

Permalink
✨ Added UI for setting tag metadata (#1632)
Browse files Browse the repository at this point in the history
no-issue

* Updated tag model with new metadata fields
* Updated Tag setting UI to handle metadata

Co-authored-by: Peter Zimon <zimo@ghost.org>
  • Loading branch information
allouis and peterzimon committed Jul 13, 2020
1 parent 8d3f4af commit bd47744
Show file tree
Hide file tree
Showing 6 changed files with 470 additions and 78 deletions.
367 changes: 305 additions & 62 deletions app/components/gh-tag-settings-form.hbs

Large diffs are not rendered by default.

115 changes: 108 additions & 7 deletions app/components/gh-tag-settings-form.js
Expand Up @@ -2,6 +2,8 @@ import Component from '@ember/component';
import Ember from 'ember';
import {computed} from '@ember/object';
import {htmlSafe} from '@ember/string';
import {or} from '@ember/object/computed';
import {run} from '@ember/runloop';
import {inject as service} from '@ember/service';

const {Handlebars} = Ember;
Expand All @@ -16,6 +18,27 @@ export default Component.extend({
// Allowed actions
setProperty: () => {},

twitterTitle: or('scratchTag.twitterTitle', 'seoTitle'),
twitterDescription: or('scratchTag.twitterDescription', 'seoDescription'),
twitterImage: or('tag.twitterImage', 'tag.featureImage'),

facebookTitle: or('scratchTag.ogTitle', 'seoTitle'),
facebookDescription: or('scratchTag.ogDescription', 'seoDescription'),
facebookImage: or('tag.ogImage', 'tag.featureImage'),

accentColor: computed('tag.accentColor', function () {
let color = this.get('tag.accentColor');
if (color && color[0] === '#') {
return color.slice(1);
}
return color;
}),

accentColorBackgroundStyle: computed('tag.accentColor', function () {
let color = this.get('tag.accentColor') || '#ffffff';
return htmlSafe(`background-color: ${color}`);
}),

title: computed('tag.isNew', function () {
if (this.get('tag.isNew')) {
return 'New tag';
Expand All @@ -24,10 +47,8 @@ export default Component.extend({
}
}),

seoTitle: computed('scratchTag.{title,metaTitle}', function () {
let metaTitle = this.scratchTag.metaTitle || '';

metaTitle = metaTitle.length > 0 ? metaTitle : this.scratchTag.title;
seoTitle: computed('scratchTag.{name,metaTitle}', function () {
let metaTitle = this.scratchTag.metaTitle || this.scratchTag.name;

if (metaTitle && metaTitle.length > 70) {
metaTitle = metaTitle.substring(0, 70).trim();
Expand All @@ -38,14 +59,15 @@ export default Component.extend({
return metaTitle;
}),

seoURL: computed('scratchTag.slug', function () {
seoURL: computed('scratchTag.{canonicalUrl,slug}', function () {
let blogUrl = this.get('config.blogUrl');
let seoSlug = this.scratchTag.slug || '';

let seoURL = `${blogUrl}/tag/${seoSlug}`;
let seoURL = this.scratchTag.canonicalUrl || `${blogUrl}/tag/${seoSlug}`;

// only append a slash to the URL if the slug exists
if (seoSlug) {

if (!seoURL.endsWith('/')) {
seoURL += '/';
}

Expand Down Expand Up @@ -77,12 +99,91 @@ export default Component.extend({
this.setProperty(property, value);
},

setTwitterImage(image) {
this.setProperty('twitterImage', image);
},

clearTwitterImage() {
this.setProperty('twitterImage', '');
},

setOgImage(image) {
this.setProperty('ogImage', image);
},

clearOgImage() {
this.setProperty('ogImage', '');
},

setCoverImage(image) {
this.setProperty('featureImage', image);
},

clearCoverImage() {
this.setProperty('featureImage', '');
},

validateCanonicalUrl() {
let newUrl = this.get('scratchTag.canonicalUrl');
let oldUrl = this.get('tag.canonicalUrl');
let errMessage = '';

this.get('tag.errors').remove('canonicalUrl');
this.get('tag.hasValidated').removeObject('canonicalUrl');

if (newUrl === '') {
this.setProperty('canonicalUrl', '');
return;
}

if (!newUrl) {
newUrl = oldUrl;
}

try {
new URL(newUrl);
this.setProperty('canonicalUrl', '');
run.schedule('afterRender', this, function () {
this.setProperty('canonicalUrl', newUrl);
});
} catch (err) {
errMessage = 'The url should be a valid url';
this.get('tag.errors').add('canonicalUrl', errMessage);
this.get('tag.hasValidated').pushObject('canonicalUrl');
}
},

validateAccentColor() {
let newColor = this.get('accentColor');
let oldColor = this.get('tag.accentColor');
let errMessage = '';

this.get('tag.errors').remove('accentColor');
this.get('tag.hasValidated').removeObject('accentColor');

if (newColor === '') {
this.setProperty('accentColor', '');
return;
}

if (!newColor) {
newColor = oldColor;
}

if (newColor[0] !== '#') {
newColor = `#${newColor}`;
}

if (newColor.match(/#[0-9A-Fa-f]{6}$/)) {
this.setProperty('accentColor', '');
run.schedule('afterRender', this, function () {
this.setProperty('accentColor', newColor);
});
} else {
errMessage = 'The color should be in valid hex format';
this.get('tag.errors').add('accentColor', errMessage);
this.get('tag.hasValidated').pushObject('accentColor');
}
}
}
});
3 changes: 3 additions & 0 deletions app/controllers/tag.js
Expand Up @@ -88,6 +88,9 @@ export default Controller.extend({
tag.setProperties(scratchProps);

try {
if (tag.get('errors').length !== 0) {
return;
}
yield tag.save();

// replace 'new' route with 'tag' route
Expand Down
10 changes: 10 additions & 0 deletions app/models/tag.js
Expand Up @@ -12,6 +12,16 @@ export default Model.extend(ValidationEngine, {
parent: attr('string'), // unused
metaTitle: attr('string'),
metaDescription: attr('string'),
twitterImage: attr('string'),
twitterTitle: attr('string'),
twitterDescription: attr('string'),
ogImage: attr('string'),
ogTitle: attr('string'),
ogDescription: attr('string'),
codeinjectionHead: attr('string'),
codeinjectionFoot: attr('string'),
canonicalUrl: attr('string'),
accentColor: attr('string'),
featureImage: attr('string'),
visibility: attr('string', {defaultValue: 'public'}),
createdAtUTC: attr('moment-utc'),
Expand Down
18 changes: 9 additions & 9 deletions app/styles/layouts/settings.css
Expand Up @@ -813,8 +813,8 @@ p.theme-validation-details {
.input-color:after {
content: "#";
position: absolute;
top: 6px;
left: 40px;
top: 9px;
left: 43px;
color: var(--midlightgrey);
font-family: "Consolas", monaco, monospace;
font-size: 13px;
Expand All @@ -825,9 +825,9 @@ p.theme-validation-details {
}

.input-color input {
padding-left: 48px;
width: 110px;
height: 33px;
padding-left: 52px;
width: 112px;
height: 38px;
padding-right: 8px;
font-family: "Consolas", monaco, monospace;
font-size: 13px;
Expand All @@ -837,8 +837,8 @@ p.theme-validation-details {
position: absolute;
top: 1px;
left: 1px;
width: 31px;
height: 31px;
width: 36px;
height: 36px;
display: inline-block;
background-color: var(--lightgrey);
border-top-left-radius: 4px;
Expand All @@ -850,8 +850,8 @@ p.theme-validation-details {
.input-color input:focus + .color-box {
top: 2px;
left: 2px;
width: 30px;
height: 29px;
width: 35px;
height: 34px;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
35 changes: 35 additions & 0 deletions app/styles/layouts/tags.css
Expand Up @@ -138,4 +138,39 @@ textarea.gh-tag-details-textarea {
margin: 4px 0 0;
border: 1px solid var(--lightgrey);
min-height: 147px;
}

.gh-tag-setting-codeinjection .CodeMirror {
padding: 0 !important;
min-height: 240px;
}

.gh-tag-setting-codeinjection .CodeMirror-scroll {
min-height: 240px;
}

label.gh-tag-setting-codeheader {
font-size: 1.3rem;
display: flex;
align-items: center;
}

.gh-tag-settings-multiprop {
display: flex;
max-width: 620px;
width: 100%;
}

.gh-tag-settings-colorcontainer {
flex-basis: 112px;
}

@media (max-width: 1080px) {
.gh-tag-settings-multiprop {
flex-direction: column;
}

.gh-tag-settings-colorcontainer {
flex-basis: unset;
}
}

0 comments on commit bd47744

Please sign in to comment.