Skip to content

Commit

Permalink
if link color blends too much make it brighter
Browse files Browse the repository at this point in the history
  • Loading branch information
dimdenGD committed Jul 20, 2022
1 parent 52ea634 commit 5056a61
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 14 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,5 @@ Go to [mobile.twitter.com](https://mobile.twitter.com).
- Ability to change default link color and font
- Ability to enable/disable Twemoji
- Ability to disable stars (favorites) back to likes (hearts)
- Ability to show custom user colors in timeline
- Ability to show custom user colors in timeline
- Dark mode support
57 changes: 55 additions & 2 deletions layouts/home/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ let pollToUpload = undefined;
let linkColors = {};
let vars = {};
let algoCursor;
chrome.storage.sync.get(['linkColor', 'font', 'heartsNotStars', 'linkColorsInTL', 'enableTwemoji', 'chronologicalTL', 'showTopicTweets'], data => {
chrome.storage.sync.get(['linkColor', 'font', 'heartsNotStars', 'linkColorsInTL', 'enableTwemoji', 'chronologicalTL', 'showTopicTweets', 'darkMode'], data => {
vars = data;
});
chrome.storage.local.get(['installed'], async data => {
Expand Down Expand Up @@ -63,6 +63,49 @@ function updateUserData() {
console.error(e);
});
}
function luminance(r, g, b) {
var a = [r, g, b].map(function(v) {
v /= 255;
return v <= 0.03928 ?
v / 12.92 :
Math.pow((v + 0.055) / 1.055, 2.4);
});
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
}
function contrast(rgb1, rgb2) {
var lum1 = luminance(rgb1[0], rgb1[1], rgb1[2]);
var lum2 = luminance(rgb2[0], rgb2[1], rgb2[2]);
var brightest = Math.max(lum1, lum2);
var darkest = Math.min(lum1, lum2);
return (brightest + 0.05) /
(darkest + 0.05);
}
const hex2rgb = (hex) => {
if(!hex.startsWith('#')) hex = `#${hex}`;
const r = parseInt(hex.slice(1, 3), 16)
const g = parseInt(hex.slice(3, 5), 16)
const b = parseInt(hex.slice(5, 7), 16)
// return {r, g, b} // return an object
return [ r, g, b ]
}

const colorShade = (col, amt) => {
col = col.replace(/^#/, '')
if (col.length === 3) col = col[0] + col[0] + col[1] + col[1] + col[2] + col[2]

let [r, g, b] = col.match(/.{2}/g);
([r, g, b] = [parseInt(r, 16) + amt, parseInt(g, 16) + amt, parseInt(b, 16) + amt])

r = Math.max(Math.min(255, r), 0).toString(16)
g = Math.max(Math.min(255, g), 0).toString(16)
b = Math.max(Math.min(255, b), 0).toString(16)

const rr = (r.length < 2 ? '0' : '') + r
const gg = (g.length < 2 ? '0' : '') + g
const bb = (b.length < 2 ? '0' : '') + b

return `#${rr}${gg}${bb}`
}
async function updateTimeline() {
seenThreads = [];
if (timeline.data.length === 0) document.getElementById('timeline').innerHTML = 'Loading tweets...';
Expand Down Expand Up @@ -167,9 +210,19 @@ async function appendTweet(t, timelineContainer, options = {}) {
if (options.noTop) tweet.classList.add('tweet-no-top');
if(vars.linkColorsInTL) {
if(linkColors[t.user.screen_name]) {
let rgb = hex2rgb(linkColors[t.user.screen_name]);
let ratio = contrast(rgb, [27, 40, 54]);
if(ratio < 4 && vars.darkMode) {
linkColors[t.user.screen_name] = colorShade(linkColors[t.user.screen_name], 80).slice(1);
}
tweet.style.setProperty('--link-color', '#'+linkColors[t.user.screen_name]);
} else {
if(t.user.profile_link_color && t.user.profile_link_color !== '1DA1F2') {
let rgb = hex2rgb(t.user.profile_link_color);
let ratio = contrast(rgb, [27, 40, 54]);
if(ratio < 4 && vars.darkMode) {
t.user.profile_link_color = colorShade(t.user.profile_link_color, 80).slice(1);
}
tweet.style.setProperty('--link-color', '#'+t.user.profile_link_color);
}
}
Expand Down Expand Up @@ -230,7 +283,7 @@ async function appendTweet(t, timelineContainer, options = {}) {
</span>
</div>
<span class="tweet-time-quote" data-timestamp="${new Date(t.quoted_status.created_at).getTime()}" title="${new Date(t.quoted_status.created_at).toLocaleString()}">${timeElapsed(new Date(t.quoted_status.created_at).getTime())}</span>
<span class="tweet-body-text-quote tweet-body-text-long" style="color:black!important">${t.quoted_status.full_text ? escape(t.quoted_status.full_text).replace(/\n/g, '<br>') : ''}</span>
<span class="tweet-body-text-quote tweet-body-text-long" style="color:var(--default-text-color)!important">${t.quoted_status.full_text ? escape(t.quoted_status.full_text).replace(/\n/g, '<br>') : ''}</span>
${t.quoted_status.extended_entities && t.quoted_status.extended_entities.media ? `
<div class="tweet-media-quote">
${t.quoted_status.extended_entities.media.map(m => `<${m.type === 'photo' ? 'img' : 'video'} ${m.ext_alt_text ? `alt="${escape(m.ext_alt_text)}" title="${escape(m.ext_alt_text)}"` : ''} crossorigin="anonymous" width="${quoteSizeFunctions[t.quoted_status.extended_entities.media.length](m.original_info.width, m.original_info.height)[0]}" height="${quoteSizeFunctions[t.quoted_status.extended_entities.media.length](m.original_info.width, m.original_info.height)[1]}" loading="lazy" ${m.type === 'video' ? 'controls' : ''} ${m.type === 'animated_gif' ? 'loop autoplay muted' : ''} src="${m.type === 'photo' ? m.media_url_https : m.video_info.variants.find(v => v.content_type === 'video/mp4').url}" class="tweet-media-element tweet-media-element-quote ${mediaClasses[t.quoted_status.extended_entities.media.length]} ${!settings.display_sensitive_media && t.quoted_status.possibly_sensitive ? 'tweet-media-element-censor' : ''}">${m.type === 'video' ? '</video>' : ''}`).join('\n')}
Expand Down
2 changes: 1 addition & 1 deletion layouts/notifications/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ async function appendTweet(t, timelineContainer, options = {}) {
</span>
</div>
<span class="tweet-time-quote" data-timestamp="${new Date(t.quoted_status.created_at).getTime()}" title="${new Date(t.quoted_status.created_at).toLocaleString()}">${timeElapsed(new Date(t.quoted_status.created_at).getTime())}</span>
<span class="tweet-body-text-quote tweet-body-text-long" style="color:black!important">${t.quoted_status.full_text ? escape(t.quoted_status.full_text).replace(/\n/g, '<br>') : ''}</span>
<span class="tweet-body-text-quote tweet-body-text-long" style="color:var(--default-text-color)!important">${t.quoted_status.full_text ? escape(t.quoted_status.full_text).replace(/\n/g, '<br>') : ''}</span>
${t.quoted_status.extended_entities && t.quoted_status.extended_entities.media ? `
<div class="tweet-media-quote">
${t.quoted_status.extended_entities.media.map(m => `<${m.type === 'photo' ? 'img' : 'video'} ${m.ext_alt_text ? `alt="${escape(m.ext_alt_text)}" title="${escape(m.ext_alt_text)}"` : ''} crossorigin="anonymous" width="${quoteSizeFunctions[t.quoted_status.extended_entities.media.length](m.original_info.width, m.original_info.height)[0]}" height="${quoteSizeFunctions[t.quoted_status.extended_entities.media.length](m.original_info.width, m.original_info.height)[1]}" loading="lazy" ${m.type === 'video' ? 'controls' : ''} ${m.type === 'animated_gif' ? 'loop autoplay muted' : ''} src="${m.type === 'photo' ? m.media_url_https : m.video_info.variants.find(v => v.content_type === 'video/mp4').url}" class="tweet-media-element tweet-media-element-quote ${mediaClasses[t.quoted_status.extended_entities.media.length]} ${!settings.display_sensitive_media && t.quoted_status.possibly_sensitive ? 'tweet-media-element-censor' : ''}">${m.type === 'video' ? '</video>' : ''}`).join('\n')}
Expand Down
58 changes: 56 additions & 2 deletions layouts/profile/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ let pinnedTweet, followersYouFollow;
let previousLastTweet, stopLoad = false;
let favoritesCursor, followingCursor, followersCursor, followersYouKnowCursor;
let vars;
chrome.storage.sync.get(['linkColor', 'font', 'heartsNotStars', 'linkColorsInTL', 'enableTwemoji'], data => {
chrome.storage.sync.get(['linkColor', 'font', 'heartsNotStars', 'linkColorsInTL', 'enableTwemoji', 'darkMode'], data => {
vars = data;
});

Expand Down Expand Up @@ -146,6 +146,50 @@ function updateSelection() {
if(subpage !== 'replies') document.getElementById('tweet-nav-replies').href = `https://twitter.com/${pageUser.screen_name}/with_replies`;
if(subpage !== 'media') document.getElementById('tweet-nav-media').href = `https://twitter.com/${pageUser.screen_name}/media`;
}
function luminance(r, g, b) {
var a = [r, g, b].map(function(v) {
v /= 255;
return v <= 0.03928 ?
v / 12.92 :
Math.pow((v + 0.055) / 1.055, 2.4);
});
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
}

function contrast(rgb1, rgb2) {
var lum1 = luminance(rgb1[0], rgb1[1], rgb1[2]);
var lum2 = luminance(rgb2[0], rgb2[1], rgb2[2]);
var brightest = Math.max(lum1, lum2);
var darkest = Math.min(lum1, lum2);
return (brightest + 0.05) /
(darkest + 0.05);
}
const hex2rgb = (hex) => {
if(!hex.startsWith('#')) hex = `#${hex}`;
const r = parseInt(hex.slice(1, 3), 16)
const g = parseInt(hex.slice(3, 5), 16)
const b = parseInt(hex.slice(5, 7), 16)
// return {r, g, b} // return an object
return [ r, g, b ]
}

const colorShade = (col, amt) => {
col = col.replace(/^#/, '')
if (col.length === 3) col = col[0] + col[0] + col[1] + col[1] + col[2] + col[2]

let [r, g, b] = col.match(/.{2}/g);
([r, g, b] = [parseInt(r, 16) + amt, parseInt(g, 16) + amt, parseInt(b, 16) + amt])

r = Math.max(Math.min(255, r), 0).toString(16)
g = Math.max(Math.min(255, g), 0).toString(16)
b = Math.max(Math.min(255, b), 0).toString(16)

const rr = (r.length < 2 ? '0' : '') + r
const gg = (g.length < 2 ? '0' : '') + g
const bb = (b.length < 2 ? '0' : '') + b

return `#${rr}${gg}${bb}`
}

function updateUserData() {
return new Promise(async (resolve, reject) => {
Expand Down Expand Up @@ -183,9 +227,19 @@ function updateUserData() {
pageUser = pageUserData;
if(customColor && customColor !== 'none') {
let r = document.querySelector(':root');
let rgb = hex2rgb(customColor);
let ratio = contrast(rgb, [27, 40, 54]);
if(ratio < 4 && vars.darkMode) {
customColor = colorShade(customColor, 80).slice(1);
}
r.style.setProperty('--link-color', `#`+customColor);
} else {
let r = document.querySelector(':root');
let rgb = hex2rgb(oldUser.profile_link_color);
let ratio = contrast(rgb, [27, 40, 54]);
if(ratio < 4 && vars.darkMode) {
oldUser.profile_link_color = colorShade(oldUser.profile_link_color, 80).slice(1);
}
if(oldUser.profile_link_color && oldUser.profile_link_color !== '1DA1F2') r.style.setProperty('--link-color', `#`+oldUser.profile_link_color);
}
if(pageUser.id_str !== user.id_str) followersYouFollow = followersYouFollowData;
Expand Down Expand Up @@ -905,7 +959,7 @@ async function appendTweet(t, timelineContainer, options = {}) {
</span>
</div>
<span class="tweet-time-quote" data-timestamp="${new Date(t.quoted_status.created_at).getTime()}" title="${new Date(t.quoted_status.created_at).toLocaleString()}">${timeElapsed(new Date(t.quoted_status.created_at).getTime())}</span>
<span class="tweet-body-text-quote tweet-body-text-long" style="color:black!important">${t.quoted_status.full_text ? escape(t.quoted_status.full_text).replace(/\n/g, '<br>') : ''}</span>
<span class="tweet-body-text-quote tweet-body-text-long" style="color:var(--default-text-color)!important">${t.quoted_status.full_text ? escape(t.quoted_status.full_text).replace(/\n/g, '<br>') : ''}</span>
${t.quoted_status.extended_entities && t.quoted_status.extended_entities.media ? `
<div class="tweet-media-quote">
${t.quoted_status.extended_entities.media.map(m => `<${m.type === 'photo' ? 'img' : 'video'} ${m.ext_alt_text ? `alt="${escape(m.ext_alt_text)}" title="${escape(m.ext_alt_text)}"` : ''} crossorigin="anonymous" width="${quoteSizeFunctions[t.quoted_status.extended_entities.media.length](m.original_info.width, m.original_info.height)[0]}" height="${quoteSizeFunctions[t.quoted_status.extended_entities.media.length](m.original_info.width, m.original_info.height)[1]}" loading="lazy" ${m.type === 'video' ? 'controls' : ''} ${m.type === 'animated_gif' ? 'loop autoplay muted' : ''} src="${m.type === 'photo' ? m.media_url_https : m.video_info.variants.find(v => v.content_type === 'video/mp4').url}" class="tweet-media-element tweet-media-element-quote ${mediaClasses[t.quoted_status.extended_entities.media.length]} ${!settings.display_sensitive_media && t.quoted_status.possibly_sensitive ? 'tweet-media-element-censor' : ''}">${m.type === 'video' ? '</video>' : ''}`).join('\n')}
Expand Down
2 changes: 1 addition & 1 deletion layouts/search/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ async function appendTweet(t, timelineContainer, options = {}) {
</span>
</div>
<span class="tweet-time-quote" data-timestamp="${new Date(t.quoted_status.created_at).getTime()}" title="${new Date(t.quoted_status.created_at).toLocaleString()}">${timeElapsed(new Date(t.quoted_status.created_at).getTime())}</span>
<span class="tweet-body-text-quote tweet-body-text-long" style="color:black!important">${t.quoted_status.full_text ? escape(t.quoted_status.full_text).replace(/\n/g, '<br>') : ''}</span>
<span class="tweet-body-text-quote tweet-body-text-long" style="color:var(--default-text-color)!important">${t.quoted_status.full_text ? escape(t.quoted_status.full_text).replace(/\n/g, '<br>') : ''}</span>
${t.quoted_status.extended_entities && t.quoted_status.extended_entities.media ? `
<div class="tweet-media-quote">
${t.quoted_status.extended_entities.media.map(m => `<${m.type === 'photo' ? 'img' : 'video'} ${m.ext_alt_text ? `alt="${escape(m.ext_alt_text)}" title="${escape(m.ext_alt_text)}"` : ''} crossorigin="anonymous" width="${quoteSizeFunctions[t.quoted_status.extended_entities.media.length](m.original_info.width, m.original_info.height)[0]}" height="${quoteSizeFunctions[t.quoted_status.extended_entities.media.length](m.original_info.width, m.original_info.height)[1]}" loading="lazy" ${m.type === 'video' ? 'controls' : ''} ${m.type === 'animated_gif' ? 'loop autoplay muted' : ''} src="${m.type === 'photo' ? m.media_url_https : m.video_info.variants.find(v => v.content_type === 'video/mp4').url}" class="tweet-media-element tweet-media-element-quote ${mediaClasses[t.quoted_status.extended_entities.media.length]} ${!settings.display_sensitive_media && t.quoted_status.possibly_sensitive ? 'tweet-media-element-censor' : ''}">${m.type === 'video' ? '</video>' : ''}`).join('\n')}
Expand Down
66 changes: 62 additions & 4 deletions layouts/settings/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,72 @@ chrome.storage.sync.get(['linkColor', 'font', 'heartsNotStars', 'linkColorsInTL'
vars = data;
});
// Util
function luminance(r, g, b) {
var a = [r, g, b].map(function(v) {
v /= 255;
return v <= 0.03928 ?
v / 12.92 :
Math.pow((v + 0.055) / 1.055, 2.4);
});
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
}
function contrast(rgb1, rgb2) {
var lum1 = luminance(rgb1[0], rgb1[1], rgb1[2]);
var lum2 = luminance(rgb2[0], rgb2[1], rgb2[2]);
var brightest = Math.max(lum1, lum2);
var darkest = Math.min(lum1, lum2);
return (brightest + 0.05) /
(darkest + 0.05);
}
const hex2rgb = (hex) => {
if(!hex.startsWith('#')) hex = `#${hex}`;
const r = parseInt(hex.slice(1, 3), 16)
const g = parseInt(hex.slice(3, 5), 16)
const b = parseInt(hex.slice(5, 7), 16)
// return {r, g, b} // return an object
return [ r, g, b ]
}

const colorShade = (col, amt) => {
col = col.replace(/^#/, '')
if (col.length === 3) col = col[0] + col[0] + col[1] + col[1] + col[2] + col[2]

let [r, g, b] = col.match(/.{2}/g);
([r, g, b] = [parseInt(r, 16) + amt, parseInt(g, 16) + amt, parseInt(b, 16) + amt])

r = Math.max(Math.min(255, r), 0).toString(16)
g = Math.max(Math.min(255, g), 0).toString(16)
b = Math.max(Math.min(255, b), 0).toString(16)

const rr = (r.length < 2 ? '0' : '') + r
const gg = (g.length < 2 ? '0' : '') + g
const bb = (b.length < 2 ? '0' : '') + b

return `#${rr}${gg}${bb}`
}
function updateUserData() {
API.verifyCredentials().then(async u => {
user = u;
const event = new CustomEvent('updateUserData', { detail: u });
document.dispatchEvent(event);
renderUserData();
let profileLinkColor = document.getElementById('profile-link-color');
let colorPreview = document.getElementById('color-preview');
let colorPreviewDark = document.getElementById('color-preview-dark');
let colorPreviewLight = document.getElementById('color-preview-light');

let profileColor;
try {
profileColor = await fetch(`https://dimden.dev/services/twitter_link_colors/get/${user.screen_name}`).then(res => res.text());
} catch(e) {};
if(profileColor && profileColor !== 'none') {
profileLinkColor.value = `#`+profileColor;
colorPreview.style.color = `#${profileColor}`;
colorPreviewLight.style.color = `#${profileColor}`;
let rgb = hex2rgb(profileColor);
let ratio = contrast(rgb, [27, 40, 54]);
if(ratio < 4) {
profileColor = colorShade(profileColor, 80).slice(1);
}
colorPreviewDark.style.color = `#${profileColor}`;
}
}).catch(e => {
if (e === "Not logged in") {
Expand Down Expand Up @@ -158,7 +208,8 @@ setTimeout(async () => {
let chrono = document.getElementById('chronological-tl');
let darkMode = document.getElementById('dark-mode');
let showTopicTweets = document.getElementById('show-topic-tweets');
let colorPreview = document.getElementById('color-preview');
let colorPreviewDark = document.getElementById('color-preview-dark');
let colorPreviewLight = document.getElementById('color-preview-light');
let root = document.querySelector(":root");

for(let i in fonts) {
Expand Down Expand Up @@ -216,7 +267,14 @@ setTimeout(async () => {
}, () => { });
});
profileLinkColor.addEventListener('change', () => {
colorPreview.style.color = profileLinkColor.value;
let previewColor = profileLinkColor.value;
colorPreviewLight.style.color = `${previewColor}`;
let rgb = hex2rgb(previewColor);
let ratio = contrast(rgb, [27, 40, 54]);
if(ratio < 4) {
previewColor = colorShade(previewColor, 80);
}
colorPreviewDark.style.color = `${previewColor}`;
});
sync.addEventListener('click', async () => {
let color = profileLinkColor.value;
Expand Down
Loading

0 comments on commit 5056a61

Please sign in to comment.