fix: UIの色設定をダークモードに対応させ、視認性を向上

This commit is contained in:
harukin-expo-dev-env
2026-03-26 08:56:31 +00:00
parent cae85fd014
commit a4e3e0833d
13 changed files with 131 additions and 23 deletions
+113 -11
View File
@@ -18,6 +18,8 @@ export interface InjectJavascriptOptions {
useUnyohub: string;
/** えれサイト使用スイッチ ("true" | "false") */
useElesite: string;
/** ダークモードかどうか */
isDark: boolean;
}
export const injectJavascriptData = ({
@@ -28,6 +30,7 @@ export const injectJavascriptData = ({
uiSetting,
useUnyohub,
useElesite,
isDark,
}: InjectJavascriptOptions): string => {
// 一番上のメニュー非表示 地図スイッチによって切り替え
const topMenu =
@@ -49,11 +52,73 @@ export const injectJavascriptData = ({
// 上部ヘッダーの取り扱い、自動再読み込み、setStringsの実行
const bootData = `
// 停止中 点滅アニメーション CSS を動的注入
// ダークモードフラグ & テーマ色定数
const _isDark = ${isDark};
const _t = _isDark
? { bg:'#0d1117', bgSec:'#161b22', bgTer:'#21262d', text:'#e6edf3', textSec:'#8b949e', border:'#30363d', cardBg:'#48505acc', shadow:'rgba(0,0,0,0.5)' }
: { bg:'#ffffff', bgSec:'#f8f8fc', bgTer:'#f0f0f0', text:'#000000', textSec:'#555555', border:'#cccccc', cardBg:'#ffffffcc', shadow:'rgba(0,0,0,0.2)' };
// ダークモード用: インライン背景色をHSL変換で暗くするヘルパー
// 彩度を維持しつつ明度(L)を指定値に設定
const _darkenBg = _isDark ? function(el, targetL) {
try {
var bg = el.style.backgroundColor;
if (!bg || bg === 'transparent') return;
var m = bg.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);
if (!m) return;
var r = +m[1]/255, g = +m[2]/255, b = +m[3]/255;
var mx = Math.max(r,g,b), mn = Math.min(r,g,b);
var l = (mx+mn)/2;
if (l < 0.12) return;
var h = 0, s = 0, d = mx - mn;
if (d > 0) {
s = l > 0.5 ? d/(2-mx-mn) : d/(mx+mn);
if (mx===r) h = ((g-b)/d + (g<b?6:0))/6;
else if (mx===g) h = ((b-r)/d+2)/6;
else h = ((r-g)/d+4)/6;
}
var nl = targetL || 0.18;
var ns = Math.min(s * 0.85, 0.7);
var hue2rgb = function(p,q,t) {
if(t<0)t+=1; if(t>1)t-=1;
if(t<1/6) return p+(q-p)*6*t;
if(t<1/2) return q;
if(t<2/3) return p+(q-p)*(2/3-t)*6;
return p;
};
var q2 = nl < 0.5 ? nl*(1+ns) : nl+ns-nl*ns;
var p2 = 2*nl - q2;
var nr = hue2rgb(p2,q2,h+1/3);
var ng = hue2rgb(p2,q2,h);
var nb = hue2rgb(p2,q2,h-1/3);
el.style.backgroundColor = 'rgb('+(nr*255|0)+','+(ng*255|0)+','+(nb*255|0)+')';
} catch(e) {}
} : function(){};
// 停止中 点滅アニメーション CSS + ダークモード CSS を動的注入
(function(){
const s = document.createElement('style');
s.textContent = '@keyframes _jrs_blink{0%,55%{opacity:1}70%,90%{opacity:0}100%{opacity:1}}' +
'@keyframes _jrs_glow{0%,55%{box-shadow:0 0 12px 3px rgba(255,0,0,0.9)}70%,90%{box-shadow:0 0 6px 2px rgba(255,0,0,0.45)}100%{box-shadow:0 0 12px 3px rgba(255,0,0,0.9)}}';
'@keyframes _jrs_glow{0%,55%{box-shadow:0 0 12px 3px rgba(255,0,0,0.9)}70%,90%{box-shadow:0 0 6px 2px rgba(255,0,0,0.45)}100%{box-shadow:0 0 12px 3px rgba(255,0,0,0.9)}}'
+ (_isDark ? (
'html,body{background-color:#2b2f36!important;}'
+ '#main{background-color:#2b2f36!important;}'
+ '#disp{background-color:transparent!important;}'
+ '#header{background-color:#343a42!important;color:#e6edf3!important;border-bottom:1px solid #444c56!important;}'
+ '#headerStr{color:#e6edf3!important;}'
+ '#topHeader{background-color:#343a42!important;border-bottom:1px solid #444c56!important;}'
+ '#topHeader div{color:#e6edf3!important;}'
+ '#topHeader .accordion{background-color:#3b4148!important;color:#e6edf3!important;}'
+ '[id^="stationBlock"]{background-color:rgba(0,0,0,0.55)!important;}'
+ '#disp>[id*=""]{background-color:rgba(0,0,0,0.35)!important;}'
+ '#pMENU_2,#pMENU_3,#pMENU_k{background-color:#343a42!important;border-color:#444c56!important;}'
+ '#pMENU_2 div,#pMENU_3 div,#pMENU_k div{color:#e6edf3!important;}'
+ '#modal_content{background-color:#343a42!important;color:#e6edf3!important;}'
+ '#modal_content button{background-color:#3b4148!important;color:#e6edf3!important;border-color:#444c56!important;}'
+ '.accordionClass{background-color:#343a42!important;color:#e6edf3!important;}'
+ 'select{background-color:#3b4148!important;color:#e6edf3!important;border-color:#444c56!important;}'
+ '#upTrainCrossBar,#dwTrainCrossBar{opacity:0.85!important;}'
) : '');
document.head.appendChild(s);
})();
@@ -752,7 +817,7 @@ export const injectJavascriptData = ({
gradient = getColors[0];
}
const optionalTextColor = optionalText.includes("最終") ? "red" : "black";
const optionalTextColor = optionalText.includes("最終") ? "red" : _t.text;
const unyohubFormation = getUnyohubFormation(列番データ);
const hasUnyohub = unyohubFormation !== null;
const unyohubStale = hasUnyohub && isUnyohubStale(列番データ);
@@ -797,11 +862,11 @@ export const injectJavascriptData = ({
badgeHtml += "<div style='position:absolute;" + badgePosition + ":0;" + offsetStyle + "background-color:#44bb44;border-radius:50%;border:1px solid #228822;width:19px;height:19px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;'><span style='color:white;font-size:10px;font-weight:bold;line-height:1;'>E</span></div>";
}
行き先情報.insertAdjacentHTML('beforebegin', "<div style='width:100%;display:flex;flex:1;flex-direction:"+(isLeft ? "column-reverse" : "column") + ";font-weight:bold;'>" + badgeHtml + "<p style='font-size:6px;padding:0;color:black;text-align:center;'>" + (TrainNumberOverride ? TrainNumberOverride : TrainNumber) + "</p><div style='flex:1;'></div><p style='font-size:8px;font-weight:bold;padding:0;color: black;text-align:center;'>" + (isWanman ? "ワンマン " : "") + "</p><p style='font-size:6px;font-weight:bold;padding:0;color: black;text-align:center;border-style:solid;border-width: "+(!!yosan2Color ? "2px" : "0px")+";border-color:" + yosan2Color + "'>" + viaData + "</p><p style='font-size:6px;font-weight:bold;padding:0;color: " + optionalTextColor + ";text-align:center;'>" + optionalText + "</p><p style='font-size:8px;font-weight:bold;padding:0;color: black;text-align:center;'>" + trainName + "</p><div style='width:100%;background:" + gradient + ";'><p style='font-size:10px;font-weight:bold;padding:0;margin:0;color:white;align-items:center;align-content:center;text-align:center;text-shadow:1px 1px 0px #00000030, -1px -1px 0px #00000030,-1px 1px 0px #00000030, 1px -1px 0px #00000030,1px 0px 0px #00000030, -1px 0px 0px #00000030,0px 1px 0px #00000030, 0px -1px 0px #00000030;'>" + (ToData ? ToData + "行" : ToData) + "</p></div><div style='width:100%;background:" + trainTypeColor + ";border-radius:"+(isLeft ? "4px 4px 0 0" : "0 0 4px 4px")+";'><p style='font-size:10px;font-weight:bold;font-style:italic;padding:0;color: white;text-align:center;'>" + trainType + "</p></div><p style='font-size:8px;font-weight:bold;padding:0;text-align:center;color: "+(hasProblem ? "red":"black")+"; "+(hasProblem ? "animation:_jrs_blink 3s linear infinite;" : "")+"'>" + (hasProblem ? "‼️停止中‼️" : "") + "</p></div>");
行き先情報.insertAdjacentHTML('beforebegin', "<div style='width:100%;display:flex;flex:1;flex-direction:"+(isLeft ? "column-reverse" : "column") + ";font-weight:bold;'>" + badgeHtml + "<p style='font-size:6px;padding:0;color:" + _t.text + ";text-align:center;'>" + (TrainNumberOverride ? TrainNumberOverride : TrainNumber) + "</p><div style='flex:1;'></div><p style='font-size:8px;font-weight:bold;padding:0;color:" + _t.text + ";text-align:center;'>" + (isWanman ? "ワンマン " : "") + "</p><p style='font-size:6px;font-weight:bold;padding:0;color:" + _t.text + ";text-align:center;border-style:solid;border-width: "+(!!yosan2Color ? "2px" : "0px")+";border-color:" + yosan2Color + "'>" + viaData + "</p><p style='font-size:6px;font-weight:bold;padding:0;color: " + optionalTextColor + ";text-align:center;'>" + optionalText + "</p><p style='font-size:8px;font-weight:bold;padding:0;color:" + _t.text + ";text-align:center;'>" + trainName + "</p><div style='width:100%;background:" + gradient + ";'><p style='font-size:10px;font-weight:bold;padding:0;margin:0;color:white;align-items:center;align-content:center;text-align:center;text-shadow:1px 1px 0px #00000030, -1px -1px 0px #00000030,-1px 1px 0px #00000030, 1px -1px 0px #00000030,1px 0px 0px #00000030, -1px 0px 0px #00000030,0px 1px 0px #00000030, 0px -1px 0px #00000030;'>" + (ToData ? ToData + "行" : ToData) + "</p></div><div style='width:100%;background:" + trainTypeColor + ";border-radius:"+(isLeft ? "4px 4px 0 0" : "0 0 4px 4px")+";'><p style='font-size:10px;font-weight:bold;font-style:italic;padding:0;color: white;text-align:center;'>" + trainType + "</p></div><p style='font-size:8px;font-weight:bold;padding:0;text-align:center;color: "+(hasProblem ? "red": _t.text)+"; "+(hasProblem ? "animation:_jrs_blink 3s linear infinite;" : "")+"'>" + (hasProblem ? "‼️停止中‼️" : "") + "</p></div>");
`: `
行き先情報.insertAdjacentHTML('beforebegin', "<p style='font-size:10px;font-weight:bold;padding:0;color: black;'>" + returnText1 + "</p>");
行き先情報.insertAdjacentHTML('beforebegin', "<div style='display:inline-flex;flex-direction:row;'><p style='font-size:10px;font-weight: bold;padding:0;color:black;'>" + (ToData ? ToData + "行 " : ToData) + "</p><p style='font-size:10px;padding:0;color:black;'>" + (TrainNumberOverride ? TrainNumberOverride : TrainNumber) + "</p></div>");
行き先情報.insertAdjacentHTML('beforebegin', "<p style='font-size:10px;font-weight:bold;padding:0;color: "+(hasProblem ? "red":"black")+"; "+(hasProblem ? "animation:_jrs_blink 3s linear infinite;" : "")+"'>" + (hasProblem ? "‼️停止中‼️" : "") + "</p>");
行き先情報.insertAdjacentHTML('beforebegin', "<p style='font-size:10px;font-weight:bold;padding:0;color:" + _t.text + ";'>" + returnText1 + "</p>");
行き先情報.insertAdjacentHTML('beforebegin', "<div style='display:inline-flex;flex-direction:row;'><p style='font-size:10px;font-weight: bold;padding:0;color:" + _t.text + ";'>" + (ToData ? ToData + "行 " : ToData) + "</p><p style='font-size:10px;padding:0;color:" + _t.text + ";'>" + (TrainNumberOverride ? TrainNumberOverride : TrainNumber) + "</p></div>");
行き先情報.insertAdjacentHTML('beforebegin', "<p style='font-size:10px;font-weight:bold;padding:0;color: "+(hasProblem ? "red": _t.text)+"; "+(hasProblem ? "animation:_jrs_blink 3s linear infinite;" : "")+"'>" + (hasProblem ? "‼️停止中‼️" : "") + "</p>");
`}
}
`;
@@ -816,24 +881,36 @@ const setNewTrainItem = (element,hasProblem,type)=>{
const data = trainDataList.find(e => e.train_id === 列番データ);
const _bc = TRAIN_TYPE_CFG[data.type];
element.style.borderColor = _bc ? _bc.borderColor : 'black';
element.style.backgroundColor = _bc ? _bc.bgColor : '#ffffffcc';
if (_bc) {
if (_isDark) {
if (_bc.bgColor === '#ffffffcc') { element.style.backgroundColor = _t.cardBg; }
else if (_bc.bgColor === '#ffd0a9ff') { element.style.backgroundColor = '#5c3a1acc'; }
else if (_bc.bgColor === '#c7c7c7cc') { element.style.backgroundColor = '#555b62cc'; }
else { element.style.backgroundColor = _bc.bgColor; }
} else {
element.style.backgroundColor = _bc.bgColor;
}
} else {
element.style.backgroundColor = _t.cardBg;
}
}else{
element.style.backgroundColor = _t.cardBg;
if(element.getAttribute('offclick').includes("express")){
element.style.borderColor = '#ff0000ff';
}else if(element.getAttribute('offclick').includes("rapid")){
element.style.borderColor = '#008cffff';
}else{
element.style.borderColor = 'black';
element.style.borderColor = _isDark ? '#30363d' : 'black';
}
}
element.style.borderWidth = '2px';
element.style.borderWidth = _isDark ? '1px' : '2px';
element.style.borderStyle = 'solid';
element.style.borderRadius = '10%';
if(hasProblem){
element.style.boxShadow = '';
element.style.animation = '_jrs_glow 3s linear infinite';
}else{
element.style.boxShadow = '0 0 4px rgba(0, 0, 0, 0.2)';
element.style.boxShadow = _isDark ? '0 2px 8px rgba(0,0,0,0.6)' : '0 0 4px rgba(0,0,0,0.2)';
element.style.animation = '';
}
element.style.margin = '2px';
@@ -1099,6 +1176,13 @@ const setStrings = () =>{
if(i.style.backgroundColor != 'rgb(247, 247, 247)'){
i.childNodes.forEach(m=> m.style.width = '20vw')
}
if (_isDark && i.nodeType === 1) {
var _cbg = getComputedStyle(i).backgroundColor;
var _cm = _cbg && _cbg.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);
if (_cm && (+_cm[1] + +_cm[2] + +_cm[3]) > 500) {
i.style.backgroundColor = '#161b22';
}
}
})
}
@@ -1112,10 +1196,12 @@ const setStrings = () =>{
document.querySelector('#pMENU_2').style.borderColor='#00d3e8';
document.querySelector('#pMENU_2').style.borderWidth='2px';
document.querySelector('#pMENU_2').style.borderRadius='10%';
document.querySelector('#pMENU_2').style.backgroundColor=_t.bgSec;
document.querySelector('#pMENU_3').style.borderStyle='solid';
document.querySelector('#pMENU_3').style.borderColor='#00d3e8';
document.querySelector('#pMENU_3').style.borderWidth='2px';
document.querySelector('#pMENU_3').style.borderRadius='10%';
document.querySelector('#pMENU_3').style.backgroundColor=_t.bgSec;
document.querySelectorAll('#pMENU_2 div').forEach((d)=>d.style.padding = '10px');
document.querySelectorAll('#pMENU_3 div').forEach((d)=>d.style.padding = '10px');
document.querySelectorAll('#topHeader div').forEach((d)=>d.style.width = '100vw');
@@ -1123,6 +1209,22 @@ const setStrings = () =>{
document.getElementById('disp').style.width = '100vw';
document.getElementById('disp').style.overflowX = 'hidden';
// ダークモード: 左右ゾーンの縦グラデーション
if (_isDark) {
document.querySelectorAll('[id^="stationBlock"]').forEach(function(block) {
// 左右ゾーン:元の縦グラデーションを継承する微妙な明暗
if (block.children[0]) block.children[0].style.backgroundImage = 'linear-gradient(to bottom, rgba(200,210,230,0.04), transparent 30%, transparent 70%, rgba(200,210,230,0.04))';
if (block.children[2]) block.children[2].style.backgroundImage = 'linear-gradient(to bottom, rgba(200,210,230,0.04), transparent 30%, transparent 70%, rgba(200,210,230,0.04))';
});
// ~区間の左右にもグラデーション
document.querySelectorAll('#disp > [id*=""]').forEach(function(row) {
var up = row.querySelector(':scope > [id^="Up"]');
var down = row.querySelector(':scope > [id^="Down"]');
if (up) up.style.backgroundImage = 'linear-gradient(to bottom, rgba(200,210,230,0.04), transparent 30%, transparent 70%, rgba(200,210,230,0.04))';
if (down) down.style.backgroundImage = 'linear-gradient(to bottom, rgba(200,210,230,0.04), transparent 30%, transparent 70%, rgba(200,210,230,0.04))';
});
}
}catch(e){
alert("本家サーバーからのデータ取得に失敗しました。");
window.ReactNativeWebView.postMessage(JSON.stringify({type:"LoadError"}));