Browse Source

Media viewer: added zooming

master
Eduard Kuzmenko 3 years ago
parent
commit
ab6a7e1725
  1. 221
      src/components/appMediaViewer.ts
  2. 16
      src/components/rangeSelector.ts
  3. 23
      src/components/swipeHandler.ts
  4. 5
      src/helpers/dom/attachGrabListeners.ts
  5. 5
      src/scss/partials/_audio.scss
  6. 103
      src/scss/partials/_ckin.scss
  7. 7
      src/scss/partials/_leftSidebar.scss
  8. 99
      src/scss/partials/_mediaViewer.scss

221
src/components/appMediaViewer.ts

@ -51,6 +51,13 @@ import setInnerHTML from "../helpers/dom/setInnerHTML"; @@ -51,6 +51,13 @@ import setInnerHTML from "../helpers/dom/setInnerHTML";
import { doubleRaf, fastRaf } from "../helpers/schedulers";
import { attachClickEvent } from "../helpers/dom/clickEvent";
import PopupDeleteMessages from "./popups/deleteMessages";
import RangeSelector from "./rangeSelector";
import attachGrabListeners, { GrabEvent } from "../helpers/dom/attachGrabListeners";
const ZOOM_STEP = 0.5;
const ZOOM_INITIAL_VALUE = 1;
const ZOOM_MIN_VALUE = 1;
const ZOOM_MAX_VALUE = 4;
// TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию
// TODO: картинки "обрезаются" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода)
@ -63,8 +70,9 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -63,8 +70,9 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
protected overlaysDiv: HTMLElement;
protected author: {[k in 'container' | 'avatarEl' | 'nameEl' | 'date']: HTMLElement} = {} as any;
protected content: {[k in 'main' | 'container' | 'media' | 'mover' | ContentAdditionType]: HTMLElement} = {} as any;
protected buttons: {[k in 'download' | 'close' | 'prev' | 'next' | 'mobile-close' | 'zoomin' | ButtonsAdditionType]: HTMLElement} = {} as any;
protected buttons: {[k in 'download' | 'close' | 'prev' | 'next' | 'mobile-close' | 'zoom' | ButtonsAdditionType]: HTMLElement} = {} as any;
protected topbar: HTMLElement;
protected moversContainer: HTMLElement;
protected tempId = 0;
protected preloader: ProgressivePreloader = null;
@ -102,7 +110,22 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -102,7 +110,22 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
protected loadMoreMedia: (older: boolean) => Promise<void>;
protected videoPlayer: VideoPlayer;
protected zoomElements: {
container: HTMLElement,
btnOut: HTMLElement,
btnIn: HTMLElement,
rangeSelector: RangeSelector
} = {} as any;
// protected zoomValue = ZOOM_INITIAL_VALUE;
protected zoomSwipeHandler: SwipeHandler;
protected zoomSwipeStartX = 0;
protected zoomSwipeStartY = 0;
protected zoomSwipeX = 0;
protected zoomSwipeY = 0;
protected ctrlKeyDown: boolean;
constructor(topButtons: Array<keyof AppMediaViewerBase<ContentAdditionType, ButtonsAdditionType, TargetType>['buttons']>) {
this.log = logger('AMV');
this.preloader = new ProgressivePreloader();
@ -153,12 +176,34 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -153,12 +176,34 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
const buttonsDiv = document.createElement('div');
buttonsDiv.classList.add(MEDIA_VIEWER_CLASSNAME + '-buttons');
topButtons.concat(['download', 'zoomin', 'close']).forEach(name => {
const button = ButtonIcon(name, {noRipple: name === 'close' || undefined});
topButtons.concat(['download', 'zoom', 'close']).forEach(name => {
const button = ButtonIcon(name, {noRipple: true});
this.buttons[name] = button;
buttonsDiv.append(button);
});
this.buttons.zoom.classList.add('zoom-in');
// * zoom
this.zoomElements.container = document.createElement('div');
this.zoomElements.container.classList.add('zoom-container');
this.zoomElements.btnOut = ButtonIcon('zoomout', {noRipple: true});
this.zoomElements.btnOut.addEventListener('click', () => this.changeZoom(false));
this.zoomElements.btnIn = ButtonIcon('zoomin', {noRipple: true});
this.zoomElements.btnIn.addEventListener('click', () => this.changeZoom(true));
this.zoomElements.rangeSelector = new RangeSelector(ZOOM_STEP, ZOOM_INITIAL_VALUE + ZOOM_STEP, ZOOM_MIN_VALUE, ZOOM_MAX_VALUE, true);
this.zoomElements.rangeSelector.setListeners();
this.zoomElements.rangeSelector.setHandlers({
onScrub: this.setZoomValue,
onMouseUp: () => this.setZoomValue()
});
this.zoomElements.container.append(this.zoomElements.btnOut, this.zoomElements.rangeSelector.container, this.zoomElements.btnIn);
this.wholeDiv.append(this.zoomElements.container);
// * content
this.content.main = document.createElement('div');
this.content.main.classList.add(MEDIA_VIEWER_CLASSNAME + '-content');
@ -187,7 +232,17 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -187,7 +232,17 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
this.buttons.next.className = `${MEDIA_VIEWER_CLASSNAME}-switcher ${MEDIA_VIEWER_CLASSNAME}-switcher-right`;
this.buttons.next.innerHTML = `<span class="tgico-down ${MEDIA_VIEWER_CLASSNAME}-next-button"></span>`;
this.wholeDiv.append(this.overlaysDiv, this.buttons.prev, this.buttons.next, this.topbar);
this.moversContainer = document.createElement('div');
this.moversContainer.classList.add(MEDIA_VIEWER_CLASSNAME + '-movers');
this.moversContainer.addEventListener('wheel', (e) => {
if(this.ctrlKeyDown) {
cancelEvent(e);
const scrollingUp = e.deltaY < 0;
this.changeZoom(!!scrollingUp);
}
});
this.wholeDiv.append(this.overlaysDiv, this.buttons.prev, this.buttons.next, this.topbar, this.moversContainer);
// * constructing html end
@ -224,6 +279,8 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -224,6 +279,8 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
}
});
this.buttons.zoom.addEventListener('click', () => this.toggleZoom());
this.wholeDiv.addEventListener('click', this.onClick);
if(isTouchSupported) {
@ -268,6 +325,80 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -268,6 +325,80 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
}
}
protected toggleZoom(enable?: boolean) {
const isVisible = this.isZooming();
if(this.zoomElements.rangeSelector.mousedown || this.ctrlKeyDown) {
enable = true;
}
if(isVisible === enable) return;
if(enable === undefined) {
enable = !isVisible;
}
this.buttons.zoom.classList.toggle('zoom-in', !enable);
this.zoomElements.container.classList.toggle('is-visible', enable);
const zoomValue = enable ? ZOOM_INITIAL_VALUE + ZOOM_STEP : 1;
this.setZoomValue(zoomValue);
if(enable) {
if(!this.zoomSwipeHandler) {
let lastDiffX: number, lastDiffY: number;
const multiplier = -1;
this.zoomSwipeHandler = new SwipeHandler({
element: this.moversContainer,
onFirstSwipe: () => {
lastDiffX = lastDiffY = 0;
this.moversContainer.classList.add('no-transition');
},
onSwipe: (xDiff, yDiff) => {
[xDiff, yDiff] = [xDiff * multiplier, yDiff * multiplier];
this.zoomSwipeX += xDiff - lastDiffX;
this.zoomSwipeY += yDiff - lastDiffY;
[lastDiffX, lastDiffY] = [xDiff, yDiff];
this.setZoomValue();
},
onReset: () => {
this.moversContainer.classList.remove('no-transition');
},
cursor: 'move'
});
} else {
this.zoomSwipeHandler.setListeners();
}
this.zoomElements.rangeSelector.setProgress(zoomValue);
} else if(!enable) {
this.zoomSwipeHandler.removeListeners();
}
}
protected changeZoom(add: boolean) {
this.zoomElements.rangeSelector.addProgress(ZOOM_STEP * (add ? 1 : -1));
this.setZoomValue();
}
protected setZoomValue = (value = this.zoomElements.rangeSelector.value) => {
// this.zoomValue = value;
if(value === ZOOM_INITIAL_VALUE) {
this.zoomSwipeX = 0;
this.zoomSwipeY = 0;
}
this.moversContainer.style.transform = `matrix(${value}, 0, 0, ${value}, ${this.zoomSwipeX}, ${this.zoomSwipeY})`;
this.zoomElements.btnOut.classList.toggle('inactive', value === ZOOM_MIN_VALUE);
this.zoomElements.btnIn.classList.toggle('inactive', value === ZOOM_MAX_VALUE);
this.toggleZoom(value > ZOOM_INITIAL_VALUE);
};
protected isZooming() {
return this.zoomElements.container.classList.contains('is-visible');
}
protected setBtnMenuToggle(buttons: ButtonMenuItemOptions[]) {
const btnMenuToggle = ButtonMenuToggle({onlyMobile: true}, 'bottom-left', buttons);
this.topbar.append(btnMenuToggle);
@ -294,6 +425,11 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -294,6 +425,11 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
this.setMoverPromise = null;
this.tempId = -1;
if(this.zoomSwipeHandler) {
this.zoomSwipeHandler.removeListeners();
this.zoomSwipeHandler = undefined;
}
/* if(appSidebarRight.historyTabIDs.slice(-1)[0] === AppSidebarRight.SLIDERITEMSIDS.forward) {
promise.then(() => {
appSidebarRight.forwardTab.closeBtn.click();
@ -301,6 +437,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -301,6 +437,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
} */
window.removeEventListener('keydown', this.onKeyDown);
window.removeEventListener('keyup', this.onKeyUp);
promise.finally(() => {
this.wholeDiv.remove();
@ -333,26 +470,56 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -333,26 +470,56 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
return;
}
const isZooming = this.isZooming();
let mover: HTMLElement = null;
['media-viewer-mover', 'media-viewer-buttons', 'media-viewer-author', 'media-viewer-caption'].find(s => {
const classNames = ['ckin__player', 'media-viewer-buttons', 'media-viewer-author', 'media-viewer-caption', 'zoom-container'];
if(isZooming) {
classNames.push('media-viewer-movers');
}
classNames.find(s => {
try {
mover = findUpClassName(target, s);
if(mover) return true;
} catch(err) {return false;}
});
if(/* target === this.mediaViewerDiv */!mover || target.tagName === 'IMG' || target.tagName === 'image') {
if(/* target === this.mediaViewerDiv */!mover || (!isZooming && (target.tagName === 'IMG' || target.tagName === 'image'))) {
this.buttons.close.click();
}
};
private onKeyDown = (e: KeyboardEvent) => {
//this.log('onKeyDown', e);
if(rootScope.overlaysActive > 1) {
return;
}
let good = true;
if(e.key === 'ArrowRight') {
this.buttons.next.click();
} else if(e.key === 'ArrowLeft') {
this.buttons.prev.click();
} else {
good = false;
}
if(e.ctrlKey || e.metaKey) {
this.ctrlKeyDown = true;
}
if(good) {
cancelEvent(e);
}
};
private onKeyUp = (e: KeyboardEvent) => {
if(!(e.ctrlKey || e.metaKey)) {
this.ctrlKeyDown = false;
if(this.isZooming()) {
this.setZoomValue();
}
}
};
@ -370,7 +537,8 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -370,7 +537,8 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
//mover.append(this.buttons.prev, this.buttons.next);
}
this.removeCenterFromMover(mover);
const zoomValue = this.isZooming() && closing /* && false */ ? this.zoomElements.rangeSelector.value : ZOOM_INITIAL_VALUE;
/* if(!(zoomValue > 1 && closing)) */ this.removeCenterFromMover(mover);
const wasActive = fromRight !== 0;
@ -444,6 +612,14 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -444,6 +612,14 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
top = rect.top;
}
if(zoomValue > 1) { // 33
// const diffX = (rect.width * zoomValue - rect.width) / 4;
const diffX = (rect.width * zoomValue - rect.width) / 2;
const diffY = (rect.height * zoomValue - rect.height) / 4;
// left -= diffX;
// top += diffY;
}
transform += `translate3d(${left}px,${top}px,0) `;
/* if(wasActive) {
@ -485,6 +661,8 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -485,6 +661,8 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
mover.style.width = containerRect.width + 'px';
mover.style.height = containerRect.height + 'px';
// const scaleX = rect.width / (containerRect.width * zoomValue);
// const scaleY = rect.height / (containerRect.height * zoomValue);
const scaleX = rect.width / containerRect.width;
const scaleY = rect.height / containerRect.height;
if(!wasActive) {
@ -499,7 +677,17 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -499,7 +677,17 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
}
//let borderRadius = '0px 0px 0px 0px';
mover.style.transform = transform;
if(closing && zoomValue > 1) {
const width = this.moversContainer.scrollWidth * scaleX;
const height = this.moversContainer.scrollHeight * scaleY;
const willBeLeft = appPhotosManager.windowW / 2 - rect.width / 2;
const willBeTop = appPhotosManager.windowH / 2 - rect.height / 2;
const left = rect.left - willBeLeft/* + (width - rect.width) / 2 */;
const top = rect.top - willBeTop/* + (height - rect.height) / 2 */;
this.moversContainer.style.transform = `matrix(${scaleX}, 0, 0, ${scaleY}, ${left}, ${top})`;
} else {
mover.style.transform = transform;
}
needOpacity && (mover.style.opacity = '0'/* !closing ? '0' : '' */);
@ -663,6 +851,8 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -663,6 +851,8 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
this.wholeDiv.classList.remove('active');
}, 0);
return ret;
setTimeout(() => {
mover.style.borderRadius = borderRadius;
@ -679,10 +869,12 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -679,10 +869,12 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
deferred.resolve();
}, delay);
mover.classList.remove('opening');
return ret;
}
mover.classList.toggle('opening', !closing);
mover.classList.add('opening');
//await new Promise((resolve) => setTimeout(resolve, 0));
//await new Promise((resolve) => window.requestAnimationFrame(resolve));
@ -713,7 +905,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -713,7 +905,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
}, 0/* delay / 2 */);
mover.dataset.timeout = '' + setTimeout(() => {
mover.classList.remove('moving');
mover.classList.remove('moving', 'opening');
if(aspecter) { // всё из-за видео, элементы управления скейлятся, так бы можно было этого не делать
if(mover.querySelector('video') || true) {
@ -848,7 +1040,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -848,7 +1040,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
const oldMover = this.content.mover;
oldMover.parentElement.append(newMover);
} else {
this.wholeDiv.append(newMover);
this.moversContainer.append(newMover);
}
return this.content.mover = newMover;
@ -1014,6 +1206,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -1014,6 +1206,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
this.setNewMover();
} else {
window.addEventListener('keydown', this.onKeyDown);
window.addEventListener('keyup', this.onKeyUp);
const mainColumns = this.pageEl.querySelector('#main-columns');
this.pageEl.insertBefore(this.wholeDiv, mainColumns);
void this.wholeDiv.offsetLeft; // reflow
@ -1039,13 +1232,13 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -1039,13 +1232,13 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
const mover = this.content.mover;
//const maxWidth = appPhotosManager.windowW - 16;
const maxWidth = this.pageEl.scrollWidth;
const maxWidth = appPhotosManager.windowW;
//const maxWidth = this.pageEl.scrollWidth;
// TODO: const maxHeight = mediaSizes.isMobile ? appPhotosManager.windowH : appPhotosManager.windowH - 100;
let padding = 0;
const windowH = appPhotosManager.windowH;
if(windowH < 1000000 && !mediaSizes.isMobile) {
padding = 32 + 120;
padding = 120;
}
const maxHeight = windowH - 120 - padding;
let thumbPromise: Promise<any> = Promise.resolve();

16
src/components/rangeSelector.ts

@ -25,9 +25,12 @@ export default class RangeSelector { @@ -25,9 +25,12 @@ export default class RangeSelector {
protected decimals: number;
constructor(protected step: number, protected value: number, protected min: number, protected max: number) {
constructor(protected step: number, value: number, protected min: number, protected max: number, withTransition = false) {
this.container = document.createElement('div');
this.container.classList.add('progress-line');
if(withTransition) {
this.container.classList.add('with-transition');
}
this.filled = document.createElement('div');
this.filled.classList.add('progress-line__filled');
@ -54,6 +57,10 @@ export default class RangeSelector { @@ -54,6 +57,10 @@ export default class RangeSelector {
this.container.append(this.filled, seek);
}
get value() {
return +this.seek.value;
}
public setHandlers(events: RangeSelector['events']) {
this.events = events;
}
@ -86,8 +93,13 @@ export default class RangeSelector { @@ -86,8 +93,13 @@ export default class RangeSelector {
};
public setProgress(value: number) {
this.setFilled(value);
this.seek.value = '' + value;
this.setFilled(+this.seek.value); // clamp
}
public addProgress(value: number) {
this.seek.value = '' + (+this.seek.value + value);
this.setFilled(+this.seek.value); // clamp
}
public setFilled(value: number) {

23
src/components/swipeHandler.ts

@ -16,10 +16,11 @@ const attachGlobalListenerTo = window; @@ -16,10 +16,11 @@ const attachGlobalListenerTo = window;
export default class SwipeHandler {
private element: HTMLElement;
private onSwipe: (xDiff: number, yDiff: number) => boolean;
private onSwipe: (xDiff: number, yDiff: number) => boolean | void;
private verifyTouchTarget: (evt: TouchEvent | MouseEvent) => boolean;
private onFirstSwipe: () => void;
private onReset: () => void;
private cursor: 'grabbing' | 'move' = 'grabbing';
private hadMove = false;
private xDown: number = null;
@ -31,9 +32,14 @@ export default class SwipeHandler { @@ -31,9 +32,14 @@ export default class SwipeHandler {
verifyTouchTarget?: SwipeHandler['verifyTouchTarget'],
onFirstSwipe?: SwipeHandler['onFirstSwipe'],
onReset?: SwipeHandler['onReset'],
cursor?: SwipeHandler['cursor']
}) {
safeAssign(this, options);
this.setListeners();
}
public setListeners() {
if(!isTouchSupported) {
this.element.addEventListener('mousedown', this.handleStart, false);
attachGlobalListenerTo.addEventListener('mouseup', this.reset);
@ -43,6 +49,16 @@ export default class SwipeHandler { @@ -43,6 +49,16 @@ export default class SwipeHandler {
}
}
public removeListeners() {
if(!isTouchSupported) {
this.element.removeEventListener('mousedown', this.handleStart, false);
attachGlobalListenerTo.removeEventListener('mouseup', this.reset);
} else {
this.element.removeEventListener('touchstart', this.handleStart, false);
attachGlobalListenerTo.removeEventListener('touchend', this.reset);
}
}
reset = (e?: Event) => {
/* if(e) {
cancelEvent(e);
@ -101,7 +117,7 @@ export default class SwipeHandler { @@ -101,7 +117,7 @@ export default class SwipeHandler {
this.hadMove = true;
if(!isTouchSupported) {
this.element.style.cursor = 'grabbing';
this.element.style.cursor = this.cursor;
}
if(this.onFirstSwipe) {
@ -124,7 +140,8 @@ export default class SwipeHandler { @@ -124,7 +140,8 @@ export default class SwipeHandler {
// }
/* reset values */
if(this.onSwipe(xDiff, yDiff)) {
const onSwipeResult = this.onSwipe(xDiff, yDiff);
if(onSwipeResult !== undefined && onSwipeResult) {
this.reset();
}
};

5
src/helpers/dom/attachGrabListeners.ts

@ -6,7 +6,10 @@ @@ -6,7 +6,10 @@
export type GrabEvent = {x: number, y: number, isTouch?: boolean};
export default function attachGrabListeners(element: HTMLElement, onStart: (position: GrabEvent) => void, onMove: (position: GrabEvent) => void, onEnd: (position: GrabEvent) => void) {
export default function attachGrabListeners(element: HTMLElement,
onStart: (position: GrabEvent) => void,
onMove: (position: GrabEvent) => void,
onEnd?: (position: GrabEvent) => void) {
// * Mouse
const onMouseMove = (event: MouseEvent) => {
onMove({x: event.pageX, y: event.pageY});

5
src/scss/partials/_audio.scss

@ -488,11 +488,8 @@ @@ -488,11 +488,8 @@
.progress-line {
--height: 2px;
--border-radius: 4px;
--thumb-size: .75rem;
flex: 1 1 auto;
margin-left: 5px;
&__seek {
--thumb-size: .75rem;
}
}
}

103
src/scss/partials/_ckin.scss

@ -45,8 +45,6 @@ @@ -45,8 +45,6 @@
}
.default {
border: 0 solid rgba(0, 0, 0, .2);
box-shadow: 0 0 20px rgba(0, 0, 0, .2);
position: relative;
font-size: 0;
//overflow: hidden;
@ -134,8 +132,12 @@ @@ -134,8 +132,12 @@
&__filled {
background: var(--primary-color);
}
&__loaded {
background-color: #fff;
}
&__loaded, & {
& {
background: rgba(255, 255, 255, .38);
}
@ -241,15 +243,12 @@ @@ -241,15 +243,12 @@
--color: #fff;
margin: 0;
width: 50px;
--thumb-size: 15px;
// https://stackoverflow.com/a/4816050
html.is-ios & {
display: none;
}
&__seek {
--thumb-size: 15px;
}
}
}
@ -268,6 +267,7 @@ video::-webkit-media-controls-enclosure { @@ -268,6 +267,7 @@ video::-webkit-media-controls-enclosure {
--color: var(--primary-color);
--height: 5px;
--border-radius: 6px;
--thumb-size: 13px;
border-radius: var(--border-radius);
height: var(--height);
position: relative;
@ -285,12 +285,10 @@ video::-webkit-media-controls-enclosure { @@ -285,12 +285,10 @@ video::-webkit-media-controls-enclosure {
}
&__seek {
--thumb-size: 13px;
-webkit-appearance: none;
-moz-appearance: none;
background: transparent;
width: 100%;
height: 100%;
cursor: pointer;
padding: 0;
margin: 0;
@ -300,63 +298,42 @@ video::-webkit-media-controls-enclosure { @@ -300,63 +298,42 @@ video::-webkit-media-controls-enclosure {
&:focus {
outline: none;
&::-webkit-slider-runnable-track {
/* &::-webkit-slider-runnable-track {
background: transparent;
}
&::-moz-range-track {
outline: none;
}
}
&::-webkit-slider-runnable-track {
width: 100%;
cursor: pointer;
border-radius: 1.3px;
-webkit-appearance: none;
} */
}
&::-webkit-slider-thumb {
height: var(--thumb-size);
width: var(--thumb-size);
border-radius: 50%;
background-color: var(--color);
cursor: pointer;
-webkit-appearance: none;
border: none;
//margin-left: -.5px;
display: none;
}
&::-moz-range-thumb {
height: var(--thumb-size);
width: var(--thumb-size);
border-radius: 50%;
background-color: var(--color);
cursor: pointer;
-webkit-appearance: none;
border: none;
//margin-left: -.5px;
display: none;
}
&::-ms-thumb {
height: var(--thumb-size);
width: var(--thumb-size);
border-radius: 50%;
background-color: var(--color);
cursor: pointer;
-webkit-appearance: none;
border: none;
//margin-left: -.5px;
&::-moz-range-track {
display: none;
}
&::-moz-range-track {
width: 100%;
height: 8.4px;
cursor: pointer;
border: 1px solid transparent;
background: transparent;
//border-radius: 1.3px;
&::-webkit-slider-runnable-track {
display: none;
}
/* &::-webkit-slider-thumb,
&::-moz-range-thumb,
&::-moz-range-track,
&::-webkit-slider-runnable-track {
-webkit-appearance: none;
background: transparent;
border-color: transparent;
color: transparent;
width: 0;
height: 0;
} */
}
&__filled {
@ -366,6 +343,20 @@ video::-webkit-media-controls-enclosure { @@ -366,6 +343,20 @@ video::-webkit-media-controls-enclosure {
&:not(.progress-line__loaded) {
background-color: var(--color);
z-index: 1;
&:after {
content: " ";
display: block;
height: var(--thumb-size);
width: var(--thumb-size);
border-radius: 50%;
background-color: var(--color);
cursor: pointer;
position: absolute;
right: 0;
top: 50%;
transform: translate(calc(var(--thumb-size) / 2), -50%);
}
}
}
@ -374,11 +365,19 @@ video::-webkit-media-controls-enclosure { @@ -374,11 +365,19 @@ video::-webkit-media-controls-enclosure {
background-color: var(--secondary-color);
}
&__seek, &__filled, &__loaded {
&__seek,
&__filled,
&__loaded {
border-radius: var(--border-radius);
position: absolute;
height: 100%;
top: 0;
bottom: 0;
}
@include animation-level(2) {
&.with-transition .progress-line__filled {
transition: width .2s;
}
}
}

7
src/scss/partials/_leftSidebar.scss

@ -1123,17 +1123,14 @@ @@ -1123,17 +1123,14 @@
.progress-line {
--height: 2px;
--color: var(--primary-color);
--border-radius: 4px;
--thumb-size: 12px;
background-color: #e6ecf0;
&__filled {
background-color: var(--primary-color);
}
&__seek {
--thumb-color: var(--primary-color);
--thumb-size: 12px;
}
}
}

99
src/scss/partials/_mediaViewer.scss

@ -4,6 +4,8 @@ @@ -4,6 +4,8 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
$inactive-opacity: .4;
.media-viewer {
position: fixed;
top: 0;
@ -119,7 +121,7 @@ @@ -119,7 +121,7 @@
word-break: break-word;
overflow: hidden;
text-overflow: ellipsis;
z-index: 5;
z-index: 4;
bottom: .75rem;
left: 0;
right: 0;
@ -151,7 +153,7 @@ @@ -151,7 +153,7 @@
.media-viewer-whole.active & {
html.no-touch & {
opacity: .4;
opacity: $inactive-opacity;
&:hover {
opacity: 1;
@ -255,7 +257,7 @@ @@ -255,7 +257,7 @@
&-mover/* , &-canvas */ {
position: fixed!important;
z-index: 4;
// z-index: 4;
//transition: .5s all;
display: flex;
justify-content: center;
@ -435,14 +437,15 @@ @@ -435,14 +437,15 @@
padding: 0 1.25rem;
.btn-icon, .media-viewer-author {
color: #8b8b8b;
color: #fff;
opacity: $inactive-opacity;
@include animation-level(2) {
transition: color var(--open-duration) ease-in-out;
transition: opacity var(--open-duration) ease-in-out, color var(--open-duration) ease-in-out, background-color var(--open-duration) ease-in-out;
}
@include hover() {
color: #fff;
opacity: 1;
}
}
@ -530,6 +533,9 @@ @@ -530,6 +533,9 @@
} */
.btn-menu-toggle {
color: rgba(255, 255, 255, $inactive-opacity);
opacity: 1;
&.menu-open {
color: #fff;
background-color: rgba(112, 117, 121, .2) !important;
@ -544,6 +550,19 @@ @@ -544,6 +550,19 @@
}
}
&-movers {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 4;
@include animation-level(2) {
transition: transform var(--open-duration);
}
}
/* &-switchers {
position: relative;
width: $large-screen;
@ -553,6 +572,74 @@ @@ -553,6 +572,74 @@
} */
}
.tgico-zoom {
&:before {
content: $tgico-zoomout;
}
&.zoom-in:before {
content: $tgico-zoomin;
}
}
.zoom-container {
width: 17.125rem;
height: 3.375rem;
background-color: rgba(0, 0, 0, .4);
border-radius: $border-radius-big;
padding: .5rem;
opacity: 1;
display: flex;
align-items: center;
justify-content: space-between;
position: absolute;
bottom: 1.25rem;
left: 50%;
transform: translateX(-50%);
z-index: 5;
@include animation-level(2) {
transition: opacity var(--open-duration);
}
.btn-icon {
color: #fff;
&.inactive {
pointer-events: none;
opacity: $inactive-opacity;
}
}
.progress-line {
--color: #fff;
--height: 2px;
flex: 1 1 auto;
margin: 0 1px;
&:before {
opacity: 1;
}
}
&:not(.is-visible),
.media-viewer-whole:not(.active) & {
opacity: 0;
pointer-events: none;
}
&.is-visible {
opacity: 1;
& ~ .media-viewer-caption {
opacity: 0 !important;
pointer-events: none;
}
}
}
.overlays {
top: 0;
left: 0;

Loading…
Cancel
Save