// ==UserScript==
// @name TweetDeck Custom Background Plus
// @name:ja TweetDeck 背景透過+
// @description Customize background script for Tweetdeck.
// @description:ja Tweetdeckに背景を付けるスクリプトです。
// @match *://tweetdeck.twitter.com/*
// @match *://twitter.com/i/cards/*
// @match *://x.com/i/tweetdeck
// @version 1.01
// @author ziopuzzle
// @namespace https://twitter.com/puzzle_koa/
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @run-at document-start
// ==/UserScript==
// matchに「*://twitter.com/i/cards/*」が存在しますが、Twitterのカード機能がiframeで読み込まれる為、スタイルを適用するために必要になります。
// htmlタグに #tdbgRoot をIDに持つdivタグを作成し、
// 子要素として #tdbg-variable, #tdbg-bg, #tdbg-style をそれぞれIDとするstyleタグを追加します。
// #tdbg-variable : 色情報やその他細かなオプションなどの値をCSSで変数として定義するstyleタグです。
// #tdbg-bg : 背景画像の情報を変数として定義するstyleタグです。
// #tdbg-style : 背景画像を表示させる為の透過や変数を実際に適用するstyleタグです。
(()=>{
'use strict';
const flagSendLog = true;
const flagUIAnimation = true;
// iframe等で読み込まれた場合はスクリプトを無効化
// Disable scripts when loaded in an iframe.
if (window.top !== window.self && new URL(document.referrer).hostname !== 'tweetdeck.twitter.com') {
return;
}
// Twitterのカード機能はiframeで読み込まれる為、例外処理でスタイル適用
// for Twitter Cards
if (location.hostname === 'twitter.com') {
const tag = document.createElement('style');
tag.id = 'tdbg-card';
tag.type = 'text/css';
tag.innerText = '.TwitterCard-container { background-color: ' + GM_getValue('tdbg-color-card', 'rgba(0, 0, 0, 0.5)') + ' !important; }';
document.getElementsByTagName('body').item(0).appendChild(tag);
return;
}
let tag, tagBG, tagVariable, navIconSpace;
let bgMain, bgDrawer;
let colPanel, colColumnHeader, colColumn, colTextBase, colTextName, colTextId, colTextTweet, colTextHashtag, colTextLink;
// deleteData();
initializeScript();
function initializeScript() {
// cssを動的に変更するために用いるstyleタグの作成
makeTag();
//ローディングアイコン書き換え
var svgLoadingSVG = '<?xml version="1.0" encoding="UTF-8"?><svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg"><defs><filter id="outline"><feDropShadow dx="-2" dy="-2" stdDeviation="0" flood-color="#000"></feDropShadow><feDropShadow dx="2" dy="-2" stdDeviation="0" flood-color="#000"></feDropShadow><feDropShadow dx="-2" dy="2" stdDeviation="0" flood-color="#000"></feDropShadow><feDropShadow dx="2" dy="2" stdDeviation="0" flood-color="#000"></feDropShadow></filter></defs><g filter="url(#outline)"><circle class="loader" cx="100" cy="100" r="85" stroke= "#ffffff" stroke-dasharray="533.8" stroke-width="13" fill="none"><animate attributeName="stroke-dashoffset" values="533.8;661.912;533.8" keyTimes="0.0;0.4;1.0" calcMode="spline" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" dur="1.2s" repeatCount="indefinite" /><animateTransform attributeName="transform" attributeType="XML" type="rotate" values="270 100 100;630 100 100;630 100 100" keyTimes="0.0;0.8;1.0" calcMode="spline" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" dur="1.2s" repeatCount="indefinite"/></circle></g></svg>';
var base64LoadingSVG = 'data:image/svg+xml,' + encodeURIComponent(svgLoadingSVG);
const elemAppLoadingImg = document.querySelector('.login-container .block .block img');
elemAppLoadingImg.setAttribute('width', '74px');
elemAppLoadingImg.setAttribute('height', '74px');
elemAppLoadingImg.src = base64LoadingSVG;
//
navIconSpace = GM_getValue('tdbg-navicon-space', 'smallest');
loadData(0x01); //背景読み込み
styleBGUpdate(); // 背景適用
styleUpdate(); // 透過処理とかもあるので1回実行(色はundefinedなのでここでは適用されない)
// Tweetdeckのデフォルトテーマが読み込まれるまで監視
if (flagSendLog) { console.log('[TDBG] Tweetdeck initialize waiting...'); }
const checkElement = document.querySelector('div.js-app');
(new MutationObserver((records, ob) => {
records.some(record => {
if ('class' == record.attributeName) {
const toClass = record.target.getAttribute(record.attributeName);
// div.js-appを監視して、読み込みが終わって.is-hiddenクラスが無くなったタイミングで初期化
if (toClass.match(/(?:(?<=\s)|^)js-app(\s|$)/) && !toClass.match(/(?:(?<=\s)|^)is-hidden(\s|$)/)) {
// 監視終了
ob.disconnect();
// 変数の初期化
if (flagSendLog) { console.log('[TDBG] Initialize...'); }
initializeColor();
loadData(0x02); // 保存されているデータの読み込み
makeObserver(); // SettingsパネルにBackgroundメニューを追加するオブジェクトの作成
styleVariableUpdate(); // 変数の適用
styleUpdate(); // cssを適用
if (flagSendLog) { console.log('[TDBG] Initialize complete!'); }
return true;
}
}
});
})).observe(document.body, { attributes: true, subtree: true });
}
function initializeColor() {
// デフォルトのTweetdeckで使われる色を用いて、色を管理する変数を初期化
const theme = (()=>{ if (!document.querySelector('html.dark')) { return 'light'; } else { return 'dark'; } })();
switch (theme) {
case 'light':
colPanel = '#FFFFFFFF'; colColumnHeader = '#FFFFFFFF'; colColumn = '#FFFFFFFF'; colTextBase = '#FFFFFFFF'; colTextName = '#38444D'; colTextId = '#8899A6'; colTextTweet = '#FFFFFF'; colTextHashtag = '#1DA1F2'; colTextLink = '#1DA1F2';
break;
case 'dark': default:
colPanel = '#15202BFF'; colColumnHeader = '#15202BFF'; colColumn = '#15202BFF'; colTextBase = '#8899A6'; colTextName = '#FFFFFF'; colTextId = '#8899A6'; colTextTweet = '#FFFFFF'; colTextHashtag = '#1DA1F2'; colTextLink = '#1DA1F2';
break;
/*
case 'blue':
colPanel = '#FFFFFFFF'; colColumnHeader = '#000000FF'; colColumn = '#000000FF'; colTextBase = '#FFFFFF'; colTextName = '#FFFFFF'; colTextId = '#FFFFFF'; colTextTweet = '#FFFFFF'; colTextHashtag = '#FFFFFF'; colTextLink = '#FFFFFF';
break;
case 'green':
colPanel = '#FFFFFFFF'; colColumnHeader = '#000000FF'; colColumn = '#000000FF'; colTextBase = '#FFFFFF'; colTextName = '#FFFFFF'; colTextId = '#FFFFFF'; colTextTweet = '#FFFFFF'; colTextHashtag = '#FFFFFF'; colTextLink = '#FFFFFF';
break;
case 'purple':
colPanel = '#FFFFFFFF'; colColumnHeader = '#000000FF'; colColumn = '#000000FF'; colTextBase = '#FFFFFF'; colTextName = '#FFFFFF'; colTextId = '#FFFFFF'; colTextTweet = '#FFFFFF'; colTextHashtag = '#FFFFFF'; colTextLink = '#FFFFFF';
break;
*/
}
}
function deleteData() {
GM_deleteValue('tdbg-bg-main');
GM_deleteValue('tdbg-bg-drawer');
GM_deleteValue('tdbg-navicon-space');
GM_deleteValue('tdbg-color-panel');
GM_deleteValue('tdbg-color-column-header');
GM_deleteValue('tdbg-color-column');
GM_deleteValue('tdbg-color-base');
GM_deleteValue('tdbg-color-name');
GM_deleteValue('tdbg-color-id');
GM_deleteValue('tdbg-color-tweet');
GM_deleteValue('tdbg-color-hashtag');
GM_deleteValue('tdbg-color-link');
}
function saveData(f) {
// bitフラグで種類を指定可能
// 000X : 背景
// 00X0 : 色データ
if (f & 0x01) {
GM_setValue('tdbg-bg-main', bgMain);
GM_setValue('tdbg-bg-drawer', bgDrawer);
}
if (f & 0x02) {
GM_setValue('tdbg-navicon-space', navIconSpace);
GM_setValue('tdbg-color-panel', colPanel);
GM_setValue('tdbg-color-column-header', colColumnHeader);
GM_setValue('tdbg-color-column', colColumn);
GM_setValue('tdbg-color-base', colTextBase);
GM_setValue('tdbg-color-name', colTextName);
GM_setValue('tdbg-color-id', colTextId);
GM_setValue('tdbg-color-tweet', colTextTweet);
GM_setValue('tdbg-color-hashtag', colTextHashtag);
GM_setValue('tdbg-color-link', colTextLink);
}
}
function loadData(f) {
// 保存されているデータの読み込み
// 引数はビットで読み込むデータの指定
// データタイプはsaveDate()を参照
if (f & 0x01) {
bgMain = GM_getValue('tdbg-bg-main', null);
bgDrawer = GM_getValue('tdbg-bg-drawer', null);
}
if (f & 0x02) {
navIconSpace = GM_getValue('tdbg-navicon-space', 'smallest');
colPanel = GM_getValue('tdbg-color-panel', colPanel);
colColumnHeader = GM_getValue('tdbg-color-column-header', colColumnHeader);
colColumn = GM_getValue('tdbg-color-column', colColumn);
colTextBase = GM_getValue('tdbg-color-base', colTextBase);
colTextName = GM_getValue('tdbg-color-name', colTextName);
colTextId = GM_getValue('tdbg-color-id', colTextId);
colTextTweet = GM_getValue('tdbg-color-tweet', colTextTweet);
colTextHashtag = GM_getValue('tdbg-color-hashtag', colTextHashtag);
colTextLink = GM_getValue('tdbg-color-link', colTextLink);
}
}
function makeObserver() {
// Settingsパネルの開閉を監視し、Backgroundsメニューの追加を行うオブジェクトの作成
(new MutationObserver((records, ob) => {
const nav = document.querySelector(".settings-modal");
if (nav) {
ob.disconnect();
(new MutationObserver(records => {
records.forEach(record => {
record.addedNodes.forEach(node => {
const menu = node.querySelector("ul.js-setting-list");
if (menu) appendMenu(menu);
});
});
})).observe(nav, { childList: true });
}
})).observe(document.body, { childList: true, subtree: true });
}
// 変更時適用にしてしまうとカラーピッカーで色をスライドするだけで重くなってしまうため、一定時間そのままなら適用。
let colorChanegeWait = null;
function funcInputColorWait(e) {
if (colorChanegeWait) clearTimeout(colorChanegeWait);
colorChanegeWait = setTimeout(funcInputColor, 100, e);
}
function funcInputColor(e) {
colorChanegeWait = null;
if (null == document.getElementById('tdbg-colorpicker-panel')) return true;
if (null == document.getElementById('tdbg-colorpicker-column-header')) return true;
if (null == document.getElementById('tdbg-colorpicker-column')) return true;
colPanel = document.getElementById('tdbg-colorpicker-panel').value + parseInt(document.getElementById('tdbg-colorslider-panel').value).toString(16).padStart(2,'0');
colColumnHeader = document.getElementById('tdbg-colorpicker-column-header').value + parseInt(document.getElementById('tdbg-colorslider-column-header').value).toString(16).padStart(2,'0');
colColumn = document.getElementById('tdbg-colorpicker-column').value + parseInt(document.getElementById('tdbg-colorslider-column').value).toString(16).padStart(2,'0');
colTextBase = document.getElementById('tdbg-colorpicker-base').value;
colTextTweet = document.getElementById('tdbg-colorpicker-tweet').value;
colTextHashtag = document.getElementById('tdbg-colorpicker-hashtag').value;
colTextLink = document.getElementById('tdbg-colorpicker-link').value;
// const selectColorPreset = document.querySelector('#tdbg-select-colorpreset');
// selectColorPreset.value = 'custom';
styleVariableUpdate();
saveData(0x02);
}
function funcInputPicture(e) {
const elmID = e.target.id;
const preview = document.getElementById(elmID + '-preview');
const url = document.getElementById(elmID + '-url');
const file = document.getElementById(elmID).files[0];
const reader = new FileReader();
reader.addEventListener('load', function () { // reader.result is base64
//preview.src = dataURItoObjectURL(reader.result);
preview.src = reader.result;
url.value = '[fileinput]';
if (elmID == 'tdbg-main-input') bgMain = reader.result;
if (elmID == 'tdbg-drawer-input') bgDrawer = reader.result;
styleBGUpdate();
saveData(0x01);
}, false);
if (file) {
reader.readAsDataURL(file);
}
// styleBGUpdate();
}
function funcRadioIconSpace(e) {
navIconSpace = e.target.value;
styleVariableUpdate();
saveData(0x02);
}
// 設定パネルを開いた際にこのユーザースクリプト用の設定ができる項目を"Backgrounds"として追加
function appendMenu(menu) {
const list = document.querySelectorAll("ul.js-setting-list li:not(.tdbg-setting)");
list.forEach(v => {v.addEventListener("click", event => {document.querySelector(".tdbg-setting").classList.remove("selected");});});
const a = document.createElement("a");
a.href = "#";
a.className = "list-link";
a.dataset.action = "background";
a.innerHTML = "<strong>Backgrounds</strong>";
a.addEventListener("click", event => openSettings());
const li = document.createElement("li");
li.className = "tdbg-setting";
li.appendChild(a);
menu.appendChild(li);
}
// 設定パネルの中の"Backgrounds"セクションをクリックした際にメニューを表示
function openSettings() {
document.querySelector("ul.js-setting-list li.selected:not(.td-userscript-background-setting)").classList.remove("selected");
const menu = document.querySelector(".tdbg-setting:not(.selected)");
// セレクタで発見できなかったら関数を抜ける
if (menu == undefined || menu == null) { return true; }
menu.classList.add("selected");
const form = document.querySelector("#global-settings");
const nonebg = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAADklEQVR4nGNgGAWDEwAAAZoAAR2CVqgAAAAASUVORK5CYII=';
form.innerHTML = `
<fieldset id="tdbg-settings">
<legend>Backgrounds Settings</legend>
<!--
<div>
<i class="icon icon-small color-twitter-blue js-toggle-switch is-actionable align-top icon-toggle-off" id="tdbg-hide-modalshadow"></i>
<span class="margin-l--4">Hide shadow(Temporary)</span>
</div>
<div class="divider-bar"></div>
-->
<div class="control-group">
<label class="control-label">Navigate Icon space</label>
<div class="tdbg-radio-group item-3 controls">
<label>
<input type="radio" name="navIconSpace" value="default">
Default
</label>
<label>
<input type="radio" name="navIconSpace" value="small">
Small
</label>
<label>
<input type="radio" name="navIconSpace" value="smallest">
Smallest
</label>
</div>
</div>
<div class="divider-bar"></div>
<!--
<div class="tdbg-controls">
<select id="tdbg-theme-select" class="tdbg-select-container" name="ThemeSelect"></select>
<div class="tdbg-theme-new">
<button>New</button>
</div>
<div class="tdbg-theme-delete">
<button>Delete</button>
</div>
</div>
-->
<div>
<div class="tdbg-controls">
<div>
<div class="tdbg-input-container">
<div class="tdbg-control-group">
<span>Main Background</span>
<div>
<label>
<div>📄</div>
<input id="tdbg-main-input" type="file" accept="image/*">
</label>
</div>
<div>
<input id="tdbg-main-input-url" type="text" name="inputBGMainImageorURL" placeholder="https://" pattern="^((https://.*)|(\[fileinput\]))$" title="URLはhttpsから始まる必要があります">
</div>
</div>
<div class="tdbg-controls">
<img id="tdbg-main-input-preview" class="tdbg-input-preview" src="' + nonebg + '" width="150" height="100" alt="Image preview...">
</div>
</div>
</div>
<div>
<div class="tdbg-input-container">
<div class="tdbg-control-group">
<span>Drawer Background</span>
<div>
<label>
<div>📄</div>
<input id="tdbg-drawer-input" type="file" accept="image/*">
</label>
</div>
<div>
<input id="tdbg-drawer-input-url" type="text" name="inputBGDrawerImageorURL" placeholder="https://" pattern="^((https://.*)|(\[fileinput\]))$" title="URLはhttpsから始まる必要があります">
</div>
</div>
<div class="tdbg-controls">
<img id="tdbg-drawer-input-preview" class="tdbg-input-preview" src="' + nonebg + '" width="150" height="100" alt="Image preview...">
</div>
</div>
</div>
</div>
<div style="clear:both;">
<!--
<div>Color Preset</div>
<select id="tdbg-select-colorpreset" class="tdbg-select-container" name="color preset">
<option value="custom">Custom</option>
<option value="light">Light(Default theme)</option>
<option value="dark">Dark(Default Dark theme)</option>
<option value="blue">Blue</option>
<option value="green">Green</option>
<option value="purple">Purple</option>
</select>
-->
<div id="tdbg-setting-color">
<div class="tdbg-flex tdbg-flex-row">
<div class="tdbg-flex tdbg-flex-column tdbg-flex-space-around">
<label class="tdbg-colorpicker"><span>Panel</span><input id="tdbg-colorpicker-panel" type="color"></label>
<label class="tdbg-colorpicker"><span>ColumnHeader</span><input id="tdbg-colorpicker-column-header" type="color"></label>
<label class="tdbg-colorpicker"><span>Column</span><input id="tdbg-colorpicker-column" type="color"></label>
</div>
<div class="tdbg-flex tdbg-flex-column tdbg-flex-space-around tdbg-flex-auto">
<label class="tdbg-colorslider"><input id="tdbg-colorslider-panel" type="range" min="0" max="255"></label>
<label class="tdbg-colorslider"><input id="tdbg-colorslider-column-header" type="range" min="0" max="255"></label>
<label class="tdbg-colorslider"><input id="tdbg-colorslider-column" type="range" min="0" max="255"></label>
</div>
</div>
<!--
<div class="tdbg-colorpicker-alpha">
<label class="tdbg-colorpicker">Panel<input id="tdbg-colorpicker-panel" type="color"></label>
<label class="tdbg-colorslider"><input id="tdbg-colorslider-panel" type="range" min="0" max="255"></label>
</div>
<div class="tdbg-colorpicker-alpha">
<label class="tdbg-colorpicker">Column<input id="tdbg-colorpicker-column" type="color"></label>
<label class="tdbg-colorslider"><input id="tdbg-colorslider-column" type="range" min="0" max="255"></label>
</div>
-->
<label class="tdbg-colorpicker">Base<input id="tdbg-colorpicker-base" type="color"></label>
<label class="tdbg-colorpicker">Name<input id="tdbg-colorpicker-name" type="color"></label>
<label class="tdbg-colorpicker">Tweet<input id="tdbg-colorpicker-tweet" type="color"></label>
<label class="tdbg-colorpicker">Hashtag<input id="tdbg-colorpicker-hashtag" type="color"></label>
<label class="tdbg-colorpicker">Link<input id="tdbg-colorpicker-link" type="color"></label>
</div>
</div>
</div>
</fieldset>
`;
document.querySelector('input[name=navIconSpace][value=' + navIconSpace + ']').checked = true;
document.getElementById('tdbg-colorpicker-panel').value = colPanel.match(/#.{6}/)[0];
document.getElementById('tdbg-colorslider-panel').value = parseInt(colPanel.match(/(?<=#.{6}).{2}/)[0], 16);
document.getElementById('tdbg-colorpicker-column-header').value = colColumnHeader.match(/#.{6}/)[0];
document.getElementById('tdbg-colorslider-column-header').value = parseInt(colColumnHeader.match(/(?<=#.{6}).{2}/)[0], 16);
document.getElementById('tdbg-colorpicker-column').value = colColumn.match(/#.{6}/)[0];
document.getElementById('tdbg-colorslider-column').value = parseInt(colColumn.match(/(?<=#.{6}).{2}/)[0], 16);
document.getElementById('tdbg-colorpicker-base').value = colTextBase;
document.getElementById('tdbg-colorpicker-name').value = colTextName;
document.getElementById('tdbg-colorpicker-tweet').value = colTextTweet;
document.getElementById('tdbg-colorpicker-hashtag').value = colTextHashtag;
document.getElementById('tdbg-colorpicker-link').value = colTextLink;
const radioIconSpace = document.getElementsByName('navIconSpace');
for (let i = 0; i < radioIconSpace.length; i++) { radioIconSpace[i].addEventListener("click", funcRadioIconSpace); }
const inputMain = document.querySelector("#tdbg-main-input");
inputMain.addEventListener('input', funcInputPicture );
if (bgMain !== undefined && bgMain !== null) {
document.querySelector("#tdbg-main-input-preview").src = bgMain;
if (isAcceptURL(bgMain)) document.querySelector("#tdbg-main-input-url").value = bgMain; else document.querySelector("#tdbg-main-input-url").value = '[fileinput]';
}
const inputDrawer = document.querySelector("#tdbg-drawer-input");
inputDrawer.addEventListener('input', funcInputPicture );
if (bgDrawer !== undefined && bgDrawer !== null) {
document.querySelector("#tdbg-drawer-input-preview").src = bgDrawer;
if (isAcceptURL(bgDrawer)) document.querySelector("#tdbg-drawer-input-url").value = bgDrawer; else document.querySelector("#tdbg-drawer-input-url").value = '[fileinput]';
}
const inputColorPickers = document.querySelectorAll('.tdbg-colorpicker input, .tdbg-colorslider input');
inputColorPickers.forEach( function (elm) { elm.addEventListener('input', funcInputColorWait); });
const selectColorPreset = document.querySelector('#tdbg-select-colorpreset');
//const isDark = document.querySelector('html.dark') != null;
//if (isDark) {selectColorPreset.value = 'dark';} else {selectColorPreset.value = 'light';}
selectColorPreset.value = 'custom';
selectColorPreset.addEventListener('change', (event) => {
selectColorPreset.value
});
}
// ファイルとURLを同じ変数で扱うため、URLか否かをチェックするための関数
function isAcceptURL(str) {
const regex = /^https:\/\/.*/;
return regex.test(str);
}
// URIじゃなくてblobで表示させたかったんだけどあれなのでblobにしたかったけどTweetdeckのContent Security Policyに引っかかってしまう
/*
function dataURItoBlob(data) {
// URIからblobを作成します。
var dataURI = data;
var byteString = atob( dataURI.split(',')[1] ) ;
var mimeType = dataURI.match( /(:)([a-z\/]+)(;)/ )[2];
for ( var i=0, l=byteString.length, content=new Uint8Array(l); l>i; i++ ) {
content[i] = byteString.charCodeAt(i);
}
return new Blob([ content ], { type: mimeType });
}
function dataURItoObjectURL(data) {
// URIから作成したblobのURLを取得します
const blob = dataURItoBlob(data);
return blob? URL.createObjectURL(blob): null;
}
*/
// 動的にcssを変更するためにstyleタグを作成するための関数
function makeTag() {
if (!document.getElementById('tdbgRoot')) {
// いくつかのStyleタグを作成するのでひとまとめにするためのdivタグを作成
const tagTDBG = document.createElement('div');
tagTDBG.id = 'tdbgRoot';
document.getElementsByTagName('html').item(0).appendChild(tagTDBG);
const tagsID = ['tdbg-variable', 'tdbg-bg', 'tdbg-style'];
let tagsElement = [];
tagsID.forEach(v => {
const styleTag = document.createElement('style');
styleTag.id = v;
styleTag.type = 'text/css';
tagTDBG.appendChild(styleTag);
tagsElement.push(styleTag);
});
tagVariable = tagsElement.shift();
tagBG = tagsElement.shift();
tag = tagsElement.shift();
}
}
function styleVariableUpdate() {
let style = '';
// 変数設定
const tableNavIconSpace = { default: 45, small: 35, smallest: 31 };
let _navIconSpacePixel = tableNavIconSpace.default;
if (navIconSpace in tableNavIconSpace) _navIconSpacePixel = tableNavIconSpace[navIconSpace];
(()=>{
style += ':root {';
if (colPanel !== undefined) style += '--tdbg-color-panel: ' + colPanel + ';';
if (colColumnHeader !== undefined) style += '--tdbg-color-column-header: ' + colColumnHeader + ';';
if (colColumn !== undefined) style += '--tdbg-color-column: ' + colColumn + ';';
if (colTextTweet !== undefined) style += '--tdbg-color-tweet: ' + colTextTweet + ';';
if (colTextHashtag !== undefined) style += '--tdbg-color-hashtag: ' + colTextHashtag + ';';
if (colTextLink !== undefined) style += '--tdbg-color-link: ' + colTextLink + ';';
style += '--tdbg-color-accent: rgb(224, 192, 128);';
style += '--tdbg-color-accent-text: #4040FF;';
style += '--tdbg-color-subaccent: rgb(160, 128, 192);';
style += '--tdbg-navicon-space: ' + _navIconSpacePixel + 'px;';
style += '}';
})();
tagVariable.innerText = style;
}
function styleBGUpdate() {
let style = '';
if (bgMain !== undefined && bgMain !== null) style += 'body { background-image: url("' + bgMain + '") !important; }'; else style += 'body { background: #4080A0 !important; }';
if (bgDrawer !== undefined && bgDrawer !== null) style += '.drawer { background-image: url("' + bgDrawer + '") !important; }'; else style += '.drawer { background: #206080 !important; }';
tagBG.innerText = style;
}
function styleUpdate() {
// styleタグを書き換えることでcssを適用
// 管理用styleタグが存在しないときはコンソールにエラー
if (tag == null) { console.error('[TDBG] Failed to apply the css because the "#tdbg-style" style tag was not found.'); return true; }
let style = '';
// 色を設定する部分
(()=>{
// タイムラインパネルやポップアップパネルの色
if (colPanel !== undefined) {
style += '#settings-modal .js-modal-panel, .js-modal-inner { background-color: var(--tdbg-color-panel) !important; }';
// カラム追加ポップアップ
style += '.mdl:not(.med-fullpanel) { background-color: var(--tdbg-color-panel) !important; }';
// 検索ポップアップ
style += '.popover { background-color: #000000A0 !important; }';
style += '.popover .caret-inner { border-bottom-color: var(--tdbg-color-panel) !important; }'
style += '.js-popover-content { background-color: var(--tdbg-color-panel) !important; border-radius: 14px !important; }'
}
// カラム(およびカラムヘッダー)の色
if (colColumnHeader !== undefined) {
style += '.column .column-header, .column-options { background-color: var(--tdbg-color-column-header) !important; }';
}
if (colColumn !== undefined) {
style += '.column .column-scroller, .column-message { background-color: var(--tdbg-color-column) !important; }';
} else {
style += '.column .column-scroller, .column-message { background-color: rgba(0, 0, 0, 0.7) !important; }';
}
// ツイートに関する色
if (colTextTweet !== undefined) style += '.tweet-text { color: var(--tdbg-color-tweet) !important }';
if (colTextHashtag !== undefined) style += '[rel=hashtag] { color: var(--tdbg-color-hashtag) !important }';
if (colTextLink !== undefined) style += '[data-full-url] { color: var(--tdbg-color-link) !important; }';
// カラムヘッダー部の更新通知の色
style += '.is-new .column-type-icon { color: var(--tdbg-color-accent) !important; }';
style += '.more-tweets-glow { background: radial-gradient(ellipse farthest-corner at 50% 100%, var(--tdbg-color-accent) 0, var(--tdbg-color-accent) 25%,hsla(0,0%,100%,0) 75%) !important; }';
// ナビゲーションバーの更新通知ドット
style += '.column-nav-updates { color: var(--tdbg-color-accent) !important; }';
// ナビゲーションバーでカラムを選択した際に選択されたカラムの周りに表示されるボーダーの色
style += '.column.is-focused { box-shadow: 0 0 0 2px var(--tdbg-color-accent) !important; }';
// スクロールバーの色
style += '.antiscroll-scrollbar, ::-webkit-scrollbar-thumb { background-color: var(--tdbg-color-accent) !important; }'; //"::-webkit-scrollbar-thumb" for Blink and WebKit base browser
style += '* { scrollbar-color: var(--tdbg-color-accent) !important; }'; //"scrollbar-color" property for Firefox
// 各種アイコン
style += '.column-header-link, .app-nav-link, .app-nav-tab, .app-search-fake { color: var(--tdbg-color-accent) !important; }';
style += '.lst-launcher .icon, html .lst-launcher .is-disabled .icon, html.dark .lst-launcher .is-disabled .icon, html .lst-launcher .is-disabled a:hover .icon, html.dark .lst-launcher .is-disabled a:hover .icon,';
style += 'html .lst-launcher .is-disabled a:focus .icon, html.dark .lst-launcher .is-disabled a:focus .icon { color: var(--tdbg-color-accent) !important; }';
style += '.app-search-fake { color: var(--tdbg-color-accent) !important; border-color: var(--tdbg-color-accent) !important; background-color: transparent !important; }';
// 各種ボタン
style += '.Button, input[type="button"], button { color: var(--tdbg-color-accent) !important; border-color: var(--tdbg-color-accent) !important; }';
// 各種アクション時
style += '.list-item.is-selected, .list-item:hover, html .lst-group .selected, html.dark .lst-group .selected,';
style += 'html .dropdown-menu .is-selectable.is-selected a , html.dark .dropdown-menu .is-selectable.is-selected a { color: var(--tdbg-color-accent-text) !important; background-color: var(--tdbg-color-accent) !important; }';
// 背景を伴うアクション時
style += '.lst-profile a:hover i, .lst-profile a:hover span, .lst-group a:hover strong, .lst-group a:hover span { color: var(--tdbg-color-accent) !important; background-color: var(--tdbg-color-accent-text) !important; }'
// 各種テキスト
style += '.txt-link, a:hover, a:active { color: var(--tdbg-color-accent) !important; }';
//
// style += '.txt-mute { color: var(--tdbg-color-subaccent) !important; }';
style += '.lst-group .selected a:hover { color: var(--tdbg-color-subaccent) !important; }';
style += '.lst-group .selected strong, .lst-group .selected span { color: var(--tdbg-color-accent-text) !important; }';
// 引用ツイート
style += '.quoted-tweet, .TwitterCard-container { background-color: rgba(0, 0, 0, 0.4) !important; }';
//
style += 'input[type=text], .detail-view-inline-text { background-color: #000000A0 !important; }'
})();
// 背景を設定する部分
(()=>{
// 背景が無い部分ができないように覆う設定
style += 'body { background-size: cover !important; background-position: center center !important; }';
style += '.drawer { background-size: cover !important; background-position: center center !important; }';
})();
// 背景を表示するために透過色を設置する部分
(()=>{
// 全体の透過
style += '.app-content, .app-columns-container { background-color: transparent !important; }';
// ポップアップの透過
style += '.mdl-column-med, .med-fullpanel, .prf-meta { background-color: transparent !important; }'
// ドロワーの透過
style += '.compose, .old-composer-footer,';
style += 'html .accounts-drawer, html.dark .accounts-drawer { background-color: transparent !important; }';
// カラムの透過
style += '.column-panel, .column-content { background-color: transparent !important; }';
// カラムヘッダーの透過
style += '.button-tray, .facet-type { background-color: transparent !important; }';
// ツイート関係の透過
// ツイートの透過
style += 'article { background-color: transparent !important; }';
// ツイート詳細の透過
style += '.column-scroller, .tweet-detail-wrapper, .detail-view-inline { background-color: transparent !important; }';
style += '.inline-reply, .reply-triangle { background-color: transparent !important; }';
// カラム透過
style += '.column { background-color: transparent !important; }';
// ポップアップにカラムが表示される際の透過
style += '.column-header-temp { background-color: transparent !important; }';
// 404ページ用
style += '.srt-holder .container { padding: 12px; background-color: rgba(0, 0, 0, 0.5); border-radius: 15px; }';
})();
// 背景設定画面
(()=>{
style += '#tdbg-settings .control-group { height: 1em; }';
style += '.tdbg-radio-group label { float: left; padding-top: 6px; }';
style += '.tdbg-radio-group.item-3 label { width: 33%; }';
style += '.tdbg-colorpicker { float: left !important; padding-right: 10px; }';
style += '.tdbg-colorpicker input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }';
style += '.tdbg-colorpicker input[type="color"]::-webkit-color-swatch { border: none; }';
style += `.tdbg-colorpicker input[type="color"] {
-webkit-appearance: none;
padding: 0;
background-color: rgba(0,0,0,0);
width: 1em;
height: 1em;
margin-left: 3px;
border-radius: 0;
border: 1px solid #FFFFFF;
float: right;
}`;
// panelの色は透過度も設定できるようにしたいのでスライダーも存在する
style += '#tdbg-setting-color .tdbg-flex .tdbg-colorpicker { vertical-align: middle; height: 2em; width: 115px; }';
style += '#tdbg-setting-color .tdbg-flex .tdbg-colorslider { vertical-align: middle; height: 2em; }';
style += '.tdbg-input-container label { padding: 4px 8px;}';
style += '.tdbg-input-container .tdbg-input-preview { object-fit: cover; border: solid 1px; }';
style += '.tdbg-input-container div { padding-bottom: 10px; }';
style += '.tdbg-input-container .tdbg-control-group { float: left; width: 360px; margin-top: 5px; }';
style += '.tdbg-input-container .tdbg-controls { float: right; }';
style += '.tdbg-input-container label > input[type=file]::-webkit-file-upload-button { display: none; }';
style += '.tdbg-input-container label > input[type=file] { flex: 1; }';
style += '.tdbg-input-container label { padding: 0; display: flex; }';
style += '.tdbg-input-container label div { position: absolute; padding: 6px; }';
style += '.tdbg-input-container label > input[type=file] { padding-left: 25px; }';
style += '.tdbg-flex { display: flex; }';
style += '.tdbg-flex-row { flex-direction: row; }';
style += '.tdbg-flex-column { flex-direction: column; }';
style += '.tdbg-flex-auto { flex-grow: 1; }';
})();
// 見栄えの為の調整
(()=>{
// ロードアイコンがgifなので背景色が背景を透過した際に見栄えが悪いため非表示
// style += '.login-container img:not(.tdbg-img) { display: none; }';
// カラムの角を丸める
style += '.column { border-radius: 15px !important; }';
// カラム間の余白を詰めて上下にも余白を取る
style += '.app-columns { padding: 2px 0 2px 2px !important; }';
style += '.column { margin: 0 2px 0 0 !important; }';
// ナビゲーションバーのアイコン間の余白を詰める
style += '.column-nav-item { height: var(--tdbg-navicon-space) !important; }';
// ナビゲーションバーのスクロールバーが透明だと使いづらいので半透明に修正
style += '.antiscroll-scrollbar { opacity: 0.5 !important; }';
style += '.antiscroll-scrollbar-shown { opacity: 1.0 !important; }';
//
style += '.app-header:not(.is-condensed) .app-search-fake .icon { opacity: 0; }';
// インラインリプライの余白を詰める
style += 'html .inline-reply > div, html.dark .inline-reply > div { padding-top: 0 !important; }';
style += '.compose-text-container { margin-top: 0px !important; }';
// リプライ入力ボックスの透過度を揃える
style += '.detail-view-inline-text { background-color: rgba(0,0,0,0.4) !important; }';
// ボーダー統一
style += '[dir=ltr] [role=button], .r-aaos50, .column { border: solid 1px !important; }';
style += '.new-composer-bottom-button, .r-18qmn74 { border: solid 1px !important; background-color: rgba(0, 0, 0, .5) !important; border-radius: 30px !important; }';
style += '.compose-reply-tweet { border: solid 1px !important; }';
style += '.app-content *:not(span):not(.replyto-caret), ::-webkit-scrollbar-track, [dir=ltr] [role=button], .r-aaos50, .r-18qmn74 { border-color: #808080 !important; }';
// ポップアップを開いた際に後ろの画面を透過
style += 'html:not(.btd-on) .med-fullpanel { background-color: #00000000 !important; }';
style += 'html:not(.btd-on) .ovl, html:not(.btd-on) .overlay { background: #000000CC !important; }';
// 404ページのheightが0になっていて背景の表示がおかしくなるのを修正
style += 'html { height: 100%; }';
})();
// TeamInvitationsカラムが見えちゃうことがあるため、開いてないときは見えないようにする
style += '.js-team-invitations-container, .drawer:not(.is-shifted-1) .js-contributor-manager-container { display: none !important; }';
// アニメーション
(()=>{
if (!flagUIAnimation) return;
// ナビゲーションバーのアイコン間の余白が変わったときに滑らかに推移
style += '.column-nav-item { transition: height 0.3s ease-out; }';
// ページロード時にカラムポップアップ演出
// style += '@keyframes fadeIn { 0% { transform: scale(0,0); opacity: 0; animation-timing-function: cubic-bezier(.3,1.52,.51,.89); } 100% { transform: scale(1); opacity: 1; }}';
// style += '.column { animation-name: fadeIn; animation-duration: 0.8s; animation-fill-mode: backwards; }';
// const columns = document.querySelectorAll('.app-columns > section');
// columns.forEach(function(e,i){ style += '.column:nth-of-type(' + (i + 1) + ') { animation-delay: ' + 0.07 * i + 's; }'; });
})();
// BetterTweetdeck導入時の修正
(()=>{
// BetterTweetdeckの設定画面を開くナビアイコンが増えたことにより、ナビアイコン列の最後が隠れてしまうのを修正
style += '.btd-loaded .column-navigator.column-navigator-overflow { height: calc(100% - 409px) !important; }';
// ツイート詳細画面のリプライ吹き出しに不自然なマージンが取られているのを修正
style += '.btd-loaded .inline-reply, .detail-view-inline { margin-top: 0px !important; }';
// カラム折りたたみ時にボーダー線が重なるのを修正
style += '.btd-column-collapsed .column-header { border: solid 0px !important }';
// カラム折りたたみ時にカラム透過色が見えてしまうのを修正(不自然な横幅を修正)
style += 'html .app-content section.column.btd-column-collapsed { width: 50px !important; }';
// 設定画面の一時的に影を消す設定を有効にしたときの補正
style += 'html.btd-on #settings-modal.ovl.tdbg-bgtransparent { background: transparent !important; }';
})();
tag.innerText = style;
}
})();