diff --git a/classes/context/Context.class.php b/classes/context/Context.class.php index 36f3686f2..a7791b05c 100644 --- a/classes/context/Context.class.php +++ b/classes/context/Context.class.php @@ -2372,9 +2372,13 @@ class Context */ public static function getBodyClass() { - self::$_instance->body_class = array_unique(self::$_instance->body_class); + $class_list = self::$_instance->body_class; + if (($color_scheme = Rhymix\Framework\UA::getColorScheme()) !== 'auto') + { + $class_list[] = 'color_scheme_' . $color_scheme; + } - return (count(self::$_instance->body_class) > 0) ? sprintf(' class="%s"', join(' ', self::$_instance->body_class)) : ''; + return (count($class_list) > 0) ? sprintf(' class="%s"', implode(' ', array_unique($class_list))) : ''; } /** diff --git a/common/framework/ua.php b/common/framework/ua.php index 9172e93f7..45ffae7ec 100644 --- a/common/framework/ua.php +++ b/common/framework/ua.php @@ -439,4 +439,41 @@ class UA return 'filename="' . preg_replace('/\./', '%2e', $filename, substr_count($filename, '.') - 1) . '"'; } } + + /** + * Get the current color scheme (auto, light, dark) + * + * @return string + */ + public static function getColorScheme(): string + { + if (isset($_COOKIE['rx_color_scheme']) && in_array($_COOKIE['rx_color_scheme'], ['light', 'dark'])) + { + return strval($_COOKIE['rx_color_scheme']); + } + else + { + return 'auto'; + } + } + + /** + * Set the color scheme (auto, light, dark) + * + * @param string $color_scheme + * @return void + */ + public static function setColorScheme(string $color_scheme) + { + if (in_array($color_scheme, ['light', 'dark'])) + { + $_COOKIE['rx_color_scheme'] = $color_scheme; + setcookie('rx_color_scheme', $color_scheme, time() + 86400 * 365, \RX_BASEURL, null, !!config('session.use_ssl_cookies')); + } + else + { + unset($_COOKIE['rx_color_scheme']); + setcookie('rx_color_scheme', 'deleted', time() - 86400, \RX_BASEURL, null); + } + } } diff --git a/common/js/common.js b/common/js/common.js index 72c5cd750..df15e3adc 100644 --- a/common/js/common.js +++ b/common/js/common.js @@ -349,6 +349,14 @@ jQuery(function($) { } }); + /* Detect color scheme */ + var body_element = $('body'); + var color_scheme_cookie = XE.cookie.get('rx_color_scheme'); + var color_scheme_detected = (window.matchMedia && window.matchMedia('(prefers-color-scheme:dark)').matches) ? 'dark' : 'light'; + if (!color_scheme_cookie || (!body_element.hasClass('color_scheme_light') && !body_element.hasClass('color_scheme_dark'))) { + body_element.addClass('color_scheme_' + color_scheme_detected).removeClass('color_scheme_' + (color_scheme_detected === 'dark' ? 'light' : 'dark')); + } + /* Editor preview replacement */ $(".editable_preview").addClass("rhymix_content xe_content").attr("tabindex", 0); $(".editable_preview").on("click", function() { @@ -766,6 +774,25 @@ function setLangType(lang_type) { XE.cookie.set('lang_type', lang_type, { path: baseurl, expires: 365 }); } +/* 색상 테마 변경 */ +function getColorScheme() { + if ($('body').hasClass('color_scheme_light')) { + return 'light'; + } else { + return 'dark'; + } +} +function setColorScheme(color_scheme) { + if (color_scheme === 'dark' || color_scheme === 'light') { + $('body').addClass('color_scheme_' + color_scheme).removeClass('color_scheme_' + (color_scheme === 'dark' ? 'light' : 'dark')); + XE.cookie.set('rx_color_scheme', color_scheme, { path: window.XE.URI(default_url).pathname(), expires: 365 }); + } else { + XE.cookie.remove('rx_color_scheme', { path: window.XE.URI(default_url).pathname() }); + color_scheme = (window.matchMedia && window.matchMedia('(prefers-color-scheme:dark)').matches) ? 'dark' : 'light'; + $('body').addClass('color_scheme_' + color_scheme).removeClass('color_scheme_' + (color_scheme === 'dark' ? 'light' : 'dark')); + } +} + /* 미리보기 */ function doDocumentPreview(obj) { var fo_obj = obj; diff --git a/tests/unit/framework/UATest.php b/tests/unit/framework/UATest.php index 9c42e98e9..b24b218e7 100644 --- a/tests/unit/framework/UATest.php +++ b/tests/unit/framework/UATest.php @@ -347,4 +347,25 @@ class UATest extends \Codeception\TestCase\Test $this->assertEquals('filename="한글 filename.jpg"', Rhymix\Framework\UA::encodeFilenameForDownload('한글 filename.jpg', 'Safari/5.0 Version/5.0')); $this->assertEquals('filename="한글 filename.jpg"', Rhymix\Framework\UA::encodeFilenameForDownload('한글 filename.jpg', 'Linux; Android 5.1.1; Version/4.0 Chrome/43.0.2357.65 Mobile Safari/537.36')); } + + public function testGetSetColorScheme() + { + $_COOKIE['rx_color_scheme'] = 'light'; + $this->assertEquals('light', Rhymix\Framework\UA::getColorScheme()); + $_COOKIE['rx_color_scheme'] = 'dark'; + $this->assertEquals('dark', Rhymix\Framework\UA::getColorScheme()); + $_COOKIE['rx_color_scheme'] = 'none'; + $this->assertEquals('auto', Rhymix\Framework\UA::getColorScheme()); + $_COOKIE['rx_color_scheme'] = 'invalid'; + $this->assertEquals('auto', Rhymix\Framework\UA::getColorScheme()); + + Rhymix\Framework\UA::setColorScheme('light'); + $this->assertEquals('light', $_COOKIE['rx_color_scheme']); + Rhymix\Framework\UA::setColorScheme('dark'); + $this->assertEquals('dark', $_COOKIE['rx_color_scheme']); + Rhymix\Framework\UA::setColorScheme('auto'); + $this->assertNull($_COOKIE['rx_color_scheme'] ?? null); + Rhymix\Framework\UA::setColorScheme('invalid'); + $this->assertNull($_COOKIE['rx_color_scheme'] ?? null); + } }