Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Languages/en_US/Profile.php
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,8 @@
$txt['theme_opt_posting'] = 'Posting';
$txt['theme_opt_moderation'] = 'Moderation';
$txt['theme_opt_personal_messages'] = 'Personal Messages';
$txt['theme_opt_colormode'] = 'Theme Color Mode';
$txt['theme_opt_variant'] = 'Theme Variant';

$txt['export_profile_data'] = 'Download profile data';
$txt['export_profile_data_desc'] = 'This section allows you to export a copy of your forum profile data to a downloadable file, optionally including your posts and personal messages.<br>Please note:<ul class="bbc_list">{list}</ul>';
Expand Down
10 changes: 10 additions & 0 deletions Languages/en_US/Themes.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@

$txt['theme_url_config'] = 'Theme URLs and Configuration';
$txt['theme_variants'] = 'Theme Variants';
$txt['theme_colormodes'] = 'Theme Color Modes';
$txt['theme_options'] = 'Theme Options and Preferences';
$txt['actual_theme_name'] = 'This theme’s name: ';
$txt['actual_theme_dir'] = 'This theme’s directory: ';
Expand All @@ -73,6 +74,7 @@
$txt['current_theme_style'] = 'This theme’s style: ';

$txt['theme_variants_default'] = 'Default theme variant';
$txt['variant_default'] = 'Default';
$txt['theme_variants_user_disable'] = 'Disable user variant selection';

$txt['site_slogan'] = 'Site slogan';
Expand Down Expand Up @@ -164,3 +166,11 @@
// Open Graph
$txt['og_image'] = 'Open Graph image';
$txt['og_image_desc'] = 'Suggested size: 175x175px. <a href="https://ogp.me/" target="_blank" class="bbc_link">Open Graph</a> is used for social media sharing.';

// Theme Mode (dark, light, system, etc)
$txt['theme_pick_colormode'] = 'Select Color Mode';
$txt['theme_colormode_default'] = 'Default color mode';
$txt['theme_colormode_user_disable'] = 'Disable user color mode selection';
$txt['colormode_light'] = 'Light';
$txt['colormode_dark'] = 'Dark';
$txt['colormode_system'] = 'System Default';
46 changes: 45 additions & 1 deletion Sources/Actions/Admin/Themes.php
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,51 @@ public function setOptions(): void
Utils::$context['sub_template'] = 'set_options';
Utils::$context['page_title'] = Lang::getTxt('theme_settings', file: 'Admin');

Utils::$context['options'] = Utils::$context['theme_options'];
// Check for variants or dark mode
if (!empty(Theme::$current->settings['theme_variants']) || !empty(Theme::$current->settings['has_dark_mode'])) {
Utils::$context['options'] = [];

// Theme Variants
if (!empty(Theme::$current->settings['theme_variants'])) {
$available_variants = [];

foreach (Theme::$current->settings['theme_variants'] as $variant) {
$available_variants[$variant] = Lang::$txt['variant_' . $variant] ?? $variant;
}

Utils::$context['options'][] = Lang::$txt['theme_opt_variant'];
Utils::$context['options'][] = [
'id' => 'theme_variant',
'label' => Lang::$txt['theme_pick_variant'],
'options' => $available_variants,
'default' => isset(Theme::$current->settings['default_variant']) && !empty(Theme::$current->settings['default_variant']) ? Theme::$current->settings['default_variant'] : Theme::$current->settings['theme_variants'][0],
'enabled' => !empty(Theme::$current->settings['theme_variants']),
];
}

// Theme Color Mode
if (!empty(Theme::$current->settings['has_dark_mode'])) {
$available_modes = [];

foreach (Theme::$current->settings['theme_colormodes'] as $mode) {
$available_modes[$mode] = Lang::$txt['colormode_' . $mode] ?? $mode;
}

Utils::$context['options'][] = Lang::$txt['theme_opt_colormode'];
Utils::$context['options'][] = [
'id' => 'theme_colormode',
'label' => Lang::$txt['theme_pick_colormode'],
'options' => $available_modes,
'default' => isset(Theme::$current->settings['default_colormode']) && !empty(Theme::$current->settings['default_colormode']) ? Theme::$current->settings['default_colormode'] : Theme::$current->settings['theme_colormodes'][0],
'enabled' => !empty(Theme::$current->settings['has_dark_mode']),
];
}

Utils::$context['options'] = array_merge(Utils::$context['options'], Utils::$context['theme_options']);
} else {
Utils::$context['options'] = Utils::$context['theme_options'];
}

