1
0
mirror of https://github.com/flarum/core.git synced 2025-08-15 04:44:08 +02:00

Compare commits

..

3 Commits

Author SHA1 Message Date
David Wheatley
3718673882 chore: remove unintended changes 2021-12-20 16:33:34 +01:00
David Wheatley
837657831f chore: replace [] with null 2021-12-20 16:27:35 +01:00
David Wheatley
0334b6c972 chore: use consistent empty vdom return types in core 2021-12-20 16:21:51 +01:00
38 changed files with 156 additions and 272 deletions

View File

@@ -9,6 +9,7 @@
<a href="https://github.styleci.io/repos/28257573"><img src="https://github.styleci.io/repos/28257573/shield?style=flat" alt="StyleCI"></a>
</p>
## About Flarum
**[Flarum](https://flarum.org/) is a delightfully simple discussion platform for your website.** It's fast and easy to use, with all the features you need to run a successful community. It is designed to be:
@@ -19,15 +20,13 @@
* **Powerful and extensible.** Customize, extend, and integrate Flarum to suit your community. Flarums architecture is amazingly flexible, with a powerful Extension API.
![Screenshot of a Flarum instance, showing multiple discussions and tags.](https://flarum.org/assets/img/home-screenshot.png)
## Installation
This repository contains Flarum's core code. If you want to set up a forum, visit the [Flarum skeleton repository](https://github.com/flarum/flarum). For support, refer to the [documentation](https://docs.flarum.org/), and ask questions on [Flarum Discuss](https://discuss.flarum.org/) (our community forum) or [Discord server](https://flarum.org/discord/).
This repository contains Flarum's core code. If you want to set up a forum, visit the [Flarum skeleton repository](https://github.com/flarum/flarum).
## Contributing
Thank you for considering contributing to Flarum! Please read the **[Contributing guide](https://docs.flarum.org/contributing)** to learn how you can help.
Thank you for considering contributing to Flarum! Please read the **[Contributing guide](https://flarum.org/docs/contributing.html)** to learn how you can help.
## Security Vulnerabilities

View File

@@ -10,17 +10,3 @@
* can fix.
*/
export default function fireDebugWarning(...args: Parameters<typeof console.warn>): void;
/**
* Fire a Flarum deprecation warning which is shown in the JS console.
*
* These warnings are only shown when the forum is in debug mode, and the function exists to
* reduce bundle size caused by multiple warnings across our JavaScript.
*
* @param message The message to display. (Short, but sweet, please!)
* @param githubId The PR or Issue ID with more info in relation to this change.
* @param [removedFrom] The version in which this feature will be completely removed. (default: 2.0)
* @param [repo] The repo which the issue or PR is located in. (default: flarum/core)
*
* @see {@link fireDebugWarning}
*/
export declare function fireDeprecationWarning(message: string, githubId: string, removedFrom?: string, repo?: string): void;

View File

@@ -42,22 +42,12 @@ export interface SearchAttrs extends ComponentAttrs {
*
* - state: SearchState instance.
*/
export default class Search<T extends SearchAttrs = SearchAttrs> extends Component<T, SearchState> {
export default class Search<T extends SearchAttrs = SearchAttrs> extends Component<T> {
/**
* The minimum query length before sources are searched.
*/
protected static MIN_SEARCH_LEN: number;
/**
* The instance of `SearchState` for this component.
*/
protected searchState: SearchState;
/**
* The instance of `SearchState` for this component.
*
* @deprecated Replace with`this.searchState` instead.
*/
protected get state(): SearchState;
protected set state(state: SearchState);
/**
* Whether or not the search input has focus.
*/

View File

@@ -1,26 +1,13 @@
import Component from '../../common/Component';
import type Mithril from 'mithril';
export interface IWelcomeHeroAttrs {
}
/**
* The `WelcomeHero` component displays a hero that welcomes the user to the
* forum.
*/
export default class WelcomeHero extends Component<IWelcomeHeroAttrs> {
/**
* @deprecated Extend the `isHidden` method instead.
*/
hidden: boolean;
oninit(vnode: Mithril.Vnode<IWelcomeHeroAttrs, this>): void;
view(vnode: Mithril.Vnode<IWelcomeHeroAttrs, this>): JSX.Element | null;
export default class WelcomeHero extends Component<import("../../common/Component").ComponentAttrs, undefined> {
constructor();
hidden: string | boolean | null | undefined;
/**
* Hide the welcome hero.
*/
hide(): void;
/**
* Determines whether the welcome hero should be hidden.
*
* @returns if the welcome hero is hidden.
*/
isHidden(): boolean;
}
import Component from "../../common/Component";

2
js/dist/admin.js generated vendored

File diff suppressed because one or more lines are too long

2
js/dist/admin.js.map generated vendored

File diff suppressed because one or more lines are too long

2
js/dist/forum.js generated vendored

File diff suppressed because one or more lines are too long

2
js/dist/forum.js.map generated vendored

File diff suppressed because one or more lines are too long

View File

@@ -20,6 +20,6 @@ export default class DashboardWidget extends Component {
* @return {VirtualElement}
*/
content() {
return [];
return null;
}
}

View File

@@ -21,7 +21,7 @@ export default class ExtensionsWidget extends DashboardWidget {
return (
<div className="ExtensionsWidget-list">
{Object.keys(categories).map((category) => (this.categorizedExtensions[category] ? this.extensionCategory(category) : ''))}
{Object.keys(categories).map((category) => !!this.categorizedExtensions[category] && this.extensionCategory(category))}
</div>
);
}
@@ -41,7 +41,7 @@ export default class ExtensionsWidget extends DashboardWidget {
<Link href={app.route('extension', { id: extension.id })}>
<div className="ExtensionListItem-content">
<span className="ExtensionListItem-icon ExtensionIcon" style={extension.icon}>
{extension.icon ? icon(extension.icon.name) : ''}
{!!extension.icon && icon(extension.icon.name)}
</span>
<span className="ExtensionListItem-title">{extension.extra['flarum-extension'].title}</span>
</div>

View File

@@ -18,7 +18,7 @@ export default class LoadingModal<ModalAttrs extends ILoadingModalAttrs = ILoadi
}
content() {
return '';
return null;
}
onsubmit(e: Event): void {

View File

@@ -56,9 +56,8 @@ export default class PermissionGrid<CustomAttrs extends IPermissionGridAttrs = I
{scopes.map((scope) => (
<th>
{scope.label}{' '}
{scope.onremove
? Button.component({ icon: 'fas fa-times', className: 'Button Button--text PermissionGrid-removeScope', onclick: scope.onremove })
: ''}
{!!scope.onremove &&
Button.component({ icon: 'fas fa-times', className: 'Button Button--text PermissionGrid-removeScope', onclick: scope.onremove })}
</th>
))}
<th>{this.scopeControlItems().toArray()}</th>

View File

@@ -175,7 +175,7 @@ export default class UserListPage extends AdminPage {
'id',
{
name: app.translator.trans('core.admin.users.grid.columns.user_id.title'),
content: (user: User) => user.id() ?? '',
content: (user: User) => user.id() ?? null,
},
100
);

View File

@@ -1,6 +1,6 @@
import app from '../common/app';
import { FlarumRequestOptions } from './Application';
import { fireDeprecationWarning } from './helpers/fireDebugWarning';
import fireDebugWarning from './helpers/fireDebugWarning';
import Model, { ModelData, SavedModelData } from './Model';
export interface MetaInformation {
@@ -123,7 +123,11 @@ export default class Store {
if (!this.models[data.type]) {
if (!allowUnregistered) {
setTimeout(() =>
fireDeprecationWarning(`Pushing object of type \`${data.type}\` not allowed, as type not yet registered in the store.`, '3206')
fireDebugWarning(
`[Flarum 2.0 Deprecation] Cannot push object of type \`${data.type}\`, as that type has not yet been registered in the store. This will throw an error in Flarum 2.0 and later.
For more information, see https://github.com/flarum/core/pull/3206.`
)
);
}

View File

@@ -37,7 +37,7 @@ export default class Dropdown extends Component {
}
view(vnode) {
const items = vnode.children ? listItems(vnode.children) : [];
const items = vnode.children ? listItems(vnode.children) : null;
const renderItems = this.attrs.lazyDraw ? this.showing : true;
return (
@@ -128,9 +128,9 @@ export default class Dropdown extends Component {
*/
getButtonContent(children) {
return [
this.attrs.icon ? icon(this.attrs.icon, { className: 'Button-icon' }) : '',
!!this.attrs.icon && icon(this.attrs.icon, { className: 'Button-icon' }),
<span className="Button-label">{this.attrs.label}</span>,
this.attrs.caretIcon ? icon(this.attrs.caretIcon, { className: 'Button-caret' }) : '',
!!this.attrs.caretIcon && icon(this.attrs.caretIcon, { className: 'Button-caret' }),
];
}

View File

@@ -89,7 +89,7 @@ export default class EditUserModal<CustomAttrs extends IEditUserModalAttrs = IEd
disabled={this.nonAdminEditingAdmin()}
/>
</div>
{!this.isEmailConfirmed() && this.userIsAdmin(app.session.user) ? (
{!this.isEmailConfirmed() && this.userIsAdmin(app.session.user) && (
<div>
{Button.component(
{
@@ -100,8 +100,6 @@ export default class EditUserModal<CustomAttrs extends IEditUserModalAttrs = IEd
app.translator.trans('core.lib.edit_user.activate_button')
)}
</div>
) : (
''
)}
</div>,
30
@@ -126,7 +124,7 @@ export default class EditUserModal<CustomAttrs extends IEditUserModalAttrs = IEd
/>
{app.translator.trans('core.lib.edit_user.set_password_label')}
</label>
{this.setPassword() ? (
{this.setPassword() && (
<input
className="FormControl"
type="password"
@@ -135,8 +133,6 @@ export default class EditUserModal<CustomAttrs extends IEditUserModalAttrs = IEd
bidi={this.password}
disabled={this.nonAdminEditingAdmin()}
/>
) : (
''
)}
</div>
</div>,

View File

@@ -105,7 +105,7 @@ export default abstract class Modal<ModalAttrs extends IInternalModalAttrs = IIn
<h3 className="App-titleControl App-titleControl--text">{this.title()}</h3>
</div>
{this.alertAttrs ? <div className="Modal-alert">{Alert.component(this.alertAttrs)}</div> : ''}
{!!this.alertAttrs && <div className="Modal-alert">{Alert.component(this.alertAttrs)}</div>}
{this.content()}
</form>

View File

@@ -65,7 +65,7 @@ export default class Navigation extends Component {
getPaneButton() {
const { pane } = app;
if (!pane || !pane.active) return '';
if (!pane || !pane.active) return null;
return Button.component({
className: 'Button Button--icon Navigation-pin' + (pane.pinned ? ' active' : ''),
@@ -81,7 +81,7 @@ export default class Navigation extends Component {
* @protected
*/
getDrawerButton() {
if (!this.attrs.drawer) return '';
if (!this.attrs.drawer) return null;
const { drawer } = app;
const user = app.session.user;

View File

@@ -12,7 +12,7 @@ export default class RequestErrorModal<CustomAttrs extends IRequestErrorModalAtt
}
title() {
return this.attrs.error.xhr ? `${this.attrs.error.xhr.status} ${this.attrs.error.xhr.statusText}` : '';
return !!this.attrs.error.xhr && `${this.attrs.error.xhr.status} ${this.attrs.error.xhr.statusText}`;
}
content() {

View File

@@ -12,6 +12,6 @@ export default class Switch extends Checkbox {
}
getDisplay() {
return this.attrs.loading ? super.getDisplay() : '';
return !!this.attrs.loading && super.getDisplay();
}
}

View File

@@ -16,21 +16,3 @@ export default function fireDebugWarning(...args: Parameters<typeof console.warn
console.warn(...args);
}
/**
* Fire a Flarum deprecation warning which is shown in the JS console.
*
* These warnings are only shown when the forum is in debug mode, and the function exists to
* reduce bundle size caused by multiple warnings across our JavaScript.
*
* @param message The message to display. (Short, but sweet, please!)
* @param githubId The PR or Issue ID with more info in relation to this change.
* @param [removedFrom] The version in which this feature will be completely removed. (default: 2.0)
* @param [repo] The repo which the issue or PR is located in. (default: flarum/core)
*
* @see {@link fireDebugWarning}
*/
export function fireDeprecationWarning(message: string, githubId: string, removedFrom: string = '2.0', repo: string = 'flarum/core'): void {
// GitHub auto-redirects between `/pull` and `/issues` for us, so using `/pull` saves 2 bytes!
fireDebugWarning(`[Flarum ${removedFrom} Deprecation] ${message}\n\nSee: https://github.com/${repo}/pull/${githubId}`);
}

View File

@@ -1,14 +1,15 @@
import { fireDeprecationWarning } from '../helpers/fireDebugWarning';
const deprecatedNotice = 'The `evented` util is deprecated and no longer supported.';
const deprecationIssueId = '2547';
/**
* The `evented` mixin provides methods allowing an object to trigger events,
* running externally registered event handlers.
*
* @deprecated v1.2, to be removed in v2.0
*/
import fireDebugWarning from '../helpers/fireDebugWarning';
const deprecatedNotice =
'The `evented` util is deprecated and will be removed in Flarum 2.0. For more info, please see https://github.com/flarum/core/issues/2547';
export default {
/**
* Arrays of registered event handlers, grouped by the event name.
@@ -26,7 +27,7 @@ export default {
* @protected
*/
getHandlers(event) {
fireDeprecationWarning(deprecatedNotice, deprecationIssueId);
fireDebugWarning(deprecatedNotice);
this.handlers = this.handlers || {};
@@ -43,7 +44,7 @@ export default {
* @public
*/
trigger(event, ...args) {
fireDeprecationWarning(deprecatedNotice, deprecationIssueId);
fireDebugWarning(deprecatedNotice);
this.getHandlers(event).forEach((handler) => handler.apply(this, args));
},
@@ -55,7 +56,7 @@ export default {
* @param {function} handler The function to handle the event.
*/
on(event, handler) {
fireDeprecationWarning(deprecatedNotice, deprecationIssueId);
fireDebugWarning(deprecatedNotice);
this.getHandlers(event).push(handler);
},
@@ -68,7 +69,7 @@ export default {
* @param {function} handler The function to handle the event.
*/
one(event, handler) {
fireDeprecationWarning(deprecatedNotice, deprecationIssueId);
fireDebugWarning(deprecatedNotice);
const wrapper = function () {
handler.apply(this, arguments);
@@ -86,7 +87,7 @@ export default {
* @param {function} handler The function that handles the event.
*/
off(event, handler) {
fireDeprecationWarning(deprecatedNotice, deprecationIssueId);
fireDebugWarning(deprecatedNotice);
const handlers = this.getHandlers(event);
const index = handlers.indexOf(handler);

View File

@@ -51,7 +51,7 @@ export default class Composer extends Component {
<div className="Composer-handle" oncreate={this.configHandle.bind(this)} />
<ul className="Composer-controls">{listItems(this.controlItems().toArray())}</ul>
<div className="Composer-content" onclick={showIfMinimized}>
{body.componentClass ? body.componentClass.component({ ...body.attrs, composer: this.state, disabled: classes.minimized }) : ''}
{!!body.componentClass && body.componentClass.component({ ...body.attrs, composer: this.state, disabled: classes.minimized })}
</div>
</div>
);

View File

@@ -125,17 +125,16 @@ export default class LogInModal<CustomAttrs extends ILoginModalAttrs = ILoginMod
}
footer() {
return [
<p className="LogInModal-forgotPassword">
<a onclick={this.forgotPassword.bind(this)}>{app.translator.trans('core.forum.log_in.forgot_password_link')}</a>
</p>,
app.forum.attribute('allowSignUp') ? (
<p className="LogInModal-signUp">{app.translator.trans('core.forum.log_in.sign_up_text', { a: <a onclick={this.signUp.bind(this)} /> })}</p>
) : (
''
),
];
return (
<>
<p className="LogInModal-forgotPassword">
<a onclick={this.forgotPassword.bind(this)}>{app.translator.trans('core.forum.log_in.forgot_password_link')}</a>
</p>
{!!app.forum.attribute('allowSignUp') && (
<p className="LogInModal-signUp">{app.translator.trans('core.forum.log_in.sign_up_text', { a: <a onclick={this.signUp.bind(this)} /> })}</p>
)}
</>
);
}
/**

View File

@@ -96,7 +96,7 @@ export default class NotificationList extends Component {
<ul className="NotificationGroup-content">
{group.notifications.map((notification) => {
const NotificationComponent = app.notificationComponents[notification.contentType()];
return NotificationComponent ? <li>{NotificationComponent.component({ notification })}</li> : '';
return !!NotificationComponent && <li>{NotificationComponent.component({ notification })}</li>;
})}
</ul>
</div>

View File

@@ -59,7 +59,7 @@ export default class Post extends Component {
<aside className="Post-actions">
<ul>
{listItems(this.actionItems().toArray())}
{controls.length ? (
{!!controls.length && (
<li>
<Dropdown
className="Post-controls"
@@ -73,8 +73,6 @@ export default class Post extends Component {
{controls}
</Dropdown>
</li>
) : (
''
)}
</ul>
</aside>
@@ -114,7 +112,7 @@ export default class Post extends Component {
* @return {Array}
*/
content() {
return [];
return null;
}
/**

View File

@@ -55,6 +55,6 @@ export default class PostMeta extends Component {
* @returns {String}
*/
getPermalink(post) {
return app.forum.attribute('baseUrl') + app.route.post(post);
return window.location.origin + app.route.post(post);
}
}

View File

@@ -18,7 +18,7 @@ export default class PostPreview extends Component {
const post = this.attrs.post;
const user = post.user();
const content = post.contentType() === 'comment' && post.contentPlain();
const excerpt = content ? highlight(content, this.attrs.highlight, 300) : '';
const excerpt = !!content && highlight(content, this.attrs.highlight, 300);
return (
<Link className="PostPreview" href={app.route.post(post)} onclick={this.attrs.onclick}>

View File

@@ -29,7 +29,10 @@ export default class PostUser extends Component {
);
}
let card = '';
/**
* @type {import('mithril').Children}
*/
let card = null;
if (!post.isHidden() && this.attrs.cardVisible) {
card = UserCard.component({

View File

@@ -9,8 +9,8 @@ import icon from '../../common/helpers/icon';
import SearchState from '../states/SearchState';
import DiscussionsSearchSource from './DiscussionsSearchSource';
import UsersSearchSource from './UsersSearchSource';
import { fireDeprecationWarning } from '../../common/helpers/fireDebugWarning';
import type Mithril from 'mithril';
import Model from '../../common/Model';
/**
* The `SearchSource` interface defines a section of search results in the
@@ -53,33 +53,14 @@ export interface SearchAttrs extends ComponentAttrs {
*
* - state: SearchState instance.
*/
export default class Search<T extends SearchAttrs = SearchAttrs> extends Component<T, SearchState> {
export default class Search<T extends SearchAttrs = SearchAttrs> extends Component<T> {
/**
* The minimum query length before sources are searched.
*/
protected static MIN_SEARCH_LEN = 3;
/**
* The instance of `SearchState` for this component.
*/
protected searchState!: SearchState;
/**
* The instance of `SearchState` for this component.
*
* @deprecated Replace with`this.searchState` instead.
*/
// TODO: [Flarum 2.0] Remove this.
// @ts-expect-error This is a get accessor, while superclass defines this as a property. This is needed to prevent breaking changes, however.
protected get state() {
fireDeprecationWarning('`state` property of the Search component is deprecated', '3212');
return this.searchState;
}
protected set state(state: SearchState) {
fireDeprecationWarning('`state` property of the Search component is deprecated', '3212');
this.searchState = state;
}
/**
* Whether or not the search input has focus.
*/

View File

@@ -34,19 +34,18 @@ export default class UserCard extends Component {
<div className={'UserCard ' + (this.attrs.className || '')} style={color && { '--usercard-bg': color }}>
<div className="darkenBackground">
<div className="container">
{controls.length
? Dropdown.component(
{
className: 'UserCard-controls App-primaryControl',
menuClassName: 'Dropdown-menu--right',
buttonClassName: this.attrs.controlsButtonClassName,
label: app.translator.trans('core.forum.user_controls.button'),
accessibleToggleLabel: app.translator.trans('core.forum.user_controls.toggle_dropdown_accessible_label'),
icon: 'fas fa-ellipsis-v',
},
controls
)
: ''}
{!!controls.length &&
Dropdown.component(
{
className: 'UserCard-controls App-primaryControl',
menuClassName: 'Dropdown-menu--right',
buttonClassName: this.attrs.controlsButtonClassName,
label: app.translator.trans('core.forum.user_controls.button'),
accessibleToggleLabel: app.translator.trans('core.forum.user_controls.toggle_dropdown_accessible_label'),
icon: 'fas fa-ellipsis-v',
},
controls
)}
<div className="UserCard-profile">
<h2 className="UserCard-identity">
@@ -60,7 +59,7 @@ export default class UserCard extends Component {
)}
</h2>
{badges.length ? <ul className="UserCard-badges badges">{listItems(badges)}</ul> : ''}
{!!badges.length && <ul className="UserCard-badges badges">{listItems(badges)}</ul>}
<ul className="UserCard-info">{listItems(this.infoItems().toArray())}</ul>
</div>

View File

@@ -39,7 +39,7 @@ export default class UsersSearchResults implements SearchSource {
.filter((e, i, arr) => arr.lastIndexOf(e) === i)
.sort((a, b) => a.displayName().localeCompare(b.displayName()));
if (!results.length) return [];
if (!results.length) return null;
return [
<li className="Dropdown-header">{app.translator.trans('core.forum.search.users_heading')}</li>,

View File

@@ -0,0 +1,50 @@
import app from '../../forum/app';
import Component from '../../common/Component';
import Button from '../../common/components/Button';
/**
* The `WelcomeHero` component displays a hero that welcomes the user to the
* forum.
*/
export default class WelcomeHero extends Component {
oninit(vnode) {
super.oninit(vnode);
this.hidden = localStorage.getItem('welcomeHidden');
}
view() {
if (this.hidden) return <div />;
const slideUp = () => {
this.$().slideUp(this.hide.bind(this));
};
return (
<header className="Hero WelcomeHero">
<div class="container">
{Button.component({
icon: 'fas fa-times',
onclick: slideUp,
className: 'Hero-close Button Button--icon Button--link',
'aria-label': app.translator.trans('core.forum.welcome_hero.hide'),
})}
<div className="containerNarrow">
<h2 className="Hero-title">{app.forum.attribute('welcomeTitle')}</h2>
<div className="Hero-subtitle">{m.trust(app.forum.attribute('welcomeMessage'))}</div>
</div>
</div>
</header>
);
}
/**
* Hide the welcome hero.
*/
hide() {
localStorage.setItem('welcomeHidden', 'true');
this.hidden = true;
}
}

View File

@@ -1,69 +0,0 @@
import app from '../app';
import Component from '../../common/Component';
import Button from '../../common/components/Button';
import type Mithril from 'mithril';
export interface IWelcomeHeroAttrs {}
const LOCAL_STORAGE_KEY = 'welcomeHidden';
/**
* The `WelcomeHero` component displays a hero that welcomes the user to the
* forum.
*/
export default class WelcomeHero extends Component<IWelcomeHeroAttrs> {
/**
* @deprecated Extend the `isHidden` method instead.
*/
hidden: boolean = false;
oninit(vnode: Mithril.Vnode<IWelcomeHeroAttrs, this>) {
super.oninit(vnode);
}
view(vnode: Mithril.Vnode<IWelcomeHeroAttrs, this>) {
if (this.isHidden()) return null;
const slideUp = () => {
this.$().slideUp(this.hide.bind(this));
};
return (
<header class="Hero WelcomeHero">
<div class="container">
<Button
icon="fas fa-times"
onclick={slideUp}
className="Hero-close Button Button--icon Button--link"
aria-label={app.translator.trans('core.forum.welcome_hero.hide')}
/>
<div class="containerNarrow">
<h2 class="Hero-title">{app.forum.attribute('welcomeTitle')}</h2>
<div class="Hero-subtitle">{m.trust(app.forum.attribute('welcomeMessage'))}</div>
</div>
</div>
</header>
);
}
/**
* Hide the welcome hero.
*/
hide() {
localStorage.setItem(LOCAL_STORAGE_KEY, 'true');
}
/**
* Determines whether the welcome hero should be hidden.
*
* @returns if the welcome hero is hidden.
*/
isHidden(): boolean {
if (!app.forum.attribute<string>('welcomeTitle')?.trim()) return true;
if (localStorage.getItem(LOCAL_STORAGE_KEY)) return true;
if (this.hidden) return true;
return false;
}
}

View File

@@ -260,7 +260,7 @@ class ComposerState {
// let the CSS decide how high it is. If it's fullscreen, then we need to
// make it as high as the window.
if (this.position === ComposerState.Position.MINIMIZED) {
return '';
return null;
} else if (this.position === ComposerState.Position.FULLSCREEN) {
return $(window).height();
}

View File

@@ -2,8 +2,8 @@
position: relative !important;
padding-top: var(--header-height);
padding-bottom: 50px;
overflow-x: hidden;
min-height: 100vh;
width: 100%;
@media @phone {
padding-top: var(--header-height-phone);
@@ -27,16 +27,13 @@
box-shadow: 0 2px 6px var(--shadow-color);
}
}
.App-primaryControl,
.App-titleControl,
.App-backControl {
.App-primaryControl, .App-titleControl, .App-backControl {
position: absolute !important;
z-index: calc(~"var(--zindex-header) + 1");
top: 0 !important;
margin: 0;
.App.affix &,
.Composer & {
.App.affix &, .Composer & {
position: fixed !important;
}
@@ -62,18 +59,15 @@
right: 0;
&.Dropdown {
.Button,
.Button-caret {
.Button, .Button-caret {
display: none !important;
}
.Dropdown-toggle,
.Button-icon {
.Dropdown-toggle, .Button-icon {
display: block !important;
}
}
}
.App-primaryControl,
.App-backControl {
.App-primaryControl, .App-backControl {
margin: 0 !important;
> .Button {
@@ -96,8 +90,7 @@
text-align: center;
color: var(--header-color) !important;
&,
> .Button {
&, > .Button {
font-size: 16px;
}
> .Button {
@@ -150,7 +143,7 @@
.drawerOpen & {
-webkit-transform: none !important;
transform: none !important;
transform: none !important;
}
}
.drawer-backdrop {
@@ -207,15 +200,12 @@
> li {
padding: 0 10px 0;
}
.FormControl,
.ButtonGroup,
.Button {
.FormControl, .ButtonGroup, .Button {
width: 100%;
text-align: left;
}
.Dropdown-menu {
.ButtonGroup,
.Button {
.ButtonGroup, .Button {
width: auto;
}
}
@@ -231,7 +221,7 @@
@media @phone {
.App-drawer {
& when (@config-colored-header = true) {
.light-contents(@name: "header-colored");
.light-contents(@name: 'header-colored');
}
}
}
@@ -255,7 +245,7 @@
}
& when (@config-colored-header = true) {
.light-contents(@name: "header-colored");
.light-contents(@name: 'header-colored');
}
}
@@ -264,8 +254,7 @@
margin-right: 25px;
}
.Header-controls {
&,
> li {
&, > li {
display: inline-block;
vertical-align: middle;
}

View File

@@ -13,7 +13,6 @@ body {
font-size: 13px;
line-height: 1.5;
overflow-y: scroll;
width: 100%;
}
h1, h2, h3, h4, h5, h6 {
@@ -66,8 +65,6 @@ p {
@media @desktop-hd {
width: @screen-desktop-hd;
}
max-width: 100%;
}
.containerNarrow {

View File

@@ -15,8 +15,7 @@
margin: 15px;
display: inline-block;
&.item-controls,
&.item-scrubber {
&.item-controls, &.item-scrubber {
margin: 0;
display: block;
}
@@ -24,27 +23,22 @@
}
}
@media @tablet-up {
.DiscussionPage-discussion > .container {
display: flex;
flex-direction: row-reverse;
}
.DiscussionPage-nav {
min-width: 150px;
float: right;
&, > ul {
width: 150px;
}
> ul {
margin-top: 24px;
position: sticky;
top: ~"calc(24px + var(--header-height))";
position: fixed;
margin-top: 30px;
z-index: 1;
width: 100%;
> li {
margin-bottom: 10px;
}
}
.ButtonGroup,
.Button {
.ButtonGroup, .Button {
width: 100%;
}
.ButtonGroup:not(.itemCount1) {
@@ -60,7 +54,7 @@
@media @tablet-up {
.DiscussionPage-stream {
margin-right: 75px;
margin-right: 225px;
}
}
@@ -138,8 +132,7 @@
}
}
// When the pane is pinned, move the other page content inwards
.App-content,
.App-footer {
.App-content, .App-footer {
.hasPane.panePinned & {
margin-left: var(--pane-width);