diff --git a/extensions/tags/composer.json b/extensions/tags/composer.json
index 29fe795f1..d5e85690b 100644
--- a/extensions/tags/composer.json
+++ b/extensions/tags/composer.json
@@ -22,6 +22,12 @@
},
"flarum-extension": {
"title": "Tags",
+ "category": "discussion",
+ "info": {
+ "donate": "https://flarum.org/donate/",
+ "website": "https://flarum.org",
+ "support": "https://discuss.flarum.org"
+ },
"icon": {
"name": "fas fa-tags",
"backgroundColor": "#F28326",
diff --git a/extensions/tags/js/src/admin/addTagPermission.js b/extensions/tags/js/src/admin/addTagPermission.js
index 9278ec133..6188830d6 100644
--- a/extensions/tags/js/src/admin/addTagPermission.js
+++ b/extensions/tags/js/src/admin/addTagPermission.js
@@ -1,12 +1,9 @@
-import { extend } from 'flarum/extend';
-import PermissionGrid from 'flarum/components/PermissionGrid';
-
-export default function() {
- extend(PermissionGrid.prototype, 'moderateItems', items => {
- items.add('tag', {
+export default function () {
+ app.extensionData
+ .for('flarum-tags')
+ .registerPermission({
icon: 'fas fa-tag',
label: app.translator.trans('flarum-tags.admin.permissions.tag_discussions_label'),
- permission: 'discussion.tag'
- }, 95);
- });
+ permission: 'discussion.tag',
+ }, 'moderate', 95);
}
diff --git a/extensions/tags/js/src/admin/addTagsPane.js b/extensions/tags/js/src/admin/addTagsPane.js
deleted file mode 100644
index 12bf1c606..000000000
--- a/extensions/tags/js/src/admin/addTagsPane.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import { extend } from 'flarum/extend';
-import AdminNav from 'flarum/components/AdminNav';
-import AdminLinkButton from 'flarum/components/AdminLinkButton';
-
-import TagsPage from './components/TagsPage';
-
-export default function() {
- app.routes.tags = {path: '/tags', component: TagsPage};
-
- app.extensionSettings['flarum-tags'] = () => m.route.set(app.route('tags'));
-
- extend(AdminNav.prototype, 'items', items => {
- items.add('tags', AdminLinkButton.component({
- href: app.route('tags'),
- icon: 'fas fa-tags',
- description: app.translator.trans('flarum-tags.admin.nav.tags_text')
- }, app.translator.trans('flarum-tags.admin.nav.tags_button')));
- });
-}
diff --git a/extensions/tags/js/src/admin/compat.js b/extensions/tags/js/src/admin/compat.js
index 2b948615a..025584d94 100644
--- a/extensions/tags/js/src/admin/compat.js
+++ b/extensions/tags/js/src/admin/compat.js
@@ -2,8 +2,6 @@ import compat from '../common/compat';
import addTagsHomePageOption from './addTagsHomePageOption';
import addTagChangePermission from './addTagChangePermission';
-import addTagsPane from './addTagsPane';
-import TagSettingsModal from './components/TagSettingsModal';
import TagsPage from './components/TagsPage';
import EditTagModal from './components/EditTagModal';
import addTagPermission from './addTagPermission';
@@ -12,8 +10,6 @@ import addTagsPermissionScope from './addTagsPermissionScope';
export default Object.assign(compat, {
'tags/addTagsHomePageOption': addTagsHomePageOption,
'tags/addTagChangePermission': addTagChangePermission,
- 'tags/addTagsPane': addTagsPane,
- 'tags/components/TagSettingsModal': TagSettingsModal,
'tags/components/TagsPage': TagsPage,
'tags/components/EditTagModal': EditTagModal,
'tags/addTagPermission': addTagPermission,
diff --git a/extensions/tags/js/src/admin/components/EditTagModal.js b/extensions/tags/js/src/admin/components/EditTagModal.js
index c1fa5dd18..acd2cd3f4 100644
--- a/extensions/tags/js/src/admin/components/EditTagModal.js
+++ b/extensions/tags/js/src/admin/components/EditTagModal.js
@@ -22,6 +22,7 @@ export default class EditTagModal extends Modal {
this.color = Stream(this.tag.color() || '');
this.icon = Stream(this.tag.icon() || '');
this.isHidden = Stream(this.tag.isHidden() || false);
+ this.primary = Stream(this.attrs.primary || false);
}
className() {
@@ -114,7 +115,8 @@ export default class EditTagModal extends Modal {
description: this.description(),
color: this.color(),
icon: this.icon(),
- isHidden: this.isHidden()
+ isHidden: this.isHidden(),
+ primary: this.primary(),
};
}
diff --git a/extensions/tags/js/src/admin/components/TagSettingsModal.js b/extensions/tags/js/src/admin/components/TagSettingsModal.js
deleted file mode 100644
index b73675298..000000000
--- a/extensions/tags/js/src/admin/components/TagSettingsModal.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import SettingsModal from 'flarum/components/SettingsModal';
-import withAttr from 'flarum/utils/withAttr';
-
-export default class TagSettingsModal extends SettingsModal {
- setMinTags(minTags, maxTags, value) {
- minTags(value);
- maxTags(Math.max(value, maxTags()));
- }
-
- className() {
- return 'TagSettingsModal Modal--small';
- }
-
- title() {
- return app.translator.trans('flarum-tags.admin.tag_settings.title');
- }
-
- form() {
- const minPrimaryTags = this.setting('flarum-tags.min_primary_tags', 0);
- const maxPrimaryTags = this.setting('flarum-tags.max_primary_tags', 0);
-
- const minSecondaryTags = this.setting('flarum-tags.min_secondary_tags', 0);
- const maxSecondaryTags = this.setting('flarum-tags.max_secondary_tags', 0);
-
- return [
-
-
-
- {app.translator.trans('flarum-tags.admin.tag_settings.required_primary_text')}
-
-
-
- {app.translator.trans('flarum-tags.admin.tag_settings.range_separator_text')}
-
-
-
,
-
-
-
-
- {app.translator.trans('flarum-tags.admin.tag_settings.required_secondary_text')}
-
-
-
- {app.translator.trans('flarum-tags.admin.tag_settings.range_separator_text')}
-
-
-
- ];
- }
-}
diff --git a/extensions/tags/js/src/admin/components/TagsPage.js b/extensions/tags/js/src/admin/components/TagsPage.js
index 7d7b9b7e6..630b026e9 100644
--- a/extensions/tags/js/src/admin/components/TagsPage.js
+++ b/extensions/tags/js/src/admin/components/TagsPage.js
@@ -1,10 +1,10 @@
import sortable from 'sortablejs';
-import Page from 'flarum/components/Page';
+import ExtensionPage from 'flarum/components/ExtensionPage';
import Button from 'flarum/components/Button';
+import withAttr from 'flarum/utils/withAttr';
import EditTagModal from './EditTagModal';
-import TagSettingsModal from './TagSettingsModal';
import tagIcon from '../../common/helpers/tagIcon';
import sortTags from '../../common/utils/sortTags';
@@ -31,7 +31,7 @@ function tagItem(tag) {
);
}
-export default class TagsPage extends Page {
+export default class TagsPage extends ExtensionPage {
oninit(vnode) {
super.oninit(vnode);
@@ -42,44 +42,89 @@ export default class TagsPage extends Page {
this.forcedRefreshKey = 0;
}
- view() {
+ content() {
+ const minPrimaryTags = this.setting('flarum-tags.min_primary_tags', 0);
+ const maxPrimaryTags = this.setting('flarum-tags.max_primary_tags', 0);
+
+ const minSecondaryTags = this.setting('flarum-tags.min_secondary_tags', 0);
+ const maxSecondaryTags = this.setting('flarum-tags.max_secondary_tags', 0);
+
return (
-
-
-
-
- {app.translator.trans('flarum-tags.admin.tags.about_tags_text')}
-
- {Button.component({
- className: 'Button Button--primary',
- icon: 'fas fa-plus',
- onclick: () => app.modal.show(EditTagModal)
- }, app.translator.trans('flarum-tags.admin.tags.create_tag_button'))}
- {Button.component({
- className: 'Button',
- onclick: () => app.modal.show(TagSettingsModal)
- }, app.translator.trans('flarum-tags.admin.tags.settings_button'))}
-
-
-
-
+
+
+
{sortTags(app.store.all('tags'))
- .filter(tag => tag.position() !== null && !tag.isChild())
+ .filter((tag) => tag.position() !== null && !tag.isChild())
.map(tagItem)}
+ {Button.component(
+ {
+ className: 'Button TagList-button',
+ icon: 'fas fa-plus',
+ onclick: () => app.modal.show(EditTagModal, { primary: true }),
+ },
+ app.translator.trans('flarum-tags.admin.tags.create_primary_tag_button')
+ )}
-
+
- {app.store.all('tags')
- .filter(tag => tag.position() === null)
+ {app.store
+ .all('tags')
+ .filter((tag) => tag.position() === null)
.sort((a, b) => a.name().localeCompare(b.name()))
.map(tagItem)}
+ {Button.component(
+ {
+ className: 'Button TagList-button',
+ icon: 'fas fa-plus',
+ onclick: () => app.modal.show(EditTagModal, { primary: false }),
+ },
+ app.translator.trans('flarum-tags.admin.tags.create_secondary_tag_button')
+ )}
+
+
+
+
+
+
{app.translator.trans('flarum-tags.admin.tag_settings.required_primary_text')}
+
+
+ {app.translator.trans('flarum-tags.admin.tag_settings.range_separator_text')}
+
+
+
+
+
+
{app.translator.trans('flarum-tags.admin.tag_settings.required_secondary_text')}
+
+
+ {app.translator.trans('flarum-tags.admin.tag_settings.range_separator_text')}
+
+
+
+
{this.submitButton()}
+
+
+
+
{app.translator.trans('flarum-tags.admin.tags.about_tags_text')}
@@ -100,6 +145,11 @@ export default class TagsPage extends Page {
});
}
+ setMinTags(minTags, maxTags, value) {
+ minTags(value);
+ maxTags(Math.max(value, maxTags()));
+ }
+
onSortUpdate(e) {
// If we've moved a tag from 'primary' to 'secondary', then we'll update
// its attributes in our local store so that when we redraw the change
diff --git a/extensions/tags/js/src/admin/index.js b/extensions/tags/js/src/admin/index.js
index db8aaf45d..4c146ae18 100644
--- a/extensions/tags/js/src/admin/index.js
+++ b/extensions/tags/js/src/admin/index.js
@@ -1,16 +1,17 @@
import Tag from '../common/models/Tag';
import addTagsPermissionScope from './addTagsPermissionScope';
import addTagPermission from './addTagPermission';
-import addTagsPane from './addTagsPane';
import addTagsHomePageOption from './addTagsHomePageOption';
import addTagChangePermission from './addTagChangePermission';
+import TagsPage from './components/TagsPage';
app.initializers.add('flarum-tags', app => {
app.store.models.tags = Tag;
+ app.extensionData.for('flarum-tags').registerPage(TagsPage);
+
addTagsPermissionScope();
addTagPermission();
- addTagsPane();
addTagsHomePageOption();
addTagChangePermission();
});
diff --git a/extensions/tags/less/admin.less b/extensions/tags/less/admin.less
index 13df8f305..0aeeefb87 100644
--- a/extensions/tags/less/admin.less
+++ b/extensions/tags/less/admin.less
@@ -3,7 +3,6 @@
@import "admin/TagsPage";
@import "admin/EditTagModal";
-@import "admin/TagSettingsModal";
.Dropdown--restrictByTag .Dropdown-menu {
max-height: 400px;
diff --git a/extensions/tags/less/admin/TagSettingsModal.less b/extensions/tags/less/admin/TagSettingsModal.less
deleted file mode 100644
index 6522257c6..000000000
--- a/extensions/tags/less/admin/TagSettingsModal.less
+++ /dev/null
@@ -1,16 +0,0 @@
-.TagSettingsModal {
- .Form-group:not(:last-child) {
- margin-bottom: 30px;
- }
-}
-.TagSettingsModal-rangeInput {
- input {
- width: 80px;
- display: inline;
- margin: 0 5px;
-
- &:first-child {
- margin-left: 0;
- }
- }
-}
diff --git a/extensions/tags/less/admin/TagsPage.less b/extensions/tags/less/admin/TagsPage.less
index 06c2197b0..843851603 100644
--- a/extensions/tags/less/admin/TagsPage.less
+++ b/extensions/tags/less/admin/TagsPage.less
@@ -1,43 +1,45 @@
-.TagsPage-header {
- background: @control-bg;
+.flarum-tags-Page {
+ padding-bottom: 140px;
+}
+
+.TagsContent-footer {
color: @control-color;
padding: 20px 0;
- .container {
- max-width: 600px;
- }
p {
- margin-bottom: 20px;
- }
- .Button {
- margin-right: 10px;
+ margin-top: 10px;
}
}
-.TagsPage-list {
- padding: 20px 0;
- .container {
- max-width: 600px;
- }
+.TagsContent-list {
+ padding: 20px 0 0;
+
}
-.TagList, .TagList ol {
+
+.TagList,
+.TagList ol {
list-style: none;
- padding: 10px 0;
- margin: 0;
+ padding: 0;
color: @muted-color;
font-size: 13px;
- > li {
+ >li {
+ display: inline-block;
+ max-height: 40px;
cursor: move;
+ width: 100%;
}
- .TagIcon, .icon {
+ .TagIcon,
+ .icon {
margin-right: 10px;
}
}
+
.TagListItem-info {
- padding: 5px 10px;
border-radius: @border-radius;
+ padding: 5px;
+ max-width: max-content;
&:hover {
background: @control-bg;
@@ -46,45 +48,110 @@
.Button {
float: right;
visibility: hidden;
- margin: -8px -10px -8px 10px;
+ margin: -8px -16px -8px 16px;
}
}
-li:not(.sortable-dragging) > .TagListItem-info:hover > .Button {
+
+li:not(.sortable-dragging)>.TagListItem-info:hover>.Button {
visibility: visible;
}
+
.TagList--primary {
font-size: 16px;
- > .sortable-placeholder {
- height: 34px;
+ >.sortable-placeholder {
+ height: 38px;
margin-bottom: 10px;
}
}
+
.TagList ol {
margin-left: 27px;
min-height: 10px;
padding: 0;
- & > :last-child {
+ &> :last-child {
margin-bottom: 10px;
}
}
+
.sortable-placeholder {
border: 2px dashed @control-bg;
border-radius: @border-radius;
- height: 29px;
+ height: 34px;
+ max-width: max-content;
}
-.TagGroup {
- padding-left: 150px;
+.SettingsGroups {
+ display: flex;
+ column-count: 3;
+ column-gap: 30px;
+ flex-wrap: wrap;
- &:first-child {
- border-bottom: 2px solid @control-bg;
+ @media (@tablet-up) {
+ .TagGroup--secondary {
+ max-width: 250px !important;
+ }
}
- > label {
- margin-left: -150px;
- float: left;
- font-weight: bold;
- margin-top: 14px;
+
+ .Form {
+ min-width: 300px;
+
+ >label {
+ margin-bottom: 10px;
+ }
+
+ .TagSettings-rangeInput {
+ input {
+ width: 80px;
+ display: inline;
+ margin: 0 5px;
+
+ &:first-child {
+ margin-left: 0;
+ }
+ }
+ }
+ }
+
+ .TagGroup,
+ .Form {
+ display: inline-grid;
+ padding: 10px 20px;
+ min-height: 20vh;
+ max-width: 400px;
+ grid-template-rows: min-content;
+ border: 1px solid @control-bg;
+ border-radius: @border-radius;
+ flex: 1 1 160px;
+
+ @media (max-width: 1209px) {
+ margin-bottom: 20px;
+ }
+
+ >ol {
+ >li {
+ margin-top: 8px;
+
+ .Button {
+ float: right;
+ visibility: hidden;
+ margin: -8px -16px -8px 16px;
+ }
+ }
+ }
+
+ .TagList-button {
+ background: none;
+ border: 1px dashed @control-bg;
+ height: 40px;
+ margin: auto auto 0 0;
+ }
+
+ >label {
+ float: left;
+ font-weight: bold;
+ color: @muted-color;
+ }
}
}
diff --git a/extensions/tags/src/Command/CreateTagHandler.php b/extensions/tags/src/Command/CreateTagHandler.php
index 08680531e..1349d2f09 100644
--- a/extensions/tags/src/Command/CreateTagHandler.php
+++ b/extensions/tags/src/Command/CreateTagHandler.php
@@ -50,11 +50,12 @@ class CreateTagHandler
);
$parentId = Arr::get($data, 'relationships.parent.data.id');
+ $primary = Arr::get($data, 'attributes.primary');
- if ($parentId !== null) {
+ if ($parentId !== null || $primary) {
$rootTags = Tag::whereNull('parent_id')->whereNotNull('position');
- if ($parentId === 0) {
+ if ($parentId === 0 || $primary) {
$tag->position = $rootTags->max('position') + 1;
} elseif ($rootTags->find($parentId)) {
$position = Tag::where('parent_id', $parentId)->max('position');