diff --git a/src/apps/dashboard/views.py b/src/apps/dashboard/views.py
index e13d3dd..06c829a 100644
--- a/src/apps/dashboard/views.py
+++ b/src/apps/dashboard/views.py
@@ -303,9 +303,12 @@ def sky_view(request):
return render(request, "apps/dashboard/sky.html", {
"preview_url": request.build_absolute_uri("/dashboard/sky/preview"),
"save_url": request.build_absolute_uri("/dashboard/sky/save"),
- "saved_sky": request.user.sky_chart_data,
+ "saved_sky": request.user.sky_chart_data,
"saved_birth_dt": request.user.sky_birth_dt,
"saved_birth_place": request.user.sky_birth_place,
+ "saved_birth_lat": request.user.sky_birth_lat,
+ "saved_birth_lon": request.user.sky_birth_lon,
+ "saved_birth_tz": request.user.sky_birth_tz,
"page_class": "page-sky",
})
@@ -338,12 +341,13 @@ def sky_save(request):
user.sky_birth_lat = body.get('birth_lat')
user.sky_birth_lon = body.get('birth_lon')
user.sky_birth_place = body.get('birth_place', '')
+ user.sky_birth_tz = body.get('birth_tz', '')
user.sky_house_system = body.get('house_system', 'O')
user.sky_chart_data = body.get('chart_data')
user.save(update_fields=[
'sky_birth_dt', 'sky_birth_lat', 'sky_birth_lon',
- 'sky_birth_place', 'sky_house_system', 'sky_chart_data',
+ 'sky_birth_place', 'sky_birth_tz', 'sky_house_system', 'sky_chart_data',
])
return JsonResponse({"saved": True})
diff --git a/src/apps/lyric/migrations/0019_sky_birth_tz.py b/src/apps/lyric/migrations/0019_sky_birth_tz.py
new file mode 100644
index 0000000..229e1e2
--- /dev/null
+++ b/src/apps/lyric/migrations/0019_sky_birth_tz.py
@@ -0,0 +1,18 @@
+# Generated by Django 6.0 on 2026-04-22 01:39
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('lyric', '0018_user_sky_fields'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='user',
+ name='sky_birth_tz',
+ field=models.CharField(blank=True, max_length=64),
+ ),
+ ]
diff --git a/src/apps/lyric/models.py b/src/apps/lyric/models.py
index 5e2b752..886a6f2 100644
--- a/src/apps/lyric/models.py
+++ b/src/apps/lyric/models.py
@@ -52,6 +52,7 @@ class User(AbstractBaseUser):
sky_birth_lat = models.DecimalField(max_digits=9, decimal_places=4, null=True, blank=True)
sky_birth_lon = models.DecimalField(max_digits=9, decimal_places=4, null=True, blank=True)
sky_birth_place = models.CharField(max_length=255, blank=True)
+ sky_birth_tz = models.CharField(max_length=64, blank=True)
sky_house_system = models.CharField(max_length=1, blank=True, default="O")
sky_chart_data = models.JSONField(null=True, blank=True)
diff --git a/src/templates/apps/dashboard/sky.html b/src/templates/apps/dashboard/sky.html
index 554aa4e..85d0d6a 100644
--- a/src/templates/apps/dashboard/sky.html
+++ b/src/templates/apps/dashboard/sky.html
@@ -19,12 +19,14 @@
-
+
-
+
Local time at birth place. Use 12:00 if unknown.
@@ -33,7 +35,8 @@
+ placeholder="auto-detected from location"
+ {% if saved_birth_tz %}value="{{ saved_birth_tz }}"{% endif %}>
@@ -109,9 +115,6 @@
const NOMINATIM = 'https://nominatim.openstreetmap.org/search';
const USER_AGENT = 'EarthmanRPG/1.0 (https://earthmanrpg.me)';
- // localStorage key — fixed for the user's personal sky (not room-scoped)
- const LS_KEY = 'natus-form:dashboard:sky';
-
let _lastChartData = null;
let _placeDebounce = null;
let _chartDebounce = null;
@@ -120,34 +123,6 @@
NatusWheel.preload();
- // ── localStorage persistence ────────────────────────────────────────────
-
- function _saveForm() {
- const data = {
- date: document.getElementById('id_nf_date').value,
- time: document.getElementById('id_nf_time').value,
- place: placeInput.value,
- lat: latInput.value,
- lon: lonInput.value,
- tz: tzInput.value,
- };
- try { localStorage.setItem(LS_KEY, JSON.stringify(data)); } catch (_) {}
- }
-
- function _restoreForm() {
- let data;
- try { data = JSON.parse(localStorage.getItem(LS_KEY) || 'null'); } catch (_) {}
- if (!data) return;
- if (data.date) document.getElementById('id_nf_date').value = data.date;
- if (data.time) document.getElementById('id_nf_time').value = data.time;
- if (data.place) placeInput.value = data.place;
- if (data.lat) latInput.value = data.lat;
- if (data.lon) lonInput.value = data.lon;
- if (data.tz) { tzInput.value = data.tz; tzHint.textContent = 'Auto-detected from coordinates.'; }
- // If we have enough data from localStorage, kick off a wheel draw
- if (_formReady()) schedulePreview();
- }
-
// ── Status helper ───────────────────────────────────────────────────────
function setStatus(msg, type) {
@@ -209,7 +184,6 @@
latInput.value = parseFloat(place.lat).toFixed(4);
lonInput.value = parseFloat(place.lon).toFixed(4);
hideSuggestions();
- _saveForm();
schedulePreview();
}
@@ -230,8 +204,7 @@
})
.then(r => r.json())
.then(data => { placeInput.value = _cityName(data.address) || data.display_name || ''; })
- .catch(() => {})
- .finally(() => _saveForm());
+ .catch(() => {});
setStatus('');
schedulePreview();
},
@@ -251,7 +224,6 @@
form.addEventListener('input', (e) => {
if (e.target === placeInput) return;
- _saveForm();
clearTimeout(_chartDebounce);
_chartDebounce = setTimeout(schedulePreview, CHART_DELAY);
});
@@ -312,6 +284,7 @@
birth_lat: parseFloat(latInput.value),
birth_lon: parseFloat(lonInput.value),
birth_place: placeInput.value,
+ birth_tz: tzInput.value.trim(),
house_system: _lastChartData.house_system || 'O',
chart_data: _lastChartData,
};
@@ -340,9 +313,9 @@
return m ? m[1] : '';
}
- // ── Restore persisted form on load ───────────────────────────────────────
+ // ── Auto-preview on load if form is pre-filled from saved sky ───────────
- _restoreForm();
+ if (_formReady()) schedulePreview();
})();
{% endblock %}