Ghost-Admin/app/templates/settings/general.hbs

518 lines
32 KiB
Handlebars
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<section class="gh-canvas">
<div>
<GhCanvasHeader class="gh-canvas-header">
<h2 class="gh-canvas-title" data-test-screen-title>
General settings
</h2>
<section class="view-actions">
<GhTaskButton @buttonText="Save settings" @task={{this.save}} @class="gh-btn gh-btn-blue gh-btn-icon" data-test-save-button="true" />
</section>
</GhCanvasHeader>
{{#if this.showLeaveSettingsModal}}
<GhFullscreenModal @modal="leave-settings"
@confirm={{action "leaveSettings"}}
@close={{action "toggleLeaveSettingsModal"}}
@modifier="action wide" />
{{/if}}
<section class="view-container">
<div class="gh-setting-header gh-first-header">Publication info</div>
<div class="flex flex-column br3 shadow-1 bg-grouped-table pa5 mt2">
<div class="gh-setting-first">
<div class="gh-setting-content">
<div class="gh-setting-title">Title &amp; description</div>
<div class="gh-setting-desc">The details used to identify your publication around the web</div>
{{#liquid-if this.pubInfoOpen}}
<div class="gh-setting-content-extended">
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{this.settings.hasValidated}} @property="title">
<GhTextInput
@value={{readonly this.settings.title}}
@input={{action (mut this.settings.title) value="target.value"}}
@focus-out={{action "validate" "title" target=this.settings}}
data-test-title-input={{true}}
/>
<GhErrorMessage @errors={{this.settings.errors}} @property="title" />
<p>The name of your site</p>
</GhFormGroup>
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{this.settings.hasValidated}} @property="description" @class="description-container">
<GhTextInput
@value={{readonly this.settings.description}}
@input={{action (mut this.settings.description) value="target.value"}}
@focus-out={{action "validate" "description" target=this.settings}}
data-test-description-input={{true}}
/>
<GhErrorMessage @errors={{this.settings.errors}} @property="description"/>
<p>Used in your theme, meta data and search results</p>
</GhFormGroup>
</div>
{{/liquid-if}}
</div>
<div class="gh-setting-action">
<button type="button" class="gh-btn" {{action (toggle "pubInfoOpen" this)}} data-test-toggle-pub-info><span>{{if this.pubInfoOpen "Close" "Expand"}}</span></button>
</div>
</div>
<div class="gh-setting">
<div class="gh-setting-content">
<div class="gh-setting-title">Site timezone</div>
<div class="gh-setting-desc">Set the time and date of your publication, used for all published posts</div>
{{#liquid-if this.timezoneOpen}}
<div class="gh-setting-content-extended">
<GhTimezoneSelect
@timezone={{this.settings.timezone}}
@availableTimezones={{this.availableTimezones}}
@update={{action "setTimezone"}} />
</div>
{{/liquid-if}}
</div>
<div class="gh-setting-action">
<button type="button" class="gh-btn" {{action (toggle "timezoneOpen" this)}} data-test-toggle-timezone><span>{{if this.timezoneOpen "Close" "Expand"}}</span></button>
</div>
</div>
<div class="gh-setting-last">
<div class="gh-setting-content">
<div class="gh-setting-title">Publication Language</div>
<div class="gh-setting-desc">Set the language/locale which is used on your site</div>
{{#liquid-if this.langOpen}}
<div class="gh-setting-content-extended">
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{this.settings.hasValidated}} @property="lang">
<GhTextInput
@value={{readonly this.settings.lang}}
@input={{action (mut this.settings.lang) value="target.value"}}
@focus-out={{action "validate" "lang" target=this.settings}}
data-test-input="lang"
/>
<GhErrorMessage @errors={{this.settings.errors}} @property="lang" />
<p>Default: English (<strong>en</strong>); you can add translation files to your theme for <a href="https://ghost.org/docs/api/handlebars-themes/helpers/translate/" target="_blank" rel="noopener">any language</a></p>
</GhFormGroup>
</div>
{{/liquid-if}}
</div>
<div class="gh-setting-action">
<button type="button" class="gh-btn" {{action (toggle "langOpen" this)}} data-test-toggle-lang><span>{{if this.langOpen "Close" "Expand"}}</span></button>
</div>
</div>
</div>
<div class="gh-setting-header">Publication identity</div>
<div class="flex flex-column br3 shadow-1 bg-grouped-table pa5">
<div class="gh-setting-first" data-test-setting="icon">
<GhUploader
@extensions={{this.iconExtensions}}
@paramsHash={{hash purpose="icon"}}
@onComplete={{action "imageUploaded" "icon"}}
as |uploader|
>
<div class="gh-setting-content">
<div class="gh-setting-title">Publication icon</div>
<div class="gh-setting-desc">A square, social icon used in the UI of your publication, at least 60x60px</div>
{{#each uploader.errors as |error|}}
<div class="gh-setting-error" data-test-error="icon">{{or error.context error.message}}</div>
{{/each}}
</div>
<div class="gh-setting-action gh-setting-action-smallimg">
{{#if uploader.isUploading}}
{{uploader.progressBar}}
{{else if this.settings.icon}}
<img class="blog-icon" src="{{this.settings.icon}}" onclick={{action "triggerFileDialog"}} alt="icon" data-test-icon-img>
<button type="button" class="gh-setting-action-smallimg-delete" {{action "removeImage" "icon"}} data-test-delete-image="icon">
<span>delete</span>
</button>
{{else}}
<button type="button" class="gh-btn" onclick={{action "triggerFileDialog"}} data-test-image-upload-btn="icon">
<span>Upload Image</span>
</button>
{{/if}}
<div style="display:none">
<GhFileInput @multiple={{false}} @action={{uploader.setFiles}} @accept={{this.iconMimeTypes}} data-test-file-input="icon" />
</div>
</div>
</GhUploader>
</div>
<div class="gh-setting" data-test-setting="logo">
<GhUploader
@extensions={{this.imageExtensions}}
@onComplete={{action "imageUploaded" "logo"}}
as |uploader|
>
<div class="gh-setting-content">
<div class="gh-setting-title">Publication logo</div>
<div class="gh-setting-desc">The primary logo for your brand displayed across your theme, should be transparent and at least 600px x 72px</div>
{{#each uploader.errors as |error|}}
<div class="gh-setting-error" data-test-error="logo">{{or error.context error.message}}</div>
{{/each}}
</div>
<div class="gh-setting-action gh-setting-action-smallimg">
{{#if uploader.isUploading}}
{{uploader.progressBar}}
{{else if this.settings.logo}}
<img class="blog-logo" src="{{this.settings.logo}}" onclick={{action "triggerFileDialog"}} alt="logo" data-test-logo-img>
<button type="button" class="gh-setting-action-smallimg-delete" {{action "removeImage" "logo"}} data-test-delete-image="logo">
<span>delete</span>
</button>
{{else}}
<button type="button" class="gh-btn" onclick={{action "triggerFileDialog"}} data-test-image-upload-btn="logo">
<span>Upload Image</span>
</button>
{{/if}}
<div style="display:none">
<GhFileInput @multiple={{false}} @action={{uploader.setFiles}} @accept={{this.imageMimeTypes}} data-test-file-input="logo" />
</div>
</div>
</GhUploader>
</div>
{{#if this.config.enableDeveloperExperiments}}
<div class="gh-setting" data-test-setting="accent-color">
<div class="gh-setting-content">
<div class="gh-setting-title">Accent Color</div>
<div class="gh-setting-desc">Primary color used in your publication theme</div>
</div>
<div class="gh-setting-action">
<GhFormGroup @errors={{settings.errors}} @hasValidated={{settings.hasValidated}} @property="accentColor" @class="input-color-form-group">
<div class="input-color">
<GhTextInput
@name="accent-color"
@placeholder="abcdef"
@autocorrect="off"
@maxlength="6"
@focus-out={{action "validateAccentColor"}}
@value={{accentColor}}
data-test-input="accentColor"
/>
<div class="color-box" style={{this.backgroundStyle}}></div>
</div>
<GhErrorMessage @errors={{settings.errors}} @property="accentColor" data-test-error="accentColor" />
</GhFormGroup>
</div>
</div>
{{/if}}
<div class="gh-setting-last" data-test-setting="coverImage">
<GhUploader
@extensions={{this.imageExtensions}}
@onComplete={{action "imageUploaded" "coverImage"}}
as |uploader|
>
<div class="gh-setting-content">
<div class="gh-setting-title">Publication cover</div>
<div class="gh-setting-desc">An optional large background image for your site</div>
{{#each uploader.errors as |error|}}
<div class="gh-setting-error" data-test-error="coverImage">{{or error.context error.message}}</div>
{{/each}}
</div>
<div class="gh-setting-action gh-setting-action-largeimg">
{{#if uploader.isUploading}}
{{uploader.progressBar}}
{{else if this.settings.coverImage}}
<img class="blog-cover" src="{{this.settings.coverImage}}" onclick={{action "triggerFileDialog"}} alt="cover photo" data-test-cover-img>
<button type="button" class="gh-setting-action-largeimg-delete" {{action "removeImage" "coverImage"}} data-test-delete-image="coverImage">
<span>delete</span>
</button>
{{else}}
<button type="button" class="gh-btn" onclick={{action "triggerFileDialog"}} data-test-image-upload-btn="coverImage">
<span>Upload Image</span>
</button>
{{/if}}
<div style="display:none">
<GhFileInput @multiple={{false}} @action={{uploader.setFiles}} @accept={{this.imageMimeTypes}} data-test-file-input="coverImage" />
</div>
</div>
</GhUploader>
</div>
</div>
<div class="gh-setting-header">Site meta settings</div>
<div class="flex flex-column br3 shadow-1 bg-grouped-table pa5">
<div class="gh-setting-first flex-column">
<div class="flex flex-row justify-between w-100">
<div class="gh-setting-content">
<div class="gh-setting-title">Meta data</div>
<div class="gh-setting-desc">Extra content for search engines</div>
</div>
<div class="gh-setting-action">
<button type="button" class="gh-btn" {{action (toggle "metaDataOpen" this)}} data-test-toggle-meta><span>{{if this.metaDataOpen "Close" "Expand"}}</span></button>
</div>
</div>
{{#liquid-if this.metaDataOpen}}
<div class="gh-setting-content-extended">
<div class="flex flex-column flex-row-ns">
<div class="flex-basis-1-2-m flex-basis-2-3-l mr5">
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{this.settings.hasValidated}} @property="metaTitle">
<label for="metaTitle">Meta title</label>
<GhTextInput
@id="metaTitle"
@type="text"
@placeholder={{truncate this.settings.title 70}}
@value={{readonly this.settings.metaTitle}}
@input={{action (mut this.settings.metaTitle) value="target.value"}}
data-test-input="metaTitle"
/>
<GhErrorMessage @errors={{this.settings.errors}} @property="metaTitle" data-test-error="metaTitle" />
<p>Recommended: <b>70</b> characters. Youve used <b>{{gh-count-down-characters this.settings.metaTitle 70}}</b></p>
</GhFormGroup>
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{this.settings.hasValidated}} @property="metaDescription">
<label for="metaDescription">Meta description</label>
<GhTextarea
@id="metaDescription"
@type="text"
@placeholder={{truncate this.settings.description 300}}
@value={{readonly this.settings.metaDescription}}
@input={{action (mut this.settings.metaDescription) value="target.value"}}
data-test-input="metaDescription"
/>
<GhErrorMessage @errors={{this.settings.errors}} @property="metaDescription" data-test-error="metaDescription" />
<p>Recommended: <b>156</b> characters. Youve used <b>{{gh-count-down-characters this.settings.metaDescription 156}}</b></p>
</GhFormGroup>
</div>
<div class="flex-basis-1-2-m flex-basis-1-3-l">
<label>Search engine result preview</label>
<div class="seo-preview">
<div class="seo-preview-title">{{truncate (or this.settings.metaTitle this.settings.title) 70}}</div>
<div class="seo-preview-link">{{truncate this.config.blogUrl 70}}</div>
<div class="seo-preview-description">{{truncate (or this.settings.metaDescription this.settings.description) 300}}</div>
</div>
</div>
</div>
</div>
{{/liquid-if}}
</div>
<div class="gh-setting flex-column">
<div class="flex flex-row justify-between w-100">
<div class="gh-setting-content">
<div class="gh-setting-title">Twitter card</div>
<div class="gh-setting-desc">Customise structured data of your site for Twitter</div>
</div>
<div class="gh-setting-action">
<button type="button" class="gh-btn" {{action (toggle "twitterCardOpen" this)}} data-test-toggle-twitter><span>{{if this.twitterCardOpen "Close" "Expand"}}</span></button>
</div>
</div>
{{#liquid-if this.twitterCardOpen}}
<div class="gh-setting-content-extended">
<div class="flex flex-column flex-row-ns">
<div class="flex-basis-1-2-m flex-basis-2-3-l mr5 nudge-top--7">
<GhFormGroup>
<GhImageUploaderWithPreview
@image={{this.settings.twitterImage}}
@text="Add Twitter image"
@allowUnsplash={{true}}
@update={{action (mut this.settings.twitterImage)}}
@remove={{action (mut this.settings.twitterImage "")}}
/>
</GhFormGroup>
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{this.settings.hasValidated}} @property="twitterTitle">
<label for="twitterTitle">Twitter title</label>
<GhTextInput
@id="twitterTitle"
@type="text"
@placeholder={{truncate this.settings.title 70}}
@value={{readonly this.settings.twitterTitle}}
@input={{action (mut this.settings.twitterTitle) value="target.value"}}
data-test-input="twitterTitle"
/>
<GhErrorMessage @errors={{this.settings.errors}} @property="twitterTitle" data-test-error="twitterTitle" />
</GhFormGroup>
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{this.settings.hasValidated}} @property="twitterDescription">
<label for="twitterDescription">Twitter description</label>
<GhTextarea
@id="twitterDescription"
@placeholder={{truncate this.settings.description 300}}
@value={{readonly this.settings.twitterDescription}}
@input={{action (mut this.settings.twitterDescription) value="target.value"}}
data-test-input="twitterDescription"
/>
<GhErrorMessage @errors={{this.settings.errors}} @property="twitterDescription" data-test-error="twitterDescription" />
</GhFormGroup>
</div>
<div class="flex-basis-1-2-m flex-basis-1-3-l nt4-ns">
<label>Preview</label>
<div class="gh-twitter-preview">
{{#if this.settings.twitterImage}}
<div class="gh-twitter-preview-image" style={{background-image-style this.settings.twitterImage}}></div>
{{/if}}
<div class="gh-twitter-preview-content">
<div class="gh-twitter-preview-title">{{or this.settings.twitterTitle this.settings.title}}</div>
<div class="gh-twitter-preview-description">{{truncate (or this.settings.twitterDescription this.settings.description) 155}}</div>
<div class="gh-twitter-preview-footer">
<div class="gh-twitter-preview-footer-left">
{{this.config.blogDomain}}
</div>
<div class="gh-twitter-preview-footer-right">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{{/liquid-if}}
</div>
<div class="gh-setting-last flex-column">
<div class="flex flex-row justify-between w-100">
<div class="gh-setting-content">
<div class="gh-setting-title">Facebook card</div>
<div class="gh-setting-desc">Customise structured data of your site</div>
</div>
<div class="gh-setting-action">
<button type="button" class="gh-btn" {{action (toggle "facebookCardOpen" this)}} data-test-toggle-facebook><span>{{if this.facebookCardOpen "Close" "Expand"}}</span></button>
</div>
</div>
{{#liquid-if this.facebookCardOpen}}
<div class="gh-setting-content-extended">
<div class="flex flex-column flex-row-ns">
<div class="flex-basis-1-2-m flex-basis-2-3-l mr5 nudge-top--7">
<GhFormGroup>
<GhImageUploaderWithPreview
@image={{this.settings.ogImage}}
@text="Add Facebook image"
@allowUnsplash={{true}}
@update={{action (mut this.settings.ogImage)}}
@remove={{action (mut this.settings.ogImage "")}}
/>
</GhFormGroup>
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{this.settings.hasValidated}} @property="ogTitle">
<label for="ogTitle">Facebook title</label>
<GhTextInput
@id="ogTitle"
@type="text"
@placeholder={{truncate this.settings.title 70}}
@value={{readonly this.settings.ogTitle}}
@input={{action (mut this.settings.ogTitle) value="target.value"}}
data-test-input="ogTitle"
/>
<GhErrorMessage @errors={{this.settings.errors}} @property="ogTitle" data-test-error="ogTitle" />
</GhFormGroup>
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{this.settings.hasValidated}} @property="ogDescription">
<label for="ogDescription">Facebook description</label>
<GhTextarea
@id="ogDescription"
@placeholder={{truncate this.settings.description 300}}
@value={{readonly this.settings.ogDescription}}
@input={{action (mut this.settings.ogDescription) value="target.value"}}
data-test-input="ogDescription"
/>
<GhErrorMessage @errors={{this.settings.errors}} @property="ogDescription" data-test-error="ogDescription" />
</GhFormGroup>
</div>
<div class="flex-basis-1-2-m flex-basis-1-3-l nt4-ns">
<label>Preview</label>
<div class="gh-og-preview">
{{#if this.settings.ogImage}}
<div class="gh-og-preview-image" style={{background-image-style this.settings.ogImage}}></div>
{{/if}}
<div class="gh-og-preview-content">
<div class="gh-og-preview-title">{{truncate (or this.settings.ogTitle this.settings.title) 88}}</div>
<div class="gh-og-preview-description">{{truncate (or this.settings.ogDescription this.settings.description) 300}}</div>
<div class="gh-og-preview-footer">
<div class="gh-og-preview-footer-left">
{{this.config.blogDomain}}
</div>
<div class="gh-og-preview-footer-right"></div>
</div>
</div>
</div>
</div>
</div>
</div>
{{/liquid-if}}
</div>
</div>
<div class="gh-setting-header">Social accounts</div>
<div class="flex flex-column br3 shadow-1 bg-grouped-table pa5">
<div class="gh-setting-first gh-setting-last">
<div class="gh-setting-content">
<div class="gh-setting-title">Social accounts</div>
<div class="gh-setting-desc">Link your social accounts for full structured data and rich card support</div>
{{#liquid-if this.socialOpen}}
<div class="gh-setting-content-extended">
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{this.settings.hasValidated}} @property="facebook">
<GhTextInput
@type="url"
@placeholder="https://www.facebook.com/ghost"
@autocorrect="off"
@value={{readonly this.settings.facebook}}
@input={{action (mut this._scratchFacebook) value="target.value"}}
@focus-out={{action "validateFacebookUrl"}}
data-test-facebook-input={{true}}
/>
<GhErrorMessage @errors={{this.settings.errors}} @property="facebook" data-test-facebook-error=true />
<p>URL of your publication's Facebook Page</p>
</GhFormGroup>
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{this.settings.hasValidated}} @property="twitter">
<GhTextInput
@type="url"
@placeholder="https://twitter.com/ghost"
@autocorrect="off"
@value={{readonly this.settings.twitter}}
@input={{action (mut this._scratchTwitter) value="target.value"}}
@focus-out={{action "validateTwitterUrl"}}
data-test-twitter-input={{true}}
/>
<GhErrorMessage @errors={{this.settings.errors}} @property="twitter" data-test-twitter-error=true />
<p>URL of your publication's Twitter profile</p>
</GhFormGroup>
</div>
{{/liquid-if}}
</div>
<div class="gh-setting-action">
<button type="button" class="gh-btn" {{action (toggle "socialOpen" this)}} data-test-toggle-social><span>{{if this.socialOpen "Close" "Expand"}}</span></button>
</div>
</div>
</div>
<div class="gh-setting-header">Advanced settings</div>
<div class="flex flex-column br3 shadow-1 bg-grouped-table pa5">
<div class="gh-setting-first gh-setting-last">
<div class="gh-setting-content">
<div class="gh-setting-title">Make this site private</div>
<div class="gh-setting-desc">
Enable protection with simple shared password. All search engine optimization and social features will be disabled.
{{#if this.settings.isPrivate}}
<span class="avoid-break-out">
<br><br>
A private RSS feed is available at
<a href="{{this.privateRSSUrl}}" target="_blank" rel="noopener">{{this.privateRSSUrl}}</a>
</span>
{{/if}}
</div>
{{#if this.settings.isPrivate}}
<div class="gh-setting-content-extended">
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{this.settings.hasValidated}} @property="password">
<GhTextInput
@value={{readonly this.settings.password}}
@name="general[password]"
@focus-out={{action "validate" "password" target=this.settings}}
@input={{action (mut this.settings.password) value="target.value"}}
data-test-password-input={{true}}
/>
<GhErrorMessage @errors={{this.settings.errors}} @property="password" data-test-password-error=true />
<p>Set the password for this site</p>
</GhFormGroup>
</div>
{{/if}}
</div>
<div class="gh-setting-action">
<div class="for-switch">
<label class="switch" for="settings-private">
<input
type="checkbox"
checked={{this.settings.isPrivate}}
id="settings-private"
onclick={{action "toggleIsPrivate" value="target.checked"}}
data-test-private-checkbox
>
<span class="input-toggle-component"></span>
</label>
</div>
</div>
</div>
</div>
</section>
</div>
</section>
{{outlet}}