Skip to content

Instantly share code, notes, and snippets.

@rsKliPPy
Last active March 2, 2018 02:23
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rsKliPPy/4d4281e6ac447b601958d2e6c4971c30 to your computer and use it in GitHub Desktop.
Save rsKliPPy/4d4281e6ac447b601958d2e6c4971c30 to your computer and use it in GitHub Desktop.
ViolentMonkey script to add a night theme to AlliedModders Forums.
// ==UserScript==
// @name AlliedModders Night Theme
// @namespace github.com/rsKliPPy/
// @match https://forums.alliedmods.net/*
// @version 1.3.0
// @downloadURL https://gist.githubusercontent.com/rsKliPPy/4d4281e6ac447b601958d2e6c4971c30/raw
// @homepageURL https://github.com/rsKliPPy
// @grant none
// @run-at document-start
// ==/UserScript==
'use strict';
const colors = {
'1': '#0A0A0A',
'2': '#212121',
'3': '#303030',
'4': '#424242',
'5': '#545452',
'primary': '#006699',
'secondary': '#486DC6',
'text': '#CACACA',
'faded-text': '#AAAAAA',
'body': '#0A0A0A',
'page': '#1A1A1A',
'code-bg': '#CCCCCC',
'quote-bg': '#4A4A4A',
'new-post': '#ffa531',
'old-post': '#424242'
};
const styles = {
// Common for every page
'$common': `
body {
background: ${colors['body']} !important;
color: ${colors['text']} !important;
}
.page {
background: ${colors['page']} !important;
color: ${colors['text']} !important;
}
.page > div {
padding: 0 10% 0px 10% !important;
}
a:link, a:visited {
color: ${colors['primary']} !important;
}
.tborder {
background: ${colors['3']} !important;
border-spacing: 0 !important;
border: none !important;
}
.tborder > tbody > tr > td {
border-top: 2px solid ${colors['page']} !important;
}
.thead {
background: ${colors['1']} !important;
color: ${colors['text']} !important;
}
.tfoot {
background: ${colors['2']} !important;
color: ${colors['text']} !important;
}
.tcat {
color: ${colors['secondary']} !important;
background: ${colors['2']} !important;
}
.alt1, .alt2, .alt3, .alt4, .alt1Active {
background: ${colors['3']} !important;
color: ${colors['text']} !important;
}
.time {
color: ${colors['secondary']} !important;
}
fieldset {
border: 2px solid ${colors['4']} !important;
}
legend {
color: ${colors['secondary']} !important;
}
.vbmenu_popup {
background: ${colors['5']} !important;
border: none !important;
}
.vbmenu_control, .vbmenu_option {
background: ${colors['2']} !important;
color: ${colors['primary']} !important;
}
.bginput {
background: ${colors['4']} !important;
color: ${colors['faded-text']} !important;
border: 1px solid ${colors['1']} !important;
padding: 2px !important;
}
select {
background-color: ${colors['4']} !important;
color: ${colors['faded-text']} !important;
border: 1px solid ${colors['1']} !important;
padding: 2px !important;
}
optgroup[label], select option {
background: ${colors['4']} !important;
color: ${colors['faded-text']} !important;
}
.button {
background: ${colors['2']} !important;
color: ${colors['text']} !important;
border: 1px solid ${colors['5']} !important;
padding: 3px 8px 3px 8px !important;
}
.button:hover {
border: 1px solid ${colors['primary']} !important;
cursor: pointer;
}
.button.large {
font-size: 12px;
padding-top: 4px !important;
padding-bottom: 4px !important;
}
.online-status {
vertical-align: middle;
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
}
.online-status.online {
background-color: #4BDE4B;
}
.online-status.offline {
background-color: ${colors['5']};
}
`,
'index': `
.home-links {
color: ${colors['text']} !important;
}
.subforum-status {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
}
.subforum-status.new {
background-color: ${colors['new-post']};
}
.subforum-status.old {
background-color: ${colors['old-post']};
}
`,
'forumdisplay': `
@keyframes thread-hot-anim {
0%, 20%, 50%, 80%, 100% { transform: translateY(0); }
40% { transform: translateY(-4px); }
60% { transform: translateY(-2px ); }
}
.thread-status {
width: 12px;
height: 12px;
}
.thread-hot {
animation: thread-hot-anim 1.5s ease infinite;
}
`,
'threadstatus': `
.thread-status {
display: inline-block;
width: 16px;
height: 16px;
border-radius: 50%;
margin: 1px;
}
.thread-status.old {
background: ${colors['old-post']};
}
.thread-status.new {
background: ${colors['new-post']};
}
.thread-status.has-posts {
width: 8px;
height: 8px;
background: #d85c5c;
position: relative;
left: -3px;
top: -3px;
}
.thread-status.lock {
background: #A0A0A0;
}
`,
'showthread': `
.ttop, .tinside, .tbottom {
border: none !important;
}
.tinside .alt2, .tinside .alt3, .tbottom .alt2, .tbottom .alt3, .tbottom .thead, .ttop .alt2, .ttop .alt3, .ttop .thead {
border-color: ${colors['4']} !important;
}
.bpost {
background: ${colors['2']} !important;
border: none !important;
}
.tinside legend, .tbottom legend, .ttop legend {
color: ${colors['primary']} !important;
}
.tinside fieldset, .tbottom fieldset, .ttop fieldset {
border-color: ${colors['4']} !important;
}
.tinside hr, .tbottom hr, .ttop hr {
color: ${colors['4']} !important;
}
.tborder[id^=post] {
padding-top: 6px;
background: ${colors['2']} !important;
}
`,
'vb-editor': `
.panel {
background: ${colors['3']} !important;
color: ${colors['text']} !important;
border: none !important;
}
.controlbar fieldset {
border: none !important;
}
.controlbar textarea {
border: 1px solid ${colors['1']} !important;
resize: vertical;
}
.vBulletin_editor {
border: 1px solid ${colors['1']} !important;
}
.panelsurround {
background: ${colors['3']} !important;
}
`,
'newreply': `
#collapseobj_threadreview hr {
color: ${colors['4']} !important;
background: ${colors['4']} !important;
}
`,
'bbcode': `
.quote {
background: ${colors['quote-bg']} !important;
border: 1px solid ${colors['1']} !important;
color: ${colors['faded-text']} !important;
}
div.alt2[dir=ltr], pre.alt2[dir=ltr] {
background: ${colors['code-bg']} !important;
border: 1px solid ${colors['1']} !important;
color: black !important;
}
`,
'search': `
.panel {
background: ${colors['2']} !important;
color: ${colors['text']} !important;
border: none !important;
}
`
};
const pageStyles = {
'/index.php': ['threadstatus', 'index'],
'/forumdisplay.php': ['threadstatus', 'forumdisplay'],
'/showthread.php': ['showthread', 'vb-editor', 'bbcode'],
'/member.php': [],
'/showgroups.php': [],
'/newreply.php': ['vb-editor', 'newreply', 'bbcode'],
'/newthread.php': ['vb-editor'],
'/private.php': ['vb-editor'],
'/search.php': ['search'],
'/subscription.php': ['vb-editor'],
'/profile.php': ['vb-editor'],
'/faq.php': ['vb-editor']
};
const imageReplaceMap = new Map();
imageReplaceMap.set('images/buttons/quote.gif', {
text: 'Reply With Quote'
});
imageReplaceMap.set('https://forums.alliedmods.net/images/buttons/multiquote_off.gif', {
text: 'Multi-Quote'
});
imageReplaceMap.set('images/buttons/quickreply.gif', {
text: 'Quick Reply'
});
imageReplaceMap.set('images/buttons/edit.gif', {
text: 'Edit'
});
imageReplaceMap.set('images/buttons/report.svg', {
text: 'Report Post'
});
imageReplaceMap.set('images/buttons/newthread.gif', {
text: 'New Topic',
classes: ['large']
});
imageReplaceMap.set('images/buttons/reply.gif', {
text: 'Post Reply',
classes: ['large']
});
imageReplaceMap.set('images/statusicon/user_offline.svg', {
notButton: true,
classes: ['online-status', 'offline']
});
imageReplaceMap.set('images/statusicon/user_online.svg', {
notButton: true,
classes: ['online-status', 'online']
});
imageReplaceMap.set('images/statusicon/subforum_new.svg', {
notButton: true,
classes: ['subforum-status', 'new']
});
imageReplaceMap.set('images/statusicon/subforum_old.svg', {
notButton: true,
classes: ['subforum-status', 'old']
});
// Transform path if needed
let pathName = location.pathname;
if(pathName === '/') {
pathName = '/index.php';
}
function mergeStyles(pagePath) {
let finalStyle = styles['$common'];
const stylesList = pageStyles[pagePath];
if(stylesList === undefined || !Array.isArray(stylesList) || stylesList.length === 0) {
return finalStyle;
}
for(const style of stylesList) {
if(styles[style] === undefined) {
continue;
}
finalStyle += '\n' + styles[style];
}
return finalStyle;
}
function applyStyles() {
if(applyStyles.alreadyApplied === undefined) {
const styleElement = document.createElement('style');
styleElement.appendChild(document.createTextNode(mergeStyles(pathName)));
document.head.appendChild(styleElement);
}
applyStyles.alreadyApplied = true;
}
function doThreadIcons() {
function addIcon(containerElement, status, title) {
const statusElement = document.createElement('div');
statusElement.classList.add('thread-status', status);
statusElement.setAttribute('title', title);
containerElement.appendChild(statusElement);
return statusElement;
}
let statusImgs = document.querySelectorAll('img[id*=_statusicon_]');
for(const imgElement of statusImgs) {
const parentElement = imgElement.parentElement;
const containerElement = document.createElement('div');
let hasStatus = false;
if(imgElement.src.includes('new')) { // New posts
addIcon(containerElement, 'new', 'New posts');
} else if(imgElement.src.includes('lock')) { // Closed
addIcon(containerElement, 'lock', 'Closed');
} else { // No new posts
addIcon(containerElement, 'old', 'No new posts');
}
if(imgElement.src.includes('hot')) { // Hot
containerElement.classList.add('thread-hot');
}
if(imgElement.src.includes('dot')) { // User has posts
addIcon(containerElement.firstElementChild, 'has-posts', imgElement.title);
}
imgElement.parentElement.replaceChild(containerElement, imgElement);
}
// Any remaining threads are deleted ones. Just hide the old image.
statusImgs = document.querySelectorAll('img[src*=statusicon]:not([title])');
for(const imgElement of statusImgs) {
imgElement.remove();
}
}
function onDocumentLoaded() {
applyStyles();
for(const tuple of imageReplaceMap) {
for(const element of document.querySelectorAll(`img[src="${tuple[0]}"]`)) {
const replaceData = tuple[1];
let newElement;
if(replaceData.notButton === true) {
newElement = document.createElement('div');
} else {
newElement = document.createElement('input');
newElement.setAttribute('type', 'button');
newElement.setAttribute('value', replaceData.text);
newElement.setAttribute('title', element.getAttribute('alt'));
newElement.classList.add('button');
}
if(replaceData.classes !== undefined) {
for(const className of replaceData.classes) {
newElement.classList.add(className);
}
}
element.parentNode.replaceChild(newElement, element);
}
}
if(pathName === '/index.php' || pathName === '/forumdisplay.php') {
doThreadIcons();
}
}
/**
* The code below makes sure that onDocumentLoaded() will be called
* as soon as possible regardless of @run-at value, for the best experience.
*/
if(document.head !== null) {
applyStyles();
}
if(document.readyState === 'complete') {
onDocumentLoaded();
} else {
let onReadyStateChange;
const onDOMContentLoaded = () => {
onDocumentLoaded();
document.removeEventListener('DOMContentLoaded', onDOMContentLoaded);
document.removeEventListener('readystatechange', onReadyStateChange);
};
onReadyStateChange = () => {
if(document.readyState === 'complete') {
onDocumentLoaded();
document.removeEventListener('DOMContentLoaded', onDOMContentLoaded);
document.removeEventListener('readystatechange', onReadyStateChange);
}
};
document.addEventListener('DOMContentLoaded', onDOMContentLoaded);
document.addEventListener('readystatechange', onReadyStateChange);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment