Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add icon picker to announcements, navigation and forums #3256

Draft
wants to merge 2 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions core/classes/Templates/AssetTree.php
Expand Up @@ -84,6 +84,7 @@ class AssetTree {
* @var string Fomantic-UI bundle v2.8 (CSS + JS)
*/
public const FOMANTIC_UI = 'FOMANTIC_UI';
public const ICON_PICKER = 'ICON_PICKER';

/**
* @var mixed Tree of all available assets, with their applicable CSS/JS files.
Expand Down Expand Up @@ -254,5 +255,13 @@ class AssetTree {
self::JQUERY,
]
],
self::ICON_PICKER => [
'js' => [
'vendor/@migliori/universal-icon-picker/assets/js/universal-icon-picker.min.js',
],
'css' => [
'vendor/fomantic-ui/dist/components/icon.min.css',
]
],
];
}
36 changes: 36 additions & 0 deletions core/includes/updates/203.php
Expand Up @@ -17,10 +17,46 @@ public function run(): void {
}
Util::setSetting('minecraft_query_interval', $query_interval);
}

// Update icon definitions to just be class names instead of full HTML
$announcements = DB::getInstance()->get('announcements', ['icon', '<>', ''])->results();
foreach ($announcements as $announcement) {
DB::getInstance()->update('announcements', $announcement->id, [
'icon' => $this->extractIconClasses($announcement->icon)
]);
}
(new Announcements($cache))->resetCache();

$custom_pages = DB::getInstance()->get('custom_pages', ['icon', '<>', ''])->results();
foreach ($custom_pages as $custom_page) {
DB::getInstance()->update('custom_pages', $custom_page->id, [
'icon' => $this->extractIconClasses($custom_page->icon)
]);
}

$forums = DB::getInstance()->get('forums', ['icon', '<>', ''])->results();
foreach ($forums as $forum) {
DB::getInstance()->update('forums', $forum->id, [
'icon' => $this->extractIconClasses($forum->icon)
]);
}

$cache->setCache('navbar_icons');
$icons = $cache->retrieveAll();
foreach ($icons as $key => $icon) {
$cache->store($key, $this->extractIconClasses($icon));
}

// Add all groups to member list selectable groups
Util::setSetting('member_list_viewable_groups', json_encode(array_map(static fn (Group $group) => $group->id, Group::all())), 'Members');

$this->setVersion('2.1.0');
}

/**
* Transform "<i class="fas fa-home"></i>" to "fas fa-home"
*/
private function extractIconClasses(string $icon_html): string {
return preg_replace('/<i class="([^"]+)"><\/i>/', '$1', $icon_html);
}
};
36 changes: 30 additions & 6 deletions custom/panel_templates/Default/core/announcements_form.tpl
Expand Up @@ -89,11 +89,24 @@
</div>
</div>
<div class="form-group">
<label for="icon">{$ICON} <span class="badge badge-info" data-toggle="popover"
data-title="{$INFO}" data-content="{$ICON_INFO}"><i
class="fa fa-question"></i></label>
<input type="text" name="icon" id="icon" class="form-control"
placeholder="fas fa-edit" value="{$ICON_VALUE}">
<label for="icon">
{$ICON}
<span class="badge badge-info" data-toggle="popover" data-title="{$INFO}" data-content="{$ICON_INFO}">
<i class="fa fa-question"></i>
</span>
</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"
id="nav-icon-picker"
style="cursor: pointer;"
>
<i class="fa fa-plus"></i>
</span>
</div>
<input type="text" name="icon" id="icon" class="form-control"
placeholder="fa-solid fa-triangle-exclamation" value="{$ICON_VALUE}">
</div>
</div>
<div class="form-group">
<label for="icon">{$ORDER}</label>
Expand Down Expand Up @@ -246,9 +259,20 @@
}).children().click(function (e) {
e.stopPropagation();
});

