theme selector
This commit is contained in:
parent
124b0e82df
commit
da5346d0a9
9 changed files with 99 additions and 20 deletions
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 4.2.7 on 2024-01-06 19:29
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('control', '0012_userpermissions_grant_unlimited_access'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='userpermissions',
|
||||
name='nonpublic_themes',
|
||||
field=models.BooleanField(default=False, verbose_name='show non-public themes in theme selector'),
|
||||
),
|
||||
]
|
|
@ -38,6 +38,8 @@ class UserPermissions(models.Model):
|
|||
|
||||
mesh_control = models.BooleanField(default=False, verbose_name=_('can access mesh control'))
|
||||
|
||||
nonpublic_themes = models.BooleanField(default=False, verbose_name=_('show non-public themes in theme selector'))
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('User Permissions')
|
||||
verbose_name_plural = _('User Permissions')
|
||||
|
|
|
@ -30,7 +30,8 @@ class Migration(migrations.Migration):
|
|||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', c3nav.mapdata.fields.I18nField(blank=True, fallback_any=True, fallback_value='{model} {pk}', plural_name='titles', verbose_name='Title')),
|
||||
('description', models.TextField()),
|
||||
('description', models.TextField(verbose_name='Description')),
|
||||
('public', models.BooleanField(default=False, verbose_name='Public')),
|
||||
('color_background', models.CharField(max_length=32, verbose_name='background color')),
|
||||
('color_wall_fill', models.CharField(max_length=32, verbose_name='wall fill color')),
|
||||
('color_wall_border', models.CharField(max_length=32, verbose_name='wall border color')),
|
||||
|
|
|
@ -11,7 +11,8 @@ class Theme(TitledMixin, models.Model):
|
|||
A theme
|
||||
"""
|
||||
# TODO: when a theme base colors change we need to bust the cache somehow
|
||||
description = models.TextField()
|
||||
description = models.TextField(verbose_name=('Description'))
|
||||
public = models.BooleanField(default=False, verbose_name=_('Public'))
|
||||
color_background = models.CharField(max_length=32, verbose_name=_('background color'))
|
||||
color_wall_fill = models.CharField(max_length=32, verbose_name=_('wall fill color'))
|
||||
color_wall_border = models.CharField(max_length=32, verbose_name=_('wall border color'))
|
||||
|
|
|
@ -13,6 +13,7 @@ def get_user_data(request):
|
|||
'logged_in': bool(request.user.is_authenticated),
|
||||
'allow_editor': can_access_editor(request),
|
||||
'allow_control_panel': request.user_permissions.control_panel,
|
||||
'show_nonpublic_themes': request.user_permissions.nonpublic_themes,
|
||||
'has_positions': Position.user_has_positions(request.user)
|
||||
}
|
||||
if permissions:
|
||||
|
|
|
@ -1100,7 +1100,7 @@ body:not(.mobileclient) .share-ui p {
|
|||
body:not(.mobileclient) .locationinput.empty .locate {
|
||||
opacity: 0.4;
|
||||
}
|
||||
main > .share-ui, #reload-msg, #app-ad {
|
||||
main > .share-ui, #reload-msg, #app-ad, main > .theme-selection {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -135,6 +135,16 @@ c3nav = {
|
|||
if ($body.is('[data-user-data]')) {
|
||||
c3nav._set_user_data(JSON.parse($body.attr('data-user-data')));
|
||||
}
|
||||
|
||||
|
||||
const theme = localStorageWrapper.getItem('c3nav-theme');
|
||||
if (theme) {
|
||||
c3nav.theme = parseInt(theme);
|
||||
}
|
||||
c3nav.themes = JSON.parse(document.getElementById('available-themes').textContent);
|
||||
if (!(c3nav.theme in c3nav.themes)) {
|
||||
c3nav.theme = 0;
|
||||
}
|
||||
},
|
||||
_searchable_locations_timer: null,
|
||||
load_searchable_locations: function(firstTime) {
|
||||
|
@ -207,6 +217,9 @@ c3nav = {
|
|||
|
||||
c3nav.random_location_groups = $main.is('[data-random-location-groups]') ? $main.attr('data-random-location-groups').split(',').map(id => parseInt(id)) : null;
|
||||
|
||||
$(document).on('click', '.theme-selection>button', c3nav.select_theme);
|
||||
|
||||
|
||||
history.replaceState(state, window.location.path);
|
||||
c3nav.load_state(state, true);
|
||||
c3nav.update_map_locations();
|
||||
|
@ -1411,7 +1424,7 @@ c3nav = {
|
|||
L.control.scale({imperial: false}).addTo(c3nav.map);
|
||||
|
||||
// setup level control
|
||||
c3nav._levelControl = new LevelControl().addTo(c3nav.map);
|
||||
c3nav._levelControl = new LevelControl({initialTheme: c3nav.theme}).addTo(c3nav.map);
|
||||
c3nav._locationLayers = {};
|
||||
c3nav._locationLayerBounds = {};
|
||||
c3nav._detailLayers = {};
|
||||
|
@ -1438,8 +1451,10 @@ c3nav = {
|
|||
c3nav._gridLayer = new L.SquareGridLayer(JSON.parse($map.attr('data-grid')));
|
||||
c3nav._gridControl = new SquareGridControl().addTo(c3nav.map);
|
||||
}
|
||||
|
||||
new ThemeControl().addTo(c3nav.map);
|
||||
if (Object.values(c3nav.themes)
|
||||
.filter(([_, isPublic]) => isPublic || c3nav.user_data.show_nonpublic_themes).length > 0) {
|
||||
new ThemeControl().addTo(c3nav.map);
|
||||
}
|
||||
|
||||
// setup user location control
|
||||
c3nav._userLocationControl = new UserLocationControl().addTo(c3nav.map);
|
||||
|
@ -1454,16 +1469,36 @@ c3nav = {
|
|||
|
||||
},
|
||||
theme: 0,
|
||||
show_theme_select: function() {
|
||||
// TODO: actual theme selection
|
||||
if (c3nav.theme === 0) {
|
||||
c3nav.theme = 1;
|
||||
} else {
|
||||
c3nav.theme = 0;
|
||||
}
|
||||
setTheme: function(theme) {
|
||||
if (theme === c3nav.theme) return;
|
||||
c3nav.theme = theme;
|
||||
localStorageWrapper.setItem('c3nav-theme', c3nav.theme);
|
||||
c3nav._levelControl.setTheme(c3nav.theme);
|
||||
// openInModal('/theme')
|
||||
},
|
||||
show_theme_select: function(e) {
|
||||
e.preventDefault();
|
||||
c3nav.open_modal(document.querySelector('main>.theme-selection').outerHTML);
|
||||
const select = document.querySelector('#modal .theme-selection select');
|
||||
for (const id in c3nav.themes) {
|
||||
const [name, is_public] = c3nav.themes[id];
|
||||
if (c3nav.user_data.show_nonpublic_themes || is_public) {
|
||||
const option = document.createElement('option');
|
||||
option.value = id;
|
||||
option.innerText = name;
|
||||
select.append(option);
|
||||
}
|
||||
}
|
||||
const currentThemeOption = select.querySelector(`[value="${c3nav.theme}"]`);
|
||||
if (currentThemeOption) {
|
||||
currentThemeOption.selected = true;
|
||||
}
|
||||
},
|
||||
select_theme: function(e) {
|
||||
var theme = parseInt(e.target.parentElement.querySelector('select').value);
|
||||
c3nav.setTheme(theme);
|
||||
history.back(); // close the modal
|
||||
},
|
||||
|
||||
_click_anywhere_popup: null,
|
||||
_click_anywhere: function(e) {
|
||||
if (e.originalEvent.target.id !== 'map') return;
|
||||
|
@ -2020,7 +2055,8 @@ function mobileclientOnResume() {
|
|||
LevelControl = L.Control.extend({
|
||||
options: {
|
||||
position: 'bottomright',
|
||||
addClasses: ''
|
||||
addClasses: '',
|
||||
initialTheme: 0,
|
||||
},
|
||||
|
||||
onAdd: function () {
|
||||
|
@ -2029,11 +2065,12 @@ LevelControl = L.Control.extend({
|
|||
this._overlayLayers = {};
|
||||
this._levelButtons = {};
|
||||
this.currentLevel = null;
|
||||
this.currentTheme = this.options.initialTheme;
|
||||
return this._container;
|
||||
},
|
||||
|
||||
createTileLayer: function(id, theme) {
|
||||
let urlPattern = (c3nav.tile_server || '/map/') + `${id}/{z}/{x}/{y}/${theme}.png`;
|
||||
createTileLayer: function(id) {
|
||||
let urlPattern = (c3nav.tile_server || '/map/') + `${id}/{z}/{x}/{y}/${this.currentTheme}.png`;
|
||||
return L.tileLayer(urlPattern, {
|
||||
minZoom: -2,
|
||||
maxZoom: 5,
|
||||
|
@ -2041,12 +2078,14 @@ LevelControl = L.Control.extend({
|
|||
});
|
||||
},
|
||||
setTheme: function(theme) {
|
||||
if (theme === this.currentTheme) return;
|
||||
this.currentTheme = theme;
|
||||
if (this.currentLevel !== null) {
|
||||
this._tileLayers[this.currentLevel].remove();
|
||||
}
|
||||
|
||||
for (const id in this._tileLayers) {
|
||||
this._tileLayers[id] = this.createTileLayer(id, theme);
|
||||
this._tileLayers[id] = this.createTileLayer(id);
|
||||
}
|
||||
|
||||
if (this.currentLevel !== null) {
|
||||
|
@ -2054,7 +2093,7 @@ LevelControl = L.Control.extend({
|
|||
}
|
||||
},
|
||||
addLevel: function (id, title) {
|
||||
this._tileLayers[id] = this.createTileLayer(id, 0);
|
||||
this._tileLayers[id] = this.createTileLayer(id);
|
||||
var overlay = L.layerGroup();
|
||||
this._overlayLayers[id] = overlay;
|
||||
|
||||
|
@ -2105,7 +2144,7 @@ LevelControl = L.Control.extend({
|
|||
buttons.removeClass('current');
|
||||
},
|
||||
|
||||
reloadMap: function() {
|
||||
reloadMap: function() { // TODO: create fresh tile layers
|
||||
if (this.currentLevel === null) return;
|
||||
var old_tile_layer = this._tileLayers[this.currentLevel],
|
||||
new_tile_layer = this.createTileLayer(this.currentLevel);
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
<meta property="og:url" content="{{ meta.canonical_url }}"/>
|
||||
<meta property="twitter:url" content="{{ meta.canonical_url }}"/>
|
||||
{% endif %}
|
||||
|
||||
{{ available_themes|json_script:"available-themes" }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
@ -248,6 +250,16 @@
|
|||
{% blocktrans with play_url="https://play.google.com/store/apps/details?id=de.c3nav.droid" apk_url="https://github.com/c3nav/c3nav-android/releases" %}Get the c3nav Android app on <a href="{{ play_url }}" target="_blank">Google Play</a> or <a href="{{ apk_url }}" target="_blank">download the APK!</a>{% endblocktrans %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="theme-selection">
|
||||
<h2>{% trans 'Select theme' %}</h2>
|
||||
<p>
|
||||
<label for="id_theme">Theme:</label>
|
||||
<select name="theme" required="" id="id_theme">
|
||||
<option value="0">{% trans 'Default theme' %}</option>
|
||||
</select>
|
||||
</p>
|
||||
<button>Save theme</button>
|
||||
</div>
|
||||
{% else %}
|
||||
<a id="embed-logo" class="embed-link" target="_blank">{% if header_logo %}<img src="{% static header_logo %}">{% else %}<span>c3nav</span>{% endif %}</a>
|
||||
<a id="embed-open" class="embed-link" target="_blank">{% trans 'open in c3nav' %}</a>
|
||||
|
|
|
@ -179,6 +179,7 @@ def map_index(request, mode=None, slug=None, slug2=None, details=None, options=N
|
|||
else:
|
||||
metadata = None
|
||||
|
||||
from c3nav.mapdata.models.theme import Theme
|
||||
ctx = {
|
||||
'bounds': json.dumps(Source.max_bounds(), separators=(',', ':')),
|
||||
'levels': json.dumps(tuple((level.pk, level.short_label) for level in levels.values()), separators=(',', ':')),
|
||||
|
@ -196,6 +197,10 @@ def map_index(request, mode=None, slug=None, slug2=None, details=None, options=N
|
|||
'embed': bool(embed),
|
||||
'imprint': settings.IMPRINT_LINK,
|
||||
'meta': metadata,
|
||||
'available_themes': {
|
||||
theme.pk: [theme.title, theme.public]
|
||||
for theme in Theme.objects.all()
|
||||
}
|
||||
}
|
||||
|
||||
if grid.enabled:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue