mirror of https://github.com/vizality/vizality
Adding my experimental plugins and fixed some stuff
parent
95994349ea
commit
e73b8c8dac
@ -0,0 +1,28 @@
|
||||
const { Plugin } = require('vizality/entities');
|
||||
const { getModule } = require('vizality/webpack');
|
||||
|
||||
const electron = require('electron').remote;
|
||||
const webContents = electron.getCurrentWebContents();
|
||||
const currentWindow = electron.getCurrentWindow();
|
||||
|
||||
module.exports = class ChannelHistory extends Plugin {
|
||||
startPlugin () {
|
||||
currentWindow.on('app-command', this.listener);
|
||||
}
|
||||
|
||||
async listener (ev, cmd) {
|
||||
if (cmd !== 'browser-backward' && cmd !== 'browser-forward') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd === 'browser-backward' && webContents.canGoBack()) {
|
||||
(await getModule([ 'history' ])).history.back();
|
||||
} else if (cmd === 'browser-forward' && webContents.canGoForward()) {
|
||||
(await getModule([ 'history' ])).history.forward();
|
||||
}
|
||||
}
|
||||
|
||||
pluginWillUnload () {
|
||||
currentWindow.off('app-command', this.listener);
|
||||
}
|
||||
};
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "Channel History",
|
||||
"version": "1.0.0",
|
||||
"description": "Allows you to navigate forwards and backwards with your side mouse buttons, like in the browser.",
|
||||
"author": "Vizality",
|
||||
"license": "GPL-3.0",
|
||||
"color": "#33FFCC"
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/* eslint-disable prefer-destructuring */
|
||||
const { Plugin } = require('vizality/entities');
|
||||
const { React, getModuleByDisplayName } = require('vizality/webpack');
|
||||
const { inject, uninject } = require('vizality/injector');
|
||||
const { Tooltip } = require('vizality/components');
|
||||
|
||||
module.exports = class ChannelMembersActivityIcons extends Plugin {
|
||||
startPlugin () {
|
||||
this.loadStylesheet('style.scss');
|
||||
|
||||
this._injectActivityIcons();
|
||||
}
|
||||
|
||||
async _injectActivityIcons () {
|
||||
const MemberListItem = await getModuleByDisplayName('MemberListItem');
|
||||
inject('channelMembersActivityIcons-members', MemberListItem.prototype, 'render', (_, res) => {
|
||||
if (!res ||
|
||||
!res.props ||
|
||||
!res.props.subText ||
|
||||
!res.props.subText.props ||
|
||||
!res.props.subText.props.activities.length
|
||||
) {
|
||||
return res;
|
||||
}
|
||||
|
||||
for (const activity of res.props.subText.props.activities) {
|
||||
if (activity.application_id &&
|
||||
activity.assets &&
|
||||
activity.assets.small_image
|
||||
) {
|
||||
res.props.children =
|
||||
React.createElement(Tooltip, {
|
||||
text: activity.name,
|
||||
position: 'left'
|
||||
}, React.createElement(
|
||||
'div', {
|
||||
className: 'vizality-members-activity-icon',
|
||||
style: { backgroundImage: `url(https://cdn.discordapp.com/app-assets/${activity.application_id}/${activity.assets.small_image}.png)` }
|
||||
}
|
||||
));
|
||||
|
||||
res.props.className += ' vz-hasActivityIcon';
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
if (activity.type && activity.type === 2) {
|
||||
res.props.children =
|
||||
React.createElement(Tooltip, {
|
||||
text: 'Spotify',
|
||||
position: 'left'
|
||||
}, React.createElement(
|
||||
'div', {
|
||||
className: 'vizality-members-activity-icon',
|
||||
style: { backgroundImage: 'url(\'/assets/f0655521c19c08c4ea4e508044ec7d8c.png\')' }
|
||||
}
|
||||
));
|
||||
|
||||
res.props.className += ' vz-hasActivityIcon';
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
pluginWillUnload () {
|
||||
uninject('channelMembersActivityIcons-members');
|
||||
}
|
||||
};
|
@ -0,0 +1,26 @@
|
||||
.membersWrap-2h-GB4 {
|
||||
.vizality-members-activity-icon {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
border-radius: 4px;
|
||||
margin-left: 5px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
// Remove custom status emoji and rich presence icon
|
||||
.emoji-2cWBLE,
|
||||
.icon-15YQ1T {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.content-3QAtGj {
|
||||
margin-right: 37px; // 8px (left margin) + 24px (icon size) + 5px (left margin)
|
||||
}
|
||||
.vz-hasActivityIcon {
|
||||
.content-3QAtGj {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Channel Members Activity Icons",
|
||||
"version": "0.0.1",
|
||||
"description": "Adds activity icons to the channel members list for users' currently playing activity.",
|
||||
"author": "Baked",
|
||||
"license": "GPL-3.0"
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
const { Plugin } = require('vizality/entities');
|
||||
const { inject, uninject } = require('vizality/injector');
|
||||
const { React, getModule } = require('vizality/webpack');
|
||||
const { classNames } = require('vizality/util');
|
||||
const { Icon } = require('vizality/components');
|
||||
|
||||
module.exports = class UtilityClasses extends Plugin {
|
||||
startPlugin () {
|
||||
this.loadStylesheet('style.scss');
|
||||
|
||||
this._injectContextMenuItems();
|
||||
this._injectContextMenuCheckboxItems();
|
||||
this._injectContextMenuControlItems();
|
||||
}
|
||||
|
||||
async _injectContextMenuItems () {
|
||||
const MenuItem = await getModule(m => m.default && m.default.displayName === 'MenuItem');
|
||||
|
||||
inject('vz-contextMenuIcons', MenuItem, 'default', (originalArgs, returnValue) => {
|
||||
if (!returnValue.props || !returnValue.props.id) return returnValue;
|
||||
|
||||
const { id } = returnValue.props;
|
||||
|
||||
returnValue.props.className = classNames(returnValue.props.className, 'vz-hasIcon');
|
||||
|
||||
const type = [
|
||||
id === 'textarea-context-languages' && 'atom',
|
||||
id === 'textarea-context-copy' && 'atom',
|
||||
id === 'textarea-context-cut' && 'atom',
|
||||
id === 'textarea-context-paste' && 'atom',
|
||||
|
||||
id === 'user-context-user-profile' && 'atom',
|
||||
id === 'user-context-mention' && 'atom',
|
||||
id === 'user-context-message-user' && 'atom',
|
||||
id === 'user-context-call' && 'atom',
|
||||
id === 'user-context-note' && 'atom',
|
||||
id === 'user-context-invite-to-server' && 'atom',
|
||||
id === 'user-context-add-friend' && 'atom',
|
||||
id === 'user-context-remove-friend' && 'atom',
|
||||
id === 'user-context-block' && 'atom',
|
||||
id === 'user-context-roles' && 'atom',
|
||||
id === 'user-context-devmode-copy-id' && 'atom',
|
||||
|
||||
id === 'message-add-reaction' && 'atom',
|
||||
id === 'message-edit' && 'atom',
|
||||
id === 'message-pin' && 'atom',
|
||||
id === 'message-quote' && 'atom',
|
||||
id === 'message-mark-unread' && 'atom',
|
||||
id === 'message-copy-link' && 'atom',
|
||||
id === 'message-copy-native-link' && 'atom',
|
||||
id === 'message-open-native-link' && 'atom',
|
||||
id === 'message-delete' && 'atom',
|
||||
id === 'message-devmode-copy-id' && 'atom'
|
||||
].filter(Boolean).join(' ');
|
||||
|
||||
if (!type) {
|
||||
console.log('Context item not specified yet: ', id);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
const icon = React.createElement(Icon, { type,
|
||||
className: 'vizality-contextMenuIcon' });
|
||||
returnValue.props.children.unshift(icon);
|
||||
|
||||
return returnValue;
|
||||
});
|
||||
}
|
||||
|
||||
async _injectContextMenuCheckboxItems () {
|
||||
const MenuCheckboxItem = await getModule(m => m.default && m.default.displayName === 'MenuCheckboxItem');
|
||||
|
||||
inject('vz-contextMenuCheckboxIcons', MenuCheckboxItem, 'default', (originalArgs, returnValue) => {
|
||||
if (!returnValue.props || !returnValue.props.id) return returnValue;
|
||||
|
||||
const { id } = returnValue.props;
|
||||
|
||||
returnValue.props.className = classNames(returnValue.props.className, 'vz-hasIcon');
|
||||
|
||||
const type = [
|
||||
id === 'textarea-context-spellcheck' && 'atom',
|
||||
|
||||
id === 'user-context-disable-video' && 'atom',
|
||||
id === 'user-context-mute' && 'atom'
|
||||
].filter(Boolean).join(' ');
|
||||
|
||||
if (!type) {
|
||||
console.log('Context checkbox item not specified yet: ', id);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
const icon = React.createElement(Icon, { type,
|
||||
className: 'vizality-contextMenuIcon' });
|
||||
returnValue.props.children.unshift(icon);
|
||||
|
||||
return returnValue;
|
||||
});
|
||||
}
|
||||
|
||||
async _injectContextMenuControlItems () {
|
||||
const MenuControlItem = await getModule(m => m.default && m.default.displayName === 'MenuControlItem');
|
||||
|
||||
inject('vz-contextMenuControlIcons', MenuControlItem, 'default', (originalArgs, returnValue) => {
|
||||
if (!returnValue.props || !returnValue.props.id || !returnValue.props.children || !returnValue.props.children[0].props) return returnValue;
|
||||
|
||||
const { id } = returnValue.props;
|
||||
|
||||
returnValue.props.className = classNames(returnValue.props.className, 'vz-hasIcon');
|
||||
|
||||
const type = [
|
||||
id === 'user-context-user-volume' && 'atom'
|
||||
].filter(Boolean).join(' ');
|
||||
|
||||
if (!type) {
|
||||
console.log('Context checkbox item not specified yet: ', id);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
const icon = React.createElement(Icon, { type,
|
||||
className: 'vizality-contextMenuIcon' });
|
||||
returnValue.props.children.unshift(icon);
|
||||
|
||||
return returnValue;
|
||||
});
|
||||
}
|
||||
|
||||
pluginWillUnload () {
|
||||
uninject('vz-contextMenuIcons');
|
||||
uninject('vz-contextMenuCheckboxIcons');
|
||||
uninject('vz-contextMenuControlIcons');
|
||||
}
|
||||
};
|
@ -0,0 +1,36 @@
|
||||
@use '../../library' as *;
|
||||
|
||||
.menu-3sdvDG {
|
||||
.vizality-icon-container {
|
||||
@include size(18px);
|
||||
display: inline-flex;
|
||||
margin-right: 12px;
|
||||
}
|
||||
.vizality-icon {
|
||||
@include size(100%);
|
||||
}
|
||||
}
|
||||
|
||||
// .menu-3sdvDG {
|
||||
// .label-22pbtT {
|
||||
// order: 1;
|
||||
// }
|
||||
// .iconContainer-2-XQPY {
|
||||
// order: 3;
|
||||
// }
|
||||
// .vizality-icon-container {
|
||||
// order: 2;
|
||||
// }
|
||||
// .imageContainer-2fGqYU {
|
||||
// order: 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
.vizality-contextMenuIcon-guildIcon {
|
||||
@include size(20px);
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
display: inline-flex;
|
||||
border-radius: 50%;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Context Menu Icons",
|
||||
"version": "0.0.1",
|
||||
"description": "Adds utility classes and icons to the left of context menu items.",
|
||||
"author": "Baked",
|
||||
"license": "GPL-3.0"
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
# Copy Raw Message
|
||||
|
||||
Lets you copy messages with its formatting still intact, you should enable
|
||||
Developer Mode in Appearance settings
|
@ -0,0 +1,34 @@
|
||||
const { Plugin } = require('vizality/entities');
|
||||
const { inject, uninject } = require('vizality/injector');
|
||||
const { React, getModule } = require('vizality/webpack');
|
||||
const { Menu } = require('vizality/components');
|
||||
|
||||
module.exports = class CopyRawMessage extends Plugin {
|
||||
startPlugin () {
|
||||
this._patchContextMenu();
|
||||
}
|
||||
|
||||
pluginWillUnload () {
|
||||
uninject('copy-raw-message');
|
||||
}
|
||||
|
||||
async _patchContextMenu () {
|
||||
const MessageContextMenu = await getModule(m => m.default && m.default.displayName === 'MessageContextMenu');
|
||||
|
||||
inject('copy-raw-message', MessageContextMenu, 'default', ([ props ], returnValue) => {
|
||||
const { message } = props;
|
||||
|
||||
if (!message || !message.content) return returnValue;
|
||||
|
||||
returnValue.props.children.push(
|
||||
React.createElement(Menu.MenuItem, {
|
||||
label: 'Copy Raw Message',
|
||||
id: 'copy-raw-message',
|
||||
action: async () => DiscordNative.clipboard.copy(message.content)
|
||||
})
|
||||
);
|
||||
|
||||
return returnValue;
|
||||
});
|
||||
}
|
||||
};
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Copy Raw Message",
|
||||
"description": "Lets you copy messages with its formatting still intact",
|
||||
"version": "1.1.0",
|
||||
"author": ".intrnl#6380",
|
||||
"license": "GPL-3.0"
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/* eslint-disable prefer-destructuring */
|
||||
const { Plugin } = require('vizality/entities');
|
||||
const { React, getModuleByDisplayName, getModule, i18n } = require('vizality/webpack');
|
||||
const { inject, uninject } = require('vizality/injector');
|
||||
const { findInReactTree, forceUpdateElement } = require('vizality/util');
|
||||
|
||||
module.exports = class CustomBanners extends Plugin {
|
||||
startPlugin () {
|
||||
this.loadStylesheet('style.scss');
|
||||
|
||||
this._patchPrivateChannelEmptyMessage();
|
||||
}
|
||||
|
||||
async _patchPrivateChannelEmptyMessage () {
|
||||
const PrivateChannelEmptyMessage = await getModuleByDisplayName('PrivateChannelEmptyMessage');
|
||||
|
||||
inject('pc-impChannelTitlebar-privateChannelsEmptyMessage', PrivateChannelEmptyMessage.prototype, 'render', (_, res) => {
|
||||
console.log(res);
|
||||
|
||||
return res;
|
||||
});
|
||||
|
||||
return async () => uninject('pc-impChannelTitlebar-privateChannelsEmptyMessage');
|
||||
}
|
||||
};
|
@ -0,0 +1,27 @@
|
||||
|
||||
@use '../../library' as *;
|
||||
|
||||
.container-Vw8GSP {
|
||||
padding: 30px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-flow: column;
|
||||
margin-bottom: 50px;
|
||||
position: relative;
|
||||
* {
|
||||
z-index: 1;
|
||||
}
|
||||
.wrapper-3t9DeA {
|
||||
border: 3px solid var(--header-primary);
|
||||
}
|
||||
&::after {
|
||||
@include size(100%);
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: linear-gradient(to top, var(--background-primary), transparent);
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Custom Banners",
|
||||
"version": "0.0.1",
|
||||
"description": "Adds Vizality's custom user profile banners and custom server banners to various parts of Discord.",
|
||||
"author": "Baked",
|
||||
"license": "GPL-3.0"
|
||||
}
|
@ -0,0 +1,209 @@
|
||||
/* eslint-disable prefer-destructuring */
|
||||
const { Plugin } = require('vizality/entities');
|
||||
const { React, getModuleByDisplayName, getModule, i18n } = require('vizality/webpack');
|
||||
const { inject, uninject } = require('vizality/injector');
|
||||
const { findInReactTree } = require('vizality/util');
|
||||
|
||||
module.exports = class ChannelTitlebar extends Plugin {
|
||||
constructor () {
|
||||
super();
|
||||
|
||||
this.guildHeader = null;
|
||||
this.activityPre = null;
|
||||
this.activity = null;
|
||||
this.activitySong = null;
|
||||
this.activityArtist = null;
|
||||
}
|
||||
|
||||
startPlugin () {
|
||||
this.loadStylesheet('style.scss');
|
||||
|
||||
this._getGuildChannelHeader();
|
||||
this.improvedChannelHeader();
|
||||
}
|
||||
|
||||
async _getGuildChannelHeader () {
|
||||
const GuildHeader = await getModuleByDisplayName('GuildHeader');
|
||||
|
||||
inject('pc-impChannelTitlebar-guildChannelHeader', GuildHeader.prototype, 'renderHeader', (_, res) => {
|
||||
this.guildHeader = res;
|
||||
|
||||
return res;
|
||||
});
|
||||
|
||||
return async () => uninject('pc-impChannelTitlebar-guildChannelHeader');
|
||||
}
|
||||
|
||||
async improvedChannelHeader () {
|
||||
const ChannelHeader = await getModuleByDisplayName('HeaderBarContainer');
|
||||
|
||||
inject('pc-impChannelTitlebar-channelHeader', ChannelHeader.prototype, 'render', (_, res) => {
|
||||
const found = findInReactTree(res, n => n.channel);
|
||||
|
||||
if (!found) {
|
||||
return res;
|
||||
}
|
||||
|
||||
let icon,
|
||||
iconId,
|
||||
iconType,
|
||||
noIconURL,
|
||||
activity,
|
||||
userActivity;
|
||||
|
||||
// @TODO: Fix this to check for status updates every 7 seconds or something
|
||||
|
||||
// Guild channel
|
||||
if (found.channel.type === 0) {
|
||||
iconId = found.guild.id;
|
||||
icon = found.guild.icon;
|
||||
iconType = 'icons';
|
||||
noIconURL = 'https://i.imgur.com/Fa13xn9.png';
|
||||
// User DM channel
|
||||
} else if (found.channel.type === 1) {
|
||||
iconId = found.channel.rawRecipients[0].id;
|
||||
icon = found.channel.rawRecipients[0].avatar;
|
||||
iconType = 'avatars';
|
||||
noIconURL = document.querySelector('.channel-2QD9_O.selected-aXhQR6 .avatar-VxgULZ') ? document.querySelector('.channel-2QD9_O.selected-aXhQR6 .avatar-VxgULZ').src : '';
|
||||
|
||||
activity = (getModule([ 'getPrimaryActivity' ], false)).getPrimaryActivity(iconId);
|
||||
|
||||
if (activity) {
|
||||
if (activity.type === 0) {
|
||||
this.activityPre = 'Playing';
|
||||
this.activity = activity.name;
|
||||
} else if (activity.type === 1) {
|
||||
this.activityPre = 'Streaming';
|
||||
this.activity = activity.details;
|
||||
} else if (activity.type === 2) {
|
||||
this.activityPre = i18n._proxyContext.messages.ACTIVITY_FEED_NOW_PLAYING_SPOTIFY.split(' ');
|
||||
this.activityPre.pop();
|
||||
this.activityPre = this.activityPre.join(' ');
|
||||
this.activitySong = activity.details;
|
||||
this.activityArtist = activity.state;
|
||||
} else if (activity.type === 3) {
|
||||
this.activityPre = 'Watching';
|
||||
this.activity = activity.name;
|
||||
} else if (activity.type === 4 && activity.state) {
|
||||
this.activityPre = null;
|
||||
this.activity = activity.state;
|
||||
} else {
|
||||
this.activityPre = null;
|
||||
this.activitySong = null;
|
||||
this.activityArtist = null;
|
||||
this.activity = null;
|
||||
}
|
||||
}
|
||||
// Group DM channel
|
||||
} else if (found.channel.type === 3) {
|
||||
iconId = found.channel.id;
|
||||
icon = found.channel.icon;
|
||||
iconType = 'channel-icons';
|
||||
noIconURL = document.querySelector('.channel-2QD9_O.selected-aXhQR6 .avatar-VxgULZ') ? document.querySelector('.channel-2QD9_O.selected-aXhQR6 .avatar-VxgULZ').src : '';
|
||||
}
|
||||
|
||||
const iconURL = icon
|
||||
? `url('https://cdn.discordapp.com/${iconType}/${iconId}/${icon}.png')`
|
||||
: `url(${noIconURL})`;
|
||||
|
||||
if (found.channel.type === 1 && activity) {
|
||||
if (activity.type === 2) {
|
||||
userActivity =
|
||||
React.createElement(
|
||||
'div', {
|
||||
className: 'vz-channel-sub-navigation-user-activity'
|
||||
},
|
||||
/*
|
||||
* React.createElement(
|
||||
* 'span', {
|
||||
* className: 'vz-channel-sub-navigation-user-activity-icon',
|
||||
* style: { backgroundImage: 'url(\'/assets/f0655521c19c08c4ea4e508044ec7d8c.png\')' }
|
||||
* }
|
||||
* ),
|
||||
*/
|
||||
React.createElement(
|
||||
'span', {
|
||||
className: 'vz-channel-sub-navigation-user-activity-pretext',
|
||||
children: this.activityPre
|
||||
}
|
||||
),
|
||||
React.createElement(
|
||||
'span', {
|
||||
className: 'vz-channel-sub-navigation-user-activity-song',
|
||||
children: this.activitySong
|
||||
}
|
||||
),
|
||||
React.createElement(
|
||||
'span', {
|
||||
className: 'vz-channel-sub-navigation-user-activity-by',
|
||||
children: 'by'
|
||||
}
|
||||
),
|
||||
React.createElement(
|
||||
'span', {
|
||||
className: 'vz-channel-sub-navigation-user-activity-artist',
|
||||
children: this.activityArtist
|
||||
}
|
||||
)
|
||||
);
|
||||
} else {
|
||||
userActivity =
|
||||
React.createElement(
|
||||
'div', {
|
||||
className: 'vz-channel-sub-navigation-user-activity'
|
||||
},
|
||||
/*
|
||||
* activity.type === 0 && activity.application_id && activity.assets && activity.assets.small_image
|
||||
* ? React.createElement(
|
||||
* 'span', {
|
||||
* className: 'vz-channel-sub-navigation-user-activity-icon',
|
||||
* style: { backgroundImage: `url('https://cdn.discordapp.com/app-assets/${activity.application_id}/${activity.assets.small_image}.png')` }
|
||||
* }
|
||||
* )
|
||||
* : '',
|
||||
*/
|
||||
this.activityPre
|
||||
? React.createElement(
|
||||
'span', {
|
||||
className: 'vz-channel-sub-navigation-user-activity-pretext',
|
||||
children: this.activityPre
|
||||
}
|
||||
)
|
||||
: '',
|
||||
React.createElement(
|
||||
'span', {
|
||||
className: 'vz-channel-sub-navigation-user-activity-text',
|
||||
children: this.activity
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const children = [
|
||||
React.createElement(
|
||||
'div', {
|
||||
className: 'vz-channel-sub-navigation-icon',
|
||||
style: {
|
||||
backgroundImage: iconURL
|
||||
}
|
||||
}
|
||||
),
|
||||
React.createElement(
|
||||
'div', {
|
||||
className: 'vz-channel-sub-navigation'
|
||||
},
|
||||
found.channel.type === 0 ? this.guildHeader : '',
|
||||
res.props.children,
|
||||
userActivity ? userActivity : ''
|
||||
)
|
||||
];
|
||||
|
||||
res.props.children = children;
|
||||
|
||||
return res;
|
||||
});
|
||||
|
||||
return async () => uninject('pc-impChannelTitlebar-channelHeader');
|
||||
}
|
||||
};
|
@ -0,0 +1,127 @@
|
||||
.title-3qD0b- {
|
||||
padding: 0 10px;
|
||||
height: 64px;
|
||||
.vz-channel-sub-navigation {
|
||||
position: relative;
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
flex-flow: row wrap;
|
||||
.iconWrapper-2OrFZ1,
|
||||
.icon-22AiRD,
|
||||
.divider-3FBTu8,
|
||||
.akaBadge-1M-1Gw,
|
||||
.nicknames-1XK4Zt {
|
||||
display: none;
|
||||
}
|
||||
.topic-TCb_qw {
|
||||
margin: 0;
|
||||
flex: 1 0 100%;
|
||||
}
|
||||
.status-1XNdyw {
|
||||
margin: 0;
|
||||
}
|
||||
.title-29uC1r {
|
||||
flex: none;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
@at-root [vz-route='guild'] & {
|
||||
flex: 1 0;
|
||||
opacity: .9;
|
||||
font-size: 14px;
|
||||
&::before {
|
||||
content: '#';
|
||||
margin-right: 1px;
|
||||
}
|
||||
}
|
||||
@at-root [vz-route='dm'] & {
|
||||
&::before {
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.spacer-3kEb8l {
|
||||
display: none;
|
||||
}
|
||||
.header-2o-2hj {
|
||||
height: auto;
|
||||
padding: 0;
|
||||
margin-right: 8px;
|
||||
box-shadow: none;
|
||||
}
|
||||
.guildIconContainer-E1JUVt {
|
||||
cursor: pointer;
|
||||
}
|
||||
.name-3YKhmS {
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
}
|
||||
.button-1w5pas {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vz-channel-sub-navigation-user-activity {
|
||||
flex: 1 0 100%;
|
||||
font-size: 14px;
|
||||
color: var(--interactive-normal);
|
||||
line-height: 1.4;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
> span {
|
||||
+ span {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.vz-channel-sub-navigation-user-activity-icon {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: contain;
|
||||
border-radius: 50%;
|
||||
flex: 0 0 auto;
|
||||
margin-right: 2px;
|
||||
display: none;
|
||||
}
|
||||
.vz-channel-sub-navigation-user-activity-song,
|
||||
.vz-channel-sub-navigation-user-activity-artist {
|
||||
color: var(--interactive-hover);
|
||||
font-weight: 700;
|
||||
}
|
||||
.vz-channel-sub-navigation-user-activity-pretext {
|
||||
+ .vz-channel-sub-navigation-user-activity-text {
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
}
|
||||
.vz-channel-sub-navigation-icon {
|
||||
height: 46px;
|
||||
width: 46px;
|
||||
margin-right: 12px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: contain;
|
||||
border-radius: 50%;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
.container-2Rl01u {
|
||||
.header-2o-2hj {
|
||||
display: none;
|
||||
}
|
||||
&.hasBanner-14PPlG {
|
||||
~ .scrollerWrap-2lJEkd {
|
||||
> .scroller-2FKFPG {
|
||||
> div {
|
||||
padding-top: 48px
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Improved Channel Titlebar",
|
||||
"version": "0.0.1",
|
||||
"description": "Addsa a sa",
|
||||
"author": "Baked",
|
||||
"license": "GPL-3.0"
|
||||
}
|
@ -0,0 +1 @@
|
||||
**I like pie**
|
@ -0,0 +1,69 @@
|
||||
const { React, getModuleByDisplayName, getModule } = require('vizality/webpack');
|
||||
const { forceUpdateElement } = require('vizality/util');
|
||||
const navigate = require('vizality/navigate');
|
||||
const { AsyncComponent, Icon, Button, Tooltip, Clickable } = require('vizality/components');
|
||||
|
||||
const AccountPanel = AsyncComponent.from(getModuleByDisplayName('AccountConnected'));
|
||||
|
||||
module.exports = class MainNav extends React.Component {
|
||||
render () {
|
||||
return (
|
||||
<nav className='vizality-main-nav'>
|
||||
<div className='vizality-main-nav__section-left'>
|
||||
<div className='vizality-main-nav__logo'></div>
|
||||
<div className='vizality-main-nav__link' onClick={() => navigate.to('dm')}>
|
||||
<Icon wrapperClassName='vizality-main-nav__link-icon-wrapper' type='mail'></Icon>
|
||||
<p className='vizality-main-nav__link-text'>Messages</p>
|
||||
</div>
|
||||
<div className='vizality-main-nav__link' onClick={() => navigate.to('discover')}>
|
||||
<Icon wrapperClassName='vizality-main-nav__link-icon-wrapper' type='discover'></Icon>
|
||||
<p className='vizality-main-nav__link-text'>Discover</p>
|
||||
</div>
|
||||
<div className='vizality-main-nav__link' onClick={() => navigate.to('friends')}>
|
||||
<Icon wrapperClassName='vizality-main-nav__link-icon-wrapper' type='users'></Icon>
|
||||
<p className='vizality-main-nav__link-text'>Friends</p>
|
||||
</div>
|
||||
<div className='vizality-main-nav__link' onClick={() => navigate.to('library')}>
|
||||
<Icon wrapperClassName='vizality-main-nav__link-icon-wrapper' type='backpack'></Icon>
|
||||
<p className='vizality-main-nav__link-text'>Library</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='vizality-main-nav__section-middle'>
|
||||
<div className='vizality-main-nav__search'>
|
||||
<div className='vizality-main-nav__search-inner'>
|
||||
<input className='vizality-main-nav__search-input' type='text' placeholder='Search' />
|
||||
<Icon wrapperClassName='vizality-main-nav__search-icon-wrapper' type='search'></Icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='vizality-main-nav__section-right'>
|
||||
<div className='vizality-main-nav__inbox' onClick={async () => (await getModule([ 'TOGGLE_INBOX' ])).TOGGLE_INBOX.action()}>
|
||||
<Icon wrapperClassName='vizality-main-nav__inbox-icon-wrapper' type='notification-bell'></Icon>
|
||||
</div>
|
||||
<div className='vizality-main-nav__account-panel'>
|
||||
<div className='vizality-main-nav__account-panel-inner'>
|
||||
<AccountPanel />
|
||||
{/* <div className='vizality-main-navigation-account-avatar-container'>
|
||||
<div className='vizality-main-navigation-account-avatar image-33JSyf' style={{ backgroundImage: `url(${this.userAvatarURL})` }}></div>
|
||||
</div>
|
||||
<div className='vizality-main-navigation-account-details-outer'>
|
||||
<div className='vizality-main-navigation-account-details-inner'>
|
||||
<div className='vizality-main-navigation-account-username-container'>
|
||||
<span className='vizality-main-navigation-account-username'>{this.username}</span>
|
||||
</div>
|
||||
<div class='vizality-main-navigation-account-status-container'>
|
||||
<div className={`${this.userStatus} vizality-main-navigation-account-status-indicator`}></div>
|
||||
<div className='vizality-main-navigation-account-activity-container'>
|
||||
<span className='vizality-main-navigation-account-activity'>{this.activity ? this.activityTypeText + this.activity.name : ''}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<icon className='tc-icon vizality-main-navigation-account-arrow'></icon>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
};
|
@ -0,0 +1,16 @@
|
||||
const { React, getModule, getModuleByDisplayName } = require('vizality/webpack');
|
||||
const { sleep } = require('vizality/util');
|
||||
const { TextInput, SwitchItem, Category, RadioGroup, SelectInput, CopyInput, TextArea, RegionSelector, SliderInput, PermissionOverrideItem } = require('vizality/components/settings');
|
||||
|
||||
class Settings extends React.Component {
|
||||
render () {
|
||||
const { getSetting, updateSetting, toggleSetting } = this.props;
|
||||
return (
|
||||
<div className='navigation-everywhere'>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Settings;
|
@ -0,0 +1,49 @@
|
||||
const { Plugin } = require('vizality/entities');
|
||||
const { inject, uninject } = require('vizality/injector');
|
||||
const { React, getModule, getModuleByDisplayName } = require('vizality/webpack');
|
||||
const { forceUpdateElement } = require('vizality/util');
|
||||
|
||||
const Settings = require('./components/Settings');
|
||||
const MainNav = require('./components/MainNav');
|
||||
|
||||
module.exports = class MainNavigation extends Plugin {
|
||||
startPlugin () {
|
||||
vizality.api.settings.registerSettings('improved-navigation', {
|
||||
category: 'improved-navigation',
|
||||
label: 'improved-navigation',
|
||||
render: Settings
|
||||
});
|
||||
|
||||
this.loadStylesheet('scss/style.scss');
|
||||
|
||||
this._injectMainNav(
|
||||
this.settings.get('position', 'top'),
|
||||
this.settings.get('link-style', 'text')
|
||||
);
|
||||
}
|
||||
|
||||
async _injectMainNav (position = 'top', linkStyle = 'text') {
|
||||
document.documentElement.setAttribute('vz-main-nav-enabled', '');
|
||||
document.documentElement.setAttribute('vz-main-nav-position', this.settings.get('position', 'top'));
|
||||
document.documentElement.setAttribute('vz-main-nav-link-style', this.settings.get('link-style', 'text'));
|
||||
|
||||
const { app } = await getModule([ 'app', 'layers' ]);
|
||||
|
||||
const Shakeable = await getModuleByDisplayName('Shakeable');
|
||||
const navBar = React.createElement(MainNav, { position, linkStyle });
|
||||
|
||||
inject('vz-mainNav', Shakeable.prototype, 'render', (originalArgs, returnValue) => [ navBar, returnValue ]);
|
||||
|
||||
setImmediate(() => forceUpdateElement(`.${app}`));
|
||||
}
|
||||
|
||||
pluginWillUnload () {
|
||||
const el = document.querySelector('.vizality-main-nav');
|
||||
|
||||
if (el) {
|
||||
el.remove();
|
||||
}
|
||||
|
||||
uninject('vz-mainNav');
|
||||
}
|
||||
};
|
@ -0,0 +1,38 @@
|
||||
@use '../../../../library/classes/layout/chat' as Chat;
|
||||
@use '../../../../library/classes/layout/chat' as chat;
|
||||
@use '../../../../library' as *;
|
||||
@use '../../../../library/classes';
|
||||
@use '../../../../library/classes' as class;
|
||||
|
||||
@use '../../../../library/icons' as * with (
|
||||
$announcement: '<svg fill="#fff" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2C6.477 2 2 6.477 2 12C2 17.522 6.477 22 12 22C17.523 22 22 17.522 22 12C22 6.477 17.523 2 12 2ZM8 6C9.104 6 10 6.896 10 8C10 9.105 9.104 10 8 10C6.896 10 6 9.105 6 8C6 6.896 6.896 6 8 6ZM18 14C18 16.617 15.14 19 12 19C8.86 19 6 16.617 6 14V13H18V14ZM16 10C14.896 10 14 9.105 14 8C14 6.896 14.896 6 16 6C17.104 6 18 6.896 18 8C18 9.105 17.104 10 16 10Z" /></svg>'
|
||||
);
|
||||
|
||||
// :root {
|
||||
// --vz-icon-search: #{svg-uri('<svg fill="#fff" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 1C19.552 1 20 1.447 20 2V3L23 2V6L20 5V6C20 6.553 19.552 7 19 7H15C14.448 7 14 6.553 14 6V2C14 1.447 14.448 1 15 1H19Z" /><path d="M20 13.5V9H22V15.5C22 16.604 21.103 17.5 20 17.5H13V19.5H17V21.5H7V19.5H11V17.5H4C2.897 17.5 2 16.604 2 15.5V4.5C2 3.397 2.897 2.5 4 2.5H12V4.5H4V13.5H20Z" /></svg>')};
|
||||
// }
|
||||
|
||||
// @use '../../../../library' as *;
|
||||
#{class('layout.chat.name')} {
|
||||
color: orange!important;
|
||||
}
|
||||
|
||||
// @use '../../../../library/classes/layout/chat' as Chat;
|
||||
#{Chat.$name} {
|
||||
color: red!important;
|
||||
}
|
||||
|
||||
// @use '../../../../library/classes';
|
||||
#{$layout-chat-name} {
|
||||
color: teal!important;
|
||||
}
|
||||
|
||||
// @use '../../../../library/classes' as classes;
|
||||
#{class.$layout-chat-name} {
|
||||
color: white!important;
|
||||
}
|
||||
|
||||
// @use '../../../../library/classes/layout/chat' as chat;
|
||||
#{chat.$name} {
|
||||
color: yellow!important;
|
||||
}
|
@ -0,0 +1,313 @@
|
||||
@use '../../../library' as *;
|
||||
|
||||
// @use 'examples';
|
||||
|
||||
$module: (
|
||||
'vz-main-nav': (
|
||||
background: var('background-floating'),
|
||||
width: 100%,
|
||||
height: 50px,
|
||||
box-shadow: var('elevation-medium'),
|
||||
border-radius: 0,
|
||||
border-color: transparent,
|
||||
border-style: none,
|
||||
border-width: 0,
|
||||
'logo': (
|
||||
icon: var('vz-logo-discord'),
|
||||
color: #fff,
|
||||
'hover': (
|
||||
color: var('vz-main-nav-logo-icon-color'),
|
||||
animation: 'vz-main-nav-logo-hover .2s forwards'
|
||||
),
|
||||
'active': (
|
||||
color: var('vz-main-nav-logo-icon-color'),
|
||||
animation: 'vz-main-nav-logo-active .1s forwards'
|
||||
)
|
||||
),
|
||||
'icon': (
|
||||
color: var('text-normal'),
|
||||
'hover': (
|
||||
color: var('vz-main-nav-link-hover-color')
|
||||
)
|
||||
),
|
||||
'link': (
|
||||
color: var('text-normal'),
|
||||
margin: 0,
|
||||
padding: 0 15px,
|
||||
font-size: 12px,
|
||||
font-weight: 700,
|
||||
text-transform: uppercase,
|
||||
'hover': (
|
||||
color: #fff,
|
||||
),
|
||||
'active': (
|
||||
color: var('vz-main-nav-link-hover-color'),
|
||||
)
|
||||
),
|
||||
'search': (
|
||||
background: var('background-tertiary'),
|
||||
color: var('text-normal'),
|
||||
box-shadow: var('elevation-medium'),
|
||||
border-radius: 4px,
|
||||
border-color: transparent,
|
||||
border-style: none,
|
||||
border-width: 0,
|
||||
'placeholder': (
|
||||
color: var('text-muted')
|
||||
),
|
||||
'focus': (
|
||||
background: var('vz-main-nav-search-background'),
|
||||
color: var('vz-main-nav-search-color'),
|
||||
box-shadow: var('vz-main-nav-search-box-shadow'),
|
||||
border-radius: var('vz-main-nav-search-border-radius'),
|
||||
border-color: var('vz-main-nav-search-border-color'),
|
||||
border-style: var('vz-main-nav-search-border-style'),
|
||||
border-width: var('vz-main-nav-search-border-width'),
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Generating CSS variables from map . . .
|
||||
:root { @include generate-css-vars($module); }
|
||||
|
||||
:root {
|
||||
--vz-main-nav-user-avatar-border-radius: #{var('vz-user-border-radius')};
|
||||
}
|
||||
|
||||
// Vizality main navigation bar
|
||||
.vizality-main-nav {
|
||||
@include size(var('vz-main-nav-width'), var('vz-main-nav-height'));
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
flex-wrap: nowrap;
|
||||
// flex: 0 0 var'vz-main-nav-height');
|
||||
background: var('vz-main-nav-background');
|
||||
border-radius: var('vz-main-nav-border-radius');
|
||||
border-width: var('vz-main-nav-border-width');
|
||||
border-style: var('vz-main-nav-border-style');
|
||||
border-color:var('vz-main-nav-border-color');
|
||||
box-shadow:var('vz-main-nav-box-shadow');
|
||||
z-index: 999;
|
||||
&__section-left {
|
||||
display: flex;
|
||||
flex: 1 1;
|
||||
flex-flow: row nowrap;
|
||||
align-items: stretch;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
}
|
||||
&__logo {
|
||||
@include size(70px, var('vz-main-nav-height'));
|
||||
@include mask(var('vz-main-nav-logo-icon'), var('vz-main-nav-logo-color'), $size: 50%);
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
z-index: 99;
|
||||
&:hover {
|
||||
animation: var('vz-main-nav-logo-hover-animation');
|
||||
}
|
||||
&:active {
|
||||
animation: var('vz-main-nav-logo-active-animation');
|
||||
}
|
||||
}
|
||||
&__link {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 18px;
|
||||
height: 100%;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
&.disabled {
|
||||
opacity: .5;
|
||||
pointer-events: none !important;
|
||||
}
|
||||
&.active {
|
||||
|
||||
}
|
||||
&:hover {
|
||||
|
||||
}
|
||||
&-text {
|
||||
margin: var('vz-main-nav-link-margin');
|
||||
padding: var('vz-main-nav-link-padding');
|
||||
font-size: var('vz-main-nav-link-font-size');
|
||||
font-weight: var('vz-main-nav-link-font-weight');
|
||||
color: var('vz-main-nav-link-color');
|
||||
text-transform: var('vz-main-nav-link-text-transform');
|
||||
line-height: 1.5;
|
||||
white-space: nowrap;
|
||||
transition: color .3s;
|
||||
}
|
||||
&-icon-wrapper {
|
||||
@include size(37px, 50px);
|
||||
display: none;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
&__section-middle {
|
||||
display: flex;
|
||||
flex: 1 1;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
&__search {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-basis: 400px;
|
||||
margin: 0 20px;
|
||||
&-inner {
|
||||
display: flex;
|
||||
flex-basis: 100%;
|
||||
}
|
||||
&-input {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
padding: 5px 30px 5px 10px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
color: var(--text-normal);
|
||||
border: none;
|
||||
background-color: var(--background-tertiary);
|
||||
background-clip: padding-box;
|
||||
border-radius: 4px;
|
||||
outline: 0;
|
||||
&::-webkit-input-placeholder {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
}
|
||||
&-icon-wrapper {
|
||||
@include size(24px);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
&__section-right {
|
||||
display: flex;
|
||||
flex: 1 1;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
}
|
||||
&__inbox {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
min-width: 30px;
|
||||
height: 100%;
|
||||
margin-right: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
&__account-panel {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: none;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 240px;
|
||||
cursor: pointer;
|
||||
&-panel-inner {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1 1 0%;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes vz-main-nav-logo-hover {
|
||||
0% {
|
||||
transform: scale(-1, 1);
|
||||
animation-timing-function: cubic-bezier(.34, 0, .2, 1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(-1.09, 1.09);
|
||||
animation-timing-function: cubic-bezier(.67, 0, .71, 1);
|
||||
}
|
||||
100% {
|
||||
transform: scale(-1.08, 1.08);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes vz-main-nav-logo-active {
|
||||
0% {
|
||||
transform: scale(1.08, 1.08);
|
||||
animation-timing-function: cubic-bezier(.17, .11, .6, .83);
|
||||
}
|
||||
|
||||
33% {
|
||||
transform: scale(.87, .87);
|
||||
animation-timing-function: cubic-bezier(.04, .25, .61, 1.01);
|
||||
}
|
||||
100% {
|
||||
transform: scale(.85, .85);
|
||||
}
|
||||
}
|
||||
|
||||
// Guilds container
|
||||
.guilds-1SWlCJ {
|
||||
// Guild create/join button
|
||||
.tutorialContainer-SGrQ1h {
|
||||
// Guild discovery button
|
||||
+ .listItem-2P_4kh {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
// Guild home button
|
||||
.tutorialContainer-1v44GL {
|
||||
display: none;
|
||||
}
|
||||
.listItem-2P_4kh {
|
||||
// Guild separator
|
||||
&.vz-isGuildSeparator {
|
||||
display: none;
|
||||
// Guild separator when unread DMs are present
|
||||
@at-root div:not(.tutorialContainer-1v44GL) + & {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
.scroller-2FKFPG {
|
||||
padding-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.container-3baos1 {
|
||||
@include size(100%);
|
||||
margin: 0;
|
||||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
@at-root .sidebar-2K8pFh & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
[vz-main-nav-position='top'] {
|
||||
.sidebar-2K8pFh {
|
||||
border-radius: 0!important;
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Navigation Everywhere",
|
||||
"version": "0.0.1",
|
||||
"description": "Adds account panel and navigation bar to the top, right, bottom, or left of the screen. Optionally, include the navigation and account panel within the servers list instead.",
|
||||
"author": "Baked",
|
||||
"license": "GPL-3.0"
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
const { Plugin } = require('vizality/entities');
|
||||
const { getModule, React, i18n: { Messages } } = require('vizality/webpack');
|
||||
const { inject, uninject } = require('vizality/injector');
|
||||
|
||||
const PersonPlay = getModule(m => m.id && m.keys().includes('./Activity'), false)('./PersonPlay').default;
|
||||
|
||||
module.exports = class GameActivityToggle extends Plugin {
|
||||
async startPlugin () {
|
||||
const classes = await getModule([ 'status', 'description' ]);
|
||||
const settings = await getModule([ 'updateRemoteSettings' ]);
|
||||
|
||||
let { showCurrentGame } = await getModule([ 'showCurrentGame' ]);
|
||||
|
||||
const Menu = await getModule(m => m.default && m.default.displayName === 'Menu');
|
||||
inject('game-activity-toggle', Menu, 'default', (originalArgs) => {
|
||||
if (originalArgs[0].navId !== 'status-picker') {
|
||||
return originalArgs;
|
||||
}
|
||||
|
||||
const [ { children } ] = originalArgs;
|
||||
|
||||
const onlineStatus = children.find(c => c.props.id === 'online');
|
||||
|
||||
// Remove the divider after 'Online' because why is there one there anyway, Discord?
|
||||
if (!Object.keys(children[children.indexOf(onlineStatus) + 1].props).length) {
|
||||
children.splice(children.indexOf(onlineStatus) + 1, 1);
|
||||
}
|
||||
|
||||
const invisibleStatus = children.find(c => c.props.id === 'invisible');
|
||||
|
||||
if (!children.find(c => c.props.id === 'game-activity')) {
|
||||
children.splice(children.indexOf(invisibleStatus) + 1, 0, React.createElement(Menu.MenuItem, {
|
||||
id: 'game-activity',
|
||||
keepItemStyles: true,
|
||||
action: () => {
|
||||
showCurrentGame = !showCurrentGame;
|
||||
return settings.updateRemoteSettings({ showCurrentGame });
|
||||
},
|
||||
render: () => React.createElement('div', {
|
||||
className: classes.statusItem,
|
||||
'aria-label': `${!showCurrentGame ? 'Show' : 'Hide'} Game Activity`
|
||||
}, React.createElement(PersonPlay), React.createElement('div', {
|
||||
className: classes.status
|
||||
}, `${!showCurrentGame ? 'Show' : 'Hide'} Game Activity`), React.createElement('div', {
|
||||
className: classes.description
|
||||
}, Messages.SHOW_CURRENT_GAME))
|
||||
}));
|
||||
}
|
||||
|
||||
return originalArgs;
|
||||
}, true);
|
||||
}
|
||||
|
||||
pluginWillUnload () {
|
||||
uninject('game-activity-toggle');
|
||||
}
|
||||
};
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Improved Status Picker",
|
||||
"version": "0.0.1",
|
||||
"description": "Adds extra functionality to the status picker popout.",
|
||||
"author": "Baked",
|
||||
"license": "GPL-3.0"
|
||||
}
|
@ -0,0 +1 @@
|
||||
**I like pie**
|
@ -0,0 +1,345 @@
|
||||
const { React, getModule, getModuleByDisplayName } = require('vizality/webpack');
|
||||
const { sleep, forceUpdateElement } = require('vizality/util');
|
||||
const { TextInput, SwitchItem, Category, RadioGroup, SelectInput, ColorPicker, CopyInput, TextArea, RegionSelector, SliderInput, PermissionOverrideItem } = require('vizality/components/settings');
|
||||
const { clipboard } = require('electron');
|
||||
|
||||
let classes = {
|
||||
initialized: false,
|
||||
flexClassName: '',
|
||||
classModule: {},
|
||||
classDivider: '',
|
||||
classDividerDef: '',
|
||||
formModule: {}
|
||||
};
|
||||
|
||||
module.exports = class Settings extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
copyInput: {
|
||||
mode: getModule(m => m.default && m.default.Modes, false).default.Modes.DEFAULT,
|
||||
text: 'Copy'
|
||||
},
|
||||
classes
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-empty-function
|
||||
async componentDidMount () {
|
||||
if (classes.initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Flex = await getModuleByDisplayName('Flex');
|
||||
classes = {
|
||||
initialized: true,
|
||||
|
||||
flexClassName: `${Flex.Direction.HORIZONTAL} ${Flex.Justify.START} ${Flex.Align.STRETCH} ${Flex.Wrap.NO_WRAP}`
|
||||
};
|
||||
|
||||
this.setState({ classes });
|
||||
}
|
||||
|
||||
render () {
|
||||
const { getSetting, updateSetting, toggleSetting } = this.props;
|
||||
return (
|
||||
<div className='advanced-titlebar'>
|
||||
<Category
|
||||
name={'Titlebar Header'}
|
||||
description={'Some options for displaying text in the top left of the titlebar.'}
|
||||
opened={getSetting('header', false)}
|
||||
onChange={() => toggleSetting('header')}
|
||||
>
|
||||
<SwitchItem
|
||||
note='Show the titlebar header text in the upper left corner.'
|
||||
value={getSetting('showHeader', true)}
|
||||
onChange={() => {
|
||||
toggleSetting('showHeader');
|
||||
setImmediate(() => forceUpdateElement('.vizality-titlebar'));
|
||||
}}
|
||||
>
|
||||
Show titlebar header text
|
||||
</SwitchItem>
|
||||
|
||||
<TextInput
|
||||
note='Change the titlebar header text.'
|
||||
defaultValue={getSetting('headerText', 'Discord')}
|
||||
required={false}
|
||||
disabled={!getSetting('showHeader', true)}
|
||||
onChange={val => {
|
||||
updateSetting('headerText', val);
|
||||
setImmediate(() => forceUpdateElement('.vizality-titlebar'));
|
||||
}}
|
||||
>
|
||||
Titlebar header text
|
||||
</TextInput>
|
||||
|
||||
{/* @TODO: Implement this
|
||||
<SwitchItem
|
||||
note='Choose a font for the titlebar header text.'
|
||||
value={getSetting('headerFont', true)}
|
||||
onChange={() => toggleSetting('headerFont')}
|
||||
>
|
||||
Titlebar header text font
|
||||
</SwitchItem> */}
|
||||
</Category>
|
||||
|
||||
<RadioGroup
|
||||
required={false}
|
||||
onChange={val => {
|
||||
updateSetting('type', val.value);
|
||||
}}
|
||||
value={getSetting('type', 'windows')}
|
||||
options={[
|
||||
{
|
||||
name: 'Windows',
|
||||
value: 'windows'
|
||||
},
|
||||
{
|
||||
name: 'Mac',
|
||||
value: 'mac'
|
||||
},
|
||||
{
|
||||
name: 'None',
|
||||
value: 'none',
|
||||
desc: 'Forcefully remove the titlebar.'
|
||||
}
|
||||
]}
|
||||
>
|
||||
Titlebar Style
|
||||
</RadioGroup>
|
||||
|
||||
<SwitchItem
|
||||
note='Shows forward, back, and refresh buttons in the top left.'
|
||||
value={getSetting('showExtras', false)}
|
||||
onChange={() => {
|
||||
toggleSetting('showExtras');
|
||||
setImmediate(() => forceUpdateElement('.vizality-titlebar'));
|
||||
}}
|
||||
>
|
||||
Extra buttons
|
||||
</SwitchItem>
|
||||
|
||||
<SelectInput
|
||||
note={'This is a select input.'}
|
||||
value={getSetting('cm-font-family', 'monaco')}
|
||||
options={[
|
||||
{
|
||||
value: 'monaco',
|
||||
label: 'Monaco'
|
||||
},
|
||||
{
|
||||
value: 'hack',
|
||||
label: 'Hack'
|
||||
},
|
||||
{
|
||||
value: 'inconsolata',
|
||||
label: 'Inconsolata'
|
||||
},
|
||||
{
|
||||
value: 'source-code-pro',
|
||||
label: 'Source Code Pro'
|
||||
}
|
||||
]}
|
||||
onChange={ret => {
|
||||
updateSetting('cm-font-family', ret.value);
|
||||
}}
|
||||
>
|
||||
Font Family
|
||||
</SelectInput>
|
||||
|
||||
<ColorPickerInput
|
||||
colors={[ 1752220, 3066993, 3447003, 10181046, 15277667, 15844367, 15105570, 15158332, 9807270, 6323595, 1146986, 2067276, 2123412, 7419530, 11342935, 12745742, 11027200, 10038562, 9936031, 5533306 ]}
|
||||
defaultColor={10070709}
|
||||
value={getSetting('cake')}
|
||||
onChange={ret => {
|
||||
updateSetting('cake', ret);
|
||||
}}
|
||||
>
|
||||
Just a simple color picker.
|
||||
</ColorPickerInput>
|
||||
<div className='pie'
|
||||
style={{
|
||||
height: 50,
|
||||
width: 50,
|
||||
marginBottom: 20,
|
||||
borderRadius: 1000,
|
||||
backgroundColor: getModule([ 'int2hex', 'getDarkness', 'isValidHex' ], false).int2hex(getSetting('cake'))
|
||||
}}>
|
||||
</div>
|
||||
|
||||
<CopyInput
|
||||
value={'Just some more pie'}
|
||||
mode={this.state.copyInput.mode}
|
||||
text={this.state.copyInput.text}
|
||||
onCopy={async val => {
|
||||
/*
|
||||
* for some reason, this selects the text in the input
|
||||
* so let's clear the selection
|
||||
*/
|
||||
window.getSelection().removeAllRanges();
|
||||
|
||||
clipboard.writeText(val);
|
||||
|
||||
window.getSelection().removeAllRanges();
|
||||
|
||||
const modeModule = (await getModule(m => m.default && m.default.Modes)).default.Modes;
|
||||
this.setState(state => state.copyInput.mode = modeModule.SUCCESS);
|
||||
this.setState(state => state.copyInput.text = 'Copied');
|
||||
await sleep(300);
|
||||
this.setState(state => state.copyInput.mode = modeModule.DEFAULT);
|
||||
this.setState(state => state.copyInput.text = 'Copy');
|
||||
}}
|
||||
>
|
||||
Just a simple copy input.
|
||||
</CopyInput>
|
||||
|
||||
<TextArea
|
||||
autofocus={false}
|
||||
autosize={false}
|
||||
disabled={false}
|
||||
flex={false}
|
||||
maxLength={120}
|
||||
name={''}
|
||||
onChange={val => {
|
||||
updateSetting('textarea-test', val);
|
||||
val -= getSetting('textarea-test').length;
|
||||
}}
|
||||
placeholder={'The best placeholder you ever saw'}
|
||||
resizeable={false}
|
||||
rows={3}
|
||||
value={getSetting('textarea-test')}
|
||||
>
|
||||
Just a simple textarea.
|
||||
</TextArea>
|
||||
|
||||
<div className={classes.flexClassName}>
|
||||
<div className={getModule([ 'flexChild' ], false)} style={{ flex: '1 1 50%' }}>
|
||||
<SelectInput
|
||||
note={'This is a select input.'}
|
||||
value={getSetting('cm-font-family', 'monaco')}
|
||||
options={[
|
||||
{
|
||||
value: 'monaco',
|
||||
label: 'Monaco'
|
||||
},
|
||||
{
|
||||
value: 'hack',
|
||||
label: 'Hack'
|
||||
},
|
||||
{
|
||||
value: 'inconsolata',
|
||||
label: 'Inconsolata'
|
||||
},
|
||||
{
|
||||
value: 'source-code-pro',
|
||||
label: 'Source Code Pro'
|
||||
}
|
||||
]}
|
||||
onChange={ret => {
|
||||
updateSetting('cm-font-family', ret.value);
|
||||
}}
|
||||
>
|
||||
Font Family
|
||||
</SelectInput>
|
||||
</div>
|
||||
<div className={getModule([ 'flexChild' ], false)} style={{ flex: '1 1 50%' }}>
|
||||
<SelectInput
|
||||
note={'This is a select input.'}
|
||||
value={getSetting('cm-font-family', 'monaco')}
|
||||
options={[
|
||||
{
|
||||
value: 'monaco',
|
||||
label: 'Monaco'
|
||||
},
|
||||
{
|
||||
value: 'hack',
|
||||
label: 'Hack'
|
||||
},
|
||||
{
|
||||
value: 'inconsolata',
|
||||
label: 'Inconsolata'
|
||||
},
|
||||
{
|
||||
value: 'source-code-pro',
|
||||
label: 'Source Code Pro'
|
||||
}
|
||||
]}
|
||||
onChange={ret => {
|
||||
updateSetting('cm-font-family', ret.value);
|
||||
}}
|
||||
>
|
||||
Font Family
|
||||
</SelectInput>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SliderInput
|
||||
disabled={false}
|
||||
note={'This is a slider input.'}
|
||||
stickToMarkers
|
||||
initialValue={15}
|
||||
markers={[ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 26 ]}
|
||||
onMarkerRender={s => `${s}px`}
|
||||
defaultValue={getSetting('cm-fontSize', 15)}
|
||||
onChange={v => {
|
||||
updateSetting('cm-fontSize', v);
|
||||
}}
|
||||
>
|
||||
Font Size
|
||||
</SliderInput>
|
||||
{/* <Checkbox
|
||||
// eslint-disable-next-line multiline-comment-style
|
||||
// align={'alignCenter-MrlN6q'}
|
||||
// color={'#7289da'}
|
||||
text={'is it working'}
|
||||
disabled={false}
|
||||
onChange={() => {
|
||||
toggleSetting('checkbox-test');
|
||||
}}
|
||||
readOnly={false}
|
||||
reverse={false}
|
||||
// shape={'box-mmYMsp'}
|
||||
size={24}
|
||||
type={'inverted'}
|
||||
value={getSetting('checkbox-test')}
|
||||
>
|
||||
Just a simple checkbox.
|
||||
</Checkbox> */}
|
||||
|
||||
{/* <RegionSelector
|
||||
disabled={false}
|
||||
error={false}
|
||||
onClick={ret => {
|
||||
console.log(ret);
|
||||
getModule([ 'RegionSelectModal' ], false)({
|
||||
onChange () {
|
||||
console.log(...arguments);
|
||||
}
|
||||
});
|
||||
}}
|
||||
region={{
|
||||
custom: false,
|
||||
deprecated: false,
|
||||
id: 'us-south',
|
||||
name: 'US South',
|
||||
optimal: true,
|
||||
vip: false
|
||||
}}
|
||||
>
|
||||
Just a simple region selector.
|
||||
</RegionSelector> */}
|
||||
|
||||
<PermissionOverrideItem
|
||||
disabled={false}
|
||||
hideBorder={false} // divider
|
||||
note={'Members with this permission can change the channel\'s name or delete it.'}
|
||||
onChange={''}
|
||||
value={'ALLOW'} // 'DENY', 'ALLOW', 'PASSTHROUGH'
|
||||
>
|
||||
Just a simple permission override item.
|
||||
</PermissionOverrideItem>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
@ -0,0 +1,81 @@
|
||||
const webContents = require('electron').remote.getCurrentWebContents();
|
||||
const { React, getModule } = require('vizality/webpack');
|
||||
const { Icon} = require('vizality/components');
|
||||
|
||||
module.exports = class Titlebar extends React.Component {
|
||||
render () {
|
||||
const { type, headerText, showExtras } = this.props;
|
||||
return (
|
||||
<>
|
||||
{type !== 'none' && <titlebar className={`vizality-titlebar ${type}`}>
|
||||
<div className='vizality-titlebar__section-left'>
|
||||
|
||||
{headerText && <div className='vizality-titlebar__header'>
|
||||
<span className='vizality-titlebar__header-text'>
|
||||
{headerText}
|
||||
</span>
|
||||
</div>}
|
||||
|
||||
{showExtras && <div
|
||||
className={`vizality-titlebar__button-container back small ${!webContents.canGoBack() ? 'disabled' : ''}`}
|
||||
title='Back'
|
||||
onClick={() => {
|
||||
getModule('history', false).history.back();
|
||||
}}
|
||||
>
|
||||
<Icon wrapperClassName='vizality-titlebar__icon-wrapper' type='caret-left'></Icon>
|
||||
</div>}
|
||||
|
||||
{showExtras && <div
|
||||
className={`vizality-titlebar__button-container forward small ${!webContents.canGoForward() ? 'disabled' : ''}`}
|
||||
title='Forward'
|
||||
onClick={() => {
|
||||
getModule('history', false).history.forward();
|
||||
}}
|
||||
>
|
||||
<Icon wrapperClassName='vizality-titlebar__icon-wrapper' type='caret-right'></Icon>
|
||||
</div>}
|
||||
|
||||
{showExtras && <div
|
||||
className='vizality-titlebar__button-container reload small'
|
||||
title='Reload'
|
||||
onClick={() => {
|
||||
window.reloadElectronApp();
|
||||
}}
|
||||
>
|
||||
<Icon wrapperClassName='vizality-titlebar__icon-wrapper' type='reload'></Icon>
|
||||
</div>}
|
||||
|
||||
</div>
|
||||
<div className='vizality-titlebar__section-middle'></div>
|
||||
<div className='vizality-titlebar__section-right'>
|
||||
<div
|
||||
className='vizality-titlebar__button-container minimize'
|
||||
onClick={() => {
|
||||
DiscordNative.window.minimize();
|
||||
}}
|
||||
>
|
||||
<Icon wrapperClassName='vizality-titlebar__icon-wrapper' type='minimize'></Icon>
|
||||
</div>
|
||||
<div
|
||||
className='vizality-titlebar__button-container maximize'
|
||||
onClick={() => {
|
||||
DiscordNative.window.maximize();
|
||||
}}
|
||||
>
|
||||
<Icon wrapperClassName='vizality-titlebar__icon-wrapper' type='maximize'></Icon>
|
||||
</div>
|
||||
<div
|
||||
className='vizality-titlebar__button-container close'
|
||||
onClick={() => {
|
||||
DiscordNative.window.close();
|
||||
}}
|
||||
>
|
||||
<Icon wrapperClassName='vizality-titlebar__icon-wrapper' type='close'></Icon>
|
||||
</div>
|
||||
</div>
|
||||
</titlebar>}
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
@ -0,0 +1,45 @@
|
||||
const { Plugin } = require('vizality/entities');
|
||||
const { inject, uninject } = require('vizality/injector');
|
||||
const { React, getModule, getModuleByDisplayName } = require('vizality/webpack');
|
||||
const { forceUpdateElement } = require('vizality/util');
|
||||
|
||||
const Settings = require('./components/Settings');
|
||||
const Titlebar = require('./components/Titlebar');
|
||||
|
||||
module.exports = class ImprovedTitlebar extends Plugin {
|
||||
startPlugin () {
|
||||
vizality.api.settings.registerSettings('improved-titlebar', {
|
||||
category: 'improved-titlebar',
|
||||
label: 'improved-titlebar',
|
||||
render: Settings
|
||||
});
|
||||
this.loadStylesheet('style.scss');
|
||||
|
||||
this._injectTitlebar(
|
||||
this.settings.get('type', 'windows'),
|
||||
this.settings.get('showHeader', true),
|
||||
this.settings.get('headerText', 'Vizality'),
|
||||
this.settings.get('showExtras', false)
|
||||
);
|
||||
}
|
||||
|
||||
async _injectTitlebar (type, showHeader, headerText, showExtras) {
|
||||
const { app } = getModule([ 'app', 'layers' ]);
|
||||
document.documentElement.setAttribute('titlebar-type', this.settings.get('type', 'windows'));
|
||||
const Shakeable = await getModuleByDisplayName('Shakeable');
|
||||
const titlebar = React.createElement(Titlebar, { type, showHeader, headerText, showExtras });
|
||||
inject('advancedTitlebar-titlebar', Shakeable.prototype, 'render', (originalArgs, returnValue) => [ titlebar, returnValue ]);
|
||||
|
||||
setImmediate(() => forceUpdateElement(`.${app}`));
|
||||
}
|
||||
|
||||
pluginWillUnload () {
|
||||
const el = document.querySelector('.vizality-titlebar');
|
||||
if (el) el.remove();
|
||||
|
||||
uninject('advancedTitlebar-titlebar');
|
||||
/*
|
||||
* @todo: impl; re-render normal titlebar (so none if linux)
|
||||
*/
|
||||
}
|
||||
};
|
@ -0,0 +1,169 @@
|
||||
@use '../../library/index' as *;
|
||||
|
||||
@font-face {
|
||||
font-family: "Uni Sans Heavy";
|
||||
src: url("//db.onlinewebfonts.com/t/4f6fb2fa3c231278167b36e966718cbb.woff2") format("woff2"),
|
||||
url("//db.onlinewebfonts.com/t/4f6fb2fa3c231278167b36e966718cbb.woff") format("woff");
|
||||
}
|
||||
|
||||
|
||||
$caret-left: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="transform: rotate(90deg);"><path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M7 10L12 15 17 10"></path></svg>';
|
||||
|
||||
$caret-right: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="transform: rotate(-90deg);"><path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M7 10L12 15 17 10"></path></svg>';
|
||||
|
||||
$app-reload: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="currentColor" d="M4 8a4 4 0 0 0 6.828 2.828l1.415 1.415A6 6 0 1 1 12 3.528V2h2v5H9V5h1.646A4 4 0 0 0 4 8z" /></svg>';
|
||||
|
||||
$app-minimize: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12"><rect fill="currentColor" width="10" height="1" x="1" y="6"></rect></svg>';
|
||||
|
||||
$app-maximize: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12"><rect width="9" height="9" x="1.5" y="1.5" fill="none" stroke="currentColor"></rect></svg>';
|
||||
|
||||
$app-close: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12"><polygon fill="currentColor" fill-rule="evenodd" points="11 1.576 6.583 6 11 10.424 10.424 11 6 6.583 1.576 11 1 10.424 5.417 6 1 1.576 1.576 1 6 5.417 10.424 1"/></svg>';
|
||||
|
||||
|
||||
:root {
|
||||
--titlebar-background: var(--background-tertiary);
|
||||
--titlebar-height: 22px;
|
||||
|
||||
--titlebar-button-width: 28px;
|
||||
--titlebar-button-small-width: 28px;
|
||||
--titlebar-button-background: transparent;
|
||||
--titlebar-button-hover-background: var(--background-modifier-hover);
|
||||
|
||||
--titlebar-button-back-size: 18px;
|
||||
--titlebar-button-forward-size: 18px;
|
||||
--titlebar-button-reload-size: 14px;
|
||||
--titlebar-button-minimize-size: 12px;
|
||||
--titlebar-button-maximize-size: 12px;
|
||||
--titlebar-button-close-size: 12px;
|
||||
|
||||
--titlebar-button-icon-color: var(--interactive-normal);
|
||||
--titlebar-button-hover-icon-color: var(--background-modifier-hover);
|
||||
|
||||
--titlebar-header-text-color: var(--text-muted);
|
||||
--titlebar-header-font-size: 14px;
|
||||
--titlebar-header-font: 'Uni Sans Heavy';
|
||||
|
||||
--titlebar-icon-back: #{svg-uri($caret-left)};
|
||||
--titlebar-icon-forward: #{svg-uri($caret-right)};
|
||||
--titlebar-icon-reload: #{svg-uri($app-reload)};
|
||||
--titlebar-icon-minimize: #{svg-uri($app-minimize)};
|
||||
--titlebar-icon-maximize: #{svg-uri($app-maximize)};
|
||||
--titlebar-icon-close: #{svg-uri($app-close)};
|
||||
|
||||
// @todo: Fix up all these CSS and use global var(--icon 's instead
|
||||
}
|
||||
|
||||
.bg-h5JY_x,
|
||||
.standardSidebarView-3F1I7i {
|
||||
top: 0!important;
|
||||
}
|
||||
.layer-3QrUeG {
|
||||
top: 0!important;
|
||||
padding: 0!important;
|
||||
}
|
||||
|
||||
.vizality-titlebar {
|
||||
height: var(--titlebar-height);
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 0;
|
||||
background: var(--titlebar-background);
|
||||
z-index: 102;
|
||||
&-section-left,
|
||||
&-section-middle,
|
||||
&-section-right {
|
||||
z-index: 1001;
|
||||
}
|
||||
&-section-left,
|
||||
&-section-right {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
&-section-middle {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
margin: 4px 0 0 0;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
&-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 10px;
|
||||
}
|
||||
&-header-text {
|
||||
text-transform: uppercase;
|
||||
font-family: var(--titlebar-header-font);
|
||||
font-size: var(--titlebar-header-font-size);
|
||||
color: var(--titlebar-header-text-color);
|
||||
}
|
||||
&-button-container {
|
||||
width: var(--titlebar-button-width);
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer !important;
|
||||
icon {
|
||||
background-color: var(--titlebar-button-icon-color);
|
||||
}
|
||||
&.small {
|
||||
width: var(--titlebar-button-small-width);
|
||||
}
|
||||
&.disabled {
|
||||
pointer-events: none !important;
|
||||
opacity: 0.3;
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--titlebar-button-hover-background);
|
||||
}
|
||||
&.back {
|
||||
icon.back {
|
||||
@include size(var(--titlebar-button-back-size));
|
||||
@include mask(var(--titlebar-icon-back));
|
||||
}
|
||||
}
|
||||
&.forward {
|
||||
icon.forward {
|
||||
@include size(var(--titlebar-button-forward-size));
|
||||
@include mask(var(--titlebar-icon-forward));
|
||||
}
|
||||
}
|
||||
&.reload {
|
||||
icon.reload {
|
||||
@include size(var(--titlebar-button-reload-size));
|
||||
@include mask(var(--titlebar-icon-reload));
|
||||
}
|
||||
}
|
||||
&.minimize {
|
||||
icon.minimize {
|
||||
@include size(var(--titlebar-button-minimize-size));
|
||||
@include mask(var(--titlebar-icon-minimize));
|
||||
}
|
||||
}
|
||||
&.maximize {
|
||||
icon.maximize {
|
||||
@include size(var(--titlebar-button-maximize-size));
|
||||
@include mask(var(--titlebar-icon-maximize));
|
||||
@at-root [data-window-maximized] & {
|
||||
@include mask(icon('app-restore'));
|
||||
}
|
||||
}
|
||||
}
|
||||
&.close {
|
||||
&:hover {
|
||||
background-color: #f04747;
|
||||
icon.close {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
icon.close {
|
||||
@include size(var(--titlebar-button-close-size));
|
||||
@include mask(var(--titlebar-icon-close));
|
||||
}
|
||||
}
|
||||
}
|
||||
@at-root [vz-titlebar-type='none'] & {
|
||||
display: none;
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Advanced Titlebar",
|
||||
"version": "0.0.1",
|
||||
"description": "Replaces the default titlebar and gives you some extra options.",
|
||||
"author": "Baked",
|
||||
"license": "GPL-3.0"
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
const { Plugin } = require('vizality/entities');
|
||||
const { inject, uninject } = require('vizality/injector');
|
||||
const { React, getModule } = require('vizality/webpack');
|
||||
const { findInReactTree } = require('vizality/util');
|
||||
const { Tooltip, Icon } = require('vizality/components');
|
||||
|
||||
module.exports = class QuickDelete extends Plugin {
|
||||
async startPlugin () {
|
||||
const deleteMessage = await getModule([ 'deleteMessage', 'sendMessage' ]);
|
||||
const MiniPopover = await getModule(m => m.default && m.default.displayName === 'MiniPopover');
|
||||
|
||||
const classes = {
|
||||
...getModule([ 'button', 'wrapper', 'disabled' ], false),
|
||||
...getModule([ 'icon', 'isHeader' ], false)
|
||||
};
|
||||
|
||||
inject('quick-delete-button', MiniPopover, 'default', (originalArgs, returnValue) => {
|
||||
const props = findInReactTree(returnValue, r => r && r.canDelete && r.message);
|
||||
|
||||
if (!props) return returnValue;
|
||||
|
||||
const oType = returnValue.props.children[1].type;
|
||||
returnValue.props.children[1].type = props => {
|
||||
const ret = oType(props);
|
||||
ret.props.children.splice(-1, 0,
|
||||
React.createElement(
|
||||
Tooltip,
|
||||
{
|
||||
className: classes.button,
|
||||
text: 'Delete',
|
||||
position: 'top'
|
||||
},
|
||||
React.createElement(Icon, {
|
||||
wrapperClassName: classes.icon,
|
||||
type: 'trash',
|
||||
onClick: () => deleteMessage.deleteMessage(props.channel.id, props.message.id)
|
||||
})
|
||||
)
|
||||
);
|
||||
return ret;
|
||||
};
|
||||
|
||||
return returnValue;
|
||||
});
|
||||
|
||||
MiniPopover.default.displayName = 'MiniPopover';
|
||||
}
|
||||
|
||||
pluginWillUnload () {
|
||||
uninject('quick-delete-button');
|
||||
}
|
||||
};
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Quick Delete",
|
||||
"version": "0.0.1",
|
||||
"description": "Adds a delete button to the message mini-popover.",
|
||||
"author": "Baked",
|
||||
"license": "GPL-3.0"
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
const { inject, uninject } = require('vizality/injector');
|
||||
const { getModule, getModuleByDisplayName } = require('vizality/webpack');
|
||||
const { findInReactTree, classNames, forceUpdateElement } = require('vizality/util');
|
||||
|
||||
module.exports = async () => {
|
||||
return () => void 0;
|
||||
|
||||
const List = await getModuleByDisplayName('List');
|
||||
|
||||
inject('vz-improved-navigation-dmChannels', List.prototype, 'renderRow', (originalArgs, returnValue) => {
|
||||
// const props = findInReactTree(returnValue, n => n.id);
|
||||
|
||||
// if (!props.id || props.id !== 'private-channels') return returnValue;
|
||||
|
||||
// const test = findInReactTree(props, n => n.key);
|
||||
|
||||
// const keys = [ 'friends', 'library', 'nitro' ];
|
||||
|
||||
// if (keys.includes(test.key)) {
|
||||
// console.log('hmm');
|
||||
// }
|
||||
|
||||
console.log(originalArgs);
|
||||
console.log(returnValue);
|
||||
|
||||
return returnValue;
|
||||
});
|
||||
|
||||
setImmediate(() => forceUpdateElement('.scroller-2FKFPG'));
|
||||
|
||||
// return async () => uninject('vz-improved-navigation-dmChannels');
|
||||
// const ConnectedPrivateChannelsList = await getModule(m => m.default && m.default.displayName === 'ConnectedPrivateChannelsList');
|
||||
|
||||
// inject('vz-improved-navigation-dmChannels', ConnectedPrivateChannelsList, 'default', (originalArgs, returnValue) => {
|
||||
// console.log(returnValue);
|
||||
|
||||
// return returnValue;
|
||||
// });
|
||||
|
||||
return async () => uninject('vz-improved-navigation-dmChannels');
|
||||
};
|
Loading…
Reference in new issue