Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEATURE: Adds full screen composer submit button and prompt #17839

Merged
merged 18 commits into from Aug 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,3 @@
<div class="composer-fullscreen-prompt" {{did-insert this.registerAnimationListener}}>
{{html-safe this.exitPrompt}}
</div>
@@ -0,0 +1,24 @@
import { action } from "@ember/object";
import GlimmerComponent from "@glimmer/component";
import I18n from "I18n";

export default class ComposerFullscreenPrompt extends GlimmerComponent {
@action
registerAnimationListener(element) {
this.#addAnimationEventListener(element);
}

#addAnimationEventListener(element) {
element.addEventListener(
"animationend",
() => {
this.args.removeFullScreenExitPrompt();
},
{ once: true }
);
}

get exitPrompt() {
return I18n.t("composer.exit_fullscreen_prompt");
}
}
47 changes: 34 additions & 13 deletions app/assets/javascripts/discourse/app/controllers/composer.js
Expand Up @@ -502,6 +502,11 @@ export default Controller.extend({
return false;
},

@action
removeFullScreenExitPrompt() {
this.set("model.showFullScreenExitPrompt", false);
},

actions: {
togglePreview() {
this.toggleProperty("showPreview");
Expand Down Expand Up @@ -655,16 +660,12 @@ export default Controller.extend({
toggle() {
this.closeAutocomplete();

if (
isEmpty(this.get("model.reply")) &&
isEmpty(this.get("model.title"))
) {
const composer = this.model;

if (isEmpty(composer?.reply) && isEmpty(composer?.title)) {
this.close();
} else {
if (
this.get("model.composeState") === Composer.OPEN ||
this.get("model.composeState") === Composer.FULLSCREEN
) {
if (composer?.viewOpenOrFullscreen) {
this.shrink();
} else {
this.cancelComposer();
Expand Down Expand Up @@ -747,9 +748,16 @@ export default Controller.extend({
return;
}

if (this.get("model.viewOpen") || this.get("model.viewFullscreen")) {
const composer = this.model;

if (composer?.viewOpen) {
this.shrink();
}

if (composer?.viewFullscreen) {
this.toggleFullscreen();
this.focusComposer();
}
},

groupsMentioned(groups) {
Expand Down Expand Up @@ -839,7 +847,11 @@ export default Controller.extend({

const composer = this.model;

if (composer.cantSubmitPost) {
if (composer?.cantSubmitPost) {
if (composer?.viewFullscreen) {
this.toggleFullscreen();
}

this.set("lastValidatedAt", Date.now());
return;
}
Expand Down Expand Up @@ -1481,13 +1493,22 @@ export default Controller.extend({

toggleFullscreen() {
this._saveDraft();
if (this.get("model.composeState") === Composer.FULLSCREEN) {
this.set("model.composeState", Composer.OPEN);

const composer = this.model;

if (composer?.viewFullscreen) {
composer?.set("composeState", Composer.OPEN);
} else {
this.set("model.composeState", Composer.FULLSCREEN);
composer?.set("composeState", Composer.FULLSCREEN);
composer?.set("showFullScreenExitPrompt", true);
}
},

@discourseComputed("model.viewFullscreen", "model.showFullScreenExitPrompt")
showFullScreenPrompt(isFullscreen, showExitPrompt) {
return isFullscreen && showExitPrompt && !this.capabilities.touch;
},

close() {
// the 'fullscreen-composer' class is added to remove scrollbars from the
// document while in fullscreen mode. If the composer is closed for any reason
Expand Down
1 change: 1 addition & 0 deletions app/assets/javascripts/discourse/app/models/composer.js
Expand Up @@ -124,6 +124,7 @@ const Composer = RestModel.extend({
noBump: false,
draftSaving: false,
draftForceSave: false,
showFullScreenExitPrompt: false,

archetypes: reads("site.archetypes"),

Expand Down
30 changes: 16 additions & 14 deletions app/assets/javascripts/discourse/app/templates/composer.hbs
Expand Up @@ -4,6 +4,10 @@
{{#if this.visible}}
<ComposerMessages @composer={{this.model}} @messageCount={{this.messageCount}} @addLinkLookup={{action "addLinkLookup"}} />

{{#if this.showFullScreenPrompt}}
<ComposerFullscreenPrompt @removeFullScreenExitPrompt={{action "removeFullScreenExitPrompt"}}/>
{{/if}}

{{#if this.model.viewOpenOrFullscreen}}
<div role="form" aria-label={{I18n this.saveLabel}} class="reply-area {{if this.canEditTags "with-tags" "without-tags"}}">
<PluginOutlet @name="composer-open" @tagName="span" @connectorTagName="div" @args={{hash model=this.model}} />
Expand Down Expand Up @@ -91,21 +95,19 @@
<PluginOutlet @name="composer-fields-below" @tagName="span" @connectorTagName="div" @args={{hash model=this.model}} />

<div class="save-or-cancel">
{{#unless this.model.viewFullscreen}}
<ComposerSaveButton @action={{action "save"}} @icon={{this.saveIcon}} @label={{this.saveLabel}} @forwardEvent={{true}} @disableSubmit={{this.disableSubmit}} />
<ComposerSaveButton @action={{action "save"}} @icon={{this.saveIcon}} @label={{this.saveLabel}} @forwardEvent={{true}} @disableSubmit={{this.disableSubmit}} />

{{#if this.site.mobileView}}
<a href {{action "cancel"}} title={{i18n "cancel"}} class="cancel">
{{#if this.canEdit}}
{{d-icon "times"}}
{{else}}
{{d-icon "far-trash-alt"}}
{{/if}}
</a>
{{else}}
<a href {{action "cancel"}} class="cancel" >{{i18n "close"}}</a>
{{/if}}
{{/unless}}
{{#if this.site.mobileView}}
<a href {{action "cancel"}} title={{i18n "cancel"}} class="cancel">
{{#if this.canEdit}}
{{d-icon "times"}}
{{else}}
{{d-icon "far-trash-alt"}}
{{/if}}
</a>
{{else}}
<a href {{action "cancel"}} class="cancel" >{{i18n "close"}}</a>
{{/if}}

{{#if this.site.mobileView}}
{{#if this.whisperOrUnlistTopic}}
Expand Down
34 changes: 34 additions & 0 deletions app/assets/javascripts/discourse/tests/acceptance/composer-test.js
Expand Up @@ -509,6 +509,12 @@ acceptance("Composer", function (needs) {
"it expands composer to full screen"
);

assert.strictEqual(
count(".composer-fullscreen-prompt"),
1,
"the exit fullscreen prompt is visible"
);

await click(".toggle-fullscreen");

assert.strictEqual(
Expand All @@ -535,6 +541,34 @@ acceptance("Composer", function (needs) {
);
});

test("Composer fullscreen submit button", async function (assert) {
await visit("/t/this-is-a-test-topic/9");
await click(".topic-post:nth-of-type(1) button.reply");

assert.strictEqual(
count("#reply-control.open"),
1,
"it starts in open state by default"
);

await click(".toggle-fullscreen");

assert.strictEqual(
count("#reply-control button.create"),
1,
"it shows composer submit button in fullscreen"
);

await fillIn(".d-editor-input", "too short");
await click("#reply-control button.create");

assert.strictEqual(
count("#reply-control.open"),
1,
"it goes back to open state if there's errors"
);
});

test("Composer can toggle between reply and createTopic", async function (assert) {
await visit("/t/this-is-a-test-topic/9");
await click(".topic-post:nth-of-type(1) button.reply");
Expand Down
21 changes: 21 additions & 0 deletions app/assets/stylesheets/desktop/compose.scss
Expand Up @@ -288,3 +288,24 @@ a.toggle-preview {
}
}
}

.composer-fullscreen-prompt {
animation: fadeIn 1s ease-in-out;
animation-delay: 1.5s;
animation-direction: reverse;
animation-fill-mode: forwards;
position: fixed;
left: 50%;
top: 10%;
transform: translate(-50%, 0);
.rtl & {
// R2 is not smart enough to support this swap
transform: translate(50%, 0);
}
z-index: z("header") + 1;
background: var(--primary-very-high);
color: var(--secondary);
padding: 0.5em 0.75em;
pointer-events: none;
border-radius: 2px;
}
3 changes: 2 additions & 1 deletion config/locales/client.en.yml
Expand Up @@ -2257,6 +2257,7 @@ en:
abandon: "close composer and discard draft"
enter_fullscreen: "enter fullscreen composer"
exit_fullscreen: "exit fullscreen composer"
exit_fullscreen_prompt: "Press <kbd>ESC</kbd> to exit full screen"
show_toolbar: "show composer toolbar"
hide_toolbar: "hide composer toolbar"
modal_ok: "OK"
Expand Down Expand Up @@ -2305,7 +2306,7 @@ en:
image_alt_text:
aria_label: Alt text for image

delete_image_button: Delete Image
delete_image_button: Delete Image

notifications:
tooltip:
Expand Down