mirror of
https://github.com/flarum/core.git
synced 2025-08-26 01:34:16 +02:00
feat: theming and extensibility improvements (#3876)
* feat: make page structure customizable across different pages (#3867) * feat: create `PageStructure` component * feat: apply to `DiscussionPage` * feat: apply to `UserPage` * feat: apply to `TagsPage` * fix: adapt subscriptions ext * chore: cleanup * chore: use grid & flexbox for the discussion list item (#3868) * chore: rename `DiscussionPage-list` to `DiscussionListPane` * chore: itemlistify `DiscussionListItem` * chore: use flex and grid for `DiscussionListItem` * chore: use flexbox for `App-header` (#3869) * chore: use flex and grid for `App-header` * chore: drop search floats * fix: adapt admin styles * chore: use flexbox in dropdowns and SplitDropdown for subscriptions (#3874) * chore: flexbox dropdown menu items * chore: normalize subscriptions menu (use slit dropdown) * chore: cleanup * chore: misc flexbox/grid changes (#3875) * chore: `TagsPage` to tsx * chore: `TagsPage` flexbox/grid * chore: `IndexPage-toolbar` flexbox * chore: `UserCard` flexbox & itemlists * fix: `Post` improve spacing logic * chore: `Post` grid and proper spacing * fix: avatar editor hover layer layout * chore: `Button` flex * chore: normalize form semantics (#3877) * chore: normalize fieldsets * fix: `LinkButton` spacing * chore: consistent form semantics * fix: styling regressions (#3878) * fix: post spacing goes off in other pages * fix: regression * feat: extract reusable components from `NotificationsDropdown` (#3879) * feat: extensible global notices (#3880) * fix: js error on null item list * feat: extensible global notices * chore: housekeeping (#3881) * chore: use CSS variables where still not using * chore: cleanup suspension modal * chore: cleanup post flag * fix: badge vertical align * chore: use CSS variables for custom coloring * chore: `icon` helper to `Icon` component * chore: `avatar` helper to `Avatar` component * fix: chunk loading fails on admin frontend * chore: format * feat: reusable `UploadImageButton` component (#3882) * chore: convert `UploadImageButton` to tsx * feat: reusable `UploadImageButton` component * feat: add `image-upload` setting type * feat: extensible default footer component (#3883) * chore: yarn format
This commit is contained in:
7
extensions/subscriptions/js/src/@types/shims.d.ts
vendored
Normal file
7
extensions/subscriptions/js/src/@types/shims.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import 'flarum/common/models/Discussion';
|
||||
|
||||
declare module 'flarum/common/models/Discussion' {
|
||||
export default interface Discussion {
|
||||
subscription(): string;
|
||||
}
|
||||
}
|
@@ -2,11 +2,12 @@ import app from 'flarum/forum/app';
|
||||
import { extend } from 'flarum/common/extend';
|
||||
import LinkButton from 'flarum/common/components/LinkButton';
|
||||
import IndexPage from 'flarum/forum/components/IndexPage';
|
||||
import IndexSidebar from 'flarum/forum/components/IndexSidebar';
|
||||
import DiscussionListState from 'flarum/forum/states/DiscussionListState';
|
||||
import GlobalSearchState from 'flarum/forum/states/GlobalSearchState';
|
||||
|
||||
export default function addSubscriptionFilter() {
|
||||
extend(IndexPage.prototype, 'navItems', function (items) {
|
||||
extend(IndexSidebar.prototype, 'navItems', function (items) {
|
||||
if (app.session.user) {
|
||||
const params = app.search.stickyParams();
|
||||
|
||||
|
@@ -17,4 +17,8 @@ export default class NewPostNotification extends Notification {
|
||||
content() {
|
||||
return app.translator.trans('flarum-subscriptions.forum.notifications.new_post_text', { user: this.attrs.notification.fromUser() });
|
||||
}
|
||||
|
||||
excerpt() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -1,115 +0,0 @@
|
||||
import app from 'flarum/forum/app';
|
||||
import Dropdown from 'flarum/common/components/Dropdown';
|
||||
import Button from 'flarum/common/components/Button';
|
||||
import Tooltip from 'flarum/common/components/Tooltip';
|
||||
import icon from 'flarum/common/helpers/icon';
|
||||
import extractText from 'flarum/common/utils/extractText';
|
||||
import classList from 'flarum/common/utils/classList';
|
||||
|
||||
import SubscriptionMenuItem from './SubscriptionMenuItem';
|
||||
|
||||
export default class SubscriptionMenu extends Dropdown {
|
||||
oninit(vnode) {
|
||||
super.oninit(vnode);
|
||||
|
||||
this.options = [
|
||||
{
|
||||
subscription: null,
|
||||
icon: 'far fa-star',
|
||||
label: app.translator.trans('flarum-subscriptions.forum.sub_controls.not_following_button'),
|
||||
description: app.translator.trans('flarum-subscriptions.forum.sub_controls.not_following_text'),
|
||||
},
|
||||
{
|
||||
subscription: 'follow',
|
||||
icon: 'fas fa-star',
|
||||
label: app.translator.trans('flarum-subscriptions.forum.sub_controls.following_button'),
|
||||
description: app.translator.trans('flarum-subscriptions.forum.sub_controls.following_text'),
|
||||
},
|
||||
{
|
||||
subscription: 'ignore',
|
||||
icon: 'far fa-eye-slash',
|
||||
label: app.translator.trans('flarum-subscriptions.forum.sub_controls.ignoring_button'),
|
||||
description: app.translator.trans('flarum-subscriptions.forum.sub_controls.ignoring_text'),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
view() {
|
||||
const discussion = this.attrs.discussion;
|
||||
const subscription = discussion.subscription();
|
||||
|
||||
let buttonLabel = app.translator.trans('flarum-subscriptions.forum.sub_controls.follow_button');
|
||||
let buttonIcon = 'far fa-star';
|
||||
const buttonClass = 'SubscriptionMenu-button--' + subscription;
|
||||
|
||||
switch (subscription) {
|
||||
case 'follow':
|
||||
buttonLabel = app.translator.trans('flarum-subscriptions.forum.sub_controls.following_button');
|
||||
buttonIcon = 'fas fa-star';
|
||||
break;
|
||||
|
||||
case 'ignore':
|
||||
buttonLabel = app.translator.trans('flarum-subscriptions.forum.sub_controls.ignoring_button');
|
||||
buttonIcon = 'far fa-eye-slash';
|
||||
break;
|
||||
|
||||
default:
|
||||
// no default
|
||||
}
|
||||
|
||||
const preferences = app.session.user.preferences();
|
||||
const notifyEmail = preferences['notify_newPost_email'];
|
||||
const notifyAlert = preferences['notify_newPost_alert'];
|
||||
const tooltipText = extractText(
|
||||
app.translator.trans(
|
||||
notifyEmail ? 'flarum-subscriptions.forum.sub_controls.notify_email_tooltip' : 'flarum-subscriptions.forum.sub_controls.notify_alert_tooltip'
|
||||
)
|
||||
);
|
||||
|
||||
const shouldShowTooltip = (notifyEmail || notifyAlert) && subscription === null;
|
||||
|
||||
const button = (
|
||||
<Button
|
||||
className={classList('Button', 'SubscriptionMenu-button', buttonClass)}
|
||||
icon={buttonIcon}
|
||||
onclick={this.saveSubscription.bind(this, discussion, ['follow', 'ignore'].indexOf(subscription) !== -1 ? null : 'follow')}
|
||||
>
|
||||
{buttonLabel}
|
||||
</Button>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="Dropdown ButtonGroup SubscriptionMenu">
|
||||
{shouldShowTooltip ? (
|
||||
<Tooltip text={tooltipText} position="bottom">
|
||||
{button}
|
||||
</Tooltip>
|
||||
) : (
|
||||
button
|
||||
)}
|
||||
|
||||
<button className={classList('Dropdown-toggle Button Button--icon', buttonClass)} data-toggle="dropdown">
|
||||
{icon('fas fa-caret-down', { className: 'Button-icon' })}
|
||||
</button>
|
||||
|
||||
<ul className="Dropdown-menu dropdown-menu Dropdown-menu--right">
|
||||
{this.options.map((attrs) => (
|
||||
<li>
|
||||
<SubscriptionMenuItem
|
||||
{...attrs}
|
||||
onclick={this.saveSubscription.bind(this, discussion, attrs.subscription)}
|
||||
active={subscription === attrs.subscription}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
saveSubscription(discussion, subscription) {
|
||||
discussion.save({ subscription });
|
||||
|
||||
this.$('.SubscriptionMenu-button').tooltip('hide');
|
||||
}
|
||||
}
|
@@ -0,0 +1,99 @@
|
||||
import app from 'flarum/forum/app';
|
||||
import Dropdown, { IDropdownAttrs } from 'flarum/common/components/Dropdown';
|
||||
import Button from 'flarum/common/components/Button';
|
||||
import extractText from 'flarum/common/utils/extractText';
|
||||
import DetailedDropdownItem from 'flarum/common/components/DetailedDropdownItem';
|
||||
import SplitDropdown from 'flarum/common/components/SplitDropdown';
|
||||
import type Discussion from 'flarum/common/models/Discussion';
|
||||
|
||||
export interface ISubscriptionMenuAttrs extends IDropdownAttrs {
|
||||
discussion: Discussion;
|
||||
}
|
||||
|
||||
export default class SubscriptionMenu<CustomAttrs extends ISubscriptionMenuAttrs = ISubscriptionMenuAttrs> extends Dropdown<CustomAttrs> {
|
||||
private options: any[] = [
|
||||
{
|
||||
subscription: null,
|
||||
icon: 'far fa-star',
|
||||
label: app.translator.trans('flarum-subscriptions.forum.sub_controls.not_following_button'),
|
||||
description: app.translator.trans('flarum-subscriptions.forum.sub_controls.not_following_text'),
|
||||
},
|
||||
{
|
||||
subscription: 'follow',
|
||||
icon: 'fas fa-star',
|
||||
label: app.translator.trans('flarum-subscriptions.forum.sub_controls.following_button'),
|
||||
description: app.translator.trans('flarum-subscriptions.forum.sub_controls.following_text'),
|
||||
},
|
||||
{
|
||||
subscription: 'ignore',
|
||||
icon: 'far fa-eye-slash',
|
||||
label: app.translator.trans('flarum-subscriptions.forum.sub_controls.ignoring_button'),
|
||||
description: app.translator.trans('flarum-subscriptions.forum.sub_controls.ignoring_text'),
|
||||
},
|
||||
];
|
||||
|
||||
private possibleButtonAttrs: any = {
|
||||
null: {
|
||||
icon: 'far fa-star',
|
||||
label: app.translator.trans('flarum-subscriptions.forum.sub_controls.follow_button'),
|
||||
},
|
||||
follow: {
|
||||
icon: 'fas fa-star',
|
||||
label: app.translator.trans('flarum-subscriptions.forum.sub_controls.following_button'),
|
||||
},
|
||||
ignore: {
|
||||
icon: 'far fa-eye-slash',
|
||||
label: app.translator.trans('flarum-subscriptions.forum.sub_controls.ignoring_button'),
|
||||
},
|
||||
};
|
||||
|
||||
view() {
|
||||
const discussion = this.attrs.discussion;
|
||||
const subscription = discussion.subscription();
|
||||
|
||||
const buttonAttrs = this.possibleButtonAttrs[subscription];
|
||||
|
||||
const preferences = app.session.user!.preferences()!;
|
||||
const notifyEmail = preferences['notify_newPost_email'];
|
||||
const notifyAlert = preferences['notify_newPost_alert'];
|
||||
const tooltipText = extractText(
|
||||
app.translator.trans(
|
||||
notifyEmail ? 'flarum-subscriptions.forum.sub_controls.notify_email_tooltip' : 'flarum-subscriptions.forum.sub_controls.notify_alert_tooltip'
|
||||
)
|
||||
);
|
||||
|
||||
const shouldShowTooltip = (notifyEmail || notifyAlert) && subscription === null;
|
||||
|
||||
return (
|
||||
<SplitDropdown
|
||||
className="SubscriptionMenu"
|
||||
buttonClassName={`SubscriptionMenu-button--${subscription}`}
|
||||
tooltip={shouldShowTooltip ? tooltipText : null}
|
||||
mainAction={
|
||||
<Button
|
||||
className={'SubscriptionMenu-button'}
|
||||
icon={buttonAttrs.icon}
|
||||
onclick={this.saveSubscription.bind(this, discussion, ['follow', 'ignore'].indexOf(subscription) !== -1 ? null : 'follow')}
|
||||
>
|
||||
{buttonAttrs.label}
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
{this.options.map((attrs) => (
|
||||
<DetailedDropdownItem
|
||||
{...attrs}
|
||||
onclick={this.saveSubscription.bind(this, discussion, attrs.subscription)}
|
||||
active={subscription === attrs.subscription}
|
||||
/>
|
||||
))}
|
||||
</SplitDropdown>
|
||||
);
|
||||
}
|
||||
|
||||
saveSubscription(discussion: Discussion, subscription: string | null): void {
|
||||
discussion.save({ subscription });
|
||||
|
||||
// @ts-ignore
|
||||
this.$('.SubscriptionMenu-button').tooltip('hide');
|
||||
}
|
||||
}
|
@@ -1,17 +0,0 @@
|
||||
import Component from 'flarum/common/Component';
|
||||
import icon from 'flarum/common/helpers/icon';
|
||||
|
||||
export default class SubscriptionMenuItem extends Component {
|
||||
view() {
|
||||
return (
|
||||
<button className="SubscriptionMenuItem hasIcon" onclick={this.attrs.onclick}>
|
||||
{this.attrs.active && icon('fas fa-check', { className: 'Button-icon' })}
|
||||
<span className="SubscriptionMenuItem-label">
|
||||
{icon(this.attrs.icon, { className: 'Button-icon' })}
|
||||
<strong>{this.attrs.label}</strong>
|
||||
<span className="SubscriptionMenuItem-description">{this.attrs.description}</span>
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user