sforkowany z mirror/soapbox
				
			Show profile preview on hover
							rodzic
							
								
									30a5a0baa9
								
							
						
					
					
						commit
						563e4e5bab
					
				| 
						 | 
				
			
			@ -18,6 +18,7 @@ import classNames from 'classnames';
 | 
			
		|||
import Icon from 'soapbox/components/icon';
 | 
			
		||||
import PollContainer from 'soapbox/containers/poll_container';
 | 
			
		||||
import { NavLink } from 'react-router-dom';
 | 
			
		||||
import UserPanel from '../features/ui/components/user_panel';
 | 
			
		||||
 | 
			
		||||
// We use the component (and not the container) since we do not want
 | 
			
		||||
// to use the progress bar to show download progress
 | 
			
		||||
| 
						 | 
				
			
			@ -104,6 +105,9 @@ class Status extends ImmutablePureComponent {
 | 
			
		|||
  state = {
 | 
			
		||||
    showMedia: defaultMediaVisibility(this.props.status, this.props.displayMedia),
 | 
			
		||||
    statusId: undefined,
 | 
			
		||||
    profilePanelVisible: false,
 | 
			
		||||
    profilePanelX: 0,
 | 
			
		||||
    profilePanelY: 0,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // Track height changes we know about to compensate scrolling
 | 
			
		||||
| 
						 | 
				
			
			@ -249,6 +253,16 @@ class Status extends ImmutablePureComponent {
 | 
			
		|||
    this.handleToggleMediaVisibility();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  isMobile = () => window.matchMedia('only screen and (max-width: 895px)').matches;
 | 
			
		||||
 | 
			
		||||
  handleProfileHover = e => {
 | 
			
		||||
    if (!this.isMobile()) this.setState({ profilePanelVisible: true, profilePanelX: e.nativeEvent.offsetX, profilePanelY: e.nativeEvent.offsetY });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleProfileLeave = e => {
 | 
			
		||||
    if (!this.isMobile()) this.setState({ profilePanelVisible: false });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  _properStatus() {
 | 
			
		||||
    const { status } = this.props;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -435,6 +449,7 @@ class Status extends ImmutablePureComponent {
 | 
			
		|||
    };
 | 
			
		||||
 | 
			
		||||
    const statusUrl = `/@${status.getIn(['account', 'acct'])}/posts/${status.get('id')}`;
 | 
			
		||||
    const { profilePanelVisible, profilePanelX, profilePanelY } = this.state;
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <HotKeys handlers={handlers}>
 | 
			
		||||
| 
						 | 
				
			
			@ -448,13 +463,15 @@ class Status extends ImmutablePureComponent {
 | 
			
		|||
                <RelativeTimestamp timestamp={status.get('created_at')} />
 | 
			
		||||
              </NavLink>
 | 
			
		||||
 | 
			
		||||
              <NavLink to={`/@${status.getIn(['account', 'acct'])}`} title={status.getIn(['account', 'acct'])} className='status__display-name'>
 | 
			
		||||
                <div className='status__avatar'>
 | 
			
		||||
                  {statusAvatar}
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <DisplayName account={status.get('account')} others={otherAccounts} />
 | 
			
		||||
              </NavLink>
 | 
			
		||||
              <div className='status__profile' onMouseEnter={this.handleProfileHover} onMouseLeave={this.handleProfileLeave}>
 | 
			
		||||
                <NavLink to={`/@${status.getIn(['account', 'acct'])}`} title={status.getIn(['account', 'acct'])} className='status__display-name'>
 | 
			
		||||
                  <div className='status__avatar'>
 | 
			
		||||
                    {statusAvatar}
 | 
			
		||||
                  </div>
 | 
			
		||||
                  <DisplayName account={status.get('account')} others={otherAccounts} />
 | 
			
		||||
                </NavLink>
 | 
			
		||||
                <UserPanel accountId={status.getIn(['account', 'id'])} visible={profilePanelVisible} style={{ top: `${profilePanelY+15}px`, left: `${profilePanelX-132}px` }} />
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            {!group && status.get('group') && (
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,6 +16,7 @@ import classNames from 'classnames';
 | 
			
		|||
import Icon from 'soapbox/components/icon';
 | 
			
		||||
import PollContainer from 'soapbox/containers/poll_container';
 | 
			
		||||
import { StatusInteractionBar } from './status_interaction_bar';
 | 
			
		||||
import UserPanel from '../../ui/components/user_panel';
 | 
			
		||||
 | 
			
		||||
export default class DetailedStatus extends ImmutablePureComponent {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -38,6 +39,9 @@ export default class DetailedStatus extends ImmutablePureComponent {
 | 
			
		|||
 | 
			
		||||
  state = {
 | 
			
		||||
    height: null,
 | 
			
		||||
    profilePanelVisible: false,
 | 
			
		||||
    profilePanelX: 0,
 | 
			
		||||
    profilePanelY: 0,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  handleOpenVideo = (media, startTime) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -81,10 +85,21 @@ export default class DetailedStatus extends ImmutablePureComponent {
 | 
			
		|||
    window.open(href, 'soapbox-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  isMobile = () => window.matchMedia('only screen and (max-width: 895px)').matches;
 | 
			
		||||
 | 
			
		||||
  handleProfileHover = e => {
 | 
			
		||||
    if (!this.isMobile()) this.setState({ profilePanelVisible: true, profilePanelX: e.nativeEvent.offsetX, profilePanelY: e.nativeEvent.offsetY });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleProfileLeave = e => {
 | 
			
		||||
    if (!this.isMobile()) this.setState({ profilePanelVisible: false });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  render() {
 | 
			
		||||
    const status = (this.props.status && this.props.status.get('reblog')) ? this.props.status.get('reblog') : this.props.status;
 | 
			
		||||
    const outerStyle = { boxSizing: 'border-box' };
 | 
			
		||||
    const { compact } = this.props;
 | 
			
		||||
    const { profilePanelVisible, profilePanelX, profilePanelY } = this.state;
 | 
			
		||||
 | 
			
		||||
    if (!status) {
 | 
			
		||||
      return null;
 | 
			
		||||
| 
						 | 
				
			
			@ -158,10 +173,13 @@ export default class DetailedStatus extends ImmutablePureComponent {
 | 
			
		|||
    return (
 | 
			
		||||
      <div style={outerStyle}>
 | 
			
		||||
        <div ref={this.setRef} className={classNames('detailed-status', { compact })}>
 | 
			
		||||
          <NavLink to={`/@${status.getIn(['account', 'acct'])}`} className='detailed-status__display-name'>
 | 
			
		||||
            <div className='detailed-status__display-avatar'><Avatar account={status.get('account')} size={48} /></div>
 | 
			
		||||
            <DisplayName account={status.get('account')} />
 | 
			
		||||
          </NavLink>
 | 
			
		||||
          <div className='detailed-status__profile' onMouseEnter={this.handleProfileHover} onMouseLeave={this.handleProfileLeave}>
 | 
			
		||||
            <NavLink to={`/@${status.getIn(['account', 'acct'])}`} className='detailed-status__display-name'>
 | 
			
		||||
              <div className='detailed-status__display-avatar'><Avatar account={status.get('account')} size={48} /></div>
 | 
			
		||||
              <DisplayName account={status.get('account')} />
 | 
			
		||||
              <UserPanel accountId={status.getIn(['account', 'id'])} visible={profilePanelVisible} style={{ top: `${profilePanelY+15}px`, left: `${profilePanelX-132}px` }} />
 | 
			
		||||
            </NavLink>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          {status.get('group') && (
 | 
			
		||||
            <div className='status__meta'>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@ import Avatar from 'soapbox/components/avatar';
 | 
			
		|||
import { shortNumberFormat } from 'soapbox/utils/numbers';
 | 
			
		||||
import { acctFull } from 'soapbox/utils/accounts';
 | 
			
		||||
import StillImage from 'soapbox/components/still_image';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
 | 
			
		||||
class UserPanel extends ImmutablePureComponent {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -17,16 +18,23 @@ class UserPanel extends ImmutablePureComponent {
 | 
			
		|||
    account: ImmutablePropTypes.map,
 | 
			
		||||
    intl: PropTypes.object.isRequired,
 | 
			
		||||
    domain: PropTypes.string,
 | 
			
		||||
    style: PropTypes.object,
 | 
			
		||||
    visible: PropTypes.bool,
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static defaultProps = {
 | 
			
		||||
    style: {},
 | 
			
		||||
    visible: true,
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  render() {
 | 
			
		||||
    const { account, intl, domain } = this.props;
 | 
			
		||||
    const { account, intl, domain, style, visible } = this.props;
 | 
			
		||||
    if (!account) return null;
 | 
			
		||||
    const displayNameHtml = { __html: account.get('display_name_html') };
 | 
			
		||||
    const acct = account.get('acct').indexOf('@') === -1 && domain ? `${account.get('acct')}@${domain}` : account.get('acct');
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <div className='user-panel'>
 | 
			
		||||
      <div className={classNames('user-panel', { 'user-panel--visible': visible })} style={style}>
 | 
			
		||||
        <div className='user-panel__container'>
 | 
			
		||||
 | 
			
		||||
          <div className='user-panel__header'>
 | 
			
		||||
| 
						 | 
				
			
			@ -84,17 +92,17 @@ class UserPanel extends ImmutablePureComponent {
 | 
			
		|||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const mapStateToProps = state => {
 | 
			
		||||
  const me = state.get('me');
 | 
			
		||||
const makeMapStateToProps = () => {
 | 
			
		||||
  const getAccount = makeGetAccount();
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    account: getAccount(state, me),
 | 
			
		||||
  };
 | 
			
		||||
  const mapStateToProps = (state, { accountId }) => ({
 | 
			
		||||
    account: getAccount(state, accountId),
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return mapStateToProps;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default injectIntl(
 | 
			
		||||
  connect(mapStateToProps, null, null, {
 | 
			
		||||
  connect(makeMapStateToProps, null, null, {
 | 
			
		||||
    forwardRef: true,
 | 
			
		||||
  })(UserPanel));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,7 @@ import { getFeatures } from 'soapbox/utils/features';
 | 
			
		|||
const mapStateToProps = state => {
 | 
			
		||||
  const me = state.get('me');
 | 
			
		||||
  return {
 | 
			
		||||
    me,
 | 
			
		||||
    account: state.getIn(['accounts', me]),
 | 
			
		||||
    hasPatron: state.getIn(['soapbox', 'extensions', 'patron', 'enabled']),
 | 
			
		||||
    features: getFeatures(state.get('instance')),
 | 
			
		||||
| 
						 | 
				
			
			@ -30,7 +31,7 @@ class HomePage extends ImmutablePureComponent {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  render() {
 | 
			
		||||
    const { children, account, hasPatron, features } = this.props;
 | 
			
		||||
    const { me, children, account, hasPatron, features } = this.props;
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <div className='page'>
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +40,7 @@ class HomePage extends ImmutablePureComponent {
 | 
			
		|||
 | 
			
		||||
            <div className='columns-area__panels__pane columns-area__panels__pane--left'>
 | 
			
		||||
              <div className='columns-area__panels__pane__inner'>
 | 
			
		||||
                <UserPanel />
 | 
			
		||||
                <UserPanel accountId={me} />
 | 
			
		||||
                {hasPatron && <FundingPanel />}
 | 
			
		||||
                <PromoPanel />
 | 
			
		||||
                <LinkFooter />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@
 | 
			
		|||
.column,
 | 
			
		||||
.drawer {
 | 
			
		||||
  flex: 1 1 100%;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  overflow: visible;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.drawer__pager {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -152,7 +152,6 @@
 | 
			
		|||
.status__info .status__display-name {
 | 
			
		||||
  display: block;
 | 
			
		||||
  max-width: 100%;
 | 
			
		||||
  padding-right: 25px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.status__info {
 | 
			
		||||
| 
						 | 
				
			
			@ -160,6 +159,27 @@
 | 
			
		|||
  z-index: 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.status__profile,
 | 
			
		||||
.detailed-status__profile {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
 | 
			
		||||
  .user-panel {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    opacity: 0;
 | 
			
		||||
    pointer-events: none;
 | 
			
		||||
    transition-property: opacity;
 | 
			
		||||
    transition-duration: 0.5s;
 | 
			
		||||
    z-index: 999;
 | 
			
		||||
 | 
			
		||||
    &--visible {
 | 
			
		||||
      opacity: 1;
 | 
			
		||||
      transition-delay: 1s;
 | 
			
		||||
      pointer-events: all;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.status-check-box {
 | 
			
		||||
  border-bottom: 1px solid var(--background-color);
 | 
			
		||||
  display: flex;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,13 @@
 | 
			
		|||
  display: flex;
 | 
			
		||||
  width: 265px;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  overflow-y: hidden;
 | 
			
		||||
 | 
			
		||||
  &,
 | 
			
		||||
  .user-panel__account__name,
 | 
			
		||||
  .user-panel__account__username {
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    text-overflow: ellipsis;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &__header {
 | 
			
		||||
    display: block;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue