diff --git a/js/admin/Gulpfile.js b/js/admin/Gulpfile.js
index c695c9a1e..51da8cfb4 100644
--- a/js/admin/Gulpfile.js
+++ b/js/admin/Gulpfile.js
@@ -1,22 +1,33 @@
var gulp = require('flarum-gulp');
+var nodeDir = 'node_modules';
+var bowerDir = '../bower_components';
+
gulp({
files: [
- 'node_modules/babel-core/external-helpers.js',
- '../bower_components/loader.js/loader.js',
- '../bower_components/mithril/mithril.js',
- '../bower_components/jquery/dist/jquery.js',
- '../bower_components/moment/moment.js',
- '../bower_components/bootstrap/dist/js/bootstrap.js',
- '../bower_components/spin.js/spin.js',
- '../bower_components/spin.js/jquery.spin.js'
+ nodeDir + '/babel-core/external-helpers.js',
+
+ bowerDir + '/es6-micro-loader/dist/system-polyfill.js',
+
+ bowerDir + '/mithril/mithril.js',
+ bowerDir + '/jquery/dist/jquery.js',
+ bowerDir + '/moment/moment.js',
+
+ bowerDir + '/bootstrap/js/affix.js',
+ bowerDir + '/bootstrap/js/dropdown.js',
+ bowerDir + '/bootstrap/js/modal.js',
+ bowerDir + '/bootstrap/js/tooltip.js',
+ bowerDir + '/bootstrap/js/transition.js',
+
+ bowerDir + '/spin.js/spin.js',
+ bowerDir + '/spin.js/jquery.spin.js'
],
- moduleFiles: [
- 'src/**/*.js',
- '../lib/**/*.js'
- ],
- bootstrapFiles: [],
- modulePrefix: 'flarum',
+ modules: {
+ 'flarum': [
+ 'src/**/*.js',
+ '../lib/**/*.js'
+ ]
+ },
externalHelpers: true,
outputFile: 'dist/app.js'
});
diff --git a/js/admin/src/app.js b/js/admin/src/app.js
index 3176fa486..a479ada87 100644
--- a/js/admin/src/app.js
+++ b/js/admin/src/app.js
@@ -1,18 +1,15 @@
-import App from 'flarum/utils/app';
+import App from 'flarum/App';
import store from 'flarum/initializers/store';
import preload from 'flarum/initializers/preload';
-import session from 'flarum/initializers/session';
import routes from 'flarum/initializers/routes';
-import timestamps from 'flarum/initializers/timestamps';
import boot from 'flarum/initializers/boot';
-var app = new App();
+const app = new App();
app.initializers.add('store', store);
-app.initializers.add('session', session);
app.initializers.add('routes', routes);
-app.initializers.add('timestamps', timestamps);
-app.initializers.add('preload', preload, {last: true});
-app.initializers.add('boot', boot, {last: true});
+app.initializers.add('preload', preload, -100);
+
+app.initializers.add('boot', boot, -100);
export default app;
diff --git a/js/admin/src/components/AdminLinkButton.js b/js/admin/src/components/AdminLinkButton.js
new file mode 100644
index 000000000..38a643bb4
--- /dev/null
+++ b/js/admin/src/components/AdminLinkButton.js
@@ -0,0 +1,15 @@
+import LinkButton from 'flarum/components/LinkButton';
+
+export default class AdminLinkButton extends LinkButton {
+ getButtonContent() {
+ const content = super.getButtonContent();
+
+ content.push(
+
+ {this.props.description}
+
+ );
+
+ return content;
+ }
+}
diff --git a/js/admin/src/components/AdminNav.js b/js/admin/src/components/AdminNav.js
new file mode 100644
index 000000000..41827fd01
--- /dev/null
+++ b/js/admin/src/components/AdminNav.js
@@ -0,0 +1,56 @@
+import Component from 'flarum/Component';
+import AdminLinkButton from 'flarum/components/AdminLinkButton';
+import SelectDropdown from 'flarum/components/SelectDropdown';
+
+import ItemList from 'flarum/utils/ItemList';
+
+export default class AdminNav extends Component {
+ view() {
+ return SelectDropdown.component({
+ className: 'AdminNav App-titleControl',
+ buttonClassName: 'Button',
+ children: this.items().toArray()
+ });
+ }
+
+ items() {
+ const items = new ItemList();
+
+ items.add('dashboard', AdminLinkButton.component({
+ href: app.route('dashboard'),
+ icon: 'bar-chart',
+ children: 'Dashboard',
+ description: 'Your forum at a glance.'
+ }));
+
+ items.add('basics', AdminLinkButton.component({
+ href: app.route('basics'),
+ icon: 'pencil',
+ children: 'Basics',
+ description: 'Set your forum title, language, and other basic settings.'
+ }));
+
+ items.add('permissions', AdminLinkButton.component({
+ href: app.route('permissions'),
+ icon: 'key',
+ children: 'Permissions',
+ description: 'Configure who can see and do what.'
+ }));
+
+ items.add('appearance', AdminLinkButton.component({
+ href: app.route('appearance'),
+ icon: 'paint-brush',
+ children: 'Appearance',
+ description: 'Customize your forum\'s colors, logos, and other variables.'
+ }));
+
+ items.add('extensions', AdminLinkButton.component({
+ href: app.route('extensions'),
+ icon: 'puzzle-piece',
+ children: 'Extensions',
+ description: 'Add extra functionality to your forum and make it your own.'
+ }));
+
+ return items;
+ }
+}
diff --git a/js/admin/src/components/AppearancePage.js b/js/admin/src/components/AppearancePage.js
new file mode 100644
index 000000000..448d9abba
--- /dev/null
+++ b/js/admin/src/components/AppearancePage.js
@@ -0,0 +1,9 @@
+import Component from 'flarum/Component';
+
+export default class AppearancePage extends Component {
+ view() {
+ return (
+
+ );
+ }
+}
diff --git a/js/admin/src/components/DashboardPage.js b/js/admin/src/components/DashboardPage.js
new file mode 100644
index 000000000..93534b5a3
--- /dev/null
+++ b/js/admin/src/components/DashboardPage.js
@@ -0,0 +1,16 @@
+import Component from 'flarum/Component';
+
+export default class DashboardPage extends Component {
+ view() {
+ return (
+
+
+
Welcome to Flarum Beta
+
This is beta software; you shouldn't use it in production.
+
You're running version X
+
Get help on X. Report bugs here. Feedback here. Contribute here.
+
+
+ );
+ }
+}
diff --git a/js/admin/src/components/ExtensionsPage.js b/js/admin/src/components/ExtensionsPage.js
new file mode 100644
index 000000000..eb7101c3c
--- /dev/null
+++ b/js/admin/src/components/ExtensionsPage.js
@@ -0,0 +1,9 @@
+import Component from 'flarum/Component';
+
+export default class ExtensionsPage extends Component {
+ view() {
+ return (
+
+ );
+ }
+}
diff --git a/js/admin/src/components/HeaderPrimary.js b/js/admin/src/components/HeaderPrimary.js
new file mode 100644
index 000000000..34ffc203c
--- /dev/null
+++ b/js/admin/src/components/HeaderPrimary.js
@@ -0,0 +1,26 @@
+import Component from 'flarum/Component';
+import ItemList from 'flarum/utils/ItemList';
+import listItems from 'flarum/helpers/listItems';
+
+/**
+ * The `HeaderPrimary` component displays primary header controls. On the
+ * default skin, these are shown just to the right of the forum title.
+ */
+export default class HeaderPrimary extends Component {
+ view() {
+ return (
+
+ {listItems(this.items().toArray())}
+
+ );
+ }
+
+ /**
+ * Build an item list for the controls.
+ *
+ * @return {ItemList}
+ */
+ items() {
+ return new ItemList();
+ }
+}
diff --git a/js/admin/src/components/HeaderSecondary.js b/js/admin/src/components/HeaderSecondary.js
new file mode 100644
index 000000000..cc1f0b268
--- /dev/null
+++ b/js/admin/src/components/HeaderSecondary.js
@@ -0,0 +1,30 @@
+import Component from 'flarum/Component';
+import SessionDropdown from 'flarum/components/SessionDropdown';
+import ItemList from 'flarum/utils/ItemList';
+import listItems from 'flarum/helpers/listItems';
+
+/**
+ * The `HeaderSecondary` component displays secondary header controls.
+ */
+export default class HeaderSecondary extends Component {
+ view() {
+ return (
+
+ {listItems(this.items().toArray())}
+
+ );
+ }
+
+ /**
+ * Build an item list for the controls.
+ *
+ * @return {ItemList}
+ */
+ items() {
+ const items = new ItemList();
+
+ items.add('session', SessionDropdown.component());
+
+ return items;
+ }
+}
diff --git a/js/admin/src/components/SessionDropdown.js b/js/admin/src/components/SessionDropdown.js
new file mode 100644
index 000000000..f4a21f159
--- /dev/null
+++ b/js/admin/src/components/SessionDropdown.js
@@ -0,0 +1,54 @@
+import avatar from 'flarum/helpers/avatar';
+import username from 'flarum/helpers/username';
+import Dropdown from 'flarum/components/Dropdown';
+import Button from 'flarum/components/Button';
+import ItemList from 'flarum/utils/ItemList';
+
+/**
+ * The `SessionDropdown` component shows a button with the current user's
+ * avatar/name, with a dropdown of session controls.
+ */
+export default class SessionDropdown extends Dropdown {
+ static initProps(props) {
+ super.initProps(props);
+
+ props.className = 'SessionDropdown';
+ props.buttonClassName = 'Button Button--user Button--flat';
+ props.menuClassName = 'Dropdown-menu--right';
+ }
+
+ view() {
+ this.props.children = this.items().toArray();
+
+ return super.view();
+ }
+
+ getButtonContent() {
+ const user = app.session.user;
+
+ return [
+ avatar(user), ' ',
+ {username(user)}
+ ];
+ }
+
+ /**
+ * Build an item list for the contents of the dropdown menu.
+ *
+ * @return {ItemList}
+ */
+ items() {
+ const items = new ItemList();
+
+ items.add('logOut',
+ Button.component({
+ icon: 'sign-out',
+ children: app.trans('core.log_out'),
+ onclick: app.session.logout.bind(app.session)
+ }),
+ -100
+ );
+
+ return items;
+ }
+}
diff --git a/js/admin/src/components/admin-nav-item.js b/js/admin/src/components/admin-nav-item.js
deleted file mode 100644
index 2f05cab67..000000000
--- a/js/admin/src/components/admin-nav-item.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import Component from 'flarum/component';
-import icon from 'flarum/helpers/icon';
-import NavItem from 'flarum/components/nav-item';
-
-export default class AdminNavItem extends NavItem {
- view() {
- var active = this.constructor.active(this.props);
- return m('li'+(active ? '.active' : ''), m('a', {href: this.props.href, config: m.route}, [
- icon(this.props.icon+' icon'),
- m('span.label', this.props.label),
- m('div.description', this.props.description)
- ]))
- }
-}
diff --git a/js/admin/src/components/admin-nav.js b/js/admin/src/components/admin-nav.js
deleted file mode 100644
index bd9c042ee..000000000
--- a/js/admin/src/components/admin-nav.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import Component from 'flarum/component';
-import UserDropdown from 'flarum/components/user-dropdown';
-import AdminNavItem from 'flarum/components/admin-nav-item';
-import DropdownSelect from 'flarum/components/dropdown-select';
-
-import ItemList from 'flarum/utils/item-list';
-import listItems from 'flarum/helpers/list-items';
-
-export default class AdminNav extends Component {
- view() {
- return DropdownSelect.component({ items: this.items().toArray() });
- }
-
- items() {
- var items = new ItemList();
-
- items.add('dashboard', AdminNavItem.component({
- href: app.route('dashboard'),
- icon: 'bar-chart',
- label: 'Dashboard',
- description: 'Your forum at a glance.'
- }));
-
- items.add('basics', AdminNavItem.component({
- href: app.route('basics'),
- icon: 'pencil',
- label: 'Basics',
- description: 'Set your forum title, language, and other basic settings.'
- }));
-
- items.add('permissions', AdminNavItem.component({
- href: app.route('permissions'),
- icon: 'key',
- label: 'Permissions',
- description: 'Configure who can see and do what.'
- }));
-
- items.add('appearance', AdminNavItem.component({
- href: app.route('appearance'),
- icon: 'paint-brush',
- label: 'Appearance',
- description: 'Customize your forum\'s colors, logos, and other variables.'
- }));
-
- items.add('extensions', AdminNavItem.component({
- href: app.route('extensions'),
- icon: 'puzzle-piece',
- label: 'Extensions',
- description: 'Add extra functionality to your forum and make it your own.'
- }));
-
- return items;
- }
-}
diff --git a/js/admin/src/components/appearance-page.js b/js/admin/src/components/appearance-page.js
deleted file mode 100644
index 5d1ddd2f1..000000000
--- a/js/admin/src/components/appearance-page.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import Component from 'flarum/component';
-
-export default class AppearancePage extends Component {
- view() {
- return m('div', 'appearance');
- }
-};
diff --git a/js/admin/src/components/basics-page.js b/js/admin/src/components/basics-page.js
deleted file mode 100644
index c5baf8a77..000000000
--- a/js/admin/src/components/basics-page.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import Component from 'flarum/component';
-
-export default class BasicsPage extends Component {
- view() {
- return m('div', 'basics');
- }
-};
diff --git a/js/admin/src/components/dashboard-page.js b/js/admin/src/components/dashboard-page.js
deleted file mode 100644
index d9dc00acb..000000000
--- a/js/admin/src/components/dashboard-page.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import Component from 'flarum/component';
-
-export default class DashboardPage extends Component {
- view() {
- return m('div', 'dashboard');
- }
-};
diff --git a/js/admin/src/components/extensions-page.js b/js/admin/src/components/extensions-page.js
deleted file mode 100644
index c1fe5e793..000000000
--- a/js/admin/src/components/extensions-page.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import Component from 'flarum/component';
-
-export default class ExtensionsPage extends Component {
- view() {
- return m('div', 'extensions');
- }
-};
diff --git a/js/admin/src/components/header-primary.js b/js/admin/src/components/header-primary.js
deleted file mode 100644
index 166a7b6cc..000000000
--- a/js/admin/src/components/header-primary.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import Component from 'flarum/component';
-import ItemList from 'flarum/utils/item-list';
-import listItems from 'flarum/helpers/list-items';
-
-export default class HeaderPrimary extends Component {
- view() {
- return m('ul.header-controls', listItems(this.items().toArray()));
- }
-
- items() {
- var items = new ItemList();
-
- return items;
- }
-}
diff --git a/js/admin/src/components/header-secondary.js b/js/admin/src/components/header-secondary.js
deleted file mode 100644
index c48343c05..000000000
--- a/js/admin/src/components/header-secondary.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import Component from 'flarum/component';
-import UserDropdown from 'flarum/components/user-dropdown';
-
-import ItemList from 'flarum/utils/item-list';
-import listItems from 'flarum/helpers/list-items';
-
-export default class HeaderSecondary extends Component {
- view() {
- return m('ul.header-controls', listItems(this.items().toArray()));
- }
-
- items() {
- var items = new ItemList();
-
- items.add('user', UserDropdown.component({ user: app.session.user }));
-
- return items;
- }
-}
diff --git a/js/admin/src/components/permissions-page.js b/js/admin/src/components/permissions-page.js
deleted file mode 100644
index bc4c0ba4a..000000000
--- a/js/admin/src/components/permissions-page.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import Component from 'flarum/component';
-
-export default class PermissionsPage extends Component {
- view() {
- return m('div', 'permissions');
- }
-};
diff --git a/js/admin/src/components/user-dropdown.js b/js/admin/src/components/user-dropdown.js
deleted file mode 100644
index 1bbbc60f5..000000000
--- a/js/admin/src/components/user-dropdown.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import Component from 'flarum/component';
-import avatar from 'flarum/helpers/avatar';
-import username from 'flarum/helpers/username';
-import DropdownButton from 'flarum/components/dropdown-button';
-import ActionButton from 'flarum/components/action-button';
-import ItemList from 'flarum/utils/item-list';
-import Separator from 'flarum/components/separator';
-
-export default class UserDropdown extends Component {
- view() {
- var user = this.props.user;
-
- return DropdownButton.component({
- buttonClass: 'btn btn-default btn-naked btn-rounded btn-user',
- menuClass: 'pull-right',
- buttonContent: [avatar(user), ' ', m('span.label', username(user))],
- items: this.items().toArray()
- });
- }
-
- items() {
- var items = new ItemList();
- var user = this.props.user;
-
- items.add('logOut',
- ActionButton.component({
- icon: 'sign-out',
- label: 'Log Out',
- onclick: app.session.logout.bind(app.session)
- })
- );
-
- return items;
- }
-}
diff --git a/js/admin/src/initializers/boot.js b/js/admin/src/initializers/boot.js
index 52e4a4574..1463ed9d5 100644
--- a/js/admin/src/initializers/boot.js
+++ b/js/admin/src/initializers/boot.js
@@ -1,38 +1,54 @@
-import ScrollListener from 'flarum/utils/scroll-listener';
-import mapRoutes from 'flarum/utils/map-routes';
+/*global FastClick*/
-import BackButton from 'flarum/components/back-button';
-import HeaderPrimary from 'flarum/components/header-primary';
-import HeaderSecondary from 'flarum/components/header-secondary';
-import Modal from 'flarum/components/modal';
-import Alerts from 'flarum/components/alerts';
-import AdminNav from 'flarum/components/admin-nav';
+import ScrollListener from 'flarum/utils/ScrollListener';
+import Drawer from 'flarum/utils/Drawer';
+import mapRoutes from 'flarum/utils/mapRoutes';
-export default function(app) {
- var id = id => document.getElementById(id);
+import Navigation from 'flarum/components/Navigation';
+import HeaderPrimary from 'flarum/components/HeaderPrimary';
+import HeaderSecondary from 'flarum/components/HeaderSecondary';
+import AdminNav from 'flarum/components/AdminNav';
+import ModalManager from 'flarum/components/ModalManager';
+import AlertManager from 'flarum/components/AlertManager';
+/**
+ * The `boot` initializer boots up the admin app. It initializes some app
+ * globals, mounts components to the page, and begins routing.
+ *
+ * @param {ForumApp} app
+ */
+export default function boot(app) {
+ m.startComputation();
+
+ m.mount(document.getElementById('app-navigation'), Navigation.component({className: 'App-backControl', drawer: true}));
+ m.mount(document.getElementById('header-navigation'), Navigation.component());
+ m.mount(document.getElementById('header-primary'), HeaderPrimary.component());
+ m.mount(document.getElementById('header-secondary'), HeaderSecondary.component());
+ m.mount(document.getElementById('admin-navigation'), AdminNav.component());
+
+ app.drawer = new Drawer();
+ app.modal = m.mount(document.getElementById('modal'), ModalManager.component());
+ app.alerts = m.mount(document.getElementById('alerts'), AlertManager.component());
app.history = {
- back: function() {
- window.location = 'http://flarum.dev';
- },
- canGoBack: function() {
- return true;
- }
+ canGoBack: () => true,
+ back: () => window.location = '/'
};
- m.mount(id('back-control'), BackButton.component({ className: 'back-control', drawer: true }));
- m.mount(id('back-button'), BackButton.component());
-
- m.mount(id('header-primary'), HeaderPrimary.component());
- m.mount(id('header-secondary'), HeaderSecondary.component());
-
- m.mount(id('admin-nav'), AdminNav.component());
-
- app.modal = m.mount(id('modal'), Modal.component());
- app.alerts = m.mount(id('alerts'), Alerts.component());
-
m.route.mode = 'hash';
- m.route(id('content'), '/', mapRoutes(app.routes));
+ m.route(document.getElementById('content'), '/', mapRoutes(app.routes));
- new ScrollListener(top => $('body').toggleClass('scrolled', top > 0)).start();
+ m.endComputation();
+
+ // Add a class to the body which indicates that the page has been scrolled
+ // down.
+ new ScrollListener(top => {
+ const $app = $('#app');
+ const offset = $app.offset().top;
+
+ $app
+ .toggleClass('affix', top >= offset)
+ .toggleClass('scrolled', top > offset);
+ }).start();
+
+ app.booted = true;
}
diff --git a/js/admin/src/initializers/routes.js b/js/admin/src/initializers/routes.js
index d0519bf82..5a5a416ae 100644
--- a/js/admin/src/initializers/routes.js
+++ b/js/admin/src/initializers/routes.js
@@ -1,15 +1,20 @@
-import DashboardPage from 'flarum/components/dashboard-page';
-import BasicsPage from 'flarum/components/basics-page';
-import PermissionsPage from 'flarum/components/permissions-page';
-import AppearancePage from 'flarum/components/appearance-page';
-import ExtensionsPage from 'flarum/components/extensions-page';
+import DashboardPage from 'flarum/components/DashboardPage';
+import BasicsPage from 'flarum/components/BasicsPage';
+import PermissionsPage from 'flarum/components/PermissionsPage';
+import AppearancePage from 'flarum/components/AppearancePage';
+import ExtensionsPage from 'flarum/components/ExtensionsPage';
+/**
+ * The `routes` initializer defines the admin app's routes.
+ *
+ * @param {App} app
+ */
export default function(app) {
app.routes = {
- 'dashboard': ['/', DashboardPage.component()],
- 'basics': ['/basics', BasicsPage.component()],
- 'permissions': ['/permissions', PermissionsPage.component()],
- 'appearance': ['/appearance', AppearancePage.component()],
- 'extensions': ['/extensions', ExtensionsPage.component()]
+ 'dashboard': {path: '/', component: DashboardPage.component()},
+ 'basics': {path: '/basics', component: BasicsPage.component()},
+ 'permissions': {path: '/permissions', component: PermissionsPage.component()},
+ 'appearance': {path: '/appearance', component: AppearancePage.component()},
+ 'extensions': {path: '/extensions', component: ExtensionsPage.component()}
};
}
diff --git a/js/forum/src/components/HeaderSecondary.js b/js/forum/src/components/HeaderSecondary.js
index a2cd4d5d8..1146e93a4 100644
--- a/js/forum/src/components/HeaderSecondary.js
+++ b/js/forum/src/components/HeaderSecondary.js
@@ -8,7 +8,7 @@ import ItemList from 'flarum/utils/ItemList';
import listItems from 'flarum/helpers/listItems';
/**
- * The `HeaderSecondary` component displays secondary footer controls, such as
+ * The `HeaderSecondary` component displays secondary header controls, such as
* the search box and the user menu. On the default skin, these are shown on the
* right side of the header.
*/
diff --git a/js/forum/src/utils/Drawer.js b/js/lib/utils/Drawer.js
similarity index 100%
rename from js/forum/src/utils/Drawer.js
rename to js/lib/utils/Drawer.js
diff --git a/less/admin/layout.less b/less/admin/AdminNav.less
similarity index 58%
rename from less/admin/layout.less
rename to less/admin/AdminNav.less
index 55321b134..21736abe5 100644
--- a/less/admin/layout.less
+++ b/less/admin/AdminNav.less
@@ -1,75 +1,79 @@
@admin-pane-width: 300px;
-.admin-nav {
- & .description {
- display: none;
- }
+.App {
+ padding-bottom: 0;
}
-.admin-content {
+.AdminLinkButton-description {
+ display: none;
+}
+.AdminContent {
padding: 20px 0;
}
+.App-content .sideNavOffset {
+ margin-top: 0;
+}
@media @desktop, @desktop-hd {
- .admin-nav {
+ .App-nav {
position: fixed;
top: @header-height;
bottom: 0;
width: @admin-pane-width;
- box-shadow: 0 2px 6px @shadow-color;
+ .box-shadow(2px 2px 6px -2px @shadow-color);
background: @body-bg;
border-top: 1px solid @control-bg;
-
- & .dropdown-select .dropdown-menu > li {
- & > a {
+ z-index: @zindex-pane;
+ overflow: auto;
+ }
+ .App-content .sideNavOffset {
+ margin-left: @admin-pane-width;
+ }
+ .App-nav .AdminNav {
+ .Dropdown-menu > li {
+ > a {
padding: 15px 15px 15px 45px;
display: block;
text-decoration: none;
white-space: normal;
}
- & > a, & > a:hover, &.active > a {
+ > a, > a:hover, &.active > a {
color: @muted-color;
}
+ > a:hover {
+ background: @control-bg;
+ }
&.active > a {
background: @control-bg;
font-weight: normal;
- & .label, & .icon {
+ .Button-label, .Button-icon {
color: @text-color;
- }
- & .label {
font-weight: bold;
}
}
- &:hover:not(.active) {
- & .label {
- text-decoration: underline;
- }
- }
}
- & .icon {
+ .Button-icon {
float: left;
margin-left: -30px;
font-size: 14px;
- margin-top: 2px;
+ margin-top: 4px !important;
}
- & .label {
+ .Button-label {
display: block;
font-size: 15px;
font-weight: normal;
margin: 0 0 5px;
}
- & .description {
+ .AdminLinkButton-description {
display: block;
font-size: 12px;
}
}
- .admin-content {
- margin-left: @admin-pane-width;
- padding: 20px;
- }
.container {
width: 100%;
+ padding: 0 30px;
+ margin: 0;
- .global-content & {
+ .App-content > & {
padding: 0;
}
}
diff --git a/less/admin/DashboardPage.less b/less/admin/DashboardPage.less
new file mode 100644
index 000000000..eacbbe62b
--- /dev/null
+++ b/less/admin/DashboardPage.less
@@ -0,0 +1,9 @@
+.DashboardPage {
+ @media @desktop-up {
+ .container {
+ max-width: 600px;
+ padding: 30px;
+ margin: 0;
+ }
+ }
+}
diff --git a/less/admin/app.less b/less/admin/app.less
index f853751ac..ba08c19e1 100644
--- a/less/admin/app.less
+++ b/less/admin/app.less
@@ -1,24 +1,6 @@
-@lib-path: "../lib";
+@import "../lib/lib.less";
-@import "@{lib-path}/bootstrap.less";
-
-// We want to specify the @fa-font-path variable AFTER we import font awesome
-// so that it overrides the default definition.
-@import "@{lib-path}/font-awesome/font-awesome.less";
-@fa-font-path: "/assets/fonts";
-
-@import url(http://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700,300,600);
-
-// Finally, with our vendor CSS loaded, we can import Flarum-specific stuff.
-@import "@{lib-path}/components.less";
-@import "@{lib-path}/buttons.less";
-@import "@{lib-path}/badges.less";
-@import "@{lib-path}/dropdowns.less";
-@import "@{lib-path}/avatars.less";
-@import "@{lib-path}/forms.less";
-@import "@{lib-path}/alerts.less";
-@import "@{lib-path}/modals.less";
-@import "@{lib-path}/layout.less";
-@import "@{lib-path}/side-nav.less";
-
-@import "layout.less";
+@import "AdminNav.less";
+@import "DashboardPage.less";
+@import "BasicsPage.less";
+@import "PermissionsPage.less";
diff --git a/less/lib/FormControl.less b/less/lib/FormControl.less
index 64e472650..66c09f2ac 100755
--- a/less/lib/FormControl.less
+++ b/less/lib/FormControl.less
@@ -40,3 +40,9 @@
height: auto;
}
}
+.helpText {
+ font-size: 12px;
+ line-height: 1.5em;
+ margin-bottom: 10px;
+ color: @muted-color;
+}
diff --git a/less/lib/scaffolding.less b/less/lib/scaffolding.less
index a48c0db1b..1ad846488 100755
--- a/less/lib/scaffolding.less
+++ b/less/lib/scaffolding.less
@@ -93,55 +93,19 @@ input[type="search"] {
-webkit-appearance: none;
}
-// Checkboxes and radios
-//
-// Indent the labels to position radios/checkboxes as hanging controls.
+.checkbox {
+ display: block;
+ padding-left: 20px;
+ margin-bottom: 5px;
+ cursor: pointer;
-// .radio,
-// .checkbox {
-// position: relative;
-// display: block;
-// margin-top: 10px;
-// margin-bottom: 10px;
-
-// label {
-// min-height: @line-height-computed; // Ensure the input doesn't jump when there is no text
-// padding-left: 20px;
-// margin-bottom: 0;
-// font-weight: normal;
-// cursor: pointer;
-// }
-// }
-// .radio input[type="radio"],
-// .radio-inline input[type="radio"],
-// .checkbox input[type="checkbox"],
-// .checkbox-inline input[type="checkbox"] {
-// position: absolute;
-// margin-left: -20px;
-// margin-top: 4px \9;
-// }
-
-// .radio + .radio,
-// .checkbox + .checkbox {
-// margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing
-// }
-
-// // Radios and checkboxes on same line
-// .radio-inline,
-// .checkbox-inline {
-// position: relative;
-// display: inline-block;
-// padding-left: 20px;
-// margin-bottom: 0;
-// vertical-align: middle;
-// font-weight: normal;
-// cursor: pointer;
-// }
-// .radio-inline + .radio-inline,
-// .checkbox-inline + .checkbox-inline {
-// margin-top: 0;
-// margin-left: 10px; // space out consecutive inline controls
-// }
+ input[type=checkbox],
+ input[type=radio] {
+ margin-left: -20px;
+ margin-top: 2px;
+ float: left;
+ }
+}
.fade {
opacity: 0;
diff --git a/src/Admin/Actions/ClientAction.php b/src/Admin/Actions/ClientAction.php
new file mode 100644
index 000000000..fa72b8d67
--- /dev/null
+++ b/src/Admin/Actions/ClientAction.php
@@ -0,0 +1,23 @@
+apiClient = $apiClient;
- $this->actor = $actor;
- }
-
- protected function render(Request $request, $routeParams = [])
- {
- $config = app('db')->table('config')->whereIn('key', ['base_url', 'api_url', 'forum_title', 'welcome_title', 'welcome_message'])->lists('value', 'key');
- $data = [];
- $session = [];
-
- if (($user = $this->actor->getUser()) && $user->exists) {
- $session = [
- 'userId' => $user->id,
- 'token' => FigRequestCookies::get($request, 'flarum_remember'),
- ];
-
- $response = $this->apiClient->send('Flarum\Api\Actions\Users\ShowAction', ['id' => $user->id]);
-
- $data = [$response->data];
- if (isset($response->included)) {
- $data = array_merge($data, $response->included);
- }
- }
-
- $view = view('flarum.admin::index')
- ->with('title', 'Administration - '.Core::config('forum_title'))
- ->with('config', $config)
- ->with('layout', 'flarum.admin::admin')
- ->with('data', $data)
- ->with('session', $session);
-
- $assetManager = app('flarum.admin.assetManager');
- $root = __DIR__.'/../../..';
- $assetManager->addFile([
- $root.'/js/admin/dist/app.js',
- $root.'/less/admin/app.less'
- ]);
-
- // event(new RenderView($view, $assetManager, $this));
-
- return $view
- ->with('styles', $assetManager->getCSSFiles())
- ->with('scripts', $assetManager->getJSFiles());
- }
-}
diff --git a/src/Admin/AdminServiceProvider.php b/src/Admin/AdminServiceProvider.php
index 9e4e5af21..be60a09d3 100644
--- a/src/Admin/AdminServiceProvider.php
+++ b/src/Admin/AdminServiceProvider.php
@@ -4,6 +4,7 @@ use Flarum\Http\RouteCollection;
use Flarum\Http\UrlGenerator;
use Illuminate\Support\ServiceProvider;
use Psr\Http\Message\ServerRequestInterface;
+use Zend\Diactoros\Response\RedirectResponse;
class AdminServiceProvider extends ServiceProvider
{
@@ -47,7 +48,7 @@ class AdminServiceProvider extends ServiceProvider
$routes->get(
'/',
'flarum.admin.index',
- $this->action('Flarum\Admin\Actions\IndexAction')
+ $this->action('Flarum\Admin\Actions\ClientAction')
);
}
diff --git a/src/Admin/Middleware/LoginWithCookieAndCheckAdmin.php b/src/Admin/Middleware/LoginWithCookieAndCheckAdmin.php
index 2cf71d4b8..8871607ea 100644
--- a/src/Admin/Middleware/LoginWithCookieAndCheckAdmin.php
+++ b/src/Admin/Middleware/LoginWithCookieAndCheckAdmin.php
@@ -1,7 +1,7 @@
actor = $actor;
+ $this->app = $app;
}
/**
@@ -23,15 +26,13 @@ class LoginWithCookieAndCheckAdmin implements MiddlewareInterface
*/
public function __invoke(Request $request, Response $response, callable $out = null)
{
- $cookies = $request->getCookieParams();
-
- if (($token = $cookies['flarum_remember']) &&
+ if (($token = array_get($request->getCookieParams(), 'flarum_remember')) &&
($accessToken = AccessToken::where('id', $token)->first()) &&
$accessToken->user->isAdmin()
) {
- $this->actor->setUser($accessToken->user);
+ $this->app->instance('flarum.actor', $accessToken->user);
} else {
- die('ur not an admin');
+ die('Access Denied');
}
return $out ? $out($request, $response) : $response;
diff --git a/src/Http/RouterMiddleware.php b/src/Http/RouterMiddleware.php
index 0e76744df..4bf6c200f 100644
--- a/src/Http/RouterMiddleware.php
+++ b/src/Http/RouterMiddleware.php
@@ -41,7 +41,7 @@ class RouterMiddleware
public function __invoke(Request $request, Response $response, callable $out = null)
{
$method = $request->getMethod();
- $uri = $request->getUri()->getPath();
+ $uri = $request->getUri()->getPath() ?: '/';
$routeInfo = $this->getDispatcher()->dispatch($method, $uri);
diff --git a/views/admin.blade.php b/views/admin.blade.php
index 28d39eb23..6a76c8e43 100644
--- a/views/admin.blade.php
+++ b/views/admin.blade.php
@@ -1,17 +1,30 @@
-