diff --git a/app/javascript/flavours/glitch/actions/trends.js b/app/javascript/flavours/glitch/actions/trends.js
new file mode 100644
index 000000000..1b0ce2b5b
--- /dev/null
+++ b/app/javascript/flavours/glitch/actions/trends.js
@@ -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,
+});
diff --git a/app/javascript/flavours/glitch/features/getting_started/components/trends.js b/app/javascript/flavours/glitch/features/getting_started/components/trends.js
new file mode 100644
index 000000000..583dbc9e1
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/getting_started/components/trends.js
@@ -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 (
+
+ {trends.take(3).map(hashtag => )}
+
+ );
+ }
+
+}
diff --git a/app/javascript/flavours/glitch/features/getting_started/containers/trends_container.js b/app/javascript/flavours/glitch/features/getting_started/containers/trends_container.js
new file mode 100644
index 000000000..1df3fb4fe
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/getting_started/containers/trends_container.js
@@ -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);
diff --git a/app/javascript/flavours/glitch/features/getting_started/index.js b/app/javascript/flavours/glitch/features/getting_started/index.js
index 0b93d8915..68b5209dc 100644
--- a/app/javascript/flavours/glitch/features/getting_started/index.js
+++ b/app/javascript/flavours/glitch/features/getting_started/index.js
@@ -8,7 +8,7 @@ import { openModal } from 'flavours/glitch/actions/modal';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
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 { List as ImmutableList } from 'immutable';
import { createSelector } from 'reselect';
@@ -16,6 +16,7 @@ import { fetchLists } from 'flavours/glitch/actions/lists';
import { preferencesLink } from 'flavours/glitch/util/backend_links';
import NavigationBar from '../compose/components/navigation_bar';
import LinkFooter from 'flavours/glitch/features/ui/components/link_footer';
+import TrendsContainer from './containers/trends_container';
const messages = defineMessages({
heading: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
@@ -182,6 +183,8 @@ const NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2);
+
+ {multiColumn && showTrends && }
);
}
diff --git a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js
index df02cafd1..1c8c7d76e 100644
--- a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js
+++ b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js
@@ -2,11 +2,12 @@ import React from 'react';
import { NavLink, withRouter } from 'react-router-dom';
import { FormattedMessage } from 'react-intl';
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 NotificationsCounterIcon from './notifications_counter_icon';
import FollowRequestsNavLink from './follow_requests_nav_link';
import ListPanel from './list_panel';
+import TrendsContainer from 'flavours/glitch/features/getting_started/containers/trends_container';
const NavigationPanel = ({ onOpenSettings }) => (
@@ -27,6 +28,9 @@ const NavigationPanel = ({ onOpenSettings }) => (
{!!preferencesLink &&
}
{!!relationshipsLink &&
}
+
+ {showTrends &&
}
+ {showTrends &&
}
);
diff --git a/app/javascript/flavours/glitch/reducers/index.js b/app/javascript/flavours/glitch/reducers/index.js
index 266d87dc1..b03590194 100644
--- a/app/javascript/flavours/glitch/reducers/index.js
+++ b/app/javascript/flavours/glitch/reducers/index.js
@@ -33,6 +33,7 @@ import suggestions from './suggestions';
import pinnedAccountsEditor from './pinned_accounts_editor';
import polls from './polls';
import identity_proofs from './identity_proofs';
+import trends from './trends';
const reducers = {
dropdown_menu,
@@ -69,6 +70,7 @@ const reducers = {
suggestions,
pinnedAccountsEditor,
polls,
+ trends,
};
export default combineReducers(reducers);
diff --git a/app/javascript/flavours/glitch/reducers/settings.js b/app/javascript/flavours/glitch/reducers/settings.js
index a37863a69..9be27a02f 100644
--- a/app/javascript/flavours/glitch/reducers/settings.js
+++ b/app/javascript/flavours/glitch/reducers/settings.js
@@ -15,6 +15,10 @@ const initialState = ImmutableMap({
skinTone: 1,
+ trends: ImmutableMap({
+ show: true,
+ }),
+
home: ImmutableMap({
shows: ImmutableMap({
reblog: true,
diff --git a/app/javascript/flavours/glitch/reducers/trends.js b/app/javascript/flavours/glitch/reducers/trends.js
new file mode 100644
index 000000000..5cecc8fca
--- /dev/null
+++ b/app/javascript/flavours/glitch/reducers/trends.js
@@ -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;
+ }
+};
diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss
index 9f59c81ff..85df8932a 100644
--- a/app/javascript/flavours/glitch/styles/components/index.scss
+++ b/app/javascript/flavours/glitch/styles/components/index.scss
@@ -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 {
diff --git a/app/javascript/flavours/glitch/styles/components/search.scss b/app/javascript/flavours/glitch/styles/components/search.scss
index 0e518997d..f8fc15b12 100644
--- a/app/javascript/flavours/glitch/styles/components/search.scss
+++ b/app/javascript/flavours/glitch/styles/components/search.scss
@@ -147,7 +147,8 @@
font-size: 24px;
line-height: 36px;
font-weight: 500;
- text-align: center;
+ text-align: right;
+ padding-right: 15px;
color: $secondary-text-color;
}
@@ -155,7 +156,12 @@
flex: 0 0 auto;
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;
}
}
diff --git a/app/javascript/flavours/glitch/styles/components/single_column.scss b/app/javascript/flavours/glitch/styles/components/single_column.scss
index aeb0abb55..1d8055fe5 100644
--- a/app/javascript/flavours/glitch/styles/components/single_column.scss
+++ b/app/javascript/flavours/glitch/styles/components/single_column.scss
@@ -54,13 +54,24 @@
margin-bottom: 10px;
height: calc(100% - 20px);
overflow-y: auto;
+ display: flex;
+ flex-direction: column;
+
+ & > a {
+ flex: 0 0 auto;
+ }
hr {
+ flex: 0 0 auto;
border: 0;
background: transparent;
border-top: 1px solid lighten($ui-base-color, 4%);
margin: 10px 0;
}
+
+ .flex-spacer {
+ background: transparent;
+ }
}
@media screen and (min-width: 600px) {
@@ -216,7 +227,6 @@
}
.getting-started__wrapper,
- .getting-started__trends,
.search {
margin-bottom: 10px;
}
diff --git a/app/javascript/flavours/glitch/util/initial_state.js b/app/javascript/flavours/glitch/util/initial_state.js
index a537b0df9..911468e6f 100644
--- a/app/javascript/flavours/glitch/util/initial_state.js
+++ b/app/javascript/flavours/glitch/util/initial_state.js
@@ -33,5 +33,6 @@ export const forceSingleColumn = getMeta('advanced_layout') === false;
export const useBlurhash = getMeta('use_blurhash');
export const usePendingItems = getMeta('use_pending_items');
export const useSystemEmojiFont = getMeta('system_emoji_font');
+export const showTrends = getMeta('trends');
export default initialState;