mirror of
https://github.com/danielbrendel/hortusfox-web.git
synced 2026-04-29 18:29:53 -05:00
#120 Theme system
This commit is contained in:
@@ -55,6 +55,7 @@ users have taken. The system features collaborative management, so you can manag
|
||||
- 🕰️ History feature
|
||||
- 💬 Group chat
|
||||
- ⚙️ Profile management
|
||||
- 🦋 Themes
|
||||
- 🔑 Admin dashboard
|
||||
- 📢 Reminders
|
||||
- 💾 Backups
|
||||
|
||||
@@ -53,6 +53,12 @@ class BaseController extends Asatru\Controller\Controller {
|
||||
UtilsModule::setLanguage($lang);
|
||||
}
|
||||
}
|
||||
|
||||
$theme = $auth_user->get('theme');
|
||||
|
||||
if (($theme) && (is_dir(public_path() . '/themes/' . $theme))) {
|
||||
ThemeModule::load(public_path() . '/themes/' . $theme);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,13 +65,14 @@ class UserController extends BaseController {
|
||||
$name = $request->params()->query('name', null);
|
||||
$email = $request->params()->query('email', null);
|
||||
$lang = $request->params()->query('lang', 'en');
|
||||
$theme = $request->params()->query('theme', 'default');
|
||||
$chatcolor = $request->params()->query('chatcolor', null);
|
||||
$show_log = $request->params()->query('show_log', false);
|
||||
$notify_tasks_overdue = $request->params()->query('notify_tasks_overdue', false);
|
||||
$notify_tasks_tomorrow = $request->params()->query('notify_tasks_tomorrow', false);
|
||||
$show_plants_aoru = $request->params()->query('show_plants_aoru', 'added');
|
||||
|
||||
UserModel::editPreferences($name, $email, $lang, $chatcolor, $show_log, $notify_tasks_overdue, $notify_tasks_tomorrow, $show_plants_aoru);
|
||||
UserModel::editPreferences($name, $email, $lang, $theme, $chatcolor, $show_log, $notify_tasks_overdue, $notify_tasks_tomorrow, $show_plants_aoru);
|
||||
|
||||
$password = $request->params()->query('password', null);
|
||||
if ($password) {
|
||||
|
||||
+3
-1
@@ -260,5 +260,7 @@ return [
|
||||
'import_successful' => 'Erfolgreich importiert!',
|
||||
'pwa_enable' => 'PWA Unterstützung aktivieren',
|
||||
'home' => 'Home',
|
||||
'enable_system_messages' => 'Systemmeldungen aktivieren'
|
||||
'enable_system_messages' => 'Systemmeldungen aktivieren',
|
||||
'theme' => 'Theme',
|
||||
'themes' => 'Themes'
|
||||
];
|
||||
+3
-1
@@ -263,5 +263,7 @@ return [
|
||||
'enable_system_messages' => 'Enable system messages',
|
||||
'plant_count' => '{count} plants',
|
||||
'danger_count' => '{count} in danger',
|
||||
'all_in_good_standing' => 'All fine'
|
||||
'all_in_good_standing' => 'All fine',
|
||||
'theme' => 'Theme',
|
||||
'themes' => 'Themes'
|
||||
];
|
||||
@@ -38,6 +38,7 @@ class UserModel_Migration {
|
||||
$this->database->add('lang VARCHAR(512) NULL');
|
||||
$this->database->add('chatcolor VARCHAR(512) NULL');
|
||||
$this->database->add('notes TEXT NULL');
|
||||
$this->database->add('theme VARCHAR(512) NULL');
|
||||
$this->database->add('show_log BOOLEAN NOT NULL DEFAULT 1');
|
||||
$this->database->add('show_plants_aoru BOOLEAN NOT NULL DEFAULT 1');
|
||||
$this->database->add('notify_tasks_overdue BOOLEAN NOT NULL DEFAULT 1');
|
||||
|
||||
@@ -182,6 +182,7 @@ class UserModel extends \Asatru\Database\Model {
|
||||
* @param $name
|
||||
* @param $email
|
||||
* @param $lang
|
||||
* @param $theme
|
||||
* @param $chatcolor
|
||||
* @param $show_log
|
||||
* @param $notify_tasks_overdue
|
||||
@@ -190,7 +191,7 @@ class UserModel extends \Asatru\Database\Model {
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function editPreferences($name, $email, $lang, $chatcolor, $show_log, $notify_tasks_overdue, $notify_tasks_tomorrow, $show_plants_aoru)
|
||||
public static function editPreferences($name, $email, $lang, $theme, $chatcolor, $show_log, $notify_tasks_overdue, $notify_tasks_tomorrow, $show_plants_aoru)
|
||||
{
|
||||
try {
|
||||
$user = static::getAuthUser();
|
||||
@@ -198,8 +199,8 @@ class UserModel extends \Asatru\Database\Model {
|
||||
throw new \Exception('User not authenticated');
|
||||
}
|
||||
|
||||
static::raw('UPDATE `' . self::tableName() . '` SET name = ?, email = ?, lang = ?, chatcolor = ?, show_log = ?, notify_tasks_overdue = ?, notify_tasks_tomorrow = ?, show_plants_aoru = ? WHERE id = ?', [
|
||||
trim($name), trim($email), $lang, $chatcolor, $show_log, $notify_tasks_overdue, $notify_tasks_tomorrow, (int)$show_plants_aoru, $user->get('id')
|
||||
static::raw('UPDATE `' . self::tableName() . '` SET name = ?, email = ?, lang = ?, theme = ?, chatcolor = ?, show_log = ?, notify_tasks_overdue = ?, notify_tasks_tomorrow = ?, show_plants_aoru = ? WHERE id = ?', [
|
||||
trim($name), trim($email), $lang, $theme, $chatcolor, $show_log, $notify_tasks_overdue, $notify_tasks_tomorrow, (int)$show_plants_aoru, $user->get('id')
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
throw $e;
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class represents your module
|
||||
*/
|
||||
class ThemeModule {
|
||||
/** @var array $theme_data */
|
||||
public static $theme_data = null;
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function load($path)
|
||||
{
|
||||
try {
|
||||
self::$theme_data = null;
|
||||
|
||||
self::$theme_data = json_decode(file_get_contents($path . '/layout.json'));
|
||||
if (!is_object(self::$theme_data)) {
|
||||
throw new \Exception('Invalid data @ ' . $path . '/layout.json: ' . print_r(self::$theme_data, true));
|
||||
}
|
||||
|
||||
if (!file_exists($path . '/' . self::$theme_data->banner)) {
|
||||
throw new \Exception('Banner asset not found');
|
||||
}
|
||||
|
||||
self::$theme_data->banner_url = asset('themes/' . self::$theme_data->name . '/' . self::$theme_data->banner);
|
||||
|
||||
self::$theme_data->inline_rules = '';
|
||||
foreach (self::$theme_data->rules as $key => $value) {
|
||||
self::$theme_data->inline_rules .= $key . ': ' . $value . ' !important;';
|
||||
}
|
||||
|
||||
if (isset(self::$theme_data->icon)) {
|
||||
if (!file_exists($path . '/' . self::$theme_data->icon->asset)) {
|
||||
throw new \Exception('Icon asset not found');
|
||||
}
|
||||
|
||||
self::$theme_data->icon->url = asset('themes/' . self::$theme_data->name . '/' . self::$theme_data->icon->asset);
|
||||
|
||||
self::$theme_data->icon->inline_rules = new \stdClass();
|
||||
|
||||
self::$theme_data->icon->inline_rules->base = '';
|
||||
foreach (self::$theme_data->icon->base as $key => $value) {
|
||||
self::$theme_data->icon->inline_rules->base .= $key . ': ' . $value . ' !important;';
|
||||
}
|
||||
|
||||
self::$theme_data->icon->inline_rules->img = '';
|
||||
foreach (self::$theme_data->icon->img as $key => $value) {
|
||||
self::$theme_data->icon->inline_rules->img .= $key . ': ' . $value . ' !important;';
|
||||
}
|
||||
}
|
||||
|
||||
if (isset(self::$theme_data->accessory)) {
|
||||
if (!file_exists($path . '/' . self::$theme_data->accessory->asset)) {
|
||||
throw new \Exception('Icon asset not found');
|
||||
}
|
||||
|
||||
self::$theme_data->accessory->url = asset('themes/' . self::$theme_data->name . '/' . self::$theme_data->accessory->asset);
|
||||
|
||||
self::$theme_data->accessory->inline_rules = new \stdClass();
|
||||
|
||||
self::$theme_data->accessory->inline_rules->base = '';
|
||||
foreach (self::$theme_data->accessory->base as $key => $value) {
|
||||
self::$theme_data->accessory->inline_rules->base .= $key . ': ' . $value . ' !important;';
|
||||
}
|
||||
|
||||
self::$theme_data->accessory->inline_rules->img = '';
|
||||
foreach (self::$theme_data->accessory->img as $key => $value) {
|
||||
self::$theme_data->accessory->inline_rules->img .= $key . ': ' . $value . ' !important;';
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function data()
|
||||
{
|
||||
try {
|
||||
return self::$theme_data;
|
||||
} catch (\Exception $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function ready()
|
||||
{
|
||||
return (is_object(self::$theme_data));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function list()
|
||||
{
|
||||
try {
|
||||
$result = [];
|
||||
|
||||
$folders = scandir(public_path() . '/themes');
|
||||
foreach ($folders as $folder) {
|
||||
if (((substr($folder, 0, 1)) !== '.') && (is_dir(public_path() . '/themes/' . $folder))) {
|
||||
$result[] = $folder;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
} catch (\Exception $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -284,6 +284,17 @@ a.navbar-burger:hover {
|
||||
height: 72px;
|
||||
}
|
||||
|
||||
.banner-accessory {
|
||||
position: relative;
|
||||
top: 172px;
|
||||
right: -83%;
|
||||
}
|
||||
|
||||
.banner-accessory img {
|
||||
width: 256px;
|
||||
height: 256px;
|
||||
}
|
||||
|
||||
.content-inner {
|
||||
position: relative;
|
||||
padding: 15px;
|
||||
|
||||
@@ -4,4 +4,10 @@
|
||||
<img src="{{ asset('img/banner-icon.png') }}" alt="banner-icon"/>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (file_exists(public_path() . '/img/banner-accessory.png'))
|
||||
<div class="banner-accessory">
|
||||
<img src="{{ asset('img/banner-accessory.png') }}" alt="banner-accessory"/>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
+17
-1
@@ -24,7 +24,12 @@
|
||||
<div id="scroller-top"></div>
|
||||
|
||||
@include('navbar.php')
|
||||
@include('banner.php')
|
||||
|
||||
@if (ThemeModule::ready())
|
||||
@include('theme.php')
|
||||
@else
|
||||
@include('banner.php')
|
||||
@endif
|
||||
|
||||
<div id="small-system-messages"></div>
|
||||
|
||||
@@ -643,6 +648,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label">{{ __('app.theme') }}</label>
|
||||
<div class="control">
|
||||
<select class="input" name="theme" id="selEditCombo">
|
||||
@foreach (ThemeModule::list() as $theme)
|
||||
<option value="{{ $theme }}" {{ ($user->get('theme') === $theme) ? 'selected' : ''}}>{{ $theme }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field {{ ((!app('chat_enable')) ? 'is-hidden': '') }}">
|
||||
<label class="label">{{ __('app.chatcolor') }}</label>
|
||||
<div class="control">
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<div class="banner" style="background-image: url('{{ ThemeModule::data()->banner_url }}'); {{ ThemeModule::data()->inline_rules }}">
|
||||
@if (isset(ThemeModule::data()->icon))
|
||||
<div class="banner-icon" style="{{ ThemeModule::data()->icon->inline_rules->base }}">
|
||||
<img src="{{ ThemeModule::data()->icon->url }}" alt="banner-icon" style="{{ ThemeModule::data()->icon->inline_rules->img }}"/>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (isset(ThemeModule::data()->accessory))
|
||||
<div class="banner-accessory" style="{{ ThemeModule::data()->accessory->inline_rules->base }}">
|
||||
<img src="{{ ThemeModule::data()->accessory->url }}" alt="banner-accessory" style="{{ ThemeModule::data()->accessory->inline_rules->img }}"/>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 837 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 113 KiB |
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "default",
|
||||
"banner": "banner.jpg",
|
||||
"rules": {
|
||||
"height": "250px"
|
||||
},
|
||||
"icon": {
|
||||
"asset": "banner-icon.png",
|
||||
"base": {
|
||||
"top": "210px",
|
||||
"left": "195px"
|
||||
},
|
||||
"img": {
|
||||
"width": "72px",
|
||||
"height": "72px"
|
||||
}
|
||||
},
|
||||
"accessory": {
|
||||
"asset": "banner-accessory.png",
|
||||
"base": {
|
||||
"top": "172px",
|
||||
"right": "-83%"
|
||||
},
|
||||
"img": {
|
||||
"width": "256px",
|
||||
"height": "256px"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user