본문 바로가기
✘✘✘ 개발일기

How to change themes between light and dark, @media

by PrettyLog 2022. 10. 10.
/* TODO */
:root {
    --loading-height: 140px;
    --white: #ffffff;
    --black: #000000;
}

.light-theme {
    --background-color: var(--white);
    --color: var(--black);
}

.dark-theme {
    --background-color: var(--black);
    --color: var(--white);
}

* {
    transition: background-color 0.2s ease, color 0.1s ease;
}

/* TODO dark mode 처리 */
@media (prefers-color-scheme: dark) {
    body {
        background-color: var(--background-color);
        color: var(--color);
    }
}
// check if OS mode is dark or not
const isDark = window.matchMedia('(prefers-color-scheme: dark)');

// OS dark mode에 change event 걸기
window
  .matchMedia('(prefers-color-scheme: dark)')
  .addEventListener('change', (e) => {
      this.setTheme(this.setIsDark(e.matches));
});

// checkbox 클릭 여부에 따라 
this.$themeCheckbox.addEventListener('change', (e) => {
  if (e.target.type == 'checkbox') {
    this.setTheme(this.setIsDark(e.target.checked));
  }
});    

// 기본 light-theme > dark: dark-theme 추가하기
LIGHT_THEME = 'light-theme';
DARK_THEME = 'dark-theme';
setTheme(isDark) {
  if (isDark) {
    this.$themeCheckbox.checked = true;
    addClass(this.DARK_THEME, document.body);
  } else {
    this.$themeCheckbox.checked = false;
    removeClass(this.DARK_THEME, document.body);
  }
}
import { create, append, removeClass, addClass } from './util.js';

export default class ThemeCheckBox {
    LIGHT_THEME = 'light-theme';
    DARK_THEME = 'dark-theme';
    isDark = false;

    constructor($target) {
        this.$target = $target;
        this.$themeCheckbox = create('div');
        append(this.$themeCheckbox);

        this.isDark = this.isDarkMode();
        this.setDarkLightModeChangeEvent();

        this.setDefaultTheme();
        this.addToggleDarkTheme();

        this.render();

    }
    setDefaultTheme() {
        document.body.classList.add(this.LIGHT_THEME);
        this.isDark && document.body.classList.add(this.DARK_THEME);
    }

    // OS에서 테마 모드 변경 시 업데이트
    setDarkLightModeChangeEvent = () => {
        window
            .matchMedia('(prefers-color-scheme: dark)')
            .addEventListener('change', (e) => {
                this.toggleTheme(this.setIsDark(e.matches));
            });
    }

    isDarkMode() {
        const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)');
        return this.setIsDark(prefersDarkScheme);
    }

    setIsDark(isDark) {
        return (this.isDark = isDark);
    }

    toggleTheme(isDark) {
        const $themeCheckbox = document.getElementById('themeCheckbox');
        if (isDark) {
            // dark mode
            // console.log('[DARK]', this.isDark);
            $themeCheckbox.checked = true;
            console.log(this.$target);
            addClass(this.DARK_THEME, document.body);
        } else {
            //light mode
            // console.log('[LIGHT]', this.isDark);
            $themeCheckbox.checked = false;
            removeClass(this.DARK_THEME, document.body);
        }
    }
    addToggleDarkTheme() {
        this.$themeCheckbox.addEventListener('change', (e) => {
            // TODO when a change event occurs, both label and input events triggers.
            // to prevent the change event from being triggered twice, set if filter
            if (e.target.type == 'checkbox') {
                this.toggleTheme(this.setIsDark(!this.isDark));
            }
        });
    }    



    render = () => {
        this.$themeCheckbox.innerHTML = `
                <input type="checkbox" id="themeCheckbox" name="themeCheckbox" ${
                    this.isDark && 'checked'
                }>
                <label for="themeCheckbox"> darkmode</label><br>
        `;
    }

}

댓글