new UniversalIconPicker('#nav-icon-picker', {
allowEmpty: false,
iconLibraries: [
'fomantic-ui.min.json',
'font-awesome.min.json',
],
onSelect: (icon) => {
document.getElementById('icon').value = icon.iconClass;
}
});
});
</script>

</body>

</html>
</html>
118 changes: 73 additions & 45 deletions custom/panel_templates/Default/core/navigation.tpl
Expand Up @@ -42,58 +42,68 @@
<form action="" method="post">
<div class="card shadow border-left-primary">
<div class="card-body">
<h5><i class="icon fa fa-info-circle"></i> {$INFO}</h5>
<h5><i class="fa fa-info-circle"></i> {$INFO}</h5>
<p>{$NAVBAR_ORDER_INSTRUCTIONS}</p>
<p>{$NAVBAR_ICON_INSTRUCTIONS}</p>
</div>
</div>
<br />
{foreach from=$NAV_ITEMS key=key item=item}
<strong>{$item.title|escape}</strong>
<div class="form-group">
<div class="row">
<div class="col-md-6">
<label for="input{$item.title|escape}">{$NAVBAR_ORDER}</label>
<input type="number" min="1" class="form-control"
id="input{$item.title|escape}"
name="inputOrder[{if isset($item.custom) && is_numeric($item.custom)}{$item.custom}{else}{$key}{/if}]"
value="{$item.order|escape}">
</div>
<div class="col-md-6">
<label for="input{$item.title|escape}Icon">{$NAVBAR_ICON}</label>
<input type="text" class="form-control" id="input{$item.title|escape}Icon"
name="inputIcon[{if isset($item.custom) && is_numeric($item.custom)}{$item.custom}{else}{$key}{/if}]"
value="{$item.icon|escape}"
placeholder='<i class="fas fa-home icon"></i>'>
<strong>{$item.title|escape}</strong>
<div class="form-group">
<div class="row">
<div class="col-md-6">
<label for="input{$item.title|escape}">{$NAVBAR_ORDER}</label>
<input type="number" min="1" class="form-control"
id="input{$item.title|escape}"
name="inputOrder[{if isset($item.custom) && is_numeric($item.custom)}{$item.custom}{else}{$key}{/if}]"
value="{$item.order|escape}">
</div>
<div class="col-md-6">
<label for="input{$item.title|escape}Icon">{$NAVBAR_ICON}</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text icon-picker"
id="nav-icon-picker-{if isset($item.custom) && is_numeric($item.custom)}{$item.custom}{else}{$key}{/if}"
style="cursor: pointer;"
>
<i class="fa fa-plus"></i>
</span>
</div>
<input type="text" class="form-control" id="input{$item.title|escape}Icon"
name="inputIcon[{if isset($item.custom) && is_numeric($item.custom)}{$item.custom}{else}{$key}{/if}]"
value="{$item.icon|escape}"
placeholder="fa-solid fa-house">
</div>
</div>
</div>
</div>
</div>
{if isset($item.items) && count($item.items)}
<br>
<strong>{$item.title|escape} &raquo; {$DROPDOWN_ITEMS}</strong>
<br />
{foreach from=$item.items key=dropdown_key item=dropdown_item}
<strong>{$dropdown_item.title|escape}</strong>
<div class="form-group">
<div class="row">
<div class="col-md-6">
<label for="input{$dropdown_item.title|escape}">{$NAVBAR_ORDER}</label>
<input type="number" min="1" class="form-control"
id="input{$dropdown_item.title|escape}"
name="inputOrder[{if isset($dropdown_item.custom) && is_numeric($dropdown_item.custom)}{$dropdown_item.custom}{else}{$dropdown_key}{/if}]"
value="{$dropdown_item.order|escape}">
</div>
<div class="col-md-6">
<label for="input{$dropdown_item.title|escape}Icon">{$NAVBAR_ICON}</label>
<input type="text" class="form-control"
id="input{$dropdown_item.title|escape}Icon"
name="inputIcon[{if isset($dropdown_item.custom) && is_numeric($dropdown_item.custom)}{$dropdown_item.custom}{else}{$dropdown_key}{/if}]"
value="{$dropdown_item.icon|escape}">
</div>
</div>
</div>
{/foreach}
{/if}
{if isset($item.items) && count($item.items)}
<br>
<strong>{$item.title|escape} &raquo; {$DROPDOWN_ITEMS}</strong>
<br />
{foreach from=$item.items key=dropdown_key item=dropdown_item}
<strong>{$dropdown_item.title|escape}</strong>
<div class="form-group">
<div class="row">
<div class="col-md-6">
<label for="input{$dropdown_item.title|escape}">{$NAVBAR_ORDER}</label>
<input type="number" min="1" class="form-control"
id="input{$dropdown_item.title|escape}"
name="inputOrder[{if isset($dropdown_item.custom) && is_numeric($dropdown_item.custom)}{$dropdown_item.custom}{else}{$dropdown_key}{/if}]"
value="{$dropdown_item.order|escape}">
</div>
<div class="col-md-6">
<label for="input{$dropdown_item.title|escape}Icon">{$NAVBAR_ICON}</label>
<input type="text" class="form-control"
id="input{$dropdown_item.title|escape}Icon"
name="inputIcon[{if isset($dropdown_item.custom) && is_numeric($dropdown_item.custom)}{$dropdown_item.custom}{else}{$dropdown_key}{/if}]"
value="{$dropdown_item.icon|escape}">
</div>
</div>
</div>
{/foreach}
{/if}

