diff --git a/src/tags/TagsList.js b/src/tags/TagsList.js
new file mode 100644
index 00000000..f93f5361
--- /dev/null
+++ b/src/tags/TagsList.js
@@ -0,0 +1,51 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import { pick, splitEvery } from 'ramda';
+import { listTags } from './reducers/tagsList';
+import './TagsList.scss';
+import { Card } from 'reactstrap';
+import ColorGenerator from '../utils/ColorGenerator';
+
+export class TagsList extends React.Component {
+ componentDidMount() {
+ const { listTags } = this.props;
+ listTags();
+ }
+
+ render() {
+ const { tagsList, colorGenerator } = this.props;
+ const tagsCount = Math.round(tagsList.tags.length);
+ if (tagsCount < 1) {
+ return
No tags
;
+ }
+
+ const tagsGroups = splitEvery(Math.round(tagsCount / 4), tagsList.tags);
+
+ return (
+
+
+ {tagsGroups.map((group, index) => (
+
+ {group.map(tag => (
+
+
+ {tag}
+
+
+ ))}
+
+ ))}
+
+
+ );
+ }
+}
+
+TagsList.defaultProps = {
+ colorGenerator: ColorGenerator
+};
+
+export default connect(pick(['tagsList']), { listTags })(TagsList);
diff --git a/src/tags/TagsList.scss b/src/tags/TagsList.scss
new file mode 100644
index 00000000..7765c0d7
--- /dev/null
+++ b/src/tags/TagsList.scss
@@ -0,0 +1,18 @@
+.tags-list__tag-container {
+ border-radius: .26rem;
+}
+
+.tags-list__tag-card.tags-list__tag-card {
+ padding: .75rem 2.5rem 0.75rem 1rem;
+ background-color: #eeeeee;
+ margin-bottom: .5rem;
+ transition: background-color 200ms, color 200ms;
+}
+.tags-list__tag-card.tags-list__tag-card:hover {
+ background-color: transparent;
+ color: #fff;
+}
+
+.tags-list__tag-title {
+ margin: 0;
+}
diff --git a/src/tags/reducers/tagsList.js b/src/tags/reducers/tagsList.js
new file mode 100644
index 00000000..c5fe5ab0
--- /dev/null
+++ b/src/tags/reducers/tagsList.js
@@ -0,0 +1,49 @@
+import ShlinkApiClient from '../../api/ShlinkApiClient';
+
+const LIST_TAGS_START = 'shlink/tagsList/LIST_TAGS_START';
+const LIST_TAGS_ERROR = 'shlink/tagsList/LIST_TAGS_ERROR';
+const LIST_TAGS = 'shlink/tagsList/LIST_TAGS';
+
+const defaultState = {
+ tags: [],
+ loading: false,
+ error: false,
+};
+
+export default function reducer(state = defaultState, action) {
+ switch(action.type) {
+ case LIST_TAGS_START:
+ return {
+ ...state,
+ loading: true,
+ error: false,
+ };
+ case LIST_TAGS_ERROR:
+ return {
+ ...state,
+ loading: false,
+ error: true,
+ };
+ case LIST_TAGS:
+ return {
+ tags: action.tags,
+ loading: false,
+ error: false,
+ };
+ default:
+ return state;
+ }
+}
+
+export const _listTags = ShlinkApiClient => async dispatch => {
+ dispatch({ type: LIST_TAGS_START });
+
+ try {
+ const tags = await ShlinkApiClient.listTags();
+ dispatch({ tags, type: LIST_TAGS });
+ } catch (e) {
+ dispatch({ type: LIST_TAGS_ERROR });
+ throw e;
+ }
+};
+export const listTags = () => _listTags(ShlinkApiClient);
diff --git a/src/utils/Tag.js b/src/utils/Tag.js
index f6a49c44..eeadfbcb 100644
--- a/src/utils/Tag.js
+++ b/src/utils/Tag.js
@@ -6,6 +6,7 @@ export default function Tag (
{
colorGenerator,
text,
+ children,
clearable,
onClick = () => ({}),
onClose = () => ({})
@@ -17,7 +18,7 @@ export default function Tag (
style={{ backgroundColor: colorGenerator.getColorForKey(text), cursor: clearable ? 'auto' : 'pointer' }}
onClick={onClick}
>
- {text}
+ {children || text}
{clearable &&
×}
);