mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-10 23:36:14 -05:00
Added TK support to feature image caption editor (#19285)
closes https://github.com/TryGhost/Product/issues/4227 - added `@onTKCountChange` to `<KoenigLexicalEditorInput>` - when present the `isTKEnabled` flag will be turned on and the `<TKCountPlugin>` registered - added `@registerAPI` support to `<KoenigLexicalEditorInput>` so we can focus the caption editor when its TK indicator is clicked - added manual display of TK indicator for the caption input - default editor indicator positioning doesn't work for this input because its container is not full editor width - hid it by adding `overflow: hidden` to the inner caption container - added custom indicator button shown when we have a non-zero count
This commit is contained in:
parent
e5c6b0a23f
commit
309aaf98aa
7 changed files with 57 additions and 5 deletions
|
@ -50,7 +50,7 @@
|
||||||
{{svg-jar "koenig/kg-trash"}}
|
{{svg-jar "koenig/kg-trash"}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between align-center">
|
<div class="relative flex justify-between align-center">
|
||||||
{{#if this.isEditingAlt}}
|
{{#if this.isEditingAlt}}
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
@ -70,6 +70,8 @@
|
||||||
@placeholderText={{if this.captionInputFocused "" "Add a caption to the feature image"}}
|
@placeholderText={{if this.captionInputFocused "" "Add a caption to the feature image"}}
|
||||||
@onFocus={{fn (mut this.captionInputFocused) true}}
|
@onFocus={{fn (mut this.captionInputFocused) true}}
|
||||||
@onBlur={{this.handleCaptionBlur}}
|
@onBlur={{this.handleCaptionBlur}}
|
||||||
|
@onTKCountChange={{this.onTKCountChange}}
|
||||||
|
@registerAPI={{this.registerEditorAPI}}
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<button
|
<button
|
||||||
|
@ -78,6 +80,12 @@
|
||||||
>
|
>
|
||||||
Alt
|
Alt
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{{#if (and this.tkCount (not this.isEditingAlt))}}
|
||||||
|
<div class="tk-indicator" data-testid="feature-image-tk-indicator" role="button" {{on "click" this.focusCaptionEditor}}>
|
||||||
|
TK
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{!-- no-image state --}}
|
{{!-- no-image state --}}
|
||||||
|
|
|
@ -18,6 +18,7 @@ export default class GhEditorFeatureImageComponent extends Component {
|
||||||
@tracked captionInputFocused = false;
|
@tracked captionInputFocused = false;
|
||||||
@tracked showUnsplashSelector = false;
|
@tracked showUnsplashSelector = false;
|
||||||
@tracked canDrop = false;
|
@tracked canDrop = false;
|
||||||
|
@tracked tkCount = 0;
|
||||||
|
|
||||||
get caption() {
|
get caption() {
|
||||||
const content = this.args.caption;
|
const content = this.args.caption;
|
||||||
|
@ -34,6 +35,18 @@ export default class GhEditorFeatureImageComponent extends Component {
|
||||||
this.args.updateCaption(cleanedHtml);
|
this.args.updateCaption(cleanedHtml);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
registerEditorAPI(API) {
|
||||||
|
this.editorAPI = API;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
focusCaptionEditor() {
|
||||||
|
if (this.editorAPI) {
|
||||||
|
this.editorAPI.focusEditor({position: 'bottom'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
handleCaptionBlur() {
|
handleCaptionBlur() {
|
||||||
this.captionInputFocused = false;
|
this.captionInputFocused = false;
|
||||||
|
@ -116,4 +129,12 @@ export default class GhEditorFeatureImageComponent extends Component {
|
||||||
this.canDrop = false;
|
this.canDrop = false;
|
||||||
setFiles([imageFile]);
|
setFiles([imageFile]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
onTKCountChange(count) {
|
||||||
|
if (this.args.onTKCountChange) {
|
||||||
|
this.tkCount = count;
|
||||||
|
this.args.onTKCountChange(count);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
@handleCaptionBlur={{@handleFeatureImageCaptionBlur}}
|
@handleCaptionBlur={{@handleFeatureImageCaptionBlur}}
|
||||||
@forceButtonDisplay={{or (not @title) (eq @title "(Untitled)") this.titleIsHovered this.titleIsFocused}}
|
@forceButtonDisplay={{or (not @title) (eq @title "(Untitled)") this.titleIsHovered this.titleIsFocused}}
|
||||||
@isHidden={{or (not @cardOptions.post.showTitleAndFeatureImage) false}}
|
@isHidden={{or (not @cardOptions.post.showTitleAndFeatureImage) false}}
|
||||||
|
@onTKCountChange={{@updateFeatureImageTkCount}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="gh-editor-title-container page-improvements">
|
<div class="gh-editor-title-container page-improvements">
|
||||||
|
|
|
@ -57,6 +57,11 @@ const EmojiPickerPlugin = ({editorResource, ...props}) => {
|
||||||
return <_EmojiPickerPlugin {...props} />;
|
return <_EmojiPickerPlugin {...props} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const TKCountPlugin = ({editorResource, ...props}) => {
|
||||||
|
const {TKCountPlugin: _TKCountPlugin} = editorResource.read();
|
||||||
|
return <_TKCountPlugin {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
export default class KoenigLexicalEditorInput extends Component {
|
export default class KoenigLexicalEditorInput extends Component {
|
||||||
@service ajax;
|
@service ajax;
|
||||||
@service feature;
|
@service feature;
|
||||||
|
@ -100,6 +105,7 @@ export default class KoenigLexicalEditorInput extends Component {
|
||||||
editorResource={this.editorResource}
|
editorResource={this.editorResource}
|
||||||
initialEditorState={this.args.lexical}
|
initialEditorState={this.args.lexical}
|
||||||
onError={this.onError}
|
onError={this.onError}
|
||||||
|
isTKEnabled={this.args.onTKCountChange ? true : false}
|
||||||
>
|
>
|
||||||
<KoenigComposableEditor
|
<KoenigComposableEditor
|
||||||
editorResource={this.editorResource}
|
editorResource={this.editorResource}
|
||||||
|
@ -112,9 +118,11 @@ export default class KoenigLexicalEditorInput extends Component {
|
||||||
className={`koenig-lexical-editor-input ${this.feature.nightShift ? 'dark' : ''}`}
|
className={`koenig-lexical-editor-input ${this.feature.nightShift ? 'dark' : ''}`}
|
||||||
placeholderText={props.placeholderText}
|
placeholderText={props.placeholderText}
|
||||||
placeholderClassName="koenig-lexical-editor-input-placeholder"
|
placeholderClassName="koenig-lexical-editor-input-placeholder"
|
||||||
|
registerAPI={this.args.registerAPI}
|
||||||
>
|
>
|
||||||
<HtmlOutputPlugin editorResource={this.editorResource} html={props.html} setHtml={props.onChangeHtml} />
|
<HtmlOutputPlugin editorResource={this.editorResource} html={props.html} setHtml={props.onChangeHtml} />
|
||||||
{this.emojiPicker ? <EmojiPickerPlugin editorResource={this.editorResource} /> : null}
|
{this.emojiPicker ? <EmojiPickerPlugin editorResource={this.editorResource} /> : null}
|
||||||
|
{this.args.onTKCountChange ? <TKCountPlugin editorResource={this.editorResource} onChange={this.args.onTKCountChange} /> : null}
|
||||||
</KoenigComposableEditor>
|
</KoenigComposableEditor>
|
||||||
</KoenigComposer>
|
</KoenigComposer>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|
|
@ -131,6 +131,7 @@ export default class LexicalEditorController extends Controller {
|
||||||
// koenig related properties
|
// koenig related properties
|
||||||
wordCount = 0;
|
wordCount = 0;
|
||||||
postTkCount = 0;
|
postTkCount = 0;
|
||||||
|
featureImageTkCount = 0;
|
||||||
|
|
||||||
/* private properties ----------------------------------------------------*/
|
/* private properties ----------------------------------------------------*/
|
||||||
|
|
||||||
|
@ -262,9 +263,9 @@ export default class LexicalEditorController extends Controller {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed('titleHasTk', 'postTkCount')
|
@computed('titleHasTk', 'postTkCount', 'featureImageTkCount')
|
||||||
get tkCount() {
|
get tkCount() {
|
||||||
return (this.titleHasTk ? 1 : 0) + this.postTkCount;
|
return (this.titleHasTk ? 1 : 0) + this.postTkCount + this.featureImageTkCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -368,6 +369,11 @@ export default class LexicalEditorController extends Controller {
|
||||||
this.set('postTkCount', count);
|
this.set('postTkCount', count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
updateFeatureImageTkCount(count) {
|
||||||
|
this.set('featureImageTkCount', count);
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
setFeatureImage(url) {
|
setFeatureImage(url) {
|
||||||
this.post.set('featureImage', url);
|
this.post.set('featureImage', url);
|
||||||
|
@ -1135,6 +1141,7 @@ export default class LexicalEditorController extends Controller {
|
||||||
this.set('showSettingsMenu', false);
|
this.set('showSettingsMenu', false);
|
||||||
this.set('wordCount', 0);
|
this.set('wordCount', 0);
|
||||||
this.set('postTkCount', 0);
|
this.set('postTkCount', 0);
|
||||||
|
this.set('featureImageTkCount', 0);
|
||||||
|
|
||||||
// remove the onbeforeunload handler as it's only relevant whilst on
|
// remove the onbeforeunload handler as it's only relevant whilst on
|
||||||
// the editor route
|
// the editor route
|
||||||
|
|
|
@ -635,6 +635,7 @@ body[data-user-is-dragging] .gh-editor-feature-image-dropzone {
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
transition: border-color .15s linear;
|
transition: border-color .15s linear;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
|
overflow: hidden; /* Hides any indicators such as TK */
|
||||||
}
|
}
|
||||||
|
|
||||||
.gh-editor-feature-image-alttext::placeholder,
|
.gh-editor-feature-image-alttext::placeholder,
|
||||||
|
@ -683,7 +684,7 @@ body[data-user-is-dragging] .gh-editor-feature-image-dropzone {
|
||||||
opacity: .5;
|
opacity: .5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gh-editor-title-container .tk-indicator {
|
.gh-editor .tk-indicator {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 15px;
|
top: 15px;
|
||||||
right: -5.6rem;
|
right: -5.6rem;
|
||||||
|
@ -691,7 +692,12 @@ body[data-user-is-dragging] .gh-editor-feature-image-dropzone {
|
||||||
color: #95A1AD;
|
color: #95A1AD;
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
cursor: default;
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gh-editor-feature-image-container .tk-indicator {
|
||||||
|
top: 0;
|
||||||
|
padding: 0 .4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gh-editor-back-button {
|
.gh-editor-back-button {
|
||||||
|
|
|
@ -79,6 +79,7 @@
|
||||||
@onEditorCreated={{this.setKoenigEditor}}
|
@onEditorCreated={{this.setKoenigEditor}}
|
||||||
@updateWordCount={{this.updateWordCount}}
|
@updateWordCount={{this.updateWordCount}}
|
||||||
@updatePostTkCount={{this.updatePostTkCount}}
|
@updatePostTkCount={{this.updatePostTkCount}}
|
||||||
|
@updateFeatureImageTkCount={{if (feature "tkReminders") this.updateFeatureImageTkCount}}
|
||||||
@featureImage={{this.post.featureImage}}
|
@featureImage={{this.post.featureImage}}
|
||||||
@featureImageAlt={{this.post.featureImageAlt}}
|
@featureImageAlt={{this.post.featureImageAlt}}
|
||||||
@featureImageCaption={{this.post.featureImageCaption}}
|
@featureImageCaption={{this.post.featureImageCaption}}
|
||||||
|
|
Loading…
Add table
Reference in a new issue