wip: avatar panning and zooming

This commit is contained in:
or-else
2021-07-10 15:39:02 -07:00
parent 72f4f47e8f
commit bc6e2ab8d2
22 changed files with 487 additions and 94 deletions
+71
View File
@@ -2154,3 +2154,74 @@ ul.tabbar li.active > a {
color: #5f9ea0;
font-weight: inherit;
}
/* Image cropping widget */
.cropper {
position: relative;
width: 16rem;
height: 18rem;
margin: auto;
align-self: center;
transform: translateZ(0);
border-radius: 0.25rem;
}
.cropper .bounding-box {
position: relative;
width: 16rem;
height: 16rem;
overflow: hidden;
z-index: 1;
border-radius: 0.25rem;
border: solid 2px #1e88e5;
}
.cropper .preview {
position: absolute;
max-height: none;
max-width: none;
z-index: -1;
}
.cropper .cutout {
position: absolute;
width: 15rem;
height: 15rem;
border: 1px dashed #999;
margin: auto;
top: 0;
bottom: 0;
right: 0;
left: 0;
box-shadow: 0 0 150rem 150rem rgb(230 246 255 / 66%);
z-index: 0;
}
.cropper .cutout.circle {
border-radius: 50%;
}
.cropper .overlay {
position: absolute;
cursor: move;
touch-action: none;
z-index: 1;
}
.cropper .zoom-wrapper {
height: 2rem;
width: 80%;
margin: 1rem auto;
text-align: center;
}
.cropper .zoom {
box-shadow: none;
pointer-events: none;
z-index: 2;
}
.cropper .zoom:focus {
outline: none;
}
+1 -1
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -95,6 +95,7 @@
"sidepanel_title_reset": "Passwort zurücksetzen",
"sidepanel_title_archive": "Archivierte Unterhaltungen",
"sidepanel_title_blocked": "Blockierte Unterhaltungen",
"sidepanel_title_crop": "Zum Anpassen ziehen",
"reconnect_countdown": "Getrennt. Wiederverbinden in {seconds}…",
"reconnect_now": "Jetzt probieren",
"push_init_failed": "Initialisierung von Push-Benachrichtigungen fehlgeschlagen",
+1
View File
@@ -154,6 +154,7 @@
"sidepanel_title_archive": "Archived Chats",
"sidepanel_title_blocked": "Blocked Chats",
"sidepanel_title_cred": "Confirm Credentials",
"sidepanel_title_crop": "Drag to Adjust",
"sidepanel_title_login": "Sign In",
"sidepanel_title_newtpk": "Start New Chat",
"sidepanel_title_register": "Create Account",
+2 -1
View File
@@ -179,5 +179,6 @@
"menu_item_restore_topic": "Restaurar",
"badge_danger": "Suspicaz",
"badge_staff": "Administración",
"badge_verified": "Verificado"
"badge_verified": "Verificado",
"sidepanel_title_crop": "Arrastra para ajustar"
}
+4
View File
@@ -617,6 +617,10 @@
"defaultMessage": "Confirm Credentials",
"description": "Sidepanel title for ValidationView."
},
"sidepanel_title_crop": {
"defaultMessage": "Drag to Adjust",
"description": "Sidepanel title for AvatarCropView."
},
"sidepanel_title_login": {
"defaultMessage": "Sign In",
"description": "Sidepanel title for LoginView."
+2 -1
View File
@@ -181,5 +181,6 @@
"menu_item_restore_topic": "복원",
"badge_danger": "의심 많은",
"badge_staff": "직원 관리하에",
"badge_verified": "확인 됨"
"badge_verified": "확인 됨",
"sidepanel_title_crop": "드래그하여 조정"
}
+2 -1
View File
@@ -179,5 +179,6 @@
"menu_item_restore_topic": "Restabili",
"badge_danger": "Suspicios",
"badge_staff": "Administrare",
"badge_verified": "Verificat"
"badge_verified": "Verificat",
"sidepanel_title_crop": "Trageți pentru a ajusta"
}
+2 -1
View File
@@ -179,5 +179,6 @@
"menu_item_restore_topic": "Разархивировать",
"badge_danger": "Подозрительный",
"badge_staff": "Администрация",
"badge_verified": "Верифицированный"
"badge_verified": "Верифицированный",
"sidepanel_title_crop": "Обрезать картинку"
}
+2 -1
View File
@@ -179,5 +179,6 @@
"menu_item_restore_topic": "从存档中恢复",
"badge_danger": "可疑的",
"badge_staff": "在员工管理下",
"badge_verified": "值得信赖"
"badge_verified": "值得信赖",
"sidepanel_title_crop": "拖动调整"
}
+12 -5
View File
@@ -96,6 +96,7 @@
"sidepanel_title_reset": "Passwort zurücksetzen",
"sidepanel_title_archive": "Archivierte Unterhaltungen",
"sidepanel_title_blocked": "Blockierte Unterhaltungen",
"sidepanel_title_crop": "Zum Anpassen ziehen",
"reconnect_countdown": "Getrennt. Wiederverbinden in {seconds}…",
"reconnect_now": "Jetzt probieren",
"push_init_failed": "Initialisierung von Push-Benachrichtigungen fehlgeschlagen",
@@ -338,6 +339,7 @@
"sidepanel_title_archive": "Archived Chats",
"sidepanel_title_blocked": "Blocked Chats",
"sidepanel_title_cred": "Confirm Credentials",
"sidepanel_title_crop": "Drag to Adjust",
"sidepanel_title_login": "Sign In",
"sidepanel_title_newtpk": "Start New Chat",
"sidepanel_title_register": "Create Account",
@@ -546,7 +548,8 @@
"menu_item_restore_topic": "Restaurar",
"badge_danger": "Suspicaz",
"badge_staff": "Administración",
"badge_verified": "Verificado"
"badge_verified": "Verificado",
"sidepanel_title_crop": "Arrastra para ajustar"
},
"ko": {
"validate_credential_action": "확인",
@@ -729,7 +732,8 @@
"menu_item_restore_topic": "복원",
"badge_danger": "의심 많은",
"badge_staff": "직원 관리하에",
"badge_verified": "확인 됨"
"badge_verified": "확인 됨",
"sidepanel_title_crop": "드래그하여 조정"
},
"ro": {
"validate_credential_action": "confirmă",
@@ -912,7 +916,8 @@
"menu_item_restore_topic": "Restabili",
"badge_danger": "Suspicios",
"badge_staff": "Administrare",
"badge_verified": "Verificat"
"badge_verified": "Verificat",
"sidepanel_title_crop": "Trageți pentru a ajusta"
},
"ru": {
"contacts_not_found": "Чатов нет<br />¯∖_(ツ)_/¯",
@@ -1095,7 +1100,8 @@
"menu_item_restore_topic": "Разархивировать",
"badge_danger": "Подозрительный",
"badge_staff": "Администрация",
"badge_verified": "Верифицированный"
"badge_verified": "Верифицированный",
"sidepanel_title_crop": "Обрезать картинку"
},
"zh": {
"archived_contacts": "已归档联系人 ({count})",
@@ -1278,6 +1284,7 @@
"menu_item_restore_topic": "从存档中恢复",
"badge_danger": "可疑的",
"badge_staff": "在员工管理下",
"badge_verified": "值得信赖"
"badge_verified": "值得信赖",
"sidepanel_title_crop": "拖动调整"
}
}
+1 -1
View File
@@ -16,7 +16,7 @@ export default class LogoView extends React.PureComponent {
<img id="logo" alt="logo" src="img/logo.svg" />
<h2>Tinode Web</h2>
</a>
<p><FormattedMessage id="label_client" defaultMessage="Client:"
<p><FormattedMessage id="label_client" defaultMessage="Client:"
description="Label for a client version" /> {version}</p>
<p><FormattedMessage id="label_server" defaultMessage="Server:"
description="Label for a server version" /> {this.props.serverVersion} ({this.props.serverAddress})</p>
+12
View File
@@ -5,6 +5,7 @@ import ErrorPanel from '../widgets/error-panel.jsx';
import LoadSpinner from '../widgets/load-spinner.jsx';
import SideNavbar from '../widgets/side-navbar.jsx';
import AvatarCropView from './avatar-crop-view.jsx';
import ContactsView from './contacts-view.jsx';
import CreateAccountView from './create-account-view.jsx';
import EditAccountView from './edit-account-view.jsx';
@@ -70,6 +71,11 @@ const messages = defineMessages({
description: 'Sidepanel title for ValidationView.',
defaultMessage: 'Confirm Credentials'
},
crop: {
id: 'sidepanel_title_crop',
description: 'Sidepanel title for AvatarCropView.',
defaultMessage: 'Drag to Adjust'
},
reset: {
id: 'sidepanel_title_reset',
description: 'Sidepanel title for PasswordResetView.',
@@ -239,6 +245,12 @@ class SidepanelView extends React.Component {
<PasswordResetView
onRequest={this.props.onPasswordResetRequest}
onReset={this.props.onResetPassword} /> :
view === 'crop' ?
<AvatarCropView
onSubmit={this.props.onAvatarCropped}
onCancel={this.props.onCancel} /> :
null}
</div>
);
+3 -1
View File
@@ -381,7 +381,7 @@ class TinodeWeb extends React.Component {
if (hash.path && hash.path.length > 0) {
// Left-side panel selector.
if (['register','settings','edit','notif','security','support','general',
'cred','reset','newtpk','archive','blocked','contacts',''].includes(hash.path[0])) {
'cred','crop','reset','newtpk','archive','blocked','contacts',''].includes(hash.path[0])) {
this.setState({sidePanelSelected: hash.path[0]});
} else {
console.log("Unknown sidepanel view", hash.path[0]);
@@ -1156,6 +1156,8 @@ class TinodeWeb extends React.Component {
path = 'edit';
} else if ('blocked' == parsed.path[0]) {
path = 'security';
} else if ('crop' == parsed.path[0]) {
path = 'general';
} else if (this.state.myUserId) {
path = 'contacts';
}
+3 -3
View File
@@ -78,12 +78,12 @@ class ValidationView extends React.PureComponent {
}</FormattedMessage>
</div>
<div className="dialog-buttons">
<button className="primary" onClick={this.handleSubmit}>
<FormattedMessage id="button_confirm" defaultMessage="Confirm" description="Button [Confirm]" />
</button>
<button className="secondary" onClick={this.handleCancel}>
<FormattedMessage id="button_cancel" defaultMessage="Cancel" description="Button [Cancel]" />
</button>
<button className="primary" onClick={this.handleSubmit}>
<FormattedMessage id="button_confirm" defaultMessage="Confirm" description="Button [Confirm]" />
</button>
</div>
</div>
);
-2
View File
@@ -166,8 +166,6 @@ export default class Cropper extends React.Component {
this.mouseY = e.pageY;
}
// this.cutoutRect = this.cutout.current.getBoundingClientRect();
window.addEventListener('mousemove', this.mouseMove, { passive: false });
window.addEventListener('touchmove', this.mouseTouch, { passive: false });
window.addEventListener('mouseup', this.mouseUp, { passive: true });
+356 -35
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+8 -37
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long