// GRINDELWALD — Tweaks application. Requires tweaks-panel.jsx (React) loaded first. // Each page inlines its own TWEAK_DEFAULTS (with EDITMODE markers) and calls // GW.mountTweaks(TWEAK_DEFAULTS). Choices also mirror to localStorage so the look // stays consistent as the visitor moves between pages. window.GW = (function () { var FONTS = { shippori: "'Shippori Mincho','Yu Mincho',serif", noto: "'Noto Serif JP','Yu Mincho',serif", zen: "'Zen Old Mincho','Yu Mincho',serif" }; var SPACE = { compact: 0.82, regular: 1, comfy: 1.22 }; var STORE = 'gw_tweaks_v1'; function apply(t) { var r = document.documentElement.style; if (t.jpFont && FONTS[t.jpFont]) r.setProperty('--font-jp', FONTS[t.jpFont]); if (Array.isArray(t.greens)) { r.setProperty('--green-900', t.greens[0]); r.setProperty('--green-800', t.greens[1]); r.setProperty('--green-700', t.greens[2]); } if (t.spacing && SPACE[t.spacing] != null) r.setProperty('--sp', SPACE[t.spacing]); if (t.red) r.setProperty('--red', t.red); } // read persisted overrides (returns {} if none) function persisted() { try { return JSON.parse(localStorage.getItem(STORE)) || {}; } catch (e) { return {}; } } // early apply — call from before paint function earlyApply() { apply(persisted()); } function mountTweaks(defaults) { var init = Object.assign({}, defaults, persisted()); apply(init); function App() { var pair = useTweaks(init); var t = pair[0], setTweak = pair[1]; React.useEffect(function () { apply(t); try { localStorage.setItem(STORE, JSON.stringify(t)); } catch (e) {} }, [t]); return React.createElement(TweaksPanel, { title: 'Tweaks' }, React.createElement(TweakSection, { label: '書体' }), React.createElement(TweakSelect, { label: '明朝体', value: t.jpFont, options: [ { value: 'shippori', label: 'しっぽり明朝' }, { value: 'noto', label: 'Noto Serif JP' }, { value: 'zen', label: 'Zen Old Mincho' } ], onChange: function (v) { setTweak('jpFont', v); } }), React.createElement(TweakSection, { label: 'メインカラー' }), React.createElement(TweakColor, { label: '深緑の濃淡', value: t.greens, options: [ ['#16291c', '#23402c', '#2f5238'], ['#1b3322', '#274a31', '#356344'], ['#21402a', '#2e5638', '#3d7049'] ], onChange: function (v) { setTweak('greens', v); } }), React.createElement(TweakColor, { label: 'スイス赤の調子', value: t.red, options: ['#c8102e', '#a4161a', '#d8232a', '#b51e3b'], onChange: function (v) { setTweak('red', v); } }), React.createElement(TweakSection, { label: '余白' }), React.createElement(TweakRadio, { label: '広さ', value: t.spacing, options: [ { value: 'compact', label: 'コンパクト' }, { value: 'regular', label: '標準' }, { value: 'comfy', label: 'ゆったり' } ], onChange: function (v) { setTweak('spacing', v); } }) ); } var root = document.createElement('div'); root.id = 'tweaks-root'; document.body.appendChild(root); ReactDOM.createRoot(root).render(React.createElement(App)); } return { mountTweaks: mountTweaks, earlyApply: earlyApply, apply: apply }; })();