Progress
This commit is contained in:
parent
35852e7fee
commit
4d7aee59c9
@ -49,6 +49,7 @@ class AccountsController < ReactController
|
|||||||
statuses.merge!(hashtag_scope) if tag_requested?
|
statuses.merge!(hashtag_scope) if tag_requested?
|
||||||
statuses.merge!(only_media_scope) if media_requested?
|
statuses.merge!(only_media_scope) if media_requested?
|
||||||
statuses.merge!(no_replies_scope) unless replies_requested?
|
statuses.merge!(no_replies_scope) unless replies_requested?
|
||||||
|
statuses.merge!(only_replies_scope) unless comments_only_requested?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -68,6 +69,10 @@ class AccountsController < ReactController
|
|||||||
Status.without_replies
|
Status.without_replies
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def only_replies_scope
|
||||||
|
Status.only_replies
|
||||||
|
end
|
||||||
|
|
||||||
def hashtag_scope
|
def hashtag_scope
|
||||||
tag = Tag.find_normalized(params[:tag])
|
tag = Tag.find_normalized(params[:tag])
|
||||||
|
|
||||||
@ -97,6 +102,8 @@ class AccountsController < ReactController
|
|||||||
short_account_media_url(@account, max_id: max_id, min_id: min_id)
|
short_account_media_url(@account, max_id: max_id, min_id: min_id)
|
||||||
elsif replies_requested?
|
elsif replies_requested?
|
||||||
short_account_with_replies_url(@account, max_id: max_id, min_id: min_id)
|
short_account_with_replies_url(@account, max_id: max_id, min_id: min_id)
|
||||||
|
elsif comments_only_requested?
|
||||||
|
short_account_comments_only_url(@account, max_id: max_id, min_id: min_id)
|
||||||
else
|
else
|
||||||
short_account_url(@account, max_id: max_id, min_id: min_id)
|
short_account_url(@account, max_id: max_id, min_id: min_id)
|
||||||
end
|
end
|
||||||
@ -110,6 +117,10 @@ class AccountsController < ReactController
|
|||||||
request.path.ends_with?('/with_replies')
|
request.path.ends_with?('/with_replies')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def comments_only_requested?
|
||||||
|
request.path.ends_with?('/comments_only')
|
||||||
|
end
|
||||||
|
|
||||||
def tag_requested?
|
def tag_requested?
|
||||||
request.path.ends_with?(Addressable::URI.parse("/tagged/#{params[:tag]}").normalize)
|
request.path.ends_with?(Addressable::URI.parse("/tagged/#{params[:tag]}").normalize)
|
||||||
end
|
end
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
class Api::V1::AccountByUsernameController < Api::BaseController
|
class Api::V1::AccountByUsernameController < Api::BaseController
|
||||||
before_action :set_account
|
before_action :set_account
|
||||||
before_action :check_account_suspension
|
before_action :check_account_suspension
|
||||||
|
before_action :check_account_local
|
||||||
|
|
||||||
respond_to :json
|
respond_to :json
|
||||||
|
|
||||||
@ -17,4 +18,9 @@ class Api::V1::AccountByUsernameController < Api::BaseController
|
|||||||
def check_account_suspension
|
def check_account_suspension
|
||||||
gone if @account.suspended?
|
gone if @account.suspended?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# if not our domain don't display
|
||||||
|
def check_account_local
|
||||||
|
gone unless @account.local?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -32,6 +32,7 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
|
|||||||
|
|
||||||
statuses.merge!(only_media_scope) if truthy_param?(:only_media)
|
statuses.merge!(only_media_scope) if truthy_param?(:only_media)
|
||||||
statuses.merge!(no_replies_scope) if truthy_param?(:exclude_replies)
|
statuses.merge!(no_replies_scope) if truthy_param?(:exclude_replies)
|
||||||
|
statuses.merge!(only_replies_scope) if truthy_param?(:only_comments)
|
||||||
statuses.merge!(no_reblogs_scope) if truthy_param?(:exclude_reblogs)
|
statuses.merge!(no_reblogs_scope) if truthy_param?(:exclude_reblogs)
|
||||||
statuses.merge!(hashtag_scope) if params[:tagged].present?
|
statuses.merge!(hashtag_scope) if params[:tagged].present?
|
||||||
|
|
||||||
@ -64,6 +65,10 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
|
|||||||
Status.without_replies
|
Status.without_replies
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def only_replies_scope
|
||||||
|
Status.only_replies
|
||||||
|
end
|
||||||
|
|
||||||
def no_reblogs_scope
|
def no_reblogs_scope
|
||||||
Status.without_reblogs
|
Status.without_reblogs
|
||||||
end
|
end
|
||||||
@ -79,7 +84,7 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def pagination_params(core_params)
|
def pagination_params(core_params)
|
||||||
params.slice(:limit, :only_media, :exclude_replies).permit(:limit, :only_media, :exclude_replies).merge(core_params)
|
params.slice(:limit, :only_media, :exclude_replies, :only_comments).permit(:limit, :only_media, :exclude_replies, :only_comments).merge(core_params)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
def insert_pagination_headers
|
||||||
|
@ -1,14 +1,31 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::GifsController < Api::BaseController
|
class Api::V1::GifsController < Api::BaseController
|
||||||
|
before_action :require_user!
|
||||||
|
|
||||||
respond_to :json
|
respond_to :json
|
||||||
|
|
||||||
skip_before_action :set_cache_headers
|
skip_before_action :set_cache_headers
|
||||||
|
|
||||||
def index
|
def categories
|
||||||
uri = URI('https://api.tenor.com/v1/categories')
|
uri = URI('https://api.tenor.com/v1/categories')
|
||||||
params = { :key => "QHFJ0C5EWGBH" }
|
theOptions = { :key => "QHFJ0C5EWGBH" }
|
||||||
uri.query = URI.encode_www_form(params)
|
uri.query = URI.encode_www_form(theOptions)
|
||||||
|
|
||||||
|
res = Net::HTTP.get_response(uri)
|
||||||
|
render json: res.body if res.is_a?(Net::HTTPSuccess)
|
||||||
|
end
|
||||||
|
|
||||||
|
def search
|
||||||
|
uri = URI('https://api.tenor.com/v1/search')
|
||||||
|
theOptions = {
|
||||||
|
:key => "QHFJ0C5EWGBH",
|
||||||
|
:media_filter => "minimal",
|
||||||
|
:limit => 30,
|
||||||
|
:q => params[:search],
|
||||||
|
:pos => params[:next] || 0
|
||||||
|
}
|
||||||
|
uri.query = URI.encode_www_form(theOptions)
|
||||||
|
|
||||||
res = Net::HTTP.get_response(uri)
|
res = Net::HTTP.get_response(uri)
|
||||||
render json: res.body if res.is_a?(Net::HTTPSuccess)
|
render json: res.body if res.is_a?(Net::HTTPSuccess)
|
||||||
|
@ -4,6 +4,7 @@ class Api::V1::NotificationsController < Api::BaseController
|
|||||||
before_action -> { doorkeeper_authorize! :read, :'read:notifications' }, except: [:clear, :dismiss, :mark_read]
|
before_action -> { doorkeeper_authorize! :read, :'read:notifications' }, except: [:clear, :dismiss, :mark_read]
|
||||||
before_action -> { doorkeeper_authorize! :write, :'write:notifications' }, only: [:clear, :dismiss, :mark_read]
|
before_action -> { doorkeeper_authorize! :write, :'write:notifications' }, only: [:clear, :dismiss, :mark_read]
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
|
before_action :set_filter_params
|
||||||
after_action :insert_pagination_headers, only: :index
|
after_action :insert_pagination_headers, only: :index
|
||||||
|
|
||||||
respond_to :json
|
respond_to :json
|
||||||
@ -49,7 +50,7 @@ class Api::V1::NotificationsController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def browserable_account_notifications
|
def browserable_account_notifications
|
||||||
current_account.notifications.browserable(exclude_types, from_account)
|
current_account.notifications.browserable(exclude_types, from_account, params[:only_verified], params[:only_following])
|
||||||
end
|
end
|
||||||
|
|
||||||
def target_statuses_from_notifications
|
def target_statuses_from_notifications
|
||||||
@ -86,6 +87,13 @@ class Api::V1::NotificationsController < Api::BaseController
|
|||||||
val
|
val
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_filter_params
|
||||||
|
params.permit(
|
||||||
|
:only_verified,
|
||||||
|
:only_following
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def from_account
|
def from_account
|
||||||
params[:account_id]
|
params[:account_id]
|
||||||
end
|
end
|
||||||
|
@ -100,12 +100,11 @@ function getFromDB(dispatch, getState, index, id) {
|
|||||||
|
|
||||||
export function fetchAccount(id) {
|
export function fetchAccount(id) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch(fetchRelationships([id]));
|
|
||||||
|
|
||||||
if (id === -1 || getState().getIn(['accounts', id], null) !== null) {
|
if (id === -1 || getState().getIn(['accounts', id], null) !== null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dispatch(fetchRelationships([id]));
|
||||||
dispatch(fetchAccountRequest(id));
|
dispatch(fetchAccountRequest(id));
|
||||||
|
|
||||||
openDB().then(db => getFromDB(
|
openDB().then(db => getFromDB(
|
||||||
@ -128,8 +127,13 @@ export function fetchAccount(id) {
|
|||||||
|
|
||||||
export function fetchAccountByUsername(username) {
|
export function fetchAccountByUsername(username) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
|
if (!username) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
api(getState).get(`/api/v1/account_by_username/${username}`).then(response => {
|
api(getState).get(`/api/v1/account_by_username/${username}`).then(response => {
|
||||||
dispatch(importFetchedAccount(response.data));
|
dispatch(importFetchedAccount(response.data))
|
||||||
|
dispatch(fetchRelationships([response.data.id]))
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
dispatch(fetchAccountSuccess());
|
dispatch(fetchAccountSuccess());
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
@ -165,14 +165,15 @@ export function expandNotifications({ maxId } = {}, done = noOp) {
|
|||||||
// filter verified and following here too
|
// filter verified and following here too
|
||||||
const params = {
|
const params = {
|
||||||
max_id: maxId,
|
max_id: maxId,
|
||||||
// only_verified: onlyVerified,
|
|
||||||
// only_following: onlyFollowing,
|
|
||||||
exclude_types: activeFilter === 'all' ? null : excludeTypesFromFilter(activeFilter),
|
exclude_types: activeFilter === 'all' ? null : excludeTypesFromFilter(activeFilter),
|
||||||
// exclude_types: activeFilter === 'all'
|
// exclude_types: activeFilter === 'all'
|
||||||
// ? excludeTypesFromSettings(getState())
|
// ? excludeTypesFromSettings(getState())
|
||||||
// : excludeTypesFromFilter(activeFilter),
|
// : excludeTypesFromFilter(activeFilter),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!!onlyVerified) params.only_verified = onlyVerified
|
||||||
|
if (!!onlyFollowing) params.only_following = onlyFollowing
|
||||||
|
|
||||||
if (!maxId && notifications.get('items').size > 0) {
|
if (!maxId && notifications.get('items').size > 0) {
|
||||||
params.since_id = notifications.getIn(['items', 0, 'id']);
|
params.since_id = notifications.getIn(['items', 0, 'id']);
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ export const fetchGifCategories = () => {
|
|||||||
|
|
||||||
dispatch(fetchGifCategoriesRequest())
|
dispatch(fetchGifCategoriesRequest())
|
||||||
|
|
||||||
api(getState).get('/api/v1/gifs').then(response => {
|
api(getState).get('/api/v1/gifs/categories').then(response => {
|
||||||
dispatch(fetchGifCategoriesSuccess(response.data.tags))
|
dispatch(fetchGifCategoriesSuccess(response.data.tags))
|
||||||
}).catch(function (error) {
|
}).catch(function (error) {
|
||||||
dispatch(fetchGifCategoriesFail(error))
|
dispatch(fetchGifCategoriesFail(error))
|
||||||
@ -29,24 +29,25 @@ export const fetchGifCategories = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchGifResults = (maxId) => {
|
export const fetchGifResults = (expand) => {
|
||||||
return function (dispatch, getState) {
|
return function (dispatch, getState) {
|
||||||
if (!me) return
|
if (!me) return
|
||||||
|
|
||||||
dispatch(fetchGifResultsRequest())
|
dispatch(fetchGifResultsRequest())
|
||||||
|
|
||||||
const searchText = getState().getIn(['tenor', 'searchText'], '');
|
const search = getState().getIn(['tenor', 'searchText'], '');
|
||||||
|
const pos = 0 //expand ? getState().getIn(['tenor', 'results'], []).length
|
||||||
|
|
||||||
axios.get(`https://api.tenor.com/v1/search?q=${searchText}&media_filter=minimal&limit=30&key=${tenorkey}`)
|
api(getState).get('/api/v1/gifs/search', { search, pos }).then((response) => {
|
||||||
.then((response) => {
|
console.log("response.data:", response.data)
|
||||||
console.log('response:', response)
|
dispatch(fetchGifResultsSuccess(response.data))
|
||||||
dispatch(fetchGifResultsSuccess(response.data.results))
|
}).catch(function (error) {
|
||||||
}).catch(function (error) {
|
dispatch(fetchGifResultsFail(error))
|
||||||
dispatch(fetchGifResultsFail(error))
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const clearGifResults = () => ({
|
export const clearGifResults = () => ({
|
||||||
type: GIFS_CLEAR_RESULTS,
|
type: GIFS_CLEAR_RESULTS,
|
||||||
})
|
})
|
||||||
@ -69,10 +70,10 @@ function fetchGifResultsRequest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchGifResultsSuccess(results) {
|
function fetchGifResultsSuccess(data) {
|
||||||
return {
|
return {
|
||||||
type: GIF_RESULTS_FETCH_SUCCESS,
|
type: GIF_RESULTS_FETCH_SUCCESS,
|
||||||
results,
|
data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) {
|
|||||||
|
|
||||||
export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);
|
export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);
|
||||||
export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done);
|
export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done);
|
||||||
export const expandAccountTimeline = (accountId, { maxId, withReplies } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, max_id: maxId });
|
export const expandAccountTimeline = (accountId, { maxId, withReplies, commentsOnly } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}${commentsOnly ? ':comments_only' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { only_comments: commentsOnly, exclude_replies: (!withReplies && !commentsOnly), max_id: maxId });
|
||||||
export const expandAccountFeaturedTimeline = accountId => expandTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true });
|
export const expandAccountFeaturedTimeline = accountId => expandTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true });
|
||||||
export const expandAccountMediaTimeline = (accountId, { maxId, limit } = {}) => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true, limit: limit || 20 });
|
export const expandAccountMediaTimeline = (accountId, { maxId, limit } = {}) => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true, limit: limit || 20 });
|
||||||
export const expandListTimeline = (id, { maxId } = {}, done = noOp) => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`, { max_id: maxId }, done);
|
export const expandListTimeline = (id, { maxId } = {}, done = noOp) => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`, { max_id: maxId }, done);
|
||||||
|
@ -136,6 +136,7 @@ export default class Button extends PureComponent {
|
|||||||
backgroundSubtle2Dark_onHover: backgroundColor === COLORS.tertiary || backgroundColor === COLORS.secondary,
|
backgroundSubtle2Dark_onHover: backgroundColor === COLORS.tertiary || backgroundColor === COLORS.secondary,
|
||||||
backgroundColorBlackOpaque_onHover: backgroundColor === COLORS.black,
|
backgroundColorBlackOpaque_onHover: backgroundColor === COLORS.black,
|
||||||
backgroundColorBrandDark_onHover: backgroundColor === COLORS.brand,
|
backgroundColorBrandDark_onHover: backgroundColor === COLORS.brand,
|
||||||
|
backgroundColorDangerDark_onHover: backgroundColor === COLORS.danger,
|
||||||
|
|
||||||
backgroundColorBrand_onHover: color === COLORS.brand && outline,
|
backgroundColorBrand_onHover: color === COLORS.brand && outline,
|
||||||
colorWhite_onHover: !!children && color === COLORS.brand && outline,
|
colorWhite_onHover: !!children && color === COLORS.brand && outline,
|
||||||
|
@ -52,7 +52,7 @@ class Comment extends ImmutablePureComponent {
|
|||||||
// : todo : add media
|
// : todo : add media
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={[_s.default, _s.px10, _s.mb10, _s.py5].join(' ')} data-comment={status.get('id')}>
|
<div className={[_s.default, _s.px15, _s.mb10, _s.py5].join(' ')} data-comment={status.get('id')}>
|
||||||
<div className={[_s.default].join(' ')} style={style}>
|
<div className={[_s.default].join(' ')} style={style}>
|
||||||
|
|
||||||
<div className={[_s.default, _s.flexRow].join(' ')}>
|
<div className={[_s.default, _s.flexRow].join(' ')}>
|
||||||
|
@ -1,20 +1,30 @@
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
|
import Button from './button'
|
||||||
import Comment from './comment'
|
import Comment from './comment'
|
||||||
|
import Text from './text'
|
||||||
|
|
||||||
export default class CommentList extends ImmutablePureComponent {
|
export default class CommentList extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
commentsLimited: PropTypes.bool,
|
||||||
descendants: ImmutablePropTypes.list,
|
descendants: ImmutablePropTypes.list,
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { descendants } = this.props
|
const {
|
||||||
|
descendants,
|
||||||
|
commentsLimited,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
const size = descendants.size
|
||||||
|
const max = Math.min(commentsLimited ? 2 : 6, size)
|
||||||
|
console.log("max:", size, max)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
descendants.map((descendant, i) => (
|
descendants.slice(0, max).map((descendant, i) => (
|
||||||
<Comment
|
<Comment
|
||||||
key={`comment-${descendant.get('statusId')}-${i}`}
|
key={`comment-${descendant.get('statusId')}-${i}`}
|
||||||
id={descendant.get('statusId')}
|
id={descendant.get('statusId')}
|
||||||
@ -22,6 +32,27 @@ export default class CommentList extends ImmutablePureComponent {
|
|||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
size > 0 && size > max &&
|
||||||
|
<div className={[_s.default, _s.flexRow, _s.px15, _s.pb5, _s.mb10, _s.alignItemsCenter].join(' ')}>
|
||||||
|
<Button
|
||||||
|
text
|
||||||
|
backgroundColor='none'
|
||||||
|
color='tertiary'
|
||||||
|
>
|
||||||
|
<Text weight='bold' color='inherit'>
|
||||||
|
View more comments
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
<div className={[_s.default, _s.marginLeftAuto].join(' ')}>
|
||||||
|
<Text color='tertiary'>
|
||||||
|
{max}
|
||||||
|
of
|
||||||
|
{size}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -33,29 +33,31 @@ class LoadMore extends PureComponent {
|
|||||||
const { disabled, visible, gap, intl } = this.props
|
const { disabled, visible, gap, intl } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<div className={[_s.default, _s.py10, _s.px10].join(' ')}>
|
||||||
block
|
<Button
|
||||||
radiusSmall
|
block
|
||||||
backgroundColor='tertiary'
|
radiusSmall
|
||||||
color='primary'
|
backgroundColor='tertiary'
|
||||||
disabled={disabled || !visible}
|
color='primary'
|
||||||
style={{ visibility: visible ? 'visible' : 'hidden' }}
|
disabled={disabled || !visible}
|
||||||
onClick={this.handleClick}
|
style={{ visibility: visible ? 'visible' : 'hidden' }}
|
||||||
aria-label={intl.formatMessage(messages.load_more)}
|
onClick={this.handleClick}
|
||||||
>
|
aria-label={intl.formatMessage(messages.load_more)}
|
||||||
{
|
>
|
||||||
!gap &&
|
{
|
||||||
<Text color='inherit'>
|
!gap &&
|
||||||
{intl.formatMessage(messages.load_more)}
|
<Text color='inherit'>
|
||||||
</Text>
|
{intl.formatMessage(messages.load_more)}
|
||||||
}
|
</Text>
|
||||||
{
|
}
|
||||||
gap &&
|
{
|
||||||
<Text align='center'>
|
gap &&
|
||||||
<Icon id='ellipsis' />
|
<Text align='center'>
|
||||||
</Text>
|
<Icon id='ellipsis' />
|
||||||
}
|
</Text>
|
||||||
</Button>
|
}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ class GifPickerModal extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleSelectGifResult = (resultId) => {
|
handleSelectGifResult = (resultId) => {
|
||||||
|
console.log("handleSelectGifResult:", resultId)
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -0,0 +1,68 @@
|
|||||||
|
import { injectIntl, defineMessages } from 'react-intl'
|
||||||
|
import { muteAccount } from '../../actions/accounts'
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
muteMessage: { id: 'confirmations.mute.message', defaultMessage: 'Are you sure you want to mute {name}?' },
|
||||||
|
cancel: { id: 'confirmation_modal.cancel', defaultMessage: 'Cancel' },
|
||||||
|
confirm: { id: 'confirmations.mute.confirm', defaultMessage: 'Mute' },
|
||||||
|
})
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => ({
|
||||||
|
isSubmitting: state.getIn(['reports', 'new', 'isSubmitting']),
|
||||||
|
account: state.getIn(['mutes', 'new', 'account']),
|
||||||
|
})
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
onConfirm(account, notifications) {
|
||||||
|
dispatch(muteAccount(account.get('id'), notifications))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export default
|
||||||
|
@connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
@injectIntl
|
||||||
|
class UnfollowModal extends PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
isSubmitting: PropTypes.bool.isRequired,
|
||||||
|
account: PropTypes.object.isRequired,
|
||||||
|
onConfirm: PropTypes.func.isRequired,
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.button.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClick = () => {
|
||||||
|
this.props.onClose()
|
||||||
|
this.props.onConfirm(this.props.account, this.props.notifications)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCancel = () => {
|
||||||
|
this.props.onClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { account, intl } = this.props
|
||||||
|
|
||||||
|
// , {
|
||||||
|
// message: <FormattedMessage id='confirmations.unfollow.message' defaultMessage='Are you sure you want to unfollow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||||
|
// confirm: intl.formatMessage(messages.unfollowConfirm),
|
||||||
|
// onConfirm: () => dispatch(unfollowAccount(account.get('id'))),
|
||||||
|
// }));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfirmationModal
|
||||||
|
title={`Mute @${account.get('acct')}`}
|
||||||
|
message={<FormattedMessage id='confirmations.mute.message' defaultMessage='Are you sure you want to mute @{name}?' values={{ name: account.get('acct') }} />}
|
||||||
|
confirm={<FormattedMessage id='mute' defaultMessage='Mute' />}
|
||||||
|
onConfirm={() => {
|
||||||
|
// dispatch(blockDomain(domain))
|
||||||
|
// dispatch(blockDomain(domain))
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import axios from 'axios'
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'
|
||||||
|
import Sticky from 'react-stickynode'
|
||||||
import classNames from 'classnames/bind'
|
import classNames from 'classnames/bind'
|
||||||
import {
|
import {
|
||||||
followAccount,
|
followAccount,
|
||||||
@ -26,9 +26,11 @@ const cx = classNames.bind(_s)
|
|||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
follow: { id: 'follow', defaultMessage: 'Follow' },
|
follow: { id: 'follow', defaultMessage: 'Follow' },
|
||||||
|
following: { id: 'following', defaultMessage: 'Following' },
|
||||||
unfollow: { id: 'unfollow', defaultMessage: 'Unfollow' },
|
unfollow: { id: 'unfollow', defaultMessage: 'Unfollow' },
|
||||||
requested: { id: 'requested', defaultMessage: 'Requested' },
|
requested: { id: 'requested', defaultMessage: 'Requested' },
|
||||||
unblock: { id: 'unblock', defaultMessage: 'Unblock' },
|
unblock: { id: 'unblock', defaultMessage: 'Unblock' },
|
||||||
|
blocked: { id: 'account.blocked', defaultMessage: 'Blocked' },
|
||||||
followers: { id: 'account.followers', defaultMessage: 'Followers' },
|
followers: { id: 'account.followers', defaultMessage: 'Followers' },
|
||||||
follows: { id: 'account.follows', defaultMessage: 'Follows' },
|
follows: { id: 'account.follows', defaultMessage: 'Follows' },
|
||||||
profile: { id: 'account.profile', defaultMessage: 'Profile' },
|
profile: { id: 'account.profile', defaultMessage: 'Profile' },
|
||||||
@ -92,6 +94,10 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||||||
openProfileOptionsPopover: PropTypes.func.isRequired,
|
openProfileOptionsPopover: PropTypes.func.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state = {
|
||||||
|
stickied: false,
|
||||||
|
}
|
||||||
|
|
||||||
handleOpenMore = () => {
|
handleOpenMore = () => {
|
||||||
const { openProfileOptionsPopover, account } = this.props
|
const { openProfileOptionsPopover, account } = this.props
|
||||||
openProfileOptionsPopover({
|
openProfileOptionsPopover({
|
||||||
@ -110,7 +116,7 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// : todo :
|
// : todo :
|
||||||
makeInfo() {
|
makeInfo = () => {
|
||||||
const { account, intl } = this.props
|
const { account, intl } = this.props
|
||||||
|
|
||||||
const info = []
|
const info = []
|
||||||
@ -132,12 +138,24 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onStickyStateChange = (status) => {
|
||||||
|
switch (status.status) {
|
||||||
|
case Sticky.STATUS_FIXED:
|
||||||
|
this.setState({ stickied: true })
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.setState({ stickied: false })
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setOpenMoreNodeRef = (n) => {
|
setOpenMoreNodeRef = (n) => {
|
||||||
this.openMoreNode = n
|
this.openMoreNode = n
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { account, intl } = this.props
|
const { account, intl } = this.props
|
||||||
|
const { stickied } = this.state
|
||||||
|
|
||||||
const tabs = !account ? null : [
|
const tabs = !account ? null : [
|
||||||
{
|
{
|
||||||
@ -160,6 +178,60 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||||||
|
|
||||||
const headerSrc = !!account ? account.get('header') : ''
|
const headerSrc = !!account ? account.get('header') : ''
|
||||||
const headerMissing = headerSrc.indexOf('/headers/original/missing.png') > -1 || !headerSrc
|
const headerMissing = headerSrc.indexOf('/headers/original/missing.png') > -1 || !headerSrc
|
||||||
|
const avatarSize = headerMissing ? '75' : '150'
|
||||||
|
|
||||||
|
let buttonText = ''
|
||||||
|
let buttonOptions = {}
|
||||||
|
|
||||||
|
if (!account) {
|
||||||
|
//
|
||||||
|
} else {
|
||||||
|
if (!account.get('relationship')) {
|
||||||
|
// Wait until the relationship is loaded
|
||||||
|
} else {
|
||||||
|
const isRequested = account.getIn(['relationship', 'requested'])
|
||||||
|
const isBlocking = account.getIn(['relationship', 'blocking'])
|
||||||
|
const isFollowing = account.getIn(['relationship', 'following'])
|
||||||
|
const isBlockedBy = account.getIn(['relationship', 'blocked_by'])
|
||||||
|
|
||||||
|
if (isRequested) {
|
||||||
|
buttonText = intl.formatMessage(messages.requested)
|
||||||
|
buttonOptions = {
|
||||||
|
onClick: this.handleFollow,
|
||||||
|
color: 'primary',
|
||||||
|
backgroundColor: 'tertiary',
|
||||||
|
}
|
||||||
|
} else if (isBlocking) {
|
||||||
|
buttonText = intl.formatMessage(messages.blocked)
|
||||||
|
buttonOptions = {
|
||||||
|
onClick: this.handleBlock,
|
||||||
|
color: 'white',
|
||||||
|
backgroundColor: 'danger',
|
||||||
|
}
|
||||||
|
} else if (isFollowing) {
|
||||||
|
buttonText = intl.formatMessage(messages.following)
|
||||||
|
buttonOptions = {
|
||||||
|
onClick: this.handleFollow,
|
||||||
|
color: 'white',
|
||||||
|
backgroundColor: 'brand',
|
||||||
|
}
|
||||||
|
} else if (isBlockedBy) {
|
||||||
|
//Don't show
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
buttonText = intl.formatMessage(messages.follow)
|
||||||
|
buttonOptions = {
|
||||||
|
onClick: this.handleFollow,
|
||||||
|
color: 'brand',
|
||||||
|
backgroundColor: 'none',
|
||||||
|
outline: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('buttonOptions:', buttonText, buttonOptions)
|
||||||
|
console.log('account: ', account)
|
||||||
|
|
||||||
const avatarContainerClasses = cx({
|
const avatarContainerClasses = cx({
|
||||||
circle: 1,
|
circle: 1,
|
||||||
@ -168,78 +240,18 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||||||
border2PX: 1,
|
border2PX: 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
const avatarSize = headerMissing ? '75' : '150'
|
const stickyBarContainerClasses = cx({
|
||||||
|
default: 1,
|
||||||
|
flexRow: 1,
|
||||||
|
px15: 1,
|
||||||
|
alignItemsCenter: 1,
|
||||||
|
displayNone: !stickied,
|
||||||
|
})
|
||||||
|
|
||||||
let buttonText = ''
|
const tabBarContainerClasses = cx({
|
||||||
let buttonOptions = {}
|
default: 1,
|
||||||
|
displayNone: stickied,
|
||||||
if (!account) {
|
})
|
||||||
console.log('no account')
|
|
||||||
} else {
|
|
||||||
if (!account.get('relationship')) {
|
|
||||||
console.log('no relationship')
|
|
||||||
// Wait until the relationship is loaded
|
|
||||||
} else if (account.getIn(['relationship', 'requested'])) {
|
|
||||||
buttonText = intl.formatMessage(messages.requested)
|
|
||||||
buttonOptions = {
|
|
||||||
narrow: true,
|
|
||||||
onClick: this.handleFollow,
|
|
||||||
color: 'primary',
|
|
||||||
backgroundColor: 'tertiary',
|
|
||||||
}
|
|
||||||
} else if (!account.getIn(['relationship', 'blocking'])) {
|
|
||||||
const isFollowing = account.getIn(['relationship', 'following'])
|
|
||||||
const isBlockedBy = account.getIn(['relationship', 'blocked_by'])
|
|
||||||
buttonText = intl.formatMessage(isFollowing ? messages.unfollow : messages.follow)
|
|
||||||
buttonOptions = {
|
|
||||||
narrow: true,
|
|
||||||
onClick: this.handleFollow,
|
|
||||||
color: 'primary',
|
|
||||||
backgroundColor: 'tertiary',
|
|
||||||
disabled: isBlockedBy,
|
|
||||||
}
|
|
||||||
} else if (account.getIn(['relationship', 'blocking'])) {
|
|
||||||
buttonText = intl.formatMessage(messages.unblock)
|
|
||||||
buttonOptions = {
|
|
||||||
narrow: true,
|
|
||||||
onClick: this.handleBlock,
|
|
||||||
color: 'primary',
|
|
||||||
backgroundColor: 'tertiary',
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.log('no nothin')
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (account.get('id') !== me && account.get('relationship', null) !== null) {
|
|
||||||
// const following = account.getIn(['relationship', 'following'])
|
|
||||||
// const requested = account.getIn(['relationship', 'requested'])
|
|
||||||
// const blocking = account.getIn(['relationship', 'blocking'])
|
|
||||||
|
|
||||||
// if (requested || blocking) {
|
|
||||||
// buttonText = intl.formatMessage(requested ? messages.requested : messages.unblock)
|
|
||||||
// buttonOptions = {
|
|
||||||
// narrow: true,
|
|
||||||
// onClick: requested ? this.handleFollow : this.handleBlock,
|
|
||||||
// color: 'primary',
|
|
||||||
// backgroundColor: 'tertiary',
|
|
||||||
// }
|
|
||||||
// } else if (!account.get('moved') || following) {
|
|
||||||
// buttonOptions = {
|
|
||||||
// narrow: true,
|
|
||||||
// outline: !following,
|
|
||||||
// color: !following ? 'brand' : 'white',
|
|
||||||
// backgroundColor: !following ? 'none' : 'brand',
|
|
||||||
// onClick: this.handleFollow,
|
|
||||||
// }
|
|
||||||
// buttonText = intl.formatMessage(following ? messages.unfollow : messages.follow)
|
|
||||||
// } else {
|
|
||||||
// console.log("SHOW ELSE")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('buttonOptions:', buttonText, buttonOptions)
|
|
||||||
console.log('account: ', account)
|
|
||||||
|
|
||||||
|
|
||||||
// : todo : "follows you", "mutual follow"
|
// : todo : "follows you", "mutual follow"
|
||||||
@ -260,7 +272,7 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||||||
|
|
||||||
<div className={[_s.default, _s.borderBottom1PX, _s.borderColorSecondary, _s.width100PC].join(' ')}>
|
<div className={[_s.default, _s.borderBottom1PX, _s.borderColorSecondary, _s.width100PC].join(' ')}>
|
||||||
|
|
||||||
<div className={[_s.default, _s.flexRow, _s.px15].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.px15, _s.mb5].join(' ')}>
|
||||||
<div className={avatarContainerClasses}>
|
<div className={avatarContainerClasses}>
|
||||||
<Avatar size={avatarSize} account={account} />
|
<Avatar size={avatarSize} account={account} />
|
||||||
</div>
|
</div>
|
||||||
@ -271,87 +283,103 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||||||
account && account.get('locked') &&
|
account && account.get('locked') &&
|
||||||
<Icon id='lock-filled' height='14px' width='14px' className={[_s.mt10, _s.ml10].join(' ')} />
|
<Icon id='lock-filled' height='14px' width='14px' className={[_s.mt10, _s.ml10].join(' ')} />
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
/* : todo :
|
||||||
|
account.getIn(['relationship', 'muting'])
|
||||||
|
*/
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={[_s.default, _s.flexRow, _s.borderBottom1PX, _s.borderColorSecondary, _s.mt5, _s.height53PX].join(' ')}>
|
<Sticky enabled onStateChange={this.onStickyStateChange}>
|
||||||
<div className={[_s.default].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.backgroundColorSecondary3, _s.borderBottom1PX, _s.borderColorSecondary, _s.height53PX].join(' ')}>
|
||||||
<TabBar tabs={tabs} large />
|
<div className={tabBarContainerClasses}>
|
||||||
</div>
|
<TabBar tabs={tabs} large />
|
||||||
|
|
||||||
{
|
|
||||||
account && account.get('id') === me &&
|
|
||||||
<div className={[_s.default, _s.flexRow, _s.marginLeftAuto, _s.py5].join(' ')}>
|
|
||||||
<Button
|
|
||||||
outline
|
|
||||||
backgroundColor='none'
|
|
||||||
color='brand'
|
|
||||||
className={[_s.justifyContentCenter, _s.alignItemsCenter].join(' ')}
|
|
||||||
href=''
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
color='inherit'
|
|
||||||
weight='bold'
|
|
||||||
size='medium'
|
|
||||||
className={[_s.px15].join(' ')}
|
|
||||||
>
|
|
||||||
Edit Profile
|
|
||||||
</Text>
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
|
||||||
|
|
||||||
{
|
<div className={stickyBarContainerClasses}>
|
||||||
account && account.get('id') !== me &&
|
<Avatar size={36} account={account} />
|
||||||
<div className={[_s.default, _s.flexRow, _s.marginLeftAuto, _s.py5].join(' ')}>
|
<div className={[_s.default, _s.ml10].join(' ')}>
|
||||||
<div ref={this.setOpenMoreNodeRef}>
|
<DisplayName account={account} noUsername large />
|
||||||
<Button
|
|
||||||
outline
|
|
||||||
icon='ellipsis'
|
|
||||||
iconWidth='18px'
|
|
||||||
iconHeight='18px'
|
|
||||||
iconClassName={_s.inheritFill}
|
|
||||||
color='brand'
|
|
||||||
backgroundColor='none'
|
|
||||||
className={[_s.justifyContentCenter, _s.alignItemsCenter, _s.mr10, _s.px10].join(' ')}
|
|
||||||
onClick={this.handleOpenMore}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<form action='https://chat.gab.com/private-message' method='POST'>
|
{
|
||||||
|
account && account.get('id') === me &&
|
||||||
|
<div className={[_s.default, _s.flexRow, _s.marginLeftAuto, _s.py5].join(' ')}>
|
||||||
<Button
|
<Button
|
||||||
type='submit'
|
|
||||||
outline
|
outline
|
||||||
icon='chat'
|
|
||||||
iconWidth='18px'
|
|
||||||
iconHeight='18px'
|
|
||||||
iconClassName={_s.inheritFill}
|
|
||||||
color='brand'
|
|
||||||
backgroundColor='none'
|
backgroundColor='none'
|
||||||
className={[_s.justifyContentCenter, _s.alignItemsCenter, _s.mr10, _s.px10].join(' ')}
|
color='brand'
|
||||||
/>
|
className={[_s.justifyContentCenter, _s.alignItemsCenter].join(' ')}
|
||||||
<input type='hidden' value={account.get('username')} name='username' />
|
href=''
|
||||||
</form>
|
>
|
||||||
|
|
||||||
<Button
|
|
||||||
{...buttonOptions}
|
|
||||||
className={[_s.justifyContentCenter, _s.alignItemsCenter].join(' ')}
|
|
||||||
>
|
|
||||||
<span className={[_s.px15].join(' ')}>
|
|
||||||
<Text
|
<Text
|
||||||
color='inherit'
|
color='inherit'
|
||||||
weight='bold'
|
weight='bold'
|
||||||
size='medium'
|
size='medium'
|
||||||
className={[_s.px15].join(' ')}
|
className={[_s.px15].join(' ')}
|
||||||
>
|
>
|
||||||
{buttonText}
|
Edit Profile
|
||||||
</Text>
|
</Text>
|
||||||
</span>
|
</Button>
|
||||||
</Button>
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
</div>
|
{
|
||||||
}
|
account && account.get('id') !== me &&
|
||||||
</div>
|
<div className={[_s.default, _s.flexRow, _s.marginLeftAuto, _s.py5].join(' ')}>
|
||||||
|
<div ref={this.setOpenMoreNodeRef}>
|
||||||
|
<Button
|
||||||
|
outline
|
||||||
|
icon='ellipsis'
|
||||||
|
iconWidth='18px'
|
||||||
|
iconHeight='18px'
|
||||||
|
iconClassName={_s.inheritFill}
|
||||||
|
color='brand'
|
||||||
|
backgroundColor='none'
|
||||||
|
className={[_s.justifyContentCenter, _s.alignItemsCenter, _s.mr10, _s.px10].join(' ')}
|
||||||
|
onClick={this.handleOpenMore}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form action='https://chat.gab.com/private-message' method='POST'>
|
||||||
|
<Button
|
||||||
|
type='submit'
|
||||||
|
outline
|
||||||
|
icon='chat'
|
||||||
|
iconWidth='18px'
|
||||||
|
iconHeight='18px'
|
||||||
|
iconClassName={_s.inheritFill}
|
||||||
|
color='brand'
|
||||||
|
backgroundColor='none'
|
||||||
|
className={[_s.justifyContentCenter, _s.alignItemsCenter, _s.mr10, _s.px10].join(' ')}
|
||||||
|
/>
|
||||||
|
<input type='hidden' value={account.get('username')} name='username' />
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{
|
||||||
|
!!buttonText &&
|
||||||
|
<Button
|
||||||
|
{...buttonOptions}
|
||||||
|
narrow
|
||||||
|
className={[_s.justifyContentCenter, _s.alignItemsCenter].join(' ')}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
color='inherit'
|
||||||
|
weight='bold'
|
||||||
|
size='medium'
|
||||||
|
className={_s.px10}
|
||||||
|
>
|
||||||
|
{buttonText}
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</Sticky>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -106,8 +106,6 @@ class Sidebar extends ImmutablePureComponent {
|
|||||||
const acct = account.get('acct')
|
const acct = account.get('acct')
|
||||||
const isPro = account.get('is_pro')
|
const isPro = account.get('is_pro')
|
||||||
|
|
||||||
console.log('showCommunityTimeline:', showCommunityTimeline)
|
|
||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
{
|
{
|
||||||
title: 'Home',
|
title: 'Home',
|
||||||
|
@ -84,7 +84,6 @@ class Status extends ImmutablePureComponent {
|
|||||||
hidden: PropTypes.bool,
|
hidden: PropTypes.bool,
|
||||||
onMoveUp: PropTypes.func,
|
onMoveUp: PropTypes.func,
|
||||||
onMoveDown: PropTypes.func,
|
onMoveDown: PropTypes.func,
|
||||||
showThread: PropTypes.bool,
|
|
||||||
getScrollPosition: PropTypes.func,
|
getScrollPosition: PropTypes.func,
|
||||||
updateScrollBottom: PropTypes.func,
|
updateScrollBottom: PropTypes.func,
|
||||||
cacheMediaWidth: PropTypes.func,
|
cacheMediaWidth: PropTypes.func,
|
||||||
@ -93,7 +92,6 @@ class Status extends ImmutablePureComponent {
|
|||||||
promoted: PropTypes.bool,
|
promoted: PropTypes.bool,
|
||||||
onOpenProUpgradeModal: PropTypes.func,
|
onOpenProUpgradeModal: PropTypes.func,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
borderless: PropTypes.bool,
|
|
||||||
isChild: PropTypes.bool,
|
isChild: PropTypes.bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,10 +265,8 @@ class Status extends ImmutablePureComponent {
|
|||||||
intl,
|
intl,
|
||||||
hidden,
|
hidden,
|
||||||
featured,
|
featured,
|
||||||
showThread,
|
|
||||||
group,
|
group,
|
||||||
promoted,
|
promoted,
|
||||||
borderless,
|
|
||||||
isChild,
|
isChild,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
@ -386,8 +382,8 @@ class Status extends ImmutablePureComponent {
|
|||||||
|
|
||||||
const containerClasses = cx({
|
const containerClasses = cx({
|
||||||
default: 1,
|
default: 1,
|
||||||
radiusSmall: !borderless && !isChild,
|
radiusSmall: !isChild,
|
||||||
// mb15: !borderless && !isChild,
|
// mb15: !isChild,
|
||||||
// backgroundColorPrimary: 1,
|
// backgroundColorPrimary: 1,
|
||||||
pb15: featured,
|
pb15: featured,
|
||||||
borderBottom1PX: featured && !isChild,
|
borderBottom1PX: featured && !isChild,
|
||||||
@ -397,9 +393,9 @@ class Status extends ImmutablePureComponent {
|
|||||||
const innerContainerClasses = cx({
|
const innerContainerClasses = cx({
|
||||||
default: 1,
|
default: 1,
|
||||||
overflowHidden: 1,
|
overflowHidden: 1,
|
||||||
radiusSmall: !borderless,
|
radiusSmall: isChild,
|
||||||
borderColorSecondary: !borderless,
|
borderColorSecondary: isChild,
|
||||||
border1PX: !borderless,
|
border1PX: isChild,
|
||||||
pb10: isChild && status.get('media_attachments').size === 0,
|
pb10: isChild && status.get('media_attachments').size === 0,
|
||||||
pb5: isChild && status.get('media_attachments').size > 1,
|
pb5: isChild && status.get('media_attachments').size > 1,
|
||||||
cursorPointer: isChild,
|
cursorPointer: isChild,
|
||||||
@ -409,7 +405,7 @@ class Status extends ImmutablePureComponent {
|
|||||||
return (
|
return (
|
||||||
<HotKeys handlers={handlers}>
|
<HotKeys handlers={handlers}>
|
||||||
<div
|
<div
|
||||||
className={containerClasses}
|
className={containerClasses}
|
||||||
tabIndex={this.props.muted ? null : 0}
|
tabIndex={this.props.muted ? null : 0}
|
||||||
data-featured={featured ? 'true' : null}
|
data-featured={featured ? 'true' : null}
|
||||||
aria-label={textForScreenReader(intl, status, rebloggedByText)}
|
aria-label={textForScreenReader(intl, status, rebloggedByText)}
|
||||||
|
@ -105,14 +105,6 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleQuoteClick = () => {
|
|
||||||
if (me) {
|
|
||||||
this.props.onQuote(this.props.status, this.context.router.history)
|
|
||||||
} else {
|
|
||||||
this.props.onOpenUnauthorizedModal()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleFavoriteClick = () => {
|
handleFavoriteClick = () => {
|
||||||
if (me) {
|
if (me) {
|
||||||
this.props.onFavorite(this.props.status)
|
this.props.onFavorite(this.props.status)
|
||||||
@ -123,17 +115,29 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
|
|
||||||
handleRepostClick = e => {
|
handleRepostClick = e => {
|
||||||
if (me) {
|
if (me) {
|
||||||
this.props.onRepost(this.props.status, e)
|
// this.props.onRepost(this.props.status, e)
|
||||||
|
this.props.onQuote(this.props.status, this.context.router.history)
|
||||||
} else {
|
} else {
|
||||||
this.props.onOpenUnauthorizedModal()
|
this.props.onOpenUnauthorizedModal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleShareClick = () => {
|
handleShareClick = () => {
|
||||||
console.log("handleShareClick:", this.shareButton, this.props.status)
|
|
||||||
this.props.onOpenStatusSharePopover(this.shareButton, this.props.status)
|
this.props.onOpenStatusSharePopover(this.shareButton, this.props.status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openLikesList = () => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleCommentsVisible = () => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
openRepostsList = () => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
setShareButton = (n) => {
|
setShareButton = (n) => {
|
||||||
this.shareButton = n
|
this.shareButton = n
|
||||||
}
|
}
|
||||||
@ -176,6 +180,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
text: 1,
|
text: 1,
|
||||||
cursorPointer: 1,
|
cursorPointer: 1,
|
||||||
fontWeightNormal: 1,
|
fontWeightNormal: 1,
|
||||||
|
underline_onHover: 1,
|
||||||
mr10: 1,
|
mr10: 1,
|
||||||
py5: 1,
|
py5: 1,
|
||||||
})
|
})
|
||||||
@ -187,7 +192,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
<div className={[_s.default, _s.flexRow, _s.px5].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.px5].join(' ')}>
|
||||||
{
|
{
|
||||||
favoriteCount > 0 &&
|
favoriteCount > 0 &&
|
||||||
<button className={interactionBtnClasses}>
|
<button className={interactionBtnClasses} onClick={this.openLikesList}>
|
||||||
<Text color='secondary' size='small'>
|
<Text color='secondary' size='small'>
|
||||||
{formatMessage(messages.likesLabel, {
|
{formatMessage(messages.likesLabel, {
|
||||||
number: favoriteCount,
|
number: favoriteCount,
|
||||||
@ -197,7 +202,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
replyCount > 0 &&
|
replyCount > 0 &&
|
||||||
<button className={interactionBtnClasses}>
|
<button className={interactionBtnClasses} onClick={this.toggleCommentsVisible}>
|
||||||
<Text color='secondary' size='small'>
|
<Text color='secondary' size='small'>
|
||||||
{formatMessage(messages.commentsLabel, {
|
{formatMessage(messages.commentsLabel, {
|
||||||
number: replyCount,
|
number: replyCount,
|
||||||
@ -207,7 +212,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
repostCount > 0 &&
|
repostCount > 0 &&
|
||||||
<button className={interactionBtnClasses}>
|
<button className={interactionBtnClasses} onClick={this.openRepostsList}>
|
||||||
<Text color='secondary' size='small'>
|
<Text color='secondary' size='small'>
|
||||||
{formatMessage(messages.repostsLabel, {
|
{formatMessage(messages.repostsLabel, {
|
||||||
number: repostCount,
|
number: repostCount,
|
||||||
|
@ -38,7 +38,9 @@ const makeGetStatusIds = () => createSelector([
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapStateToProps = (state, {timelineId}) => {
|
const mapStateToProps = (state, { timelineId }) => {
|
||||||
|
if (!timelineId) return {}
|
||||||
|
|
||||||
const getStatusIds = makeGetStatusIds();
|
const getStatusIds = makeGetStatusIds();
|
||||||
const promotion = promotions.length > 0 && sample(promotions.filter(p => p.timeline_id === timelineId));
|
const promotion = promotions.length > 0 && sample(promotions.filter(p => p.timeline_id === timelineId));
|
||||||
|
|
||||||
@ -181,15 +183,15 @@ class StatusList extends ImmutablePureComponent {
|
|||||||
contextType={timelineId}
|
contextType={timelineId}
|
||||||
group={group}
|
group={group}
|
||||||
withGroupAdmin={withGroupAdmin}
|
withGroupAdmin={withGroupAdmin}
|
||||||
showThread
|
commentsLimited
|
||||||
/>
|
/>
|
||||||
{
|
{ /* : todo : */
|
||||||
promotedStatus && index === promotion.position &&
|
promotedStatus && index === promotion.position &&
|
||||||
<Status
|
<Status
|
||||||
id={promotion.status_id}
|
id={promotion.status_id}
|
||||||
contextType={timelineId}
|
contextType={timelineId}
|
||||||
promoted
|
promoted
|
||||||
showThread
|
commentsLimited
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
@ -205,7 +207,7 @@ class StatusList extends ImmutablePureComponent {
|
|||||||
onMoveUp={this.handleMoveUp}
|
onMoveUp={this.handleMoveUp}
|
||||||
onMoveDown={this.handleMoveDown}
|
onMoveDown={this.handleMoveDown}
|
||||||
contextType={timelineId}
|
contextType={timelineId}
|
||||||
showThread
|
commentsLimited
|
||||||
/>
|
/>
|
||||||
)).concat(scrollableContent)
|
)).concat(scrollableContent)
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ const cx = classNames.bind(_s)
|
|||||||
const COLORS = {
|
const COLORS = {
|
||||||
primary: 'primary',
|
primary: 'primary',
|
||||||
secondary: 'secondary',
|
secondary: 'secondary',
|
||||||
|
tertiary: 'tertiary',
|
||||||
brand: 'brand',
|
brand: 'brand',
|
||||||
error: 'error',
|
error: 'error',
|
||||||
white: 'white',
|
white: 'white',
|
||||||
@ -78,6 +79,7 @@ export default class Text extends PureComponent {
|
|||||||
|
|
||||||
colorPrimary: color === COLORS.primary,
|
colorPrimary: color === COLORS.primary,
|
||||||
colorSecondary: color === COLORS.secondary,
|
colorSecondary: color === COLORS.secondary,
|
||||||
|
colorTertiary: color === COLORS.tertiary,
|
||||||
colorBrand: color === COLORS.brand,
|
colorBrand: color === COLORS.brand,
|
||||||
colorWhite: color === COLORS.white,
|
colorWhite: color === COLORS.white,
|
||||||
colorGabPro: color === COLORS.pro,
|
colorGabPro: color === COLORS.pro,
|
||||||
|
@ -12,15 +12,17 @@ const messages = defineMessages({
|
|||||||
|
|
||||||
const emptyList = ImmutableList()
|
const emptyList = ImmutableList()
|
||||||
|
|
||||||
const mapStateToProps = (state, { account, withReplies = false }) => {
|
const mapStateToProps = (state, { account, commentsOnly = false }) => {
|
||||||
const accountId = !!account ? account.getIn(['id'], null) : -1
|
const accountId = !!account ? account.getIn(['id'], null) : -1
|
||||||
|
|
||||||
const path = withReplies ? `${accountId}:with_replies` : accountId
|
const path = commentsOnly ? `${accountId}:comments_only` : accountId
|
||||||
|
|
||||||
|
console.log("commentsOnly, path:", commentsOnly, path)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
accountId,
|
accountId,
|
||||||
statusIds: state.getIn(['timelines', `account:${path}`, 'items'], emptyList),
|
statusIds: state.getIn(['timelines', `account:${path}`, 'items'], emptyList),
|
||||||
featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned`, 'items'], emptyList),
|
featuredStatusIds: commentsOnly ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned`, 'items'], emptyList),
|
||||||
isLoading: state.getIn(['timelines', `account:${path}`, 'isLoading']),
|
isLoading: state.getIn(['timelines', `account:${path}`, 'isLoading']),
|
||||||
hasMore: state.getIn(['timelines', `account:${path}`, 'hasMore']),
|
hasMore: state.getIn(['timelines', `account:${path}`, 'hasMore']),
|
||||||
}
|
}
|
||||||
@ -38,33 +40,33 @@ class AccountTimeline extends ImmutablePureComponent {
|
|||||||
featuredStatusIds: ImmutablePropTypes.list,
|
featuredStatusIds: ImmutablePropTypes.list,
|
||||||
isLoading: PropTypes.bool,
|
isLoading: PropTypes.bool,
|
||||||
hasMore: PropTypes.bool,
|
hasMore: PropTypes.bool,
|
||||||
withReplies: PropTypes.bool,
|
commentsOnly: PropTypes.bool,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
const { accountId, withReplies } = this.props
|
const { accountId, commentsOnly } = this.props
|
||||||
|
|
||||||
if (accountId && accountId !== -1) {
|
if (accountId && accountId !== -1) {
|
||||||
this.props.dispatch(fetchAccountIdentityProofs(accountId))
|
this.props.dispatch(fetchAccountIdentityProofs(accountId))
|
||||||
|
|
||||||
if (!withReplies) {
|
if (!commentsOnly) {
|
||||||
this.props.dispatch(expandAccountFeaturedTimeline(accountId))
|
this.props.dispatch(expandAccountFeaturedTimeline(accountId))
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.dispatch(expandAccountTimeline(accountId, { withReplies }))
|
this.props.dispatch(expandAccountTimeline(accountId, { commentsOnly }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
if (nextProps.accountId && nextProps.accountId !== -1 && (nextProps.accountId !== this.props.accountId && nextProps.accountId) || nextProps.withReplies !== this.props.withReplies) {
|
if (nextProps.accountId && nextProps.accountId !== -1 && (nextProps.accountId !== this.props.accountId && nextProps.accountId) || nextProps.commentsOnly !== this.props.commentsOnly) {
|
||||||
this.props.dispatch(fetchAccountIdentityProofs(nextProps.accountId))
|
this.props.dispatch(fetchAccountIdentityProofs(nextProps.accountId))
|
||||||
|
|
||||||
if (!nextProps.withReplies) {
|
if (!nextProps.commentsOnly) {
|
||||||
this.props.dispatch(expandAccountFeaturedTimeline(nextProps.accountId))
|
this.props.dispatch(expandAccountFeaturedTimeline(nextProps.accountId))
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.dispatch(expandAccountTimeline(nextProps.accountId, { withReplies: nextProps.withReplies }))
|
this.props.dispatch(expandAccountTimeline(nextProps.accountId, { commentsOnly: nextProps.commentsOnly }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +74,7 @@ class AccountTimeline extends ImmutablePureComponent {
|
|||||||
if (this.props.accountId && this.props.accountId !== -1) {
|
if (this.props.accountId && this.props.accountId !== -1) {
|
||||||
this.props.dispatch(expandAccountTimeline(this.props.accountId, {
|
this.props.dispatch(expandAccountTimeline(this.props.accountId, {
|
||||||
maxId,
|
maxId,
|
||||||
withReplies: this.props.withReplies
|
commentsOnly: this.props.commentsOnly
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,6 +91,8 @@ class AccountTimeline extends ImmutablePureComponent {
|
|||||||
|
|
||||||
if (!account) return null
|
if (!account) return null
|
||||||
|
|
||||||
|
console.log("statusIds:", statusIds)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StatusList
|
<StatusList
|
||||||
scrollKey='account_timeline'
|
scrollKey='account_timeline'
|
||||||
|
@ -193,8 +193,8 @@ class ComposeForm extends ImmutablePureComponent {
|
|||||||
selectionStart = selectionEnd;
|
selectionStart = selectionEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.autosuggestTextarea.textbox.setSelectionRange(selectionStart, selectionEnd);
|
// this.autosuggestTextarea.textbox.setSelectionRange(selectionStart, selectionEnd);
|
||||||
this.autosuggestTextarea.textbox.focus();
|
// this.autosuggestTextarea.textbox.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,6 +332,14 @@ class ComposeForm extends ImmutablePureComponent {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ /*
|
||||||
|
(isUploading || hasGif) &&
|
||||||
|
<div className={[_s.default, _s.px15].join(' ')}>
|
||||||
|
<UploadForm replyToId={replyToId} />
|
||||||
|
</div>
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
!edit && hasPoll &&
|
!edit && hasPoll &&
|
||||||
<div className={[_s.default, _s.px15].join(' ')}>
|
<div className={[_s.default, _s.px15].join(' ')}>
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
|
import ProgressBar from '../../../../components/progress_bar'
|
||||||
|
import Upload from '../media_upload_item'
|
||||||
|
import SensitiveMediaButton from '../sensitive_media_button'
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => ({
|
||||||
|
mediaIds: state.getIn(['compose', 'media_attachments']).map(item => item.get('id')),
|
||||||
|
isUploading: state.getIn(['compose', 'is_uploading']),
|
||||||
|
uploadProgress: state.getIn(['compose', 'progress']),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default
|
||||||
|
@connect(mapStateToProps)
|
||||||
|
class GifForm extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
mediaIds: ImmutablePropTypes.list.isRequired,
|
||||||
|
isUploading: PropTypes.bool,
|
||||||
|
uploadProgress: PropTypes.number,
|
||||||
|
};
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const {
|
||||||
|
mediaIds,
|
||||||
|
isUploading,
|
||||||
|
uploadProgress,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={_s.default}>
|
||||||
|
<div className={[_s.default, _s.flexRow, _s.flexWrap].join(' ')}>
|
||||||
|
<Upload id={id} key={id} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import ProgressBar from '../../../../components/progress_bar'
|
import ProgressBar from '../../../components/progress_bar'
|
||||||
import Upload from '../media_upload_item'
|
import Upload from './media_upload_item'
|
||||||
import SensitiveMediaButton from '../sensitive_media_button'
|
import SensitiveMediaButton from './sensitive_media_button'
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state) => ({
|
||||||
mediaIds: state.getIn(['compose', 'media_attachments']).map(item => item.get('id')),
|
mediaIds: state.getIn(['compose', 'media_attachments']).map(item => item.get('id')),
|
@ -1 +0,0 @@
|
|||||||
export { default } from './upload_form'
|
|
@ -1,10 +0,0 @@
|
|||||||
.compose-form-upload-wrapper {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form-uploads-wrapper {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
padding: 5px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
@ -111,7 +111,6 @@ const makeMapStateToProps = () => {
|
|||||||
ancestorsIds,
|
ancestorsIds,
|
||||||
descendantsIds,
|
descendantsIds,
|
||||||
askReplyConfirmation: state.getIn(['compose', 'text']).trim().length !== 0,
|
askReplyConfirmation: state.getIn(['compose', 'text']).trim().length !== 0,
|
||||||
domain: state.getIn(['meta', 'domain']),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -135,7 +134,7 @@ class Status extends ImmutablePureComponent {
|
|||||||
descendantsIds: ImmutablePropTypes.list,
|
descendantsIds: ImmutablePropTypes.list,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
askReplyConfirmation: PropTypes.bool,
|
askReplyConfirmation: PropTypes.bool,
|
||||||
domain: PropTypes.string.isRequired,
|
contextType: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
@ -412,7 +411,8 @@ class Status extends ImmutablePureComponent {
|
|||||||
ancestorsIds,
|
ancestorsIds,
|
||||||
descendantsIds,
|
descendantsIds,
|
||||||
intl,
|
intl,
|
||||||
domain
|
contextType,
|
||||||
|
commentsLimited,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
let ancestors, descendants
|
let ancestors, descendants
|
||||||
@ -441,11 +441,13 @@ class Status extends ImmutablePureComponent {
|
|||||||
toggleSensitive: this.handleHotkeyToggleSensitive,
|
toggleSensitive: this.handleHotkeyToggleSensitive,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log("descendantsIds.size > 0:", descendantsIds.size > 0)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={this.setRef} className={_s.mb15}>
|
<div ref={this.setRef} className={_s.mb15}>
|
||||||
<Block>
|
<Block>
|
||||||
{
|
{
|
||||||
/* ancestors */
|
/* : todo : ancestors if is comment */
|
||||||
}
|
}
|
||||||
|
|
||||||
<HotKeys handlers={handlers}>
|
<HotKeys handlers={handlers}>
|
||||||
@ -453,13 +455,10 @@ class Status extends ImmutablePureComponent {
|
|||||||
|
|
||||||
<StatusContainer
|
<StatusContainer
|
||||||
id={status.get('id')}
|
id={status.get('id')}
|
||||||
contextType={'timelineId'}
|
contextType={contextType}
|
||||||
showThread
|
|
||||||
borderless={descendantsIds && descendantsIds.size > 0}
|
|
||||||
// onOpenVideo={this.handleOpenVideo}
|
// onOpenVideo={this.handleOpenVideo}
|
||||||
// onOpenMedia={this.handleOpenMedia}
|
// onOpenMedia={this.handleOpenMedia}
|
||||||
// onToggleHidden={this.handleToggleHidden}
|
// onToggleHidden={this.handleToggleHidden}
|
||||||
// domain={domain}
|
|
||||||
// showMedia={this.state.showMedia}
|
// showMedia={this.state.showMedia}
|
||||||
// onToggleMediaVisibility={this.handleToggleMediaVisibility}
|
// onToggleMediaVisibility={this.handleToggleMediaVisibility}
|
||||||
/>
|
/>
|
||||||
@ -472,7 +471,10 @@ class Status extends ImmutablePureComponent {
|
|||||||
<div className={[_s.default, _s.mr10, _s.ml10, _s.mb10, _s.borderColorSecondary, _s.borderBottom1PX].join(' ')}/>
|
<div className={[_s.default, _s.mr10, _s.ml10, _s.mb10, _s.borderColorSecondary, _s.borderBottom1PX].join(' ')}/>
|
||||||
}
|
}
|
||||||
|
|
||||||
<CommentList descendants={descendantsIds} />
|
<CommentList
|
||||||
|
commentsLimited={commentsLimited}
|
||||||
|
descendants={descendantsIds}
|
||||||
|
/>
|
||||||
</Block>
|
</Block>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -26,13 +26,12 @@ export default class ProfileLayout extends ImmutablePureComponent {
|
|||||||
noHeader
|
noHeader
|
||||||
noComposeButton
|
noComposeButton
|
||||||
>
|
>
|
||||||
|
<div className={[_s.default, _s.width1015PX, _s.flexRow, _s.justifyContentSpaceBetween, _s.pr15].join(' ')}>
|
||||||
<div className={[_s.default, _s.width1015PX, _s.flexRow, _s.justifyContentSpaceBetween, _s.pl15, _s.py15].join(' ')}>
|
|
||||||
<div className={[_s.default, _s.z1, _s.width100PC].join(' ')}>
|
<div className={[_s.default, _s.z1, _s.width100PC].join(' ')}>
|
||||||
|
|
||||||
<ProfileHeader account={account} />
|
<ProfileHeader account={account} />
|
||||||
|
|
||||||
<div className={[_s.default, _s.width1015PX, _s.flexRow, _s.justifyContentSpaceBetween, _s.pr15, _s.py15].join(' ')}>
|
<div className={[_s.default, _s.width100PC, _s.flexRow, _s.justifyContentSpaceBetween, _s.py15].join(' ')}>
|
||||||
<div className={[_s.default, _s.width645PX, _s.z1].join(' ')}>
|
<div className={[_s.default, _s.width645PX, _s.z1].join(' ')}>
|
||||||
<div className={_s.default}>
|
<div className={_s.default}>
|
||||||
{children}
|
{children}
|
||||||
@ -40,7 +39,7 @@ export default class ProfileLayout extends ImmutablePureComponent {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={[_s.default, _s.width340PX].join(' ')}>
|
<div className={[_s.default, _s.width340PX].join(' ')}>
|
||||||
<Sticky top={15} enabled>
|
<Sticky top={63} enabled>
|
||||||
<div className={[_s.default, _s.width340PX].join(' ')}>
|
<div className={[_s.default, _s.width340PX].join(' ')}>
|
||||||
{layout}
|
{layout}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Fragment } from 'react'
|
import { Fragment } from 'react'
|
||||||
import { defineMessages, injectIntl } from 'react-intl'
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
|
import queryString from 'query-string'
|
||||||
import { setFilter } from '../actions/notifications'
|
import { setFilter } from '../actions/notifications'
|
||||||
import PageTitle from '../features/ui/util/page_title'
|
import PageTitle from '../features/ui/util/page_title'
|
||||||
import LinkFooter from '../components/link_footer'
|
import LinkFooter from '../components/link_footer'
|
||||||
@ -8,13 +9,22 @@ import NotificationFilterPanel from '../components/panel/notification_filter_pan
|
|||||||
import TrendsPanel from '../components/panel/trends_panel'
|
import TrendsPanel from '../components/panel/trends_panel'
|
||||||
import DefaultLayout from '../layouts/default_layout'
|
import DefaultLayout from '../layouts/default_layout'
|
||||||
|
|
||||||
|
const filters = [
|
||||||
|
'all',
|
||||||
|
'mention',
|
||||||
|
'favourite',
|
||||||
|
'reblog',
|
||||||
|
'poll',
|
||||||
|
'follow',
|
||||||
|
]
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' },
|
notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' },
|
||||||
mentions: { id: 'notifications.filter.mentions', defaultMessage: 'Mentions' },
|
mention: { id: 'notifications.filter.mentions', defaultMessage: 'Mentions' },
|
||||||
likes: { id: 'likes', defaultMessage: 'Likes' },
|
favourite: { id: 'likes', defaultMessage: 'Likes' },
|
||||||
reposts: { id: 'reposts', defaultMessage: 'Reposts' },
|
reblog: { id: 'reposts', defaultMessage: 'Reposts' },
|
||||||
polls: { id: 'polls', defaultMessage: 'Poll' },
|
poll: { id: 'polls', defaultMessage: 'Poll' },
|
||||||
follows: { id: 'notifications.filter.follows', defaultMessage: 'Follows' },
|
follow: { id: 'notifications.filter.follows', defaultMessage: 'Follows' },
|
||||||
all: { id: 'notifications.filter.all', defaultMessage: 'All' },
|
all: { id: 'notifications.filter.all', defaultMessage: 'All' },
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -39,16 +49,31 @@ class NotificationsPage extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
setFilter: PropTypes.func.isRequired,
|
children: PropTypes.node.isRequired,
|
||||||
selectedFilter: PropTypes.string.isRequired,
|
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
notificationCount: PropTypes.number.isRequired,
|
notificationCount: PropTypes.number.isRequired,
|
||||||
|
setFilter: PropTypes.func.isRequired,
|
||||||
|
selectedFilter: PropTypes.string.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
// : todo : on pop change filter active type
|
componentDidMount() {
|
||||||
|
this.checkForQueryStringChange(this.context.router.route.location)
|
||||||
|
}
|
||||||
|
|
||||||
onClick(notificationType) {
|
checkForQueryStringChange = (location) => {
|
||||||
this.props.setFilter('active', notificationType)
|
try {
|
||||||
|
const qp = queryString.parse(location.search)
|
||||||
|
const view = `${qp.view}`.toLowerCase()
|
||||||
|
if (filters.indexOf(view) > -1) {
|
||||||
|
this.onChangeActiveFilter(view)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeActiveFilter(notificationType) {
|
||||||
|
this.props.setFilter(notificationType)
|
||||||
|
|
||||||
if (notificationType === 'all') {
|
if (notificationType === 'all') {
|
||||||
this.context.router.history.push('/notifications')
|
this.context.router.history.push('/notifications')
|
||||||
@ -59,44 +84,17 @@ class NotificationsPage extends PureComponent {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
intl,
|
|
||||||
children,
|
children,
|
||||||
|
intl,
|
||||||
|
notificationCount,
|
||||||
selectedFilter,
|
selectedFilter,
|
||||||
notificationCount
|
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
const tabs = [
|
const tabs = filters.map((filter) => ({
|
||||||
{
|
title: intl.formatMessage(messages[filter]),
|
||||||
title: intl.formatMessage(messages.all),
|
onClick: () => this.onChangeActiveFilter(filter),
|
||||||
onClick: () => this.onClick('all'),
|
active: selectedFilter === filter,
|
||||||
active: selectedFilter === 'all',
|
}))
|
||||||
},
|
|
||||||
{
|
|
||||||
title: intl.formatMessage(messages.mentions),
|
|
||||||
onClick: () => this.onClick('mention'),
|
|
||||||
active: selectedFilter === 'mention',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: intl.formatMessage(messages.likes),
|
|
||||||
onClick: () => this.onClick('favourite'),
|
|
||||||
active: selectedFilter === 'favourite',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: intl.formatMessage(messages.reposts),
|
|
||||||
onClick: () => this.onClick('reblog'),
|
|
||||||
active: selectedFilter === 'reblog',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: intl.formatMessage(messages.polls),
|
|
||||||
onClick: () => this.onClick('poll'),
|
|
||||||
active: selectedFilter === 'poll',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: intl.formatMessage(messages.follows),
|
|
||||||
onClick: () => this.onClick('follow'),
|
|
||||||
active: selectedFilter === 'follow',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DefaultLayout
|
<DefaultLayout
|
||||||
|
@ -61,7 +61,8 @@ class ProfilePage extends ImmutablePureComponent {
|
|||||||
params: { username },
|
params: { username },
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
const title = !!account ? account.get('display_name') : username
|
const name = !!account ? account.get('display_name_html') : ''
|
||||||
|
console.log("name:", name, account)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ProfileLayout
|
<ProfileLayout
|
||||||
@ -75,7 +76,7 @@ class ProfilePage extends ImmutablePureComponent {
|
|||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<PageTitle path={title} />
|
<PageTitle path={`${name} (@${username})`} />
|
||||||
{
|
{
|
||||||
!account && <ColumnIndicator type='loading' />
|
!account && <ColumnIndicator type='loading' />
|
||||||
}
|
}
|
||||||
|
@ -224,6 +224,7 @@ export default function notifications(state = initialState, action) {
|
|||||||
case NOTIFICATIONS_FILTER_SET:
|
case NOTIFICATIONS_FILTER_SET:
|
||||||
return state.withMutations(mutable => {
|
return state.withMutations(mutable => {
|
||||||
mutable.set('items', ImmutableList()).set('hasMore', true)
|
mutable.set('items', ImmutableList()).set('hasMore', true)
|
||||||
|
console.log("NOTIFICATIONS_FILTER_SET:", action.path, action.value)
|
||||||
mutable.setIn(['filter', action.path], action.value)
|
mutable.setIn(['filter', action.path], action.value)
|
||||||
})
|
})
|
||||||
case NOTIFICATIONS_SCROLL_TOP:
|
case NOTIFICATIONS_SCROLL_TOP:
|
||||||
|
@ -16,6 +16,7 @@ const initialState = ImmutableMap({
|
|||||||
results: [],
|
results: [],
|
||||||
chosenUrl: '',
|
chosenUrl: '',
|
||||||
searchText: '',
|
searchText: '',
|
||||||
|
next: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: false,
|
error: false,
|
||||||
})
|
})
|
||||||
@ -27,7 +28,8 @@ export default function (state = initialState, action) {
|
|||||||
return state.set('loading', true)
|
return state.set('loading', true)
|
||||||
case GIF_RESULTS_FETCH_SUCCESS:
|
case GIF_RESULTS_FETCH_SUCCESS:
|
||||||
return state.withMutations(map => {
|
return state.withMutations(map => {
|
||||||
map.set('results', action.results);
|
map.set('results', action.data.results);
|
||||||
|
map.set('next', action.data.next);
|
||||||
map.set('error', false);
|
map.set('error', false);
|
||||||
map.set('loading', false);
|
map.set('loading', false);
|
||||||
});
|
});
|
||||||
|
@ -356,6 +356,11 @@ body {
|
|||||||
background-color: #DE2960;
|
background-color: #DE2960;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.backgroundColorDangerDark_onHover:hover {
|
||||||
|
background-color: #c72c5b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.colorPrimary {
|
.colorPrimary {
|
||||||
color: #2d3436;
|
color: #2d3436;
|
||||||
}
|
}
|
||||||
|
@ -41,19 +41,28 @@ class Notification < ApplicationRecord
|
|||||||
validates :account_id, uniqueness: { scope: [:activity_type, :activity_id] }
|
validates :account_id, uniqueness: { scope: [:activity_type, :activity_id] }
|
||||||
validates :activity_type, inclusion: { in: TYPE_CLASS_MAP.values }
|
validates :activity_type, inclusion: { in: TYPE_CLASS_MAP.values }
|
||||||
|
|
||||||
scope :browserable, ->(exclude_types = [], account_id = nil) {
|
scope :browserable, ->(exclude_types = [], account_id = nil, only_verified = false, only_following = false) {
|
||||||
types = TYPE_CLASS_MAP.values - activity_types_from_types(exclude_types + [:follow_request])
|
types = TYPE_CLASS_MAP.values - activity_types_from_types(exclude_types + [:follow_request])
|
||||||
# if account_id.nil?
|
|
||||||
puts "-----VERTS------"
|
# Notification.includes(:from_account).where(activity_type: types, accounts: {
|
||||||
Notification.includes(:from_account).where(activity_type: types, accounts: {
|
# is_verified: true
|
||||||
is_verified: true
|
# })
|
||||||
})
|
|
||||||
# joins(:account).where({ 'from_account.id' => 6 })
|
theOptions = { :activity_type => types }
|
||||||
# is_verified: false
|
|
||||||
# )
|
if !account_id.nil?
|
||||||
# els
|
theOptions.from_account_id = account_id
|
||||||
# where(activity_type: types, from_account_id: account_id)
|
end
|
||||||
# end
|
|
||||||
|
if only_verified
|
||||||
|
theOptions[:accounts] = {
|
||||||
|
:is_verified => true
|
||||||
|
}
|
||||||
|
|
||||||
|
Notification.includes(:from_account).where(theOptions)
|
||||||
|
else
|
||||||
|
where(theOptions)
|
||||||
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
cache_associated :from_account, status: STATUS_INCLUDES, mention: [status: STATUS_INCLUDES], favourite: [:account, status: STATUS_INCLUDES], follow: :account, poll: [status: STATUS_INCLUDES]
|
cache_associated :from_account, status: STATUS_INCLUDES, mention: [status: STATUS_INCLUDES], favourite: [:account, status: STATUS_INCLUDES], follow: :account, poll: [status: STATUS_INCLUDES]
|
||||||
|
@ -87,7 +87,8 @@ class Status < ApplicationRecord
|
|||||||
scope :remote, -> { where(local: false).or(where.not(uri: nil)) }
|
scope :remote, -> { where(local: false).or(where.not(uri: nil)) }
|
||||||
scope :local, -> { where(local: true).or(where(uri: nil)) }
|
scope :local, -> { where(local: true).or(where(uri: nil)) }
|
||||||
|
|
||||||
scope :without_replies, -> { where('statuses.reply = FALSE OR statuses.in_reply_to_account_id = statuses.account_id') }
|
scope :only_replies, -> { where('statuses.reply = TRUE') }
|
||||||
|
scope :without_replies, -> { where('statuses.reply = FALSE') }
|
||||||
scope :without_reblogs, -> { where('statuses.reblog_of_id IS NULL') }
|
scope :without_reblogs, -> { where('statuses.reblog_of_id IS NULL') }
|
||||||
scope :with_public_visibility, -> { where(visibility: :public) }
|
scope :with_public_visibility, -> { where(visibility: :public) }
|
||||||
scope :tagged_with, ->(tag) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag }) }
|
scope :tagged_with, ->(tag) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag }) }
|
||||||
|
@ -329,12 +329,16 @@ Rails.application.routes.draw do
|
|||||||
resources :gab_trends, only: [:index]
|
resources :gab_trends, only: [:index]
|
||||||
resources :streaming, only: [:index]
|
resources :streaming, only: [:index]
|
||||||
resources :custom_emojis, only: [:index]
|
resources :custom_emojis, only: [:index]
|
||||||
resources :gifs, only: [:index]
|
|
||||||
resources :suggestions, only: [:index, :destroy]
|
resources :suggestions, only: [:index, :destroy]
|
||||||
resources :scheduled_statuses, only: [:index, :show, :update, :destroy]
|
resources :scheduled_statuses, only: [:index, :show, :update, :destroy]
|
||||||
resources :preferences, only: [:index]
|
resources :preferences, only: [:index]
|
||||||
resources :trends, only: [:index]
|
resources :trends, only: [:index]
|
||||||
|
|
||||||
|
namespace :gifs do
|
||||||
|
get :categories
|
||||||
|
get :search
|
||||||
|
end
|
||||||
|
|
||||||
resources :conversations, only: [:index, :destroy] do
|
resources :conversations, only: [:index, :destroy] do
|
||||||
member do
|
member do
|
||||||
post :read
|
post :read
|
||||||
@ -462,6 +466,7 @@ Rails.application.routes.draw do
|
|||||||
|
|
||||||
get '/tags/:tag', to: 'react#react'
|
get '/tags/:tag', to: 'react#react'
|
||||||
get '/:username/with_replies', to: 'accounts#show', username: username_regex, as: :short_account_with_replies
|
get '/:username/with_replies', to: 'accounts#show', username: username_regex, as: :short_account_with_replies
|
||||||
|
get '/:username/comments_only', to: 'accounts#show', username: username_regex, as: :short_account_comments_only
|
||||||
get '/:username/media', to: 'accounts#show', username: username_regex, as: :short_account_media
|
get '/:username/media', to: 'accounts#show', username: username_regex, as: :short_account_media
|
||||||
get '/:username/tagged/:tag', to: 'accounts#show', username: username_regex, as: :short_account_tag
|
get '/:username/tagged/:tag', to: 'accounts#show', username: username_regex, as: :short_account_tag
|
||||||
get '/:username/posts/:statusId/reblogs', to: 'statuses#show', username: username_regex
|
get '/:username/posts/:statusId/reblogs', to: 'statuses#show', username: username_regex
|
||||||
|
Loading…
Reference in New Issue
Block a user