Using JS and custom CSS for real-life needs

Stanislau Holadau
6 min readFeb 8, 2024

Since my early days of using computers, I’ve had a passion for tailoring system aesthetics and functionality to my needs. Nowadays, I’m less focused on the visual aspects — perhaps due to the appealing default look of Windows 11 — but I continue to leverage my skills and experience to streamline and enhance my work and daily routines. With AI tools this process is even smoother.

Case 1 — Highlight keywords on any job listing site

My partner is currently on the hunt for a Frontend Developer position. So I assist her in monitoring job openings. However, the task of looking through tons of listings can be quite monotonous. This led me to seek out ways to make this routine more manageable.

While many job portals offer notification services for new listings, their search engines are often not smart enough. They tend to notify us about “new” positions that aren’t actually new or don’t align with my partner’s skill set. Until we have a robust AI solution that intelligently matches skills with job descriptions, I find myself manually navigating through countless job sites.

In an effort to simplify this process, I recently created a script (thank you ChatGPT!) designed to ease the job scanning ordeal. I use the Tampermonkey browser extension that can execute custom Javascript on any website. This script highlights keywords: green for a positive match and red for a negative one, making the process straightforward.

Despite my limited knowledge of JavaScript, ChatGPT has been an invaluable resource. After a few rounds of tweaks and debugging, I’ve successfully crafted this script:

