forked from cybrespace/pinafore
		
	tweak media images and video
This commit is contained in:
		
							parent
							
								
									e0cc3ff6dd
								
							
						
					
					
						commit
						9264f85505
					
				
					 12 changed files with 151 additions and 44 deletions
				
			
		| 
						 | 
				
			
			@ -8,4 +8,12 @@
 | 
			
		|||
  :global(.free-text p) {
 | 
			
		||||
    margin: 30px 0;
 | 
			
		||||
  }
 | 
			
		||||
  :global(.free-text) {
 | 
			
		||||
    overflow-y: auto; /* fixes weird iOS Safari bug where scrolling gets stuck */
 | 
			
		||||
  }
 | 
			
		||||
  @media (max-width: 767px) {
 | 
			
		||||
    :global(.free-text) {
 | 
			
		||||
      margin: 10px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
<:Window bind:innerHeight />
 | 
			
		||||
<Nav page={{page}} />
 | 
			
		||||
 | 
			
		||||
<div class="container" on:scroll="onScroll(event)" ref:node>
 | 
			
		||||
<div class="container" on:scroll="onScroll(event)" on:fullscreen="onFullscreenChange()" ref:node>
 | 
			
		||||
  <main>
 | 
			
		||||
    <slot></slot>
 | 
			
		||||
  </main>
 | 
			
		||||
| 
						 | 
				
			
			@ -12,6 +12,7 @@
 | 
			
		|||
 | 
			
		||||
  import debounce from 'lodash/debounce'
 | 
			
		||||
  import throttle from 'lodash/throttle'
 | 
			
		||||
  import { isFullscreen, attachFullscreenListener, detachFullscreenListener } from '../_utils/fullscreen'
 | 
			
		||||
  import { mark, stop } from '../_utils/marks'
 | 
			
		||||
 | 
			
		||||
  const SCROLL_EVENT_DELAY = 300
 | 
			
		||||
| 
						 | 
				
			
			@ -42,6 +43,9 @@
 | 
			
		|||
      scroll(node, callback) {
 | 
			
		||||
        const onScroll = throttle(event => {
 | 
			
		||||
          mark('onScroll')
 | 
			
		||||
          if (this.get('fullscreen')) {
 | 
			
		||||
            return
 | 
			
		||||
          }
 | 
			
		||||
          callback(event)
 | 
			
		||||
          stop('onScroll')
 | 
			
		||||
        }, SCROLL_EVENT_DELAY, {
 | 
			
		||||
| 
						 | 
				
			
			@ -55,6 +59,17 @@
 | 
			
		|||
            node.removeEventListener('scroll', onScroll);
 | 
			
		||||
          }
 | 
			
		||||
        };
 | 
			
		||||
      },
 | 
			
		||||
      fullscreen(node, callback) {
 | 
			
		||||
        const onFullscreen = (() => {
 | 
			
		||||
          callback()
 | 
			
		||||
        })
 | 
			
		||||
        attachFullscreenListener(onFullscreen)
 | 
			
		||||
        return {
 | 
			
		||||
          teardown() {
 | 
			
		||||
            detachFullscreenListener(onFullscreen)
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +78,12 @@
 | 
			
		|||
          scrollTop: event.target.scrollTop,
 | 
			
		||||
          scrollHeight: event.target.scrollHeight
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      onFullscreenChange() {
 | 
			
		||||
        mark('onFullscreenChange')
 | 
			
		||||
        console.log('is fullscreen? ', isFullscreen())
 | 
			
		||||
        this.set({ fullscreen: isFullscreen() })
 | 
			
		||||
        stop('onFullscreenChange')
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
	};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,15 +17,9 @@
 | 
			
		|||
    0% {
 | 
			
		||||
      transform: rotate(0deg);
 | 
			
		||||
    }
 | 
			
		||||
    25% {
 | 
			
		||||
      transform: rotate(90deg);
 | 
			
		||||
    }
 | 
			
		||||
    50% {
 | 
			
		||||
      transform: rotate(180deg);
 | 
			
		||||
    }
 | 
			
		||||
    75% {
 | 
			
		||||
      transform: rotate(270deg);
 | 
			
		||||
    }
 | 
			
		||||
    100% {
 | 
			
		||||
      transform: rotate(360deg);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
		 Before Width: | Height: | Size: 600 B After Width: | Height: | Size: 503 B  | 
							
								
								
									
										68
									
								
								routes/_components/Media.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								routes/_components/Media.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,68 @@
 | 
			
		|||
<div class="status-media" style="grid-template-columns: repeat(auto-fit, minmax({{minMediaWidth}}px, 1fr));">
 | 
			
		||||
  {{#each mediaAttachments as media}}
 | 
			
		||||
  <div class="status-media-container">
 | 
			
		||||
    {{#if media.type === 'video'}}
 | 
			
		||||
      <video class="{{hasNoNativeWidthHeight(media) ? 'no-native-width-height' : ''}}"
 | 
			
		||||
             poster="{{media.preview_url}}"
 | 
			
		||||
             src="{{media.url}}"
 | 
			
		||||
             width="{{getSmallWidth(media)}}"
 | 
			
		||||
             height="{{getSmallHeight(media)}}"
 | 
			
		||||
             controls
 | 
			
		||||
      />
 | 
			
		||||
    {{else}}
 | 
			
		||||
      <img class="{{hasNoNativeWidthHeight(media) ? 'no-native-width-height' : ''}}"
 | 
			
		||||
           src="{{media.preview_url}}"
 | 
			
		||||
           alt="{{media.description || ''}}"
 | 
			
		||||
           width="{{getSmallWidth(media)}}"
 | 
			
		||||
           height="{{getSmallHeight(media)}}"/>
 | 
			
		||||
    {{/if}}
 | 
			
		||||
  </div>
 | 
			
		||||
  {{/each}}
 | 
			
		||||
</div>
 | 
			
		||||
<style>
 | 
			
		||||
  .status-media {
 | 
			
		||||
    grid-area: status-media;
 | 
			
		||||
    display: grid;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    justify-items: center;
 | 
			
		||||
    grid-column-gap: 10px;
 | 
			
		||||
    grid-row-gap: 10px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .status-media-container {
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
  }
 | 
			
		||||
  .status-media .no-native-width-height {
 | 
			
		||||
    background-color: var(--mask-bg);
 | 
			
		||||
  }
 | 
			
		||||
  .status-media {
 | 
			
		||||
    max-width: calc(100vw - 40px);
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .status-media video, .status-media img {
 | 
			
		||||
    max-width: calc(100vw - 40px);
 | 
			
		||||
    object-fit: cover;
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
  const DEFAULT_MEDIA_WIDTH = 300
 | 
			
		||||
  const DEFAULT_MEDIA_HEIGHT = 200
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    helpers: {
 | 
			
		||||
      getSmallWidth: media => media.meta && media.meta.small && typeof media.meta.small.width === 'number' ?  media.meta.small.width : DEFAULT_MEDIA_WIDTH,
 | 
			
		||||
      getSmallHeight: media => media.meta && media.meta.small && typeof media.meta.small.height === 'number' ?  media.meta.small.height : DEFAULT_MEDIA_HEIGHT,
 | 
			
		||||
      hasNoNativeWidthHeight: media => !(media && media.meta && media.meta.small && typeof media.meta.small.width === 'number' && typeof media.meta.small.height === 'number'),
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
      minMediaWidth: (mediaAttachments) => Math.min.apply(Math, mediaAttachments.map(media => media.meta && media.meta.small && typeof media.meta.small.width === 'number' ?  media.meta.small.width : DEFAULT_MEDIA_WIDTH))
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -46,13 +46,7 @@
 | 
			
		|||
      </svg>
 | 
			
		||||
    </button>
 | 
			
		||||
  </div>
 | 
			
		||||
  <!--<div class="status-media" style="grid-template-columns: repeat(auto-fit, minmax({{minMediaWidth}}px, 1fr));">
 | 
			
		||||
    {{#each originalMedia as media}}
 | 
			
		||||
      <div class="status-media-container">
 | 
			
		||||
        <img src="{{media.preview_url}}" alt="{{media.description || ''}}"/>
 | 
			
		||||
      </div>
 | 
			
		||||
    {{/each}}
 | 
			
		||||
  </div>-->
 | 
			
		||||
  <Media mediaAttachments="{{originalMediaAttachments}}" />
 | 
			
		||||
</article>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
| 
						 | 
				
			
			@ -66,7 +60,7 @@
 | 
			
		|||
        "status-sidebar status-author"
 | 
			
		||||
        "status-sidebar status-content"
 | 
			
		||||
        ".............. status-toolbar"
 | 
			
		||||
        ".............. status-media";
 | 
			
		||||
        "status-media   status-media";
 | 
			
		||||
    grid-template-columns: 58px 1fr;
 | 
			
		||||
    border-bottom: 1px solid var(--main-border);
 | 
			
		||||
    /* will-change: transform; */ /* TODO: is this necessary? */
 | 
			
		||||
| 
						 | 
				
			
			@ -188,31 +182,18 @@
 | 
			
		|||
    fill: var(--action-button-fill-color-active);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
  .status-media {
 | 
			
		||||
    grid-area: status-media;
 | 
			
		||||
    display: grid;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    justify-items: center;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .status-media-container {
 | 
			
		||||
  }
 | 
			
		||||
  .status-media-container img {
 | 
			
		||||
    object-fit: cover;
 | 
			
		||||
  }
 | 
			
		||||
  */
 | 
			
		||||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
  import Avatar from './Avatar.html'
 | 
			
		||||
  import Media from './Media.html'
 | 
			
		||||
  import { mark, stop } from '../_utils/marks'
 | 
			
		||||
  import IntlRelativeFormat from 'intl-relativeformat'
 | 
			
		||||
  const relativeFormat = new IntlRelativeFormat('en-US');
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    components: {
 | 
			
		||||
      Avatar
 | 
			
		||||
      Avatar,
 | 
			
		||||
      Media
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
      createdAtDate: (status) => status.created_at,
 | 
			
		||||
| 
						 | 
				
			
			@ -224,8 +205,7 @@
 | 
			
		|||
      },
 | 
			
		||||
      originalStatus: (status) => status.reblog ? status.reblog : status,
 | 
			
		||||
      originalAccount: (originalStatus) => originalStatus.account,
 | 
			
		||||
      originalMedia: (originalStatus) => originalStatus.media_attachments,
 | 
			
		||||
      minMediaWidth: (originalMedia) => Math.min.apply(Math, originalMedia.map(_ => _.meta.small.width))
 | 
			
		||||
      originalMediaAttachments: (originalStatus) => originalStatus.media_attachments,
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,8 @@
 | 
			
		|||
<div class="virtual-list-item {{shown ? 'shown' : ''}}"
 | 
			
		||||
     virtual-list-key="{{key}}"
 | 
			
		||||
     ref:node
 | 
			
		||||
     style="transform: translate3d(0, {{offset}}px, 0);"
 | 
			
		||||
     style="transform: translateY({{offset}}px
 | 
			
		||||
     );"
 | 
			
		||||
>
 | 
			
		||||
  <:Component {component} virtualProps="{{props}}" virtualIndex="{{index}}" virtualLength="{{$numItems}}"/>
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										23
									
								
								routes/_utils/fullscreen.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								routes/_utils/fullscreen.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
export const isFullscreen = () => !!(document.fullscreenElement ||
 | 
			
		||||
  document.webkitFullscreenElement ||
 | 
			
		||||
  document.mozFullScreenElement);
 | 
			
		||||
 | 
			
		||||
export const attachFullscreenListener = (listener) => {
 | 
			
		||||
  if ('onfullscreenchange' in document) {
 | 
			
		||||
    document.addEventListener('fullscreenchange', listener);
 | 
			
		||||
  } else if ('onwebkitfullscreenchange' in document) {
 | 
			
		||||
    document.addEventListener('webkitfullscreenchange', listener);
 | 
			
		||||
  } else if ('onmozfullscreenchange' in document) {
 | 
			
		||||
    document.addEventListener('mozfullscreenchange', listener);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const detachFullscreenListener = (listener) => {
 | 
			
		||||
  if ('onfullscreenchange' in document) {
 | 
			
		||||
    document.removeEventListener('fullscreenchange', listener);
 | 
			
		||||
  } else if ('onwebkitfullscreenchange' in document) {
 | 
			
		||||
    document.removeEventListener('webkitfullscreenchange', listener);
 | 
			
		||||
  } else if ('onmozfullscreenchange' in document) {
 | 
			
		||||
    document.removeEventListener('mozfullscreenchange', listener);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,8 @@
 | 
			
		|||
import { Store } from 'svelte/store.js'
 | 
			
		||||
import { mark, stop } from '../_utils/marks'
 | 
			
		||||
 | 
			
		||||
const VIEWPORT_RENDER_FACTOR = 4
 | 
			
		||||
 | 
			
		||||
class VirtualListStore extends Store {
 | 
			
		||||
  constructor(state) {
 | 
			
		||||
    super(state)
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +48,7 @@ virtualListStore.compute('visibleItems',
 | 
			
		|||
    ['items', 'scrollTop', 'itemHeights', 'offsetHeight'],
 | 
			
		||||
    (items, scrollTop, itemHeights, offsetHeight) => {
 | 
			
		||||
  mark('compute visibleItems')
 | 
			
		||||
  let renderBuffer = 3 * offsetHeight
 | 
			
		||||
  let renderBuffer = VIEWPORT_RENDER_FACTOR * offsetHeight
 | 
			
		||||
  let visibleItems = []
 | 
			
		||||
  let totalOffset = 0
 | 
			
		||||
  let len = items.length
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,9 +9,9 @@
 | 
			
		|||
    margin: 20px auto;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @media (min-width: 768px) {
 | 
			
		||||
  @media (max-width: 767px) {
 | 
			
		||||
    ul.settings-list {
 | 
			
		||||
      max-width: 80%;
 | 
			
		||||
      max-width: 90%;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,5 +43,10 @@
 | 
			
		|||
  .settings-list-item .offset-for-icon {
 | 
			
		||||
    margin-left: 44px;
 | 
			
		||||
  }
 | 
			
		||||
  .settings-list-item span {
 | 
			
		||||
    white-space: nowrap;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    text-overflow: ellipsis;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -4,7 +4,7 @@
 | 
			
		|||
 | 
			
		||||
<Layout page='settings'>
 | 
			
		||||
  <SettingsLayout page='settings/instances/{{params.instanceName}}' label="{{params.instanceName}}">
 | 
			
		||||
    <h1>{{params.instanceName}}</h1>
 | 
			
		||||
    <h1 class="instance-name-h1">{{params.instanceName}}</h1>
 | 
			
		||||
 | 
			
		||||
    {{#if instanceUserAccount}}
 | 
			
		||||
      <h2>Logged in as:</h2>
 | 
			
		||||
| 
						 | 
				
			
			@ -87,6 +87,11 @@
 | 
			
		|||
    margin: 0 5px;
 | 
			
		||||
    flex-basis: 100%;
 | 
			
		||||
  }
 | 
			
		||||
  .instance-name-h1 {
 | 
			
		||||
    white-space: nowrap;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    text-overflow: ellipsis;
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
  import { store } from '../../_utils/store'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,12 +26,6 @@
 | 
			
		|||
  </SettingsLayout>
 | 
			
		||||
</Layout>
 | 
			
		||||
<style>
 | 
			
		||||
  @media (max-width: 767px) {
 | 
			
		||||
    input.new-instance-input {
 | 
			
		||||
      max-width: 90%;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  input.new-instance-input {
 | 
			
		||||
    min-width: 50%;
 | 
			
		||||
    max-width: 100%;
 | 
			
		||||
| 
						 | 
				
			
			@ -49,6 +43,12 @@
 | 
			
		|||
    display: block;
 | 
			
		||||
    margin: 20px 5px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @media (max-width: 767px) {
 | 
			
		||||
    input.new-instance-input {
 | 
			
		||||
      max-width: 80%;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
  import Layout from '../../_components/Layout.html';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue