[Glitch] Add trends UI with admin and user settings

Port 9072fe5ab6 to glitch-soc

Signed-off-by: Thibaut Girka <thib@sitedethib.com>
pull/1210/head
Eugen Rochko 2019-08-06 17:57:52 +02:00 committed by ThibG
parent 3c70fb9146
commit 8b630f7e54
12 changed files with 178 additions and 5 deletions

View File

@ -0,0 +1,32 @@
import api from 'flavours/glitch/util/api';
export const TRENDS_FETCH_REQUEST = 'TRENDS_FETCH_REQUEST';
export const TRENDS_FETCH_SUCCESS = 'TRENDS_FETCH_SUCCESS';
export const TRENDS_FETCH_FAIL = 'TRENDS_FETCH_FAIL';
export const fetchTrends = () => (dispatch, getState) => {
dispatch(fetchTrendsRequest());
api(getState)
.get('/api/v1/trends')
.then(({ data }) => dispatch(fetchTrendsSuccess(data)))
.catch(err => dispatch(fetchTrendsFail(err)));
};
export const fetchTrendsRequest = () => ({
type: TRENDS_FETCH_REQUEST,
skipLoading: true,
});
export const fetchTrendsSuccess = trends => ({
type: TRENDS_FETCH_SUCCESS,
trends,
skipLoading: true,
});
export const fetchTrendsFail = error => ({
type: TRENDS_FETCH_FAIL,
error,
skipLoading: true,
skipAlert: true,
});

View File

@ -0,0 +1,43 @@
import React from 'react';
import ImmutablePureComponent from 'react-immutable-pure-component';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import Hashtag from 'flavours/glitch/components/hashtag';
export default class Trends extends ImmutablePureComponent {
static defaultProps = {
loading: false,
};
static propTypes = {
trends: ImmutablePropTypes.list,
fetchTrends: PropTypes.func.isRequired,
};
componentDidMount () {
this.props.fetchTrends();
this.refreshInterval = setInterval(() => this.props.fetchTrends(), 36000);
}
componentWillUnmount () {
if (this.refreshInterval) {
clearInterval(this.refreshInterval);
}
}
render () {
const { trends } = this.props;
if (!trends || trends.isEmpty()) {
return null;
}
return (
<div className='getting-started__trends'>
{trends.take(3).map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
</div>
);
}
}

View File

@ -0,0 +1,13 @@
import { connect } from 'react-redux';
import { fetchTrends } from '../../../actions/trends';
import Trends from '../components/trends';
const mapStateToProps = state => ({
trends: state.getIn(['trends', 'items']),
});
const mapDispatchToProps = dispatch => ({
fetchTrends: () => dispatch(fetchTrends()),
});
export default connect(mapStateToProps, mapDispatchToProps)(Trends);

View File

@ -8,7 +8,7 @@ import { openModal } from 'flavours/glitch/actions/modal';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
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 { me, profile_directory } from 'flavours/glitch/util/initial_state'; import { me, profile_directory, showTrends } from 'flavours/glitch/util/initial_state';
import { fetchFollowRequests } from 'flavours/glitch/actions/accounts'; import { fetchFollowRequests } from 'flavours/glitch/actions/accounts';
import { List as ImmutableList } from 'immutable'; import { List as ImmutableList } from 'immutable';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
@ -16,6 +16,7 @@ import { fetchLists } from 'flavours/glitch/actions/lists';
import { preferencesLink } from 'flavours/glitch/util/backend_links'; import { preferencesLink } from 'flavours/glitch/util/backend_links';
import NavigationBar from '../compose/components/navigation_bar'; import NavigationBar from '../compose/components/navigation_bar';
import LinkFooter from 'flavours/glitch/features/ui/components/link_footer'; import LinkFooter from 'flavours/glitch/features/ui/components/link_footer';
import TrendsContainer from './containers/trends_container';
const messages = defineMessages({ const messages = defineMessages({
heading: { id: 'getting_started.heading', defaultMessage: 'Getting started' }, heading: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
@ -182,6 +183,8 @@ const NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2);
<LinkFooter /> <LinkFooter />
</div> </div>
{multiColumn && showTrends && <TrendsContainer />}
</Column> </Column>
); );
} }

View File

@ -2,11 +2,12 @@ import React from 'react';
import { NavLink, withRouter } from 'react-router-dom'; import { NavLink, withRouter } from 'react-router-dom';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import Icon from 'flavours/glitch/components/icon'; import Icon from 'flavours/glitch/components/icon';
import { profile_directory } from 'flavours/glitch/util/initial_state'; import { profile_directory, showTrends } from 'flavours/glitch/util/initial_state';
import { preferencesLink, relationshipsLink } from 'flavours/glitch/util/backend_links'; import { preferencesLink, relationshipsLink } from 'flavours/glitch/util/backend_links';
import NotificationsCounterIcon from './notifications_counter_icon'; import NotificationsCounterIcon from './notifications_counter_icon';
import FollowRequestsNavLink from './follow_requests_nav_link'; import FollowRequestsNavLink from './follow_requests_nav_link';
import ListPanel from './list_panel'; import ListPanel from './list_panel';
import TrendsContainer from 'flavours/glitch/features/getting_started/containers/trends_container';
const NavigationPanel = ({ onOpenSettings }) => ( const NavigationPanel = ({ onOpenSettings }) => (
<div className='navigation-panel'> <div className='navigation-panel'>
@ -27,6 +28,9 @@ const NavigationPanel = ({ onOpenSettings }) => (
{!!preferencesLink && <a className='column-link column-link--transparent' href={preferencesLink} target='_blank'><Icon className='column-link__icon' icon='cog' fixedWidth /><FormattedMessage id='navigation_bar.preferences' defaultMessage='Preferences' /></a>} {!!preferencesLink && <a className='column-link column-link--transparent' href={preferencesLink} target='_blank'><Icon className='column-link__icon' icon='cog' fixedWidth /><FormattedMessage id='navigation_bar.preferences' defaultMessage='Preferences' /></a>}
<a className='column-link column-link--transparent' href='#' onClick={onOpenSettings}><Icon className='column-link__icon' icon='cogs' fixedWidth /><FormattedMessage id='navigation_bar.app_settings' defaultMessage='App settings' /></a> <a className='column-link column-link--transparent' href='#' onClick={onOpenSettings}><Icon className='column-link__icon' icon='cogs' fixedWidth /><FormattedMessage id='navigation_bar.app_settings' defaultMessage='App settings' /></a>
{!!relationshipsLink && <a className='column-link column-link--transparent' href={relationshipsLink} target='_blank'><Icon className='column-link__icon' icon='users' fixedWidth /><FormattedMessage id='navigation_bar.follows_and_followers' defaultMessage='Follows and followers' /></a>} {!!relationshipsLink && <a className='column-link column-link--transparent' href={relationshipsLink} target='_blank'><Icon className='column-link__icon' icon='users' fixedWidth /><FormattedMessage id='navigation_bar.follows_and_followers' defaultMessage='Follows and followers' /></a>}
{showTrends && <div className='flex-spacer' />}
{showTrends && <TrendsContainer />}
</div> </div>
); );

View File

@ -33,6 +33,7 @@ import suggestions from './suggestions';
import pinnedAccountsEditor from './pinned_accounts_editor'; import pinnedAccountsEditor from './pinned_accounts_editor';
import polls from './polls'; import polls from './polls';
import identity_proofs from './identity_proofs'; import identity_proofs from './identity_proofs';
import trends from './trends';
const reducers = { const reducers = {
dropdown_menu, dropdown_menu,
@ -69,6 +70,7 @@ const reducers = {
suggestions, suggestions,
pinnedAccountsEditor, pinnedAccountsEditor,
polls, polls,
trends,
}; };
export default combineReducers(reducers); export default combineReducers(reducers);

View File

@ -15,6 +15,10 @@ const initialState = ImmutableMap({
skinTone: 1, skinTone: 1,
trends: ImmutableMap({
show: true,
}),
home: ImmutableMap({ home: ImmutableMap({
shows: ImmutableMap({ shows: ImmutableMap({
reblog: true, reblog: true,

View File

@ -0,0 +1,23 @@
import { TRENDS_FETCH_REQUEST, TRENDS_FETCH_SUCCESS, TRENDS_FETCH_FAIL } from '../actions/trends';
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
const initialState = ImmutableMap({
items: ImmutableList(),
isLoading: false,
});
export default function trendsReducer(state = initialState, action) {
switch(action.type) {
case TRENDS_FETCH_REQUEST:
return state.set('isLoading', true);
case TRENDS_FETCH_SUCCESS:
return state.withMutations(map => {
map.set('items', fromJS(action.trends));
map.set('isLoading', false);
});
case TRENDS_FETCH_FAIL:
return state.set('isLoading', false);
default:
return state;
}
};

View File

@ -903,6 +903,38 @@
} }
} }
} }
&__trends {
flex: 0 1 auto;
opacity: 1;
animation: fade 150ms linear;
margin-top: 10px;
@media screen and (max-height: 810px) {
.trends__item:nth-child(3) {
display: none;
}
}
@media screen and (max-height: 720px) {
.trends__item:nth-child(2) {
display: none;
}
}
@media screen and (max-height: 670px) {
display: none;
}
.trends__item {
border-bottom: 0;
padding: 10px;
&__current {
color: $darker-text-color;
}
}
}
} }
.column-link__badge { .column-link__badge {

View File

@ -147,7 +147,8 @@
font-size: 24px; font-size: 24px;
line-height: 36px; line-height: 36px;
font-weight: 500; font-weight: 500;
text-align: center; text-align: right;
padding-right: 15px;
color: $secondary-text-color; color: $secondary-text-color;
} }
@ -155,7 +156,12 @@
flex: 0 0 auto; flex: 0 0 auto;
width: 50px; width: 50px;
path { path:first-child {
fill: rgba($highlight-text-color, 0.25) !important;
fill-opacity: 1 !important;
}
path:last-child {
stroke: lighten($highlight-text-color, 6%) !important; stroke: lighten($highlight-text-color, 6%) !important;
} }
} }

View File

@ -54,13 +54,24 @@
margin-bottom: 10px; margin-bottom: 10px;
height: calc(100% - 20px); height: calc(100% - 20px);
overflow-y: auto; overflow-y: auto;
display: flex;
flex-direction: column;
& > a {
flex: 0 0 auto;
}
hr { hr {
flex: 0 0 auto;
border: 0; border: 0;
background: transparent; background: transparent;
border-top: 1px solid lighten($ui-base-color, 4%); border-top: 1px solid lighten($ui-base-color, 4%);
margin: 10px 0; margin: 10px 0;
} }
.flex-spacer {
background: transparent;
}
} }
@media screen and (min-width: 600px) { @media screen and (min-width: 600px) {
@ -216,7 +227,6 @@
} }
.getting-started__wrapper, .getting-started__wrapper,
.getting-started__trends,
.search { .search {
margin-bottom: 10px; margin-bottom: 10px;
} }

View File

@ -33,5 +33,6 @@ export const forceSingleColumn = getMeta('advanced_layout') === false;
export const useBlurhash = getMeta('use_blurhash'); export const useBlurhash = getMeta('use_blurhash');
export const usePendingItems = getMeta('use_pending_items'); export const usePendingItems = getMeta('use_pending_items');
export const useSystemEmojiFont = getMeta('system_emoji_font'); export const useSystemEmojiFont = getMeta('system_emoji_font');
export const showTrends = getMeta('trends');
export default initialState; export default initialState;