add floating compose button
This commit is contained in:
		
							parent
							
								
									62c82a05c0
								
							
						
					
					
						commit
						58b700788c
					
				
					 11 changed files with 195 additions and 49 deletions
				
			
		| 
						 | 
				
			
			@ -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-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-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 />
 | 
			
		||||
  {{#if contentWarningShown}}
 | 
			
		||||
    <div class="compose-content-warning-wrapper"
 | 
			
		||||
| 
						 | 
				
			
			@ -11,12 +11,16 @@
 | 
			
		|||
  <ComposeToolbar :realm :postPrivacy :media :contentWarningShown :text />
 | 
			
		||||
  <ComposeLengthIndicator :length :overLimit />
 | 
			
		||||
  <ComposeMedia :realm :media />
 | 
			
		||||
  <ComposeButton :length :overLimit on:click="onClickPostButton()" />
 | 
			
		||||
</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>
 | 
			
		||||
  .compose-box {
 | 
			
		||||
    border-radius: 4px;
 | 
			
		||||
    padding: 20px;
 | 
			
		||||
    padding: 20px 20px 0 20px;
 | 
			
		||||
    display: grid;
 | 
			
		||||
    align-items: flex-start;
 | 
			
		||||
    grid-template-areas:
 | 
			
		||||
| 
						 | 
				
			
			@ -25,24 +29,50 @@
 | 
			
		|||
      "avatar input      input     input"
 | 
			
		||||
      "avatar gauge      gauge     gauge"
 | 
			
		||||
      "avatar toolbar    toolbar   length"
 | 
			
		||||
      "avatar media      media     media"
 | 
			
		||||
      "avatar button     button    button";
 | 
			
		||||
      "avatar media      media     media";
 | 
			
		||||
    grid-template-columns: min-content minmax(0, max-content) 1fr 1fr;
 | 
			
		||||
    border-bottom: 1px solid var(--main-border);
 | 
			
		||||
    width: 560px;
 | 
			
		||||
    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 {
 | 
			
		||||
    grid-area: cw;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @media (max-width: 767px) {
 | 
			
		||||
    .compose-box {
 | 
			
		||||
      padding: 10px 10px;
 | 
			
		||||
      padding: 10px 10px 0 10px;
 | 
			
		||||
      max-width: calc(100vw - 20px);
 | 
			
		||||
      width: 580px;
 | 
			
		||||
    }
 | 
			
		||||
    .compose-box.dialog-size {
 | 
			
		||||
      width: 560px;
 | 
			
		||||
      max-width: calc(100vw - 40px);
 | 
			
		||||
    }
 | 
			
		||||
    .compose-box-button-wrapper {
 | 
			
		||||
      top: 5px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
| 
						 | 
				
			
			@ -59,20 +89,35 @@
 | 
			
		|||
  import { store } from '../../_store/store'
 | 
			
		||||
  import { slide } from 'svelte-transitions'
 | 
			
		||||
  import { postStatus, insertHandleForReply } from '../../_actions/compose'
 | 
			
		||||
  import { importDialogs } from '../../_utils/asyncModules'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
      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
 | 
			
		||||
        insertHandleForReply(realm)
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.observe('postedStatusForRealm', postedStatusForRealm => {
 | 
			
		||||
        if (postedStatusForRealm !== realm) {
 | 
			
		||||
          return
 | 
			
		||||
        }
 | 
			
		||||
        this.fire('postedStatus')
 | 
			
		||||
        // if this is a reply, go back immediately after it's posted
 | 
			
		||||
        this.observe('postedStatusForRealm', postedStatusForRealm => {
 | 
			
		||||
          if (postedStatusForRealm === realm) {
 | 
			
		||||
            window.history.back()
 | 
			
		||||
          }
 | 
			
		||||
        }, {init: false})
 | 
			
		||||
        if (realm !== 'home' && realm !== 'dialog') {
 | 
			
		||||
          window.history.back()
 | 
			
		||||
        }
 | 
			
		||||
      }, {init: false})
 | 
			
		||||
    },
 | 
			
		||||
    ondestroy() {
 | 
			
		||||
      if (this.__stickyObserver) {
 | 
			
		||||
        this.__stickyObserver.disconnect()
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    components: {
 | 
			
		||||
| 
						 | 
				
			
			@ -107,23 +152,32 @@
 | 
			
		|||
      slide
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      onClickPostButton() {
 | 
			
		||||
        let text = this.get('text')
 | 
			
		||||
        let media = this.get('media')
 | 
			
		||||
        let postPrivacyKey = this.get('postPrivacyKey')
 | 
			
		||||
        let contentWarning = this.get('contentWarning')
 | 
			
		||||
        let sensitive = media.length && !!contentWarning
 | 
			
		||||
        let realm = this.get('realm')
 | 
			
		||||
        let mediaIds = media.map(_ => _.data.id)
 | 
			
		||||
        let inReplyTo = realm === 'home' ? null : realm
 | 
			
		||||
        let overLimit = this.get('overLimit')
 | 
			
		||||
      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 media = this.get('media')
 | 
			
		||||
          let postPrivacyKey = this.get('postPrivacyKey')
 | 
			
		||||
          let contentWarning = this.get('contentWarning')
 | 
			
		||||
          let sensitive = media.length && !!contentWarning
 | 
			
		||||
          let realm = this.get('realm')
 | 
			
		||||
          let mediaIds = media.map(_ => _.data.id)
 | 
			
		||||
          let inReplyTo = (realm === 'home' || realm === 'dialog') ? null : realm
 | 
			
		||||
          let overLimit = this.get('overLimit')
 | 
			
		||||
 | 
			
		||||
        if (!text || overLimit) {
 | 
			
		||||
          return // do nothing if invalid
 | 
			
		||||
          if (!text || overLimit) {
 | 
			
		||||
            return // do nothing if invalid
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          /* no await */
 | 
			
		||||
          postStatus(realm, text, inReplyTo, mediaIds,
 | 
			
		||||
            sensitive, contentWarning, postPrivacyKey)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* no await */ postStatus(realm, text, inReplyTo, mediaIds,
 | 
			
		||||
          sensitive, contentWarning, postPrivacyKey)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,26 +1,40 @@
 | 
			
		|||
<button class="primary compose-box-button"
 | 
			
		||||
        :disabled
 | 
			
		||||
        on:click>
 | 
			
		||||
  <span class="{{$postingStatus ? 'hidden' : ''}}">
 | 
			
		||||
    Toot!
 | 
			
		||||
  </span>
 | 
			
		||||
  <div class="compose-box-button-spinner {{$postingStatus ? 'spin' : 'hidden'}}"
 | 
			
		||||
       aria-hidden="true">
 | 
			
		||||
    <svg class="compose-box-button-spinner-svg">
 | 
			
		||||
      <use xlink:href="#fa-spinner" />
 | 
			
		||||
    </svg>
 | 
			
		||||
  </div>
 | 
			
		||||
</button>
 | 
			
		||||
<div class="compose-box-button-halo frosted-glass">
 | 
			
		||||
  <button class="primary compose-box-button"
 | 
			
		||||
          :disabled
 | 
			
		||||
          aria-label="{{sticky ? 'Compose' : 'Toot!'}}"
 | 
			
		||||
          on:click>
 | 
			
		||||
    <span class="{{$postingStatus || sticky ? 'hidden' : ''}}">
 | 
			
		||||
      Toot!
 | 
			
		||||
    </span>
 | 
			
		||||
    <div class="compose-box-button-spinner {{$postingStatus ? 'spin' : 'hidden'}}"
 | 
			
		||||
         aria-hidden="true">
 | 
			
		||||
      <svg class="compose-box-button-svg">
 | 
			
		||||
        <use xlink:href="#fa-spinner" />
 | 
			
		||||
      </svg>
 | 
			
		||||
    </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>
 | 
			
		||||
</div>
 | 
			
		||||
<style>
 | 
			
		||||
  .compose-box-button-halo {
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
    margin: 5px 15px 15px 5px;
 | 
			
		||||
    background: var(--compose-button-halo);
 | 
			
		||||
  }
 | 
			
		||||
  .compose-box-button {
 | 
			
		||||
    grid-area: button;
 | 
			
		||||
    justify-self: right;
 | 
			
		||||
    text-transform: uppercase;
 | 
			
		||||
    margin-top: 10px;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    margin: 5px;
 | 
			
		||||
  }
 | 
			
		||||
  .compose-box-button-spinner {
 | 
			
		||||
    pointer-events: none;
 | 
			
		||||
  .compose-box-button-spinner, .compose-box-button-compose {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
| 
						 | 
				
			
			@ -31,11 +45,20 @@
 | 
			
		|||
    left: 0;
 | 
			
		||||
    right: 0;
 | 
			
		||||
  }
 | 
			
		||||
  .compose-box-button-spinner-svg {
 | 
			
		||||
  .compose-box-button-svg {
 | 
			
		||||
    width: 24px;
 | 
			
		||||
    height: 24px;
 | 
			
		||||
    fill: var(--button-primary-text);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @media (max-width: 767px) {
 | 
			
		||||
    .compose-box-button-halo {
 | 
			
		||||
      margin: 5px;
 | 
			
		||||
    }
 | 
			
		||||
    .compose-box-button {
 | 
			
		||||
      margin: 5px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
  import { store } from '../../_store/store'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								routes/_components/dialog/ComposeDialog.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								routes/_components/dialog/ComposeDialog.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 class="modal-dialog-contents {{fadedIn ? '' : 'hidden'}} {{muted ? 'muted-style' : ''}}"
 | 
			
		||||
     role="dialog"
 | 
			
		||||
     aria-label="{{label}}"
 | 
			
		||||
     aria-label="{{label || ''}}"
 | 
			
		||||
     ref:node
 | 
			
		||||
>
 | 
			
		||||
  <div class="modal-dialog-document" role="document" style="background: {{background || '#000'}};">
 | 
			
		||||
| 
						 | 
				
			
			@ -41,7 +41,10 @@
 | 
			
		|||
    position: fixed;
 | 
			
		||||
    top: 50%;
 | 
			
		||||
    left: 50%;
 | 
			
		||||
    -webkit-filter: blur(0);
 | 
			
		||||
    will-change: transform;
 | 
			
		||||
    transform: translate(-50%, -50%);
 | 
			
		||||
    -webkit-font-smoothing: antialiased; /* fix for transform:translate causing blurry text in Chrome/Safari */
 | 
			
		||||
    padding: 0;
 | 
			
		||||
    border: 1px solid var(--main-border);
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,3 +4,4 @@ export * from './showVideoDialog'
 | 
			
		|||
export * from './showEmojiDialog'
 | 
			
		||||
export * from './showPostPrivacyDialog'
 | 
			
		||||
export * from './showStatusOptionsDialog'
 | 
			
		||||
export * from './showComposeDialog'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										11
									
								
								routes/_components/dialog/showComposeDialog.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								routes/_components/dialog/showComposeDialog.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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-active: darken($compose-background, 5%);
 | 
			
		||||
  --compose-autosuggest-outline: lighten($focus-outline, 5%);
 | 
			
		||||
 | 
			
		||||
  --compose-button-halo: rgba(255, 255, 255, 0.2);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,9 +16,9 @@
 | 
			
		|||
 | 
			
		||||
  <style>
 | 
			
		||||
/* 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.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>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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-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-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>
 | 
			
		||||
  <!-- The application will be rendered inside this element,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										27
									
								
								tests/spec/108-compose-dialog.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								tests/spec/108-compose-dialog.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 instanceInput = $('#instanceInput')
 | 
			
		||||
export const modalDialog = $('#modal-dialog')
 | 
			
		||||
export const modalDialogContents = $('.modal-dialog-contents')
 | 
			
		||||
export const closeDialogButton = $('.close-dialog-button')
 | 
			
		||||
export const notificationsNavButton = $('nav a[href="/notifications"]')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue