Last active
March 2, 2018 02:23
-
-
Save rsKliPPy/4d4281e6ac447b601958d2e6c4971c30 to your computer and use it in GitHub Desktop.
ViolentMonkey script to add a night theme to AlliedModders Forums.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==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