diff --git a/extensions/tags/js/bootstrap.js b/extensions/tags/js/bootstrap.js index 4d6317826..f6b326bc2 100644 --- a/extensions/tags/js/bootstrap.js +++ b/extensions/tags/js/bootstrap.js @@ -17,6 +17,10 @@ app.initializers.add('flarum-tags', function() { app.routes['tags'] = ['/tags', TagsPage.component()]; app.routes['tag'] = ['/t/:tags', IndexPage.component()]; + app.route.tag = function(tag) { + return app.route('tag', { tags: tag.slug() }); + }; + // Register models. app.store.models['tags'] = Tag; Discussion.prototype.tags = Model.many('tags'); diff --git a/extensions/tags/js/src/add-tag-list.js b/extensions/tags/js/src/add-tag-list.js index 1e4714e33..8f3c142ee 100644 --- a/extensions/tags/js/src/add-tag-list.js +++ b/extensions/tags/js/src/add-tag-list.js @@ -4,25 +4,26 @@ import NavItem from 'flarum/components/nav-item'; import Separator from 'flarum/components/separator'; import TagNavItem from 'flarum-tags/components/tag-nav-item'; +import TagsPage from 'flarum-tags/components/tags-page'; export default function() { // Add a link to the tags page, as well as a list of all the tags, // to the index page's sidebar. extend(IndexPage.prototype, 'navItems', function(items) { items.add('tags', NavItem.component({ - icon: 'reorder', + icon: 'th-large', label: 'Tags', href: app.route('tags'), config: m.route }), {last: true}); + if (app.current instanceof TagsPage) return; + items.add('separator', Separator.component(), {last: true}); var params = this.stickyParams(); var tags = app.store.all('tags'); - items.add('untagged', TagNavItem.component({params}), {last: true}); - var addTag = tag => { var currentTag = this.currentTag(); var active = currentTag === tag; diff --git a/extensions/tags/js/src/components/tags-page.js b/extensions/tags/js/src/components/tags-page.js index bd5a34ae7..89db7fc3a 100644 --- a/extensions/tags/js/src/components/tags-page.js +++ b/extensions/tags/js/src/components/tags-page.js @@ -1,38 +1,75 @@ import Component from 'flarum/component'; import WelcomeHero from 'flarum/components/welcome-hero'; +import IndexPage from 'flarum/components/index-page'; import icon from 'flarum/helpers/icon'; +import listItems from 'flarum/helpers/list-items'; +import abbreviateNumber from 'flarum/utils/abbreviate-number'; +import humanTime from 'flarum/helpers/human-time'; + +import sortTags from 'flarum-tags/utils/sort-tags'; export default class TagsPage extends Component { constructor(props) { super(props); - this.categories = m.prop(app.store.all('categories')); + this.tags = sortTags(app.store.all('tags').filter(tag => !tag.parent())); + + app.current = this; + app.history.push('tags'); } view() { - return m('div.categories-area', [ - m('div.title-control.categories-forum-title', app.config.forum_title), - WelcomeHero.component(), + var pinned = this.tags.filter(tag => tag.position() !== null); + var cloud = this.tags.filter(tag => tag.position() === null); + + return m('div.tags-area', {config: this.onload.bind(this)}, [ + IndexPage.prototype.hero(), m('div.container', [ - m('ul.category-list.category-list-tiles', [ - m('li.filter-tile', [ - m('a', {href: app.route('index'), config: m.route}, 'All Discussions'), - // m('ul.filter-list', [ - // m('li', m('a', {href: app.route('index'), config: m.route}, m('span', [icon('star'), ' Following']))), - // m('li', m('a', {href: app.route('index'), config: m.route}, m('span', [icon('envelope-o'), ' Inbox']))) - // ]) + m('nav.side-nav.index-nav', [ + m('ul', listItems(IndexPage.prototype.sidebarItems().toArray())) + ]), + m('div.offset-content.tags-content', [ + m('ul.tag-tiles', [ + pinned.map(tag => { + var lastDiscussion = tag.lastDiscussion(); + var children = app.store.all('tags').filter(child => { + var parent = child.parent(); + return parent && parent.id() == tag.id(); + }); + + return m('li.tag-tile', {style: 'background-color: '+tag.color()}, [ + m('a.tag-info', {href: app.route.tag(tag), config: m.route}, [ + m('h3.name', tag.name()), + m('p.description', tag.description()), + children ? m('div.children', children.map(tag => + m('a', {href: app.route.tag(tag), config: m.route, onclick: (e) => e.stopPropagation()}, tag.name()) + )) : '' + ]), + lastDiscussion + ? m('a.last-discussion', { + href: app.route.discussion(lastDiscussion, lastDiscussion.lastPostNumber()), + config: m.route + }, [m('span.title', lastDiscussion.title()), humanTime(lastDiscussion.lastTime())]) + : m('span.last-discussion') + ]); + }) ]), - this.categories().map(category => - m('li.category-tile', {style: 'background-color: '+category.color()}, [ - m('a', {href: app.route('category', {categories: category.slug()}), config: m.route}, [ - m('h3.title', category.title()), - m('p.description', category.description()), - m('span.count', category.discussionsCount()+' discussions'), - ]) - ]) - ) + m('div.tag-cloud', [ + m('h4', 'Tags'), + m('div.tag-cloud-content', cloud.map(tag => + m('a', {href: app.route.tag(tag), config: m.route, style: tag.color() ? 'color: '+tag.color() : ''}, tag.name()) + )) + ]) ]) ]) ]); } + + onload(element, isInitialized, context) { + IndexPage.prototype.onload.apply(this, arguments); + } + + onunload() { + IndexPage.prototype.onunload.apply(this); + } } diff --git a/extensions/tags/less/extension.less b/extensions/tags/less/extension.less index c68cc472f..08b9f27ac 100644 --- a/extensions/tags/less/extension.less +++ b/extensions/tags/less/extension.less @@ -212,3 +212,123 @@ } } } + + +.tag-tiles { + list-style-type: none; + padding: 0; + margin: 0; + overflow: hidden; + + & > li { + float: left; + width: ~"calc(50% - 1px)"; + height: 200px; + margin-right: 1px; + margin-bottom: 1px; + overflow: hidden; + + &:first-child { + border-radius: @border-radius-base 0 0 0; + } + &:nth-child(2) { + border-radius: 0 @border-radius-base 0 0; + } + &:nth-last-child(2):nth-child(even), &:last-child { + border-radius: 0 0 @border-radius-base 0; + } + &:nth-last-child(2):nth-child(odd), &:last-child:nth-child(odd) { + border-radius: 0 0 0 @border-radius-base; + } + } +} +.tag-tile { + position: relative; + + &, & a { + color: #fff; + } + & .tag-info, & .last-discussion { + padding: 20px; + text-decoration: none; + display: block; + position: absolute; + left: 0; + right: 0; + } + & > a { + transition: background 0.2s; + + &:hover { + background: fade(#000, 10%); + } + &:active { + background: fade(#000, 20%); + } + } + & .tag-info { + top: 0; + bottom: 55px; + padding-right: 20px; + + & .name { + font-size: 20px; + margin: 0 0 10px; + font-weight: normal; + } + & .description { + color: fade(#fff, 50%); + margin: 0 0 15px; + } + & .children { + text-transform: uppercase; + font-weight: 600; + font-size: 12px; + + & > a { + margin-right: 15px; + } + } + } + & .last-discussion { + bottom: 0; + height: 55px; + border-top: 1px solid rgba(0, 0, 0, 0.1); + padding-top: 17px; + padding-bottom: 17px; + color: fade(#fff, 50%); + + & .title { + margin-right: 15px; + } + } +} +.tag-cloud { + margin-top: 30px; + text-align: center; + + & h4 { + font-size: 12px; + font-weight: bold; + color: @fl-body-muted-color; + text-transform: uppercase; + margin-bottom: 15px; + + &:before { + .fa(); + content: @fa-var-tags; + margin-right: 5px; + font-size: 14px; + } + } +} +.tag-cloud-content { + font-size: 14px; + + &, & a { + color: @fl-body-muted-color; + } + & a { + margin: 0 6px; + } +}