|
|
| (同じ利用者による、間の2版が非表示) |
| 1行目: |
1行目: |
| /* ここにあるすべてのJavaScriptは、すべてのページ読み込みですべての利用者に対して読み込まれます */ | | /* ここにあるすべてのJavaScriptは、すべてのページ読み込みですべての利用者に対して読み込まれます */ |
| // ========================================
| |
| // ダークモード切り替え機能(サイドバー&上部バー配置版)
| |
| // MediaWiki:Common.js に追加してください
| |
| // ========================================
| |
|
| |
| (function() {
| |
| 'use strict';
| |
|
| |
| // 設定
| |
| const THEME_KEY = 'fluent-theme-preference';
| |
| const THEME_DARK = 'dark';
| |
| const THEME_LIGHT = 'light';
| |
| const THEME_AUTO = 'auto';
| |
|
| |
| // 現在のテーマを取得
| |
| function getCurrentTheme() {
| |
| return localStorage.getItem(THEME_KEY) || THEME_AUTO;
| |
| }
| |
|
| |
| // テーマを適用
| |
| function applyTheme(theme) {
| |
| const html = document.documentElement;
| |
| html.classList.remove('theme-dark', 'theme-light', 'theme-auto');
| |
| html.classList.add('theme-' + theme);
| |
| localStorage.setItem(THEME_KEY, theme);
| |
| updateAllThemeButtons(theme);
| |
| }
| |
|
| |
| // すべてのボタンを更新
| |
| function updateAllThemeButtons(theme) {
| |
| const buttons = document.querySelectorAll('.theme-toggle-button, .theme-toggle-link');
| |
| buttons.forEach(function(button) {
| |
| updateThemeButton(button, theme);
| |
| });
| |
| }
| |
|
| |
| // ボタンの表示を更新
| |
| function updateThemeButton(button, theme) {
| |
| if (!button) return;
| |
|
| |
| const configs = {
| |
| 'light': {
| |
| icon: '☀️',
| |
| text: 'ライトモード',
| |
| title: 'ライトモードに切り替え',
| |
| nextMode: 'ダークモードに切り替え'
| |
| },
| |
| 'dark': {
| |
| icon: '🌙',
| |
| text: 'ダークモード',
| |
| title: 'ダークモードに切り替え',
| |
| nextMode: '自動モードに切り替え'
| |
| },
| |
| 'auto': {
| |
| icon: '🌗',
| |
| text: '自動切替',
| |
| title: '自動(システム設定)',
| |
| nextMode: 'ライトモードに切り替え'
| |
| }
| |
| };
| |
|
| |
| const config = configs[theme];
| |
|
| |
| // アイコン要素があれば更新
| |
| const iconSpan = button.querySelector('.theme-icon');
| |
| if (iconSpan) {
| |
| iconSpan.textContent = config.icon;
| |
| }
| |
|
| |
| // テキスト要素があれば更新
| |
| const textSpan = button.querySelector('.theme-text');
| |
| if (textSpan) {
| |
| textSpan.textContent = config.text;
| |
| }
| |
|
| |
| // ボタン全体のテキストを更新(テキストリンク用)
| |
| if (button.classList.contains('theme-toggle-text-only')) {
| |
| button.textContent = config.icon + ' ' + config.text;
| |
| }
| |
|
| |
| button.title = config.nextMode;
| |
| button.setAttribute('aria-label', config.nextMode);
| |
| }
| |
|
| |
| // テーマを切り替え
| |
| function toggleTheme(e) {
| |
| if (e) {
| |
| e.preventDefault();
| |
| e.stopPropagation();
| |
| }
| |
|
| |
| const current = getCurrentTheme();
| |
| let next;
| |
|
| |
| switch(current) {
| |
| case THEME_LIGHT:
| |
| next = THEME_DARK;
| |
| break;
| |
| case THEME_DARK:
| |
| next = THEME_AUTO;
| |
| break;
| |
| case THEME_AUTO:
| |
| default:
| |
| next = THEME_LIGHT;
| |
| break;
| |
| }
| |
|
| |
| applyTheme(next);
| |
| }
| |
|
| |
| // サイドバーにボタンを追加
| |
| function addSidebarButton() {
| |
| // 既に存在する場合はスキップ
| |
| if (document.getElementById('theme-toggle-sidebar')) return;
| |
|
| |
| // サイドバーの「ツール」セクションを探す
| |
| const sideNavigation = document.getElementById('site-navigation');
| |
| if (!sideNavigation) return;
| |
|
| |
| // ボタンコンテナを作成
| |
| const container = document.createElement('div');
| |
| container.id = 'theme-toggle-sidebar';
| |
| container.className = 'theme-toggle-container';
| |
|
| |
| // タイトル(オプション)
| |
| const title = document.createElement('h3');
| |
| title.textContent = '表示設定';
| |
| title.className = 'theme-section-title';
| |
|
| |
| // ボタンを作成
| |
| const button = document.createElement('button');
| |
| button.className = 'theme-toggle-button theme-toggle-sidebar-button';
| |
| button.setAttribute('aria-label', 'テーマ切り替え');
| |
| button.setAttribute('type', 'button');
| |
|
| |
| const iconSpan = document.createElement('span');
| |
| iconSpan.className = 'theme-icon';
| |
|
| |
| const textSpan = document.createElement('span');
| |
| textSpan.className = 'theme-text';
| |
|
| |
| button.appendChild(iconSpan);
| |
| button.appendChild(textSpan);
| |
| button.addEventListener('click', toggleTheme);
| |
|
| |
| container.appendChild(title);
| |
| container.appendChild(button);
| |
|
| |
| // サイドバーの先頭に追加
| |
| sideNavigation.insertBefore(container, sideNavigation.firstChild);
| |
|
| |
| return button;
| |
| }
| |
|
| |
| // 上部バーにボタンを追加
| |
| function addTopBarButton() {
| |
| // 既に存在する場合はスキップ
| |
| if (document.getElementById('theme-toggle-topbar')) return;
| |
|
| |
| // ページツール(編集、履歴などのエリア)を探す
| |
| const pageTools = document.getElementById('page-tools');
| |
| if (!pageTools) return;
| |
|
| |
| // ボタンを作成
| |
| const button = document.createElement('button');
| |
| button.id = 'theme-toggle-topbar';
| |
| button.className = 'theme-toggle-button theme-toggle-topbar-button';
| |
| button.setAttribute('aria-label', 'テーマ切り替え');
| |
| button.setAttribute('type', 'button');
| |
|
| |
| const iconSpan = document.createElement('span');
| |
| iconSpan.className = 'theme-icon';
| |
| iconSpan.style.marginRight = '4px';
| |
|
| |
| const textSpan = document.createElement('span');
| |
| textSpan.className = 'theme-text';
| |
|
| |
| button.appendChild(iconSpan);
| |
| button.appendChild(textSpan);
| |
| button.addEventListener('click', toggleTheme);
| |
|
| |
| // ページツールの最後に追加
| |
| pageTools.appendChild(button);
| |
|
| |
| return button;
| |
| }
| |
|
| |
| // ヘッダーにシンプルなボタンを追加(右上)
| |
| function addHeaderButton() {
| |
| // 既に存在する場合はスキップ
| |
| if (document.getElementById('theme-toggle-header')) return;
| |
|
| |
| const userTools = document.getElementById('user-tools');
| |
| if (!userTools) return;
| |
|
| |
| // シンプルなアイコンボタンを作成
| |
| const button = document.createElement('button');
| |
| button.id = 'theme-toggle-header';
| |
| button.className = 'theme-toggle-button theme-toggle-header-button';
| |
| button.setAttribute('aria-label', 'テーマ切り替え');
| |
| button.setAttribute('type', 'button');
| |
|
| |
| const iconSpan = document.createElement('span');
| |
| iconSpan.className = 'theme-icon';
| |
|
| |
| button.appendChild(iconSpan);
| |
| button.addEventListener('click', toggleTheme);
| |
|
| |
| // search-iconの後に挿入
| |
| const searchIcon = document.getElementById('search-icon');
| |
| if (searchIcon && searchIcon.nextSibling) {
| |
| userTools.insertBefore(button, searchIcon.nextSibling);
| |
| } else {
| |
| userTools.appendChild(button);
| |
| }
| |
|
| |
| return button;
| |
| }
| |
|
| |
| // 初期化
| |
| function init() {
| |
| // 複数の場所にボタンを追加
| |
| addSidebarButton(); // サイドバーに追加
| |
| addTopBarButton(); // 上部バー(ページツール)に追加
| |
| addHeaderButton(); // ヘッダー右上に追加
| |
|
| |
| // 保存されたテーマを適用
| |
| const savedTheme = getCurrentTheme();
| |
| applyTheme(savedTheme);
| |
| }
| |
|
| |
| // DOMContentLoaded時に初期化
| |
| if (document.readyState === 'loading') {
| |
| document.addEventListener('DOMContentLoaded', init);
| |
| } else {
| |
| init();
| |
| }
| |
|
| |
| // MediaWikiフックとの連携
| |
| if (typeof mw !== 'undefined' && mw.hook) {
| |
| mw.hook('wikipage.content').add(function() {
| |
| const savedTheme = getCurrentTheme();
| |
| applyTheme(savedTheme);
| |
| });
| |
| }
| |
| })();
| |