add floating compose button
This commit is contained in:
parent
62c82a05c0
commit
58b700788c
|
@ -31,5 +31,6 @@ module.exports = [
|
||||||
{id: 'fa-exclamation-triangle', src: 'node_modules/font-awesome-svg-png/white/svg/exclamation-triangle.svg', title: 'Content warning'},
|
{id: 'fa-exclamation-triangle', src: 'node_modules/font-awesome-svg-png/white/svg/exclamation-triangle.svg', title: 'Content warning'},
|
||||||
{id: 'fa-check', src: 'node_modules/font-awesome-svg-png/white/svg/check.svg', title: 'Check'},
|
{id: 'fa-check', src: 'node_modules/font-awesome-svg-png/white/svg/check.svg', title: 'Check'},
|
||||||
{id: 'fa-trash', src: 'node_modules/font-awesome-svg-png/white/svg/trash-o.svg', title: 'Delete'},
|
{id: 'fa-trash', src: 'node_modules/font-awesome-svg-png/white/svg/trash-o.svg', title: 'Delete'},
|
||||||
{id: 'fa-hourglass', src: 'node_modules/font-awesome-svg-png/white/svg/hourglass.svg', title: 'Follow requested'}
|
{id: 'fa-hourglass', src: 'node_modules/font-awesome-svg-png/white/svg/hourglass.svg', title: 'Follow requested'},
|
||||||
|
{id: 'fa-pencil', src: 'node_modules/font-awesome-svg-png/white/svg/pencil.svg', title: 'Compose'}
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="compose-box {{overLimit ? 'over-char-limit' : ''}}">
|
<div class="compose-box {{overLimit ? 'over-char-limit' : ''}} {{realm === 'dialog' ? 'dialog-size' : '' }}">
|
||||||
<ComposeAuthor />
|
<ComposeAuthor />
|
||||||
{{#if contentWarningShown}}
|
{{#if contentWarningShown}}
|
||||||
<div class="compose-content-warning-wrapper"
|
<div class="compose-content-warning-wrapper"
|
||||||
|
@ -11,12 +11,16 @@
|
||||||
<ComposeToolbar :realm :postPrivacy :media :contentWarningShown :text />
|
<ComposeToolbar :realm :postPrivacy :media :contentWarningShown :text />
|
||||||
<ComposeLengthIndicator :length :overLimit />
|
<ComposeLengthIndicator :length :overLimit />
|
||||||
<ComposeMedia :realm :media />
|
<ComposeMedia :realm :media />
|
||||||
<ComposeButton :length :overLimit on:click="onClickPostButton()" />
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="compose-box-button-sentinel" ref:sentinel></div>
|
||||||
|
<div class="compose-box-button-wrapper" >
|
||||||
|
<ComposeButton :length :overLimit :sticky on:click="onClickPostButton()" />
|
||||||
|
</div>
|
||||||
|
<div class="compose-box-border-bottom"></div>
|
||||||
<style>
|
<style>
|
||||||
.compose-box {
|
.compose-box {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 20px;
|
padding: 20px 20px 0 20px;
|
||||||
display: grid;
|
display: grid;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
|
@ -25,24 +29,50 @@
|
||||||
"avatar input input input"
|
"avatar input input input"
|
||||||
"avatar gauge gauge gauge"
|
"avatar gauge gauge gauge"
|
||||||
"avatar toolbar toolbar length"
|
"avatar toolbar toolbar length"
|
||||||
"avatar media media media"
|
"avatar media media media";
|
||||||
"avatar button button button";
|
|
||||||
grid-template-columns: min-content minmax(0, max-content) 1fr 1fr;
|
grid-template-columns: min-content minmax(0, max-content) 1fr 1fr;
|
||||||
border-bottom: 1px solid var(--main-border);
|
|
||||||
width: 560px;
|
width: 560px;
|
||||||
max-width: calc(100vw - 40px);
|
max-width: calc(100vw - 40px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.compose-box.dialog-size {
|
||||||
|
width: 540px;
|
||||||
|
max-width: calc(100vw - 80px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.compose-box-border-bottom {
|
||||||
|
height: 1px;
|
||||||
|
background: var(--main-border);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compose-box-button-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
position: -webkit-sticky;
|
||||||
|
position: sticky;
|
||||||
|
top: 10px;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
.compose-content-warning-wrapper {
|
.compose-content-warning-wrapper {
|
||||||
grid-area: cw;
|
grid-area: cw;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
.compose-box {
|
.compose-box {
|
||||||
padding: 10px 10px;
|
padding: 10px 10px 0 10px;
|
||||||
max-width: calc(100vw - 20px);
|
max-width: calc(100vw - 20px);
|
||||||
width: 580px;
|
width: 580px;
|
||||||
}
|
}
|
||||||
|
.compose-box.dialog-size {
|
||||||
|
width: 560px;
|
||||||
|
max-width: calc(100vw - 40px);
|
||||||
|
}
|
||||||
|
.compose-box-button-wrapper {
|
||||||
|
top: 5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
|
@ -59,20 +89,35 @@
|
||||||
import { store } from '../../_store/store'
|
import { store } from '../../_store/store'
|
||||||
import { slide } from 'svelte-transitions'
|
import { slide } from 'svelte-transitions'
|
||||||
import { postStatus, insertHandleForReply } from '../../_actions/compose'
|
import { postStatus, insertHandleForReply } from '../../_actions/compose'
|
||||||
|
import { importDialogs } from '../../_utils/asyncModules'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
oncreate() {
|
oncreate() {
|
||||||
let realm = this.get('realm')
|
let realm = this.get('realm')
|
||||||
if (realm !== 'home') {
|
if (realm === 'home') {
|
||||||
|
this.__stickyObserver = new IntersectionObserver(entries => {
|
||||||
|
this.set({sticky: !entries[0].isIntersecting})
|
||||||
|
})
|
||||||
|
this.__stickyObserver.observe(this.refs.sentinel)
|
||||||
|
} else if (realm !== 'dialog') {
|
||||||
// if this is a reply, populate the handle immediately
|
// if this is a reply, populate the handle immediately
|
||||||
insertHandleForReply(realm)
|
insertHandleForReply(realm)
|
||||||
|
}
|
||||||
|
|
||||||
// if this is a reply, go back immediately after it's posted
|
|
||||||
this.observe('postedStatusForRealm', postedStatusForRealm => {
|
this.observe('postedStatusForRealm', postedStatusForRealm => {
|
||||||
if (postedStatusForRealm === realm) {
|
if (postedStatusForRealm !== realm) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.fire('postedStatus')
|
||||||
|
// if this is a reply, go back immediately after it's posted
|
||||||
|
if (realm !== 'home' && realm !== 'dialog') {
|
||||||
window.history.back()
|
window.history.back()
|
||||||
}
|
}
|
||||||
}, {init: false})
|
}, {init: false})
|
||||||
|
},
|
||||||
|
ondestroy() {
|
||||||
|
if (this.__stickyObserver) {
|
||||||
|
this.__stickyObserver.disconnect()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
@ -107,7 +152,14 @@
|
||||||
slide
|
slide
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onClickPostButton() {
|
async onClickPostButton() {
|
||||||
|
if (this.get('sticky')) {
|
||||||
|
// when the button is sticky, we're scrolled down the home timeline,
|
||||||
|
// so we should launch a new compose dialog
|
||||||
|
let dialogs = await importDialogs()
|
||||||
|
dialogs.showComposeDialog()
|
||||||
|
} else {
|
||||||
|
// else we're actually posting a new toot
|
||||||
let text = this.get('text')
|
let text = this.get('text')
|
||||||
let media = this.get('media')
|
let media = this.get('media')
|
||||||
let postPrivacyKey = this.get('postPrivacyKey')
|
let postPrivacyKey = this.get('postPrivacyKey')
|
||||||
|
@ -115,16 +167,18 @@
|
||||||
let sensitive = media.length && !!contentWarning
|
let sensitive = media.length && !!contentWarning
|
||||||
let realm = this.get('realm')
|
let realm = this.get('realm')
|
||||||
let mediaIds = media.map(_ => _.data.id)
|
let mediaIds = media.map(_ => _.data.id)
|
||||||
let inReplyTo = realm === 'home' ? null : realm
|
let inReplyTo = (realm === 'home' || realm === 'dialog') ? null : realm
|
||||||
let overLimit = this.get('overLimit')
|
let overLimit = this.get('overLimit')
|
||||||
|
|
||||||
if (!text || overLimit) {
|
if (!text || overLimit) {
|
||||||
return // do nothing if invalid
|
return // do nothing if invalid
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no await */ postStatus(realm, text, inReplyTo, mediaIds,
|
/* no await */
|
||||||
|
postStatus(realm, text, inReplyTo, mediaIds,
|
||||||
sensitive, contentWarning, postPrivacyKey)
|
sensitive, contentWarning, postPrivacyKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,26 +1,40 @@
|
||||||
|
<div class="compose-box-button-halo frosted-glass">
|
||||||
<button class="primary compose-box-button"
|
<button class="primary compose-box-button"
|
||||||
:disabled
|
:disabled
|
||||||
|
aria-label="{{sticky ? 'Compose' : 'Toot!'}}"
|
||||||
on:click>
|
on:click>
|
||||||
<span class="{{$postingStatus ? 'hidden' : ''}}">
|
<span class="{{$postingStatus || sticky ? 'hidden' : ''}}">
|
||||||
Toot!
|
Toot!
|
||||||
</span>
|
</span>
|
||||||
<div class="compose-box-button-spinner {{$postingStatus ? 'spin' : 'hidden'}}"
|
<div class="compose-box-button-spinner {{$postingStatus ? 'spin' : 'hidden'}}"
|
||||||
aria-hidden="true">
|
aria-hidden="true">
|
||||||
<svg class="compose-box-button-spinner-svg">
|
<svg class="compose-box-button-svg">
|
||||||
<use xlink:href="#fa-spinner" />
|
<use xlink:href="#fa-spinner" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="compose-box-button-compose {{sticky ? '' : 'hidden'}}"
|
||||||
|
aria-hidden="true">
|
||||||
|
<svg class="compose-box-button-svg">
|
||||||
|
<use xlink:href="#fa-pencil" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
<style>
|
<style>
|
||||||
|
.compose-box-button-halo {
|
||||||
|
border-radius: 2px;
|
||||||
|
margin: 5px 15px 15px 5px;
|
||||||
|
background: var(--compose-button-halo);
|
||||||
|
}
|
||||||
.compose-box-button {
|
.compose-box-button {
|
||||||
grid-area: button;
|
grid-area: button;
|
||||||
justify-self: right;
|
justify-self: right;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
margin-top: 10px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
margin: 5px;
|
||||||
}
|
}
|
||||||
.compose-box-button-spinner {
|
.compose-box-button-spinner, .compose-box-button-compose {
|
||||||
pointer-events: none;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -31,11 +45,20 @@
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
.compose-box-button-spinner-svg {
|
.compose-box-button-svg {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
fill: var(--button-primary-text);
|
fill: var(--button-primary-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.compose-box-button-halo {
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
.compose-box-button {
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import { store } from '../../_store/store'
|
import { store } from '../../_store/store'
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<ModalDialog :label :shown :closed :title background="var(--main-bg)">
|
||||||
|
<ComposeBox realm="dialog" on:postedStatus="onPostedStatus()" />
|
||||||
|
</ModalDialog>
|
||||||
|
<script>
|
||||||
|
import ModalDialog from './ModalDialog.html'
|
||||||
|
import ComposeBox from '../compose/ComposeBox.html'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
ModalDialog,
|
||||||
|
ComposeBox
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async show() {
|
||||||
|
this.set({shown: true})
|
||||||
|
},
|
||||||
|
onPostedStatus() {
|
||||||
|
this.set({closed: true})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -4,7 +4,7 @@
|
||||||
></div>
|
></div>
|
||||||
<div class="modal-dialog-contents {{fadedIn ? '' : 'hidden'}} {{muted ? 'muted-style' : ''}}"
|
<div class="modal-dialog-contents {{fadedIn ? '' : 'hidden'}} {{muted ? 'muted-style' : ''}}"
|
||||||
role="dialog"
|
role="dialog"
|
||||||
aria-label="{{label}}"
|
aria-label="{{label || ''}}"
|
||||||
ref:node
|
ref:node
|
||||||
>
|
>
|
||||||
<div class="modal-dialog-document" role="document" style="background: {{background || '#000'}};">
|
<div class="modal-dialog-document" role="document" style="background: {{background || '#000'}};">
|
||||||
|
@ -41,7 +41,10 @@
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
|
-webkit-filter: blur(0);
|
||||||
|
will-change: transform;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
|
-webkit-font-smoothing: antialiased; /* fix for transform:translate causing blurry text in Chrome/Safari */
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: 1px solid var(--main-border);
|
border: 1px solid var(--main-border);
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
|
|
|
@ -4,3 +4,4 @@ export * from './showVideoDialog'
|
||||||
export * from './showEmojiDialog'
|
export * from './showEmojiDialog'
|
||||||
export * from './showPostPrivacyDialog'
|
export * from './showPostPrivacyDialog'
|
||||||
export * from './showStatusOptionsDialog'
|
export * from './showStatusOptionsDialog'
|
||||||
|
export * from './showComposeDialog'
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import ComposeDialog from './ComposeDialog.html'
|
||||||
|
|
||||||
|
export function showComposeDialog () {
|
||||||
|
let dialog = new ComposeDialog({
|
||||||
|
target: document.getElementById('modal-dialog'),
|
||||||
|
data: {
|
||||||
|
label: 'Compose dialog'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
dialog.show()
|
||||||
|
}
|
|
@ -78,4 +78,6 @@
|
||||||
--compose-autosuggest-item-hover: $compose-background;
|
--compose-autosuggest-item-hover: $compose-background;
|
||||||
--compose-autosuggest-item-active: darken($compose-background, 5%);
|
--compose-autosuggest-item-active: darken($compose-background, 5%);
|
||||||
--compose-autosuggest-outline: lighten($focus-outline, 5%);
|
--compose-autosuggest-outline: lighten($focus-outline, 5%);
|
||||||
|
|
||||||
|
--compose-button-halo: rgba(255, 255, 255, 0.2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* auto-generated w/ build-sass.js */
|
/* auto-generated w/ build-sass.js */
|
||||||
body{--button-primary-bg:#6081e6;--button-primary-text:#fff;--button-primary-border:#132c76;--button-primary-bg-active:#456ce2;--button-primary-bg-hover:#6988e7;--button-bg:#e6e6e6;--button-text:#333;--button-border:#a7a7a7;--button-bg-active:#bfbfbf;--button-bg-hover:#f2f2f2;--input-border:#dadada;--anchor-text:#4169e1;--main-bg:#fff;--body-bg:#e8edfb;--body-text-color:#333;--main-border:#dadada;--svg-fill:#4169e1;--form-bg:#f7f7f7;--form-border:#c1c1c1;--nav-bg:#4169e1;--nav-border:#214cce;--nav-a-border:#4169e1;--nav-a-selected-border:#fff;--nav-a-selected-bg:#6d8ce8;--nav-svg-fill:#fff;--nav-text-color:#fff;--nav-a-selected-border-hover:#fff;--nav-a-selected-bg-hover:#839deb;--nav-a-bg-hover:#577ae4;--nav-a-border-hover:#4169e1;--nav-svg-fill-hover:#fff;--nav-text-color-hover:#fff;--action-button-fill-color:#90a8ee;--action-button-fill-color-hover:#a2b6f0;--action-button-fill-color-active:#577ae4;--action-button-fill-color-pressed:#2351dc;--action-button-fill-color-pressed-hover:#3862e0;--action-button-fill-color-pressed-active:#1d44b8;--settings-list-item-bg:#fff;--settings-list-item-text:#4169e1;--settings-list-item-text-hover:#4169e1;--settings-list-item-border:#dadada;--settings-list-item-bg-active:#e6e6e6;--settings-list-item-bg-hover:#fafafa;--toast-bg:#333;--toast-border:#fafafa;--toast-text:#fff;--mask-bg:#333;--mask-svg-fill:#fff;--mask-opaque-bg:rgba(51,51,51,0.8);--loading-bg:#ededed;--deemphasized-text-color:#666;--focus-outline:#c5d1f6;--very-deemphasized-link-color:rgba(65,105,225,0.6);--very-deemphasized-text-color:rgba(102,102,102,0.6);--status-direct-background:#d2dcf8;--main-theme-color:#4169e1;--warning-color:#e01f19;--alt-input-bg:rgba(255,255,255,0.7);--muted-modal-bg:transparent;--muted-modal-focus:#999;--muted-modal-hover:rgba(255,255,255,0.2);--compose-autosuggest-item-hover:#ced8f7;--compose-autosuggest-item-active:#b8c7f4;--compose-autosuggest-outline:#dbe3f9}
|
body{--button-primary-bg:#6081e6;--button-primary-text:#fff;--button-primary-border:#132c76;--button-primary-bg-active:#456ce2;--button-primary-bg-hover:#6988e7;--button-bg:#e6e6e6;--button-text:#333;--button-border:#a7a7a7;--button-bg-active:#bfbfbf;--button-bg-hover:#f2f2f2;--input-border:#dadada;--anchor-text:#4169e1;--main-bg:#fff;--body-bg:#e8edfb;--body-text-color:#333;--main-border:#dadada;--svg-fill:#4169e1;--form-bg:#f7f7f7;--form-border:#c1c1c1;--nav-bg:#4169e1;--nav-border:#214cce;--nav-a-border:#4169e1;--nav-a-selected-border:#fff;--nav-a-selected-bg:#6d8ce8;--nav-svg-fill:#fff;--nav-text-color:#fff;--nav-a-selected-border-hover:#fff;--nav-a-selected-bg-hover:#839deb;--nav-a-bg-hover:#577ae4;--nav-a-border-hover:#4169e1;--nav-svg-fill-hover:#fff;--nav-text-color-hover:#fff;--action-button-fill-color:#90a8ee;--action-button-fill-color-hover:#a2b6f0;--action-button-fill-color-active:#577ae4;--action-button-fill-color-pressed:#2351dc;--action-button-fill-color-pressed-hover:#3862e0;--action-button-fill-color-pressed-active:#1d44b8;--settings-list-item-bg:#fff;--settings-list-item-text:#4169e1;--settings-list-item-text-hover:#4169e1;--settings-list-item-border:#dadada;--settings-list-item-bg-active:#e6e6e6;--settings-list-item-bg-hover:#fafafa;--toast-bg:#333;--toast-border:#fafafa;--toast-text:#fff;--mask-bg:#333;--mask-svg-fill:#fff;--mask-opaque-bg:rgba(51,51,51,0.8);--loading-bg:#ededed;--deemphasized-text-color:#666;--focus-outline:#c5d1f6;--very-deemphasized-link-color:rgba(65,105,225,0.6);--very-deemphasized-text-color:rgba(102,102,102,0.6);--status-direct-background:#d2dcf8;--main-theme-color:#4169e1;--warning-color:#e01f19;--alt-input-bg:rgba(255,255,255,0.7);--muted-modal-bg:transparent;--muted-modal-focus:#999;--muted-modal-hover:rgba(255,255,255,0.2);--compose-autosuggest-item-hover:#ced8f7;--compose-autosuggest-item-active:#b8c7f4;--compose-autosuggest-outline:#dbe3f9;--compose-button-halo:rgba(255,255,255,0.2)}
|
||||||
body{margin:0;font-family:system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue;font-size:14px;line-height:1.4;color:var(--body-text-color);background:var(--body-bg);position:fixed;left:0;right:0;bottom:0;top:0}.container{overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;will-change:transform;position:absolute;top:72px;left:0;right:0;bottom:0}@media (max-width: 767px){.container{top:62px}}main{position:relative;width:602px;max-width:100vw;padding:0;box-sizing:border-box;margin:30px auto 15px;background:var(--main-bg);border:1px solid var(--main-border);border-radius:1px;min-height:70vh}@media (max-width: 767px){main{margin:5px auto 15px}}footer{width:602px;max-width:100vw;box-sizing:border-box;margin:20px auto;border-radius:1px;background:var(--main-bg);font-size:0.9em;padding:20px;border:1px solid var(--main-border)}h1,h2,h3,h4,h5,h6{margin:0 0 0.5em 0;font-weight:400;line-height:1.2}h1{font-size:2em}a{color:var(--anchor-text);text-decoration:none}a:visited{color:var(--anchor-text)}a:hover{text-decoration:underline}input{border:1px solid var(--input-border);padding:5px;box-sizing:border-box}button,.button{font-size:1.2em;background:var(--button-bg);border-radius:2px;padding:10px 15px;border:1px solid var(--button-border);cursor:pointer;color:var(--button-text)}button:hover,.button:hover{background:var(--button-bg-hover);text-decoration:none}button:active,.button:active{background:var(--button-bg-active)}button[disabled],.button[disabled]{opacity:0.35;pointer-events:none;cursor:not-allowed}button.primary,.button.primary{border:1px solid var(--button-primary-border);background:var(--button-primary-bg);color:var(--button-primary-text)}button.primary:hover,.button.primary:hover{background:var(--button-primary-bg-hover)}button.primary:active,.button.primary:active{background:var(--button-primary-bg-active)}p,label,input{font-size:1.3em}ul,li,p{padding:0;margin:0}.hidden{opacity:0}*:focus{outline:2px solid var(--focus-outline)}button::-moz-focus-inner{border:0}input:required,input:invalid{box-shadow:none}textarea{font-family:inherit;font-size:inherit;box-sizing:border-box}@keyframes spin{0%{transform:rotate(0deg)}50%{transform:rotate(180deg)}100%{transform:rotate(360deg)}}.spin{animation:spin 2s infinite linear}.ellipsis::after{content:"\2026"}
|
body{margin:0;font-family:system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue;font-size:14px;line-height:1.4;color:var(--body-text-color);background:var(--body-bg);position:fixed;left:0;right:0;bottom:0;top:0}.container{overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;will-change:transform;position:absolute;top:72px;left:0;right:0;bottom:0}@media (max-width: 767px){.container{top:62px}}main{position:relative;width:602px;max-width:100vw;padding:0;box-sizing:border-box;margin:30px auto 15px;background:var(--main-bg);border:1px solid var(--main-border);border-radius:1px;min-height:70vh}@media (max-width: 767px){main{margin:5px auto 15px}}footer{width:602px;max-width:100vw;box-sizing:border-box;margin:20px auto;border-radius:1px;background:var(--main-bg);font-size:0.9em;padding:20px;border:1px solid var(--main-border)}h1,h2,h3,h4,h5,h6{margin:0 0 0.5em 0;font-weight:400;line-height:1.2}h1{font-size:2em}a{color:var(--anchor-text);text-decoration:none}a:visited{color:var(--anchor-text)}a:hover{text-decoration:underline}input{border:1px solid var(--input-border);padding:5px;box-sizing:border-box}button,.button{font-size:1.2em;background:var(--button-bg);border-radius:2px;padding:10px 15px;border:1px solid var(--button-border);cursor:pointer;color:var(--button-text)}button:hover,.button:hover{background:var(--button-bg-hover);text-decoration:none}button:active,.button:active{background:var(--button-bg-active)}button[disabled],.button[disabled]{opacity:0.35;pointer-events:none;cursor:not-allowed}button.primary,.button.primary{border:1px solid var(--button-primary-border);background:var(--button-primary-bg);color:var(--button-primary-text)}button.primary:hover,.button.primary:hover{background:var(--button-primary-bg-hover)}button.primary:active,.button.primary:active{background:var(--button-primary-bg-active)}p,label,input{font-size:1.3em}ul,li,p{padding:0;margin:0}.hidden{opacity:0}*:focus{outline:2px solid var(--focus-outline)}button::-moz-focus-inner{border:0}input:required,input:invalid{box-shadow:none}textarea{font-family:inherit;font-size:inherit;box-sizing:border-box}@keyframes spin{0%{transform:rotate(0deg)}50%{transform:rotate(180deg)}100%{transform:rotate(360deg)}}.spin{animation:spin 2s infinite linear}.ellipsis::after{content:"\2026"}
|
||||||
body.offline,body.theme-hotpants.offline,body.theme-majesty.offline,body.theme-oaken.offline,body.theme-scarlet.offline,body.theme-seafoam.offline,body.theme-gecko.offline{--button-primary-bg:#ababab;--button-primary-text:#fff;--button-primary-border:#4d4d4d;--button-primary-bg-active:#9c9c9c;--button-primary-bg-hover:#b0b0b0;--button-bg:#e6e6e6;--button-text:#333;--button-border:#a7a7a7;--button-bg-active:#bfbfbf;--button-bg-hover:#f2f2f2;--input-border:#dadada;--anchor-text:#999;--main-bg:#fff;--body-bg:#fafafa;--body-text-color:#333;--main-border:#dadada;--svg-fill:#999;--form-bg:#f7f7f7;--form-border:#c1c1c1;--nav-bg:#999;--nav-border:gray;--nav-a-border:#999;--nav-a-selected-border:#fff;--nav-a-selected-bg:#b3b3b3;--nav-svg-fill:#fff;--nav-text-color:#fff;--nav-a-selected-border-hover:#fff;--nav-a-selected-bg-hover:#bfbfbf;--nav-a-bg-hover:#a6a6a6;--nav-a-border-hover:#999;--nav-svg-fill-hover:#fff;--nav-text-color-hover:#fff;--action-button-fill-color:#c7c7c7;--action-button-fill-color-hover:#d1d1d1;--action-button-fill-color-active:#a6a6a6;--action-button-fill-color-pressed:#878787;--action-button-fill-color-pressed-hover:#949494;--action-button-fill-color-pressed-active:#737373;--settings-list-item-bg:#fff;--settings-list-item-text:#999;--settings-list-item-text-hover:#999;--settings-list-item-border:#dadada;--settings-list-item-bg-active:#e6e6e6;--settings-list-item-bg-hover:#fafafa;--toast-bg:#333;--toast-border:#fafafa;--toast-text:#fff;--mask-bg:#333;--mask-svg-fill:#fff;--mask-opaque-bg:rgba(51,51,51,0.8);--loading-bg:#ededed;--deemphasized-text-color:#666;--focus-outline:#bfbfbf;--very-deemphasized-link-color:rgba(153,153,153,0.6);--very-deemphasized-text-color:rgba(102,102,102,0.6);--status-direct-background:#ededed;--main-theme-color:#999;--warning-color:#e01f19;--alt-input-bg:rgba(255,255,255,0.7);--muted-modal-bg:transparent;--muted-modal-focus:#999;--muted-modal-hover:rgba(255,255,255,0.2);--compose-autosuggest-item-hover:#c4c4c4;--compose-autosuggest-item-active:#b8b8b8;--compose-autosuggest-outline:#ccc}
|
body.offline,body.theme-hotpants.offline,body.theme-majesty.offline,body.theme-oaken.offline,body.theme-scarlet.offline,body.theme-seafoam.offline,body.theme-gecko.offline{--button-primary-bg:#ababab;--button-primary-text:#fff;--button-primary-border:#4d4d4d;--button-primary-bg-active:#9c9c9c;--button-primary-bg-hover:#b0b0b0;--button-bg:#e6e6e6;--button-text:#333;--button-border:#a7a7a7;--button-bg-active:#bfbfbf;--button-bg-hover:#f2f2f2;--input-border:#dadada;--anchor-text:#999;--main-bg:#fff;--body-bg:#fafafa;--body-text-color:#333;--main-border:#dadada;--svg-fill:#999;--form-bg:#f7f7f7;--form-border:#c1c1c1;--nav-bg:#999;--nav-border:gray;--nav-a-border:#999;--nav-a-selected-border:#fff;--nav-a-selected-bg:#b3b3b3;--nav-svg-fill:#fff;--nav-text-color:#fff;--nav-a-selected-border-hover:#fff;--nav-a-selected-bg-hover:#bfbfbf;--nav-a-bg-hover:#a6a6a6;--nav-a-border-hover:#999;--nav-svg-fill-hover:#fff;--nav-text-color-hover:#fff;--action-button-fill-color:#c7c7c7;--action-button-fill-color-hover:#d1d1d1;--action-button-fill-color-active:#a6a6a6;--action-button-fill-color-pressed:#878787;--action-button-fill-color-pressed-hover:#949494;--action-button-fill-color-pressed-active:#737373;--settings-list-item-bg:#fff;--settings-list-item-text:#999;--settings-list-item-text-hover:#999;--settings-list-item-border:#dadada;--settings-list-item-bg-active:#e6e6e6;--settings-list-item-bg-hover:#fafafa;--toast-bg:#333;--toast-border:#fafafa;--toast-text:#fff;--mask-bg:#333;--mask-svg-fill:#fff;--mask-opaque-bg:rgba(51,51,51,0.8);--loading-bg:#ededed;--deemphasized-text-color:#666;--focus-outline:#bfbfbf;--very-deemphasized-link-color:rgba(153,153,153,0.6);--very-deemphasized-text-color:rgba(102,102,102,0.6);--status-direct-background:#ededed;--main-theme-color:#999;--warning-color:#e01f19;--alt-input-bg:rgba(255,255,255,0.7);--muted-modal-bg:transparent;--muted-modal-focus:#999;--muted-modal-hover:rgba(255,255,255,0.2);--compose-autosuggest-item-hover:#c4c4c4;--compose-autosuggest-item-active:#b8b8b8;--compose-autosuggest-outline:#ccc;--compose-button-halo:rgba(255,255,255,0.2)}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
@ -109,6 +109,7 @@ body.offline,body.theme-hotpants.offline,body.theme-majesty.offline,body.theme-o
|
||||||
<symbol id="fa-check" viewBox="0 0 1792 1792"><title>Check</title><path d="M1671 566q0 40-28 68l-724 724-136 136q-28 28-68 28t-68-28l-136-136-362-362q-28-28-28-68t28-68l136-136q28-28 68-28t68 28l294 295 656-657q28-28 68-28t68 28l136 136q28 28 28 68z"></path></symbol>
|
<symbol id="fa-check" viewBox="0 0 1792 1792"><title>Check</title><path d="M1671 566q0 40-28 68l-724 724-136 136q-28 28-68 28t-68-28l-136-136-362-362q-28-28-28-68t28-68l136-136q28-28 68-28t68 28l294 295 656-657q28-28 68-28t68 28l136 136q28 28 28 68z"></path></symbol>
|
||||||
<symbol id="fa-trash" viewBox="0 0 1792 1792"><title>Delete</title><path d="M704 736v576q0 14-9 23t-23 9h-64q-14 0-23-9t-9-23V736q0-14 9-23t23-9h64q14 0 23 9t9 23zm256 0v576q0 14-9 23t-23 9h-64q-14 0-23-9t-9-23V736q0-14 9-23t23-9h64q14 0 23 9t9 23zm256 0v576q0 14-9 23t-23 9h-64q-14 0-23-9t-9-23V736q0-14 9-23t23-9h64q14 0 23 9t9 23zm128 724V512H448v948q0 22 7 40.5t14.5 27 10.5 8.5h832q3 0 10.5-8.5t14.5-27 7-40.5zM672 384h448l-48-117q-7-9-17-11H738q-10 2-17 11zm928 32v64q0 14-9 23t-23 9h-96v948q0 83-47 143.5t-113 60.5H480q-66 0-113-58.5T320 1464V512h-96q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h309l70-167q15-37 54-63t79-26h320q40 0 79 26t54 63l70 167h309q14 0 23 9t9 23z"></path></symbol>
|
<symbol id="fa-trash" viewBox="0 0 1792 1792"><title>Delete</title><path d="M704 736v576q0 14-9 23t-23 9h-64q-14 0-23-9t-9-23V736q0-14 9-23t23-9h64q14 0 23 9t9 23zm256 0v576q0 14-9 23t-23 9h-64q-14 0-23-9t-9-23V736q0-14 9-23t23-9h64q14 0 23 9t9 23zm256 0v576q0 14-9 23t-23 9h-64q-14 0-23-9t-9-23V736q0-14 9-23t23-9h64q14 0 23 9t9 23zm128 724V512H448v948q0 22 7 40.5t14.5 27 10.5 8.5h832q3 0 10.5-8.5t14.5-27 7-40.5zM672 384h448l-48-117q-7-9-17-11H738q-10 2-17 11zm928 32v64q0 14-9 23t-23 9h-96v948q0 83-47 143.5t-113 60.5H480q-66 0-113-58.5T320 1464V512h-96q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h309l70-167q15-37 54-63t79-26h320q40 0 79 26t54 63l70 167h309q14 0 23 9t9 23z"></path></symbol>
|
||||||
<symbol id="fa-hourglass" viewBox="0 0 1792 1792"><title>Follow requested</title><path d="M1632 1600q14 0 23 9t9 23v128q0 14-9 23t-23 9H160q-14 0-23-9t-9-23v-128q0-14 9-23t23-9h1472zm-1374-64q3-55 16-107t30-95 46-87 53.5-76 64.5-69.5 66-60 70.5-55T671 939t65-43q-43-28-65-43t-66.5-47.5-70.5-55-66-60-64.5-69.5-53.5-76-46-87-30-95-16-107h1276q-3 55-16 107t-30 95-46 87-53.5 76-64.5 69.5-66 60-70.5 55T1121 853t-65 43q43 28 65 43t66.5 47.5 70.5 55 66 60 64.5 69.5 53.5 76 46 87 30 95 16 107H258zM1632 0q14 0 23 9t9 23v128q0 14-9 23t-23 9H160q-14 0-23-9t-9-23V32q0-14 9-23t23-9h1472z"></path></symbol>
|
<symbol id="fa-hourglass" viewBox="0 0 1792 1792"><title>Follow requested</title><path d="M1632 1600q14 0 23 9t9 23v128q0 14-9 23t-23 9H160q-14 0-23-9t-9-23v-128q0-14 9-23t23-9h1472zm-1374-64q3-55 16-107t30-95 46-87 53.5-76 64.5-69.5 66-60 70.5-55T671 939t65-43q-43-28-65-43t-66.5-47.5-70.5-55-66-60-64.5-69.5-53.5-76-46-87-30-95-16-107h1276q-3 55-16 107t-30 95-46 87-53.5 76-64.5 69.5-66 60-70.5 55T1121 853t-65 43q43 28 65 43t66.5 47.5 70.5 55 66 60 64.5 69.5 53.5 76 46 87 30 95 16 107H258zM1632 0q14 0 23 9t9 23v128q0 14-9 23t-23 9H160q-14 0-23-9t-9-23V32q0-14 9-23t23-9h1472z"></path></symbol>
|
||||||
|
<symbol id="fa-pencil" viewBox="0 0 1792 1792"><title>Compose</title><path d="M491 1536l91-91-235-235-91 91v107h128v128h107zm523-928q0-22-22-22-10 0-17 7l-542 542q-7 7-7 17 0 22 22 22 10 0 17-7l542-542q7-7 7-17zm-54-192l416 416-832 832H128v-416zm683 96q0 53-37 90l-166 166-416-416 166-165q36-38 90-38 53 0 91 38l235 234q37 39 37 91z"></path></symbol>
|
||||||
</svg><!-- end insert svg here -->
|
</svg><!-- end insert svg here -->
|
||||||
</svg>
|
</svg>
|
||||||
<!-- The application will be rendered inside this element,
|
<!-- The application will be rendered inside this element,
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import {
|
||||||
|
composeButton, getNthStatus, scrollToStatus, scrollToTopOfTimeline, modalDialog, sleep, showMoreButton,
|
||||||
|
scrollContainerToTop
|
||||||
|
} from '../utils'
|
||||||
|
import { foobarRole } from '../roles'
|
||||||
|
|
||||||
|
fixture`108-compose-dialog.js`
|
||||||
|
.page`http://localhost:4002`
|
||||||
|
|
||||||
|
test('can compose using a dialog', async t => {
|
||||||
|
await t.useRole(foobarRole)
|
||||||
|
await scrollToStatus(t, 15)
|
||||||
|
await t.expect(modalDialog.getAttribute('aria-hidden')).eql('true')
|
||||||
|
.click(composeButton)
|
||||||
|
.expect(modalDialog.hasAttribute('aria-hidden')).notOk()
|
||||||
|
.typeText(modalDialog.find('.compose-box-input'), 'hello from the modal')
|
||||||
|
.click(modalDialog.find('.compose-box-button-compose'))
|
||||||
|
.expect(modalDialog.getAttribute('aria-hidden')).eql('true')
|
||||||
|
await sleep(5000)
|
||||||
|
await scrollToTopOfTimeline(t)
|
||||||
|
await t.hover(getNthStatus(0))
|
||||||
|
await scrollContainerToTop()
|
||||||
|
await t
|
||||||
|
.expect(showMoreButton.innerText).contains('Show 1 more')
|
||||||
|
.click(showMoreButton)
|
||||||
|
await t.expect(getNthStatus(0).innerText).contains('hello from the modal', {timeout: 20000})
|
||||||
|
})
|
|
@ -6,6 +6,7 @@ const SCROLL_INTERVAL = 1
|
||||||
|
|
||||||
export const settingsButton = $('nav a[aria-label=Settings]')
|
export const settingsButton = $('nav a[aria-label=Settings]')
|
||||||
export const instanceInput = $('#instanceInput')
|
export const instanceInput = $('#instanceInput')
|
||||||
|
export const modalDialog = $('#modal-dialog')
|
||||||
export const modalDialogContents = $('.modal-dialog-contents')
|
export const modalDialogContents = $('.modal-dialog-contents')
|
||||||
export const closeDialogButton = $('.close-dialog-button')
|
export const closeDialogButton = $('.close-dialog-button')
|
||||||
export const notificationsNavButton = $('nav a[href="/notifications"]')
|
export const notificationsNavButton = $('nav a[href="/notifications"]')
|
||||||
|
|
Loading…
Reference in New Issue