Utils::$context['theme_settings'] = Theme::$current->settings;

if (empty($_REQUEST['who'])) {
Expand Down
76 changes: 64 additions & 12 deletions Sources/Theme.php
Original file line number Diff line number Diff line change
Expand Up @@ -2157,6 +2157,47 @@ protected function loadCss(): void
self::loadCSSFile('noscript.css', ['minimize' => true, 'order_pos' => 1, 'noscript' => true], 'smf_noscript');
}

/**
* Loads the theme mode, if applicable.
*/
protected function loadMode(): void
{
Utils::$context['theme_colormode'] = '';

if (!empty($this->settings['has_dark_mode'])) {
// Theme Modes
$this->settings['theme_colormodes'] = ['light', 'system', 'dark'];

// Overriding - for previews and that ilk.
if (!empty($_REQUEST['mode'])) {
$_SESSION['theme_colormode'] = $_REQUEST['mode'];

// If the user is logged, save this to their profile
if (User::$me->is_logged && \in_array($_SESSION['theme_colormode'], $this->settings['theme_colormodes'])) {
Db::$db->insert(
'replace',
'{db_prefix}themes',
['id_theme' => 'int', 'id_member' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'],
[self::$current->settings['theme_id'], User::$me->id, 'theme_colormode', $_SESSION['theme_colormode']],
['id_theme', 'id_member', 'variable'],
);
}
}

// User selection?
if (empty($this->settings['disable_user_mode']) || User::$me->allowedTo('admin_forum')) {
Utils::$context['theme_colormode'] = !empty($_SESSION['theme_colormode']) && \in_array($_SESSION['theme_colormode'], $this->settings['theme_colormodes']) ? $_SESSION['theme_colormode'] : (!empty($this->options['theme_colormode']) && \in_array($this->options['theme_colormode'], $this->settings['theme_colormodes']) ? $this->options['theme_colormode'] : '');
}

// If no color mode, set a default
if (empty(Utils::$context['theme_colormode']) || !\in_array(Utils::$context['theme_colormode'], $this->settings['theme_colormodes'])) {
Utils::$context['theme_colormode'] = !empty($this->settings['default_colormode']) && \in_array($this->settings['default_colormode'], $this->settings['theme_colormodes']) ? $this->settings['default_colormode'] : $this->settings['theme_colormodes'][0];
}

self::loadCSSFile('dark.css', ['order_pos' => 2, 'attributes' => (Utils::$context['theme_colormode'] == 'system' ? ['media' => '(prefers-color-scheme: dark)'] : [])], 'smf_dark');
}
}

/**
* Loads the correct theme variant, if applicable.
*/
Expand All @@ -2167,11 +2208,34 @@ protected function loadVariant(): void
Utils::$context['theme_variant_url'] = '';

if (!empty($this->settings['theme_variants'])) {
// Add the default variant
$this->settings['theme_variants'] = array_unique(array_merge(['default'], $this->settings['theme_variants']));

// Overriding - for previews and that ilk.
if (!empty($_REQUEST['variant'])) {
$_SESSION['id_variant'] = $_REQUEST['variant'];

// If the user is logged, save this to their profile
if (User::$me->is_logged && \in_array($_SESSION['id_variant'], $this->settings['theme_variants'])) {
Db::$db->insert(
'replace',
'{db_prefix}themes',
['id_theme' => 'int', 'id_member' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'],
[self::$current->settings['theme_id'], User::$me->id, 'theme_variant', $_SESSION['id_variant']],
['id_theme', 'id_member', 'variable'],
);
}
}

/*
* Attempt to load a variants file for variable overriding
* using data attribute (:root[data-variant="variant"])
*
* This is useful when you only want a single file for
* recoloring the variants.
*/
self::loadCSSFile('variants.css', ['order_pos' => 0], 'smf_variants');

// User selection?
if (empty($this->settings['disable_user_variant']) || User::$me->allowedTo('admin_forum')) {
Utils::$context['theme_variant'] = !empty($_SESSION['id_variant']) && \in_array($_SESSION['id_variant'], $this->settings['theme_variants']) ? $_SESSION['id_variant'] : (!empty($this->options['theme_variant']) && \in_array($this->options['theme_variant'], $this->settings['theme_variants']) ? $this->options['theme_variant'] : '');
Expand All @@ -2181,18 +2245,6 @@ protected function loadVariant(): void
if (Utils::$context['theme_variant'] == '' || !\in_array(Utils::$context['theme_variant'], $this->settings['theme_variants'])) {
Utils::$context['theme_variant'] = !empty($this->settings['default_variant']) && \in_array($this->settings['default_variant'], $this->settings['theme_variants']) ? $this->settings['default_variant'] : $this->settings['theme_variants'][0];
}

// Do this to keep things easier in the templates.
Utils::$context['theme_variant'] = '_' . Utils::$context['theme_variant'];
Utils::$context['theme_variant_url'] = Utils::$context['theme_variant'] . '/';

if (!empty(Utils::$context['theme_variant'])) {
self::loadCSSFile('index' . Utils::$context['theme_variant'] . '.css', ['order_pos' => 300], 'smf_index' . Utils::$context['theme_variant']);

if (Utils::$context['right_to_left']) {
self::loadCSSFile('rtl' . Utils::$context['theme_variant'] . '.css', ['order_pos' => 4200], 'smf_rtl' . Utils::$context['theme_variant']);
}
}
}
}

Expand Down
124 changes: 78 additions & 46 deletions Themes/default/Themes.template.php
Original file line number Diff line number Diff line change
Expand Up @@ -511,8 +511,7 @@ function template_set_settings()
</dl>';

// Do we allow theme variants?
if (!empty(Utils::$context['theme_variants']))
{
if (!empty(Utils::$context['theme_variants'])) {
echo '
<div class="title_bar">
<h3 class="titlebg config_hd">
Expand Down Expand Up @@ -544,6 +543,38 @@ function template_set_settings()
<img src="', Utils::$context['theme_variants'][Utils::$context['default_variant']]['thumbnail'], '" id="variant_preview" alt="">';
}

// Color modes for the theme?
if (!empty(Theme::$current->settings['has_dark_mode'])) {
echo '
<div class="title_bar">
<h3 class="titlebg config_hd">
', Lang::$txt['theme_colormodes'], '
</h3>
</div>
<dl class="settings">
<dt>
<label for="colormode">', Lang::$txt['theme_colormode_default'], '</label>
</dt>
<dd>
<select id="colormode" name="options[default_colormode]">';

foreach (Theme::$current->settings['theme_colormodes'] as $mode)
echo '
<option value="', $mode, '"', Theme::$current->settings['default_colormode'] == $mode ? ' selected' : '', '>', Lang::$txt['colormode_' . $mode], '</option>';

echo '
</select>
</dd>
<dt>
<label for="disable_user_mode">', Lang::$txt['theme_colormode_user_disable'], '</label>
</dt>
<dd>
<input type="hidden" name="options[disable_user_mode]" value="0">
<input type="checkbox" name="options[disable_user_mode]" id="disable_user_mode"', !empty(Utils::$context['theme_settings']['disable_user_mode']) ? ' checked' : '', ' value="1">
</dd>
</dl>';
}

echo '
<div class="title_bar">
<h3 class="titlebg config_hd">
Expand Down Expand Up @@ -690,65 +721,66 @@ function template_set_settings()
function template_pick()
{
echo '
<div id="pick_theme">
<form action="', Config::$scripturl, '?action=themechooser" method="post" accept-charset="UTF-8">';
<form action="', Config::$scripturl, '?action=themechooser" method="post" accept-charset="UTF-8">';

// Just go through each theme and show its information - thumbnail, etc.
foreach (Utils::$context['available_themes'] as $theme)
for ($i = 0; $i < 2; $i++)
{
echo '
<div class="cat_bar">
<h3 class="catbg">
<div class="cat_bar">
<h3 class="catbg">', Lang::getTxt($i == 0 ? 'current_theme' : 'theme_pick', file: 'Themes'), '</h3>
</div>
<div class="windowbg">';

// Just go through each theme and show its information - thumbnail, etc.
foreach (Utils::$context['available_themes'] as $theme)
{
if (($theme['selected'] && $i == 0) || (!$theme['selected'] && $i == 1))
{
echo '
<div class="title_bar">
<h3 class="titlebg">
', $theme['name'], '
</h3>
</div>
<div class="windowbg', $theme['selected'] ? ' selected' : '', '">
<div class="flow_hidden">
<div class="floatright">
<a href="', Config::$scripturl, '?action=themechooser;u=', Utils::$context['current_member'], ';theme=', $theme['id'], ';', Utils::$context['session_var'], '=', Utils::$context['session_id'], '" id="theme_thumb_preview_', $theme['id'], '" title="', Lang::getTxt('theme_preview', file: 'Themes'), '">
<img src="', $theme['thumbnail_href'], '" id="theme_thumb_', $theme['id'], '" alt="" class="padding theme_thumbnail">
</a>
</div>
<p>', $theme['description'], '</p>';

if (!empty($theme['variants']))
{
echo '
<label for="variant', $theme['id'], '"><strong>', $theme['pick_label'], '</strong></label>:
<select id="variant', $theme['id'], '" name="vrt[', $theme['id'], ']" onchange="changeVariant(', $theme['id'], ', this);">';
<div>
<small><i>', $theme['description'], '</i></small>';

foreach ($theme['variants'] as $key => $variant)
echo '
<option value="', $key, '"', $theme['selected_variant'] == $key ? ' selected' : '', '>', $variant['label'], '</option>';
if (!empty($theme['variants']))
{
echo '
<label><strong>', $theme['pick_label'], '</strong>
<select data-theme-id="', $theme['id'], '" name="vrt[', $theme['id'], ']">';

echo '
</select>';
}
foreach ($theme['variants'] as $key => $variant)
echo '
<option value="', $key, '"', $theme['selected_variant'] == $key ? ' selected' : '', ' data-url="', $variant['thumbnail'], '">', $variant['label'], '</option>';

echo '
<br>
<p>
<em class="smalltext">', Lang::getTxt('theme_num_users', [$theme['num_users']], file: 'Themes'), '</em>
</p>
<br>
<ul>
<li class="lower_padding">
<input type="submit" name="save[', $theme['id'], ']" value="', Lang::getTxt('theme_set', file: 'Themes'), '" class="button">
</li>
<li>
<a class="button" href="', Config::$scripturl, '?action=themechooser;theme=', $theme['id'], '" id="theme_preview_', $theme['id'], '">', Lang::getTxt('theme_preview', file: 'Themes'), '</a>
</li>
</ul>
echo '
</select>
</label>';
}

echo '
<div>
<input type="submit" name="save[', $theme['id'], ']" value="', Lang::getTxt('theme_set', file:'Themes'), '" class="button">
<a class="button" href="', Config::$scripturl, '?action=theme;sa=pick;theme=', $theme['id'], '" id="theme_preview_', $theme['id'], '">', Lang::getTxt('theme_preview', file:'Themes'), '</a>
</div>
</div>
<div>
<a href="', Config::$scripturl, '?action=theme;sa=pick;u=', Utils::$context['current_member'], ';theme=', $theme['id'], ';', Utils::$context['session_var'], '=', Utils::$context['session_id'], '" id="theme_thumb_preview_', $theme['id'], '" title="', Lang::getTxt('theme_preview', file: 'Themes'), '">
<img src="', $theme['thumbnail_href'], '" id="theme_thumb_', $theme['id'], '" alt="" class="padding theme_thumbnail">
</a>
</div>';
}
}

echo '
<input type="hidden" name="', Utils::$context['session_var'], '" value="', Utils::$context['session_id'], '">
<input type="hidden" name="', Utils::$context['pick-th_token_var'], '" value="', Utils::$context['pick-th_token'], '">
<input type="hidden" name="u" value="', Utils::$context['current_member'], '">
</form>
</div><!-- #pick_theme -->';
</div>
<input type="hidden" name="', Utils::$context['session_var'], '" value="', Utils::$context['session_id'], '">
<input type="hidden" name="', Utils::$context['pick-th_token_var'], '" value="', Utils::$context['pick-th_token'], '">
<input type="hidden" name="u" value="', Utils::$context['current_member'], '">';
}
}

/**
Expand Down
Loading