(function() {
'use strict';

function init() {
createHighlightButton();
addKeyboardShortcut();
}

function createHighlightButton() {
const button = document.createElement('button');
button.textContent = 'Highlight keywords';
button.style.position = 'fixed';
button.style.left = '10px';
button.style.bottom = '10px';
button.style.zIndex = '10000';
button.addEventListener('click', applyStyles);
document.body.appendChild(button);
}

// adding handling of CTRL+Q
function addKeyboardShortcut() {
document.addEventListener('keydown', function(event) {
if (event.ctrlKey && event.key === 'q') {
applyStyles();
event.preventDefault(); // prevent standard usage of CTRL+Q
}
});
}


// Apply styles
function applyStyles() {

const whitelist = ['javascript', 'junior', 'frontend', 'react',
'typescript', 'wroclaw', 'wrocław', 'node.js', 'scss', 'sass', 'html', 'css',
'web developer', 'intern', 'staż'];

const blacklist = ['senior', '.net', 'python', 'lead', 'fullstack',
'full-stack', 'years', 'angular', 'vue', 'full stack', 'C#', 'c+',
'ruby', ' lat', ' letn', 'java ', 'minumum', 'german', 'backend',
'devops', 'php', 'sql', 'middle', 'mid'];

const selectors = ['a.card__job-link','p.card__job-snippet','div.jobPreview__header--location', 'h1.jobPreview__header--title', 'div.jobPreview__body--description',
'#__next > div.MuiBox-root > div > div > div.MuiBox-root > div > div > div > div > h1',
'#__next > div.MuiBox-root > div > div > div.MuiBox-root > div > div:nth-child(4) > div > p',
'#__next > div.MuiBox-root > div > div > div.MuiBox-root > div > div > div:nth-child(2) > div > div',
'#__next > div.MuiBox-root > div > div > div.MuiBox-root > div > div:nth-child(3) > div > ul',
'#__next > div.MuiBox-root > div > div > div.MuiBox-root > div > div:nth-child(4) > div li',
'#__next > div.MuiBox-root > div > div > div.MuiBox-root > div > div > div:nth-child(2) > div > div:nth-child(2) > div > div > div > div h2',
'div.artdeco-entity-lockup__content',
'div.job-details-jobs-unified-top-card__container--two-pane h2',
'div.job-details-jobs-unified-top-card__primary-description-without-tagline',
'div.job-details-jobs-unified-top-card__job-insight-view-model-secondary',
'article.jobs-description__container',
'h1.job-details-jobs-unified-top-card__job-title',
'aside.tw-w-full',
'div.posting-details-description > h1',
'ul.posting-info-row',
'div#posting-requirements',
'section.d-block > div',
'section.d-block ol'];

// Highlight keywords in specified selectors
selectors.forEach(selector => {
document.querySelectorAll(selector).forEach(element => {
whitelist.forEach(word => highlightText(element, word, 'green'));
blacklist.forEach(word => highlightText(element, word, 'red'));
});
});
}

// Highlight text with specified color
function highlightText(node, word, color) {
console.log('highlightText executed.');
if (node.nodeType === 3) { // Node is text
const regex = new RegExp(`(\\b${word}\\b)`, 'gi'); // use regexp to find the word
const matches = [...node.data.matchAll(regex)];

matches.forEach(match => {
if (match.index !== undefined) {
const matchIndex = match.index;
const matchEnd = matchIndex + match[0].length;
const beforeText = node.data.substring(0, matchIndex);
const afterText = node.data.substring(matchEnd);
const highlightedText = document.createElement('span');
highlightedText.style.fontWeight = 'bold';
highlightedText.style.fontSize = 'inherit';
highlightedText.style.color = color;
highlightedText.textContent = ' ' + match[0];

const parentNode = node.parentNode;
const beforeTextNode = document.createTextNode(beforeText);
const afterTextNode = document.createTextNode(afterText);

parentNode.replaceChild(afterTextNode, node);
parentNode.insertBefore(highlightedText, afterTextNode);
parentNode.insertBefore(beforeTextNode, highlightedText);

// update the node for next iteration, in case of other matches.
node = afterTextNode;
}
});
} else if (node.nodeType === 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) {
Array.from(node.childNodes).forEach(child => highlightText(child, word, color));
}
}


// Initialize the script
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();

Result:

Instructions:

  1. Specifying Target Sites (@match):
    Use the @match directive to define which websites your script should affect. This ensures the script runs only on these pages, optimizing performance and preventing unintended changes on other sites.

Example:

// @match        https://www.linkedin.com/jobs/*
// @match https://*.anothersite.com/*

Alternatively, you can specify the sites in the Settings section of the script.

2. Defining Keywords:
The ‘whitelist’ and ‘blacklist’ arrays are used to identify text content for highlighting. This step is crucial for tailoring the script’s behavior to specific content.

Example:

const whitelist = ['desired', 'keyword1', 'keyword2'];
const blacklist = ['undesired', 'keywordA', 'keywordB'];

3. Identifying CSS Selectors:
Inspect the HTML structure of the target web pages to determine the most specific and relevant CSS selectors for the elements you want to modify. This precision helps in avoiding performance issues.

Example:

const selectors = ['div.specific-class', 'a.direct-link', 'span.highlight-text'];

4. Test and enjoy!
Go to a site you mentioned in the @match section, and click on a button in the left bottom corner. This will execute the script. You can also use the Ctrl+Q combination to execute it.

Case 2 — Apply custom CSS to adjust any site

Working with Salesforce instances and distinguishing between them, especially when toggling between admin and end-user interfaces, can be quite a challenge due to their similar appearances. Utilizing the Stylus browser extension to inject custom CSS into web pages is a clever solution to visually differentiate these environments.

This simple CSS rule replaces the logo on the Salesforce admin setup:

.slds-global-header__logo {
background-image: url("https://www.fourpaws.com/-/media/Project/OneWeb/FourPaws/Images/articles/cat-corner/small-cat-breeds/munchkin-cropped.jpg") !important;
}

So now I have a cat instead of the default Salesforce logo :)

To apply it only for the admin setup interface, I used
“URL starting with” = https://mycompany-uat.sandbox.lightning.force.com/lightning/setup/

To apply it only for the end-user interface, I create a copy of the style with another cat and “URL starting with” = https://mycompany-uat.sandbox.lightning.force.com/lightning/o/

You can use Stylus for many other purposes:

  1. Removing Unwanted Elements: By targeting specific elements with CSS selectors, you can hide distracting or unnecessary content on frequently visited websites. However, identifying the right CSS selector requires a bit of investigation using the browser’s developer tools.
.advertisement {
display: none !important;
}

2. Customizing Website Appearance: Adjusting font sizes and styles can greatly improve readability, especially on sites with outdated designs or small text. This customization can make reading more comfortable and accessible.

p.main-content {
font-size: 16px !important;
font-family: Arial, sans-serif !important;
}

By the way, Stylus has a huge library of ready-made styles you can apply for popular sites. For example https://userstyles.org/styles/browse?search_terms=github&type=false

--

--