{/foreach}
<hr>
Expand Down Expand Up @@ -130,6 +140,24 @@

{include file='scripts.tpl'}

<script>
$(document).ready(function () {
$('.icon-picker').each(function () {
const id = $(this).attr('id').replace('nav-icon-picker-', '');
new UniversalIconPicker('#nav-icon-picker-' + id, {
allowEmpty: false,
iconLibraries: [
'fomantic-ui.min.json',
'font-awesome.min.json',
],
onSelect: (icon) => {
document.getElementsByName('inputIcon[' + id + ']')[0].value = icon.iconClass;
}
});
});
});
</script>

</body>

</html>
</html>
34 changes: 30 additions & 4 deletions custom/panel_templates/Default/forum/forums_edit.tpl
Expand Up @@ -78,9 +78,24 @@
</div>

<div class="form-group">
<label for="InputIcon">{$FORUM_ICON}</label>
<input type="text" name="icon" class="form-control" id="InputIcon"
placeholder='<i class="fas fa-comment icon">' value="{$FORUM_ICON_VALUE}">
<label for="InputIcon">
{$FORUM_ICON}
<span class="badge badge-info" data-toggle="popover" data-title="{$INFO}" data-content="{$ICON_INFO}">
<i class="fa fa-question"></i>
</span>
</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"
id="nav-icon-picker"
style="cursor: pointer;"
>
<i class="fa fa-plus"></i>
</span>
</div>
<input type="text" name="icon" class="form-control" id="InputIcon"
placeholder="fa-solid fa-comment" value="{$FORUM_ICON_VALUE}">
</div>
</div>

<div class="form-group">
Expand Down Expand Up @@ -387,9 +402,20 @@

$("#InputHooks").select2({ placeholder: "{$NO_ITEM_SELECTED}" });
$("#InputDefaultLabels").select2({ placeholder: "{$NO_ITEM_SELECTED}" });

new UniversalIconPicker('#nav-icon-picker', {
allowEmpty: false,
iconLibraries: [
'fomantic-ui.min.json',
'font-awesome.min.json',
],
onSelect: (icon) => {
document.getElementById('InputIcon').value = icon.iconClass;
}
});
});
</script>

</body>

</html>
</html>