change: Konzerte ohne Zeitfenster — Chips nur noch bei den Veroeffentlichungen
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
17a677a5a5
commit
ae357b0eb9
9 files changed
+52
-34
No files matched your search
+7
-3
@@ -81,7 +81,7 @@ Die Android-App zählt eigenständig weiter (mehrere APKs pro Release). Welche d
|
|||||||
|
|
||||||
## [3.1] — 2026-09-22
|
## [3.1] — 2026-09-22
|
||||||
|
|
||||||
**Android:** 1.15 (versionCode 18) → 1.23 (versionCode 26). 1.16 brachte den Rollbalken, 1.17 bis 1.21 machten ihn bedienbar, 1.19 das Bearbeiten der Warteschlange, 1.22 die Wischgeste, den Mischen-Fehler und die zwei neuen Designs, 1.23 den Honigtopf und die Gesamtdauer, 1.24 die Konzerte.
|
**Android:** 1.15 (versionCode 18) → 1.23 (versionCode 26). 1.16 brachte den Rollbalken, 1.17 bis 1.21 machten ihn bedienbar, 1.19 das Bearbeiten der Warteschlange, 1.22 die Wischgeste, den Mischen-Fehler und die zwei neuen Designs, 1.23 den Honigtopf und die Gesamtdauer, 1.24 die Konzerte, 1.25 sie ohne Zeitfenster.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- **Konzerte deiner Künstler (Web + Android)** — die Zeitleiste hat einen zweiten Reiter: neben
|
- **Konzerte deiner Künstler (Web + Android)** — die Zeitleiste hat einen zweiten Reiter: neben
|
||||||
@@ -92,8 +92,12 @@ Die Android-App zählt eigenständig weiter (mehrere APKs pro Release). Welche d
|
|||||||
- **Bewusst nicht in eine gemeinsame Liste gemischt.** Veröffentlichungen liegen hinter dir,
|
- **Bewusst nicht in eine gemeinsame Liste gemischt.** Veröffentlichungen liegen hinter dir,
|
||||||
Konzerte vor dir. Chronologisch gemischt stünde „heute" mittendrin und man wüsste nie, ob man
|
Konzerte vor dir. Chronologisch gemischt stünde „heute" mittendrin und man wüsste nie, ob man
|
||||||
vorwärts oder rückwärts liest. Deshalb läuft die Konzertliste **nach vorn**: das nächste
|
vorwärts oder rückwärts liest. Deshalb läuft die Konzertliste **nach vorn**: das nächste
|
||||||
Konzert zuerst. Das Zeitfenster (90/30/365) gilt je Reiter getrennt — bei den Konzerten zeigt
|
Konzert zuerst, nach Monat gruppiert wie bei den Veröffentlichungen.
|
||||||
es nach vorn, Vorgabe ein Jahr.
|
- **Kein Zeitfenster bei den Konzerten.** Die Chips 90/30/365 waren dort zuerst mit dabei und
|
||||||
|
ergaben keinen Sinn: Ticketmaster liefert ohnehin nur Anstehendes, und bei Terminen will man
|
||||||
|
alles Angekündigte sehen — eine Tagesgrenze schneidet nur willkürlich ab. Die Chip-Reihe
|
||||||
|
erscheint jetzt nur noch beim Reiter *Neu erschienen*; der Endpunkt beachtet ein
|
||||||
|
mitgeschicktes Fenster weiterhin, verlangt es aber nicht mehr.
|
||||||
- **Gegenprobe gegen die Stichwortsuche.** Ticketmaster wird über den Namen abgefragt
|
- **Gegenprobe gegen die Stichwortsuche.** Ticketmaster wird über den Namen abgefragt
|
||||||
(`keyword=`), nicht über `attractionId` — dieselbe Unschärfe wie bei der Deezer-Zuordnung.
|
(`keyword=`), nicht über `attractionId` — dieselbe Unschärfe wie bei der Deezer-Zuordnung.
|
||||||
Jeder Treffer wird deshalb gegengeprüft: der Künstlername muss im Veranstaltungs- **oder**
|
Jeder Treffer wird deshalb gegengeprüft: der Künstlername muss im Veranstaltungs- **oder**
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ android {
|
|||||||
applicationId = "com.novasonic.app"
|
applicationId = "com.novasonic.app"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 27
|
versionCode = 28
|
||||||
versionName = "1.24"
|
versionName = "1.25"
|
||||||
// Host der eigenen NovaSonic-Web-App — Ziel der geteilten Links. Einmal in
|
// Host der eigenen NovaSonic-Web-App — Ziel der geteilten Links. Einmal in
|
||||||
// gradle.properties setzen (novasonicHost=music.example.com); ohne Angabe bleibt der
|
// gradle.properties setzen (novasonicHost=music.example.com); ohne Angabe bleibt der
|
||||||
// Platzhalter stehen und der App-Link greift schlicht nicht.
|
// Platzhalter stehen und der App-Link greift schlicht nicht.
|
||||||
|
|||||||
@@ -40,11 +40,12 @@ object ReleasesClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Anstehende Konzerte derselben Kuenstler — gleicher Weg, anderer Endpunkt. */
|
/** Anstehende Konzerte derselben Kuenstler — gleicher Weg, anderer Endpunkt. */
|
||||||
suspend fun konzerte(backendUrl: String, artists: List<ArtistRef>, days: Int): ArtistKonzerteResponse {
|
suspend fun konzerte(backendUrl: String, artists: List<ArtistRef>): ArtistKonzerteResponse {
|
||||||
if (backendUrl.isBlank() || artists.isEmpty()) return ArtistKonzerteResponse()
|
if (backendUrl.isBlank() || artists.isEmpty()) return ArtistKonzerteResponse()
|
||||||
|
// Ohne `days`: das Backend liefert alles Angekuendigte.
|
||||||
return http.post("${backendUrl.trimEnd('/')}/api/artist-concerts") {
|
return http.post("${backendUrl.trimEnd('/')}/api/artist-concerts") {
|
||||||
contentType(ContentType.Application.Json)
|
contentType(ContentType.Application.Json)
|
||||||
setBody(ArtistKonzerteRequest(artists, days))
|
setBody(ArtistKonzerteRequest(artists))
|
||||||
}.body()
|
}.body()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,4 +56,4 @@ data class ArtistKonzerteResponse(
|
|||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ArtistKonzerteRequest(val artists: List<ArtistRef>, val days: Int)
|
data class ArtistKonzerteRequest(val artists: List<ArtistRef>)
|
||||||
@@ -91,16 +91,17 @@ fun ArtistNewsScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Das Zeitfenster gilt nur fuer die Veroeffentlichungen. Konzerte sind ohnehin Zukunft,
|
||||||
|
// dort will man alles Angekuendigte sehen — eine Tagesgrenze schnitte nur willkuerlich ab.
|
||||||
|
if (state.reiter == NewsReiter.RELEASES) {
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
modifier = Modifier.padding(start = 16.dp, top = 8.dp, bottom = 10.dp),
|
modifier = Modifier.padding(start = 16.dp, top = 8.dp, bottom = 10.dp),
|
||||||
) {
|
) {
|
||||||
// 90 Tage zuerst, weil es die Vorgabe ist — der aktive Chip steht dann vorn.
|
// 90 Tage zuerst, weil es die Vorgabe ist — der aktive Chip steht dann vorn.
|
||||||
// Bei den Konzerten zeigt dasselbe Fenster nach VORN, dort sind 1 Jahr die Vorgabe.
|
|
||||||
val aktuell = if (state.reiter == NewsReiter.KONZERTE) state.tageKonzerte else state.tage
|
|
||||||
listOf(90 to "90 Tage", 30 to "30 Tage", 365 to "1 Jahr").forEach { (tage, label) ->
|
listOf(90 to "90 Tage", 30 to "30 Tage", 365 to "1 Jahr").forEach { (tage, label) ->
|
||||||
FilterChip(
|
FilterChip(
|
||||||
selected = aktuell == tage,
|
selected = state.tage == tage,
|
||||||
onClick = { vm.setzeTage(tage) },
|
onClick = { vm.setzeTage(tage) },
|
||||||
label = { Text(label, fontSize = 12.sp) },
|
label = { Text(label, fontSize = 12.sp) },
|
||||||
colors = FilterChipDefaults.filterChipColors(
|
colors = FilterChipDefaults.filterChipColors(
|
||||||
@@ -110,6 +111,9 @@ fun ArtistNewsScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Spacer(Modifier.height(10.dp))
|
||||||
|
}
|
||||||
HorizontalDivider(color = MaterialTheme.colorScheme.outline)
|
HorizontalDivider(color = MaterialTheme.colorScheme.outline)
|
||||||
|
|
||||||
when {
|
when {
|
||||||
@@ -125,7 +129,7 @@ fun ArtistNewsScreen(
|
|||||||
state.reiter == NewsReiter.KONZERTE && state.keinSchluessel -> Hinweis("🎟",
|
state.reiter == NewsReiter.KONZERTE && state.keinSchluessel -> Hinweis("🎟",
|
||||||
"Kein Ticketmaster-Schlüssel hinterlegt", "Im Backend TICKETMASTER_API_KEY setzen.")
|
"Kein Ticketmaster-Schlüssel hinterlegt", "Im Backend TICKETMASTER_API_KEY setzen.")
|
||||||
state.reiter == NewsReiter.KONZERTE && state.konzerte.isEmpty() -> Hinweis("🎪",
|
state.reiter == NewsReiter.KONZERTE && state.konzerte.isEmpty() -> Hinweis("🎪",
|
||||||
"Keine Termine in den nächsten ${state.tageKonzerte} Tagen",
|
"Keine anstehenden Termine",
|
||||||
"Gesucht wird weltweit über den Künstlernamen.")
|
"Gesucht wird weltweit über den Künstlernamen.")
|
||||||
state.reiter == NewsReiter.KONZERTE -> LazyColumn(contentPadding = PaddingValues(bottom = 90.dp)) {
|
state.reiter == NewsReiter.KONZERTE -> LazyColumn(contentPadding = PaddingValues(bottom = 90.dp)) {
|
||||||
var letzterMonat = ""
|
var letzterMonat = ""
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ data class ArtistNewsUiState(
|
|||||||
val reiter: NewsReiter = NewsReiter.RELEASES,
|
val reiter: NewsReiter = NewsReiter.RELEASES,
|
||||||
val releases: List<ArtistRelease> = emptyList(),
|
val releases: List<ArtistRelease> = emptyList(),
|
||||||
val konzerte: List<ArtistKonzert> = emptyList(),
|
val konzerte: List<ArtistKonzert> = emptyList(),
|
||||||
/** Zeitfenster der Konzerte — nach VORN, deshalb ein eigener Wert. */
|
|
||||||
val tageKonzerte: Int = 365,
|
|
||||||
val keinSchluessel: Boolean = false,
|
val keinSchluessel: Boolean = false,
|
||||||
/** Schlüssel (Künstler + Album, normalisiert) alles dessen, was schon in der Bibliothek liegt. */
|
/** Schlüssel (Künstler + Album, normalisiert) alles dessen, was schon in der Bibliothek liegt. */
|
||||||
val vorhanden: Set<String> = emptySet(),
|
val vorhanden: Set<String> = emptySet(),
|
||||||
@@ -59,13 +57,13 @@ class ArtistNewsViewModel(app: Application) : AndroidViewModel(app) {
|
|||||||
if (r == NewsReiter.KONZERTE && _state.value.konzerte.isEmpty()) ladeKonzerte()
|
if (r == NewsReiter.KONZERTE && _state.value.konzerte.isEmpty()) ladeKonzerte()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Zeitfenster setzen — es gilt je Reiter, weil es in verschiedene Richtungen zeigt. */
|
/** Zeitfenster setzen — gibt es nur bei den Veroeffentlichungen. */
|
||||||
fun setzeTage(tage: Int) {
|
fun setzeTage(tage: Int) = laden(tage)
|
||||||
if (_state.value.reiter == NewsReiter.KONZERTE) ladeKonzerte(tage) else laden(tage)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ladeKonzerte(tage: Int = _state.value.tageKonzerte) = viewModelScope.launch {
|
// Kein Zeitfenster: Ticketmaster liefert ohnehin nur Anstehendes, und dort will man alles
|
||||||
_state.value = _state.value.copy(isLoading = true, tageKonzerte = tage, error = null,
|
// Angekuendigte sehen — eine Tagesgrenze schnitte nur willkuerlich ab.
|
||||||
|
fun ladeKonzerte() = viewModelScope.launch {
|
||||||
|
_state.value = _state.value.copy(isLoading = true, error = null,
|
||||||
keineGefolgten = false, keinBackend = false, keinSchluessel = false)
|
keineGefolgten = false, keinBackend = false, keinSchluessel = false)
|
||||||
try {
|
try {
|
||||||
val backendUrl = runCatching { repo.getBackendUrl() }.getOrDefault("")
|
val backendUrl = runCatching { repo.getBackendUrl() }.getOrDefault("")
|
||||||
@@ -78,7 +76,7 @@ class ArtistNewsViewModel(app: Application) : AndroidViewModel(app) {
|
|||||||
_state.value = _state.value.copy(isLoading = false, keineGefolgten = true)
|
_state.value = _state.value.copy(isLoading = false, keineGefolgten = true)
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
val antwort = ReleasesClient.konzerte(backendUrl, kuenstler, tage)
|
val antwort = ReleasesClient.konzerte(backendUrl, kuenstler)
|
||||||
_state.value = _state.value.copy(
|
_state.value = _state.value.copy(
|
||||||
konzerte = antwort.konzerte,
|
konzerte = antwort.konzerte,
|
||||||
keinSchluessel = antwort.keinSchluessel,
|
keinSchluessel = antwort.keinSchluessel,
|
||||||
|
|||||||
@@ -102,11 +102,13 @@ async function inHaeppchen(items, groesse, fn) {
|
|||||||
/**
|
/**
|
||||||
* @param {Array<{id,name}>} kuenstler Navidrome-Künstler
|
* @param {Array<{id,name}>} kuenstler Navidrome-Künstler
|
||||||
* @param {string} apiKey Ticketmaster-Schlüssel
|
* @param {string} apiKey Ticketmaster-Schlüssel
|
||||||
* @param {number} tage Zeitfenster nach vorn
|
* @param {number} tage Zeitfenster nach vorn; 0 = kein Fenster (Vorgabe)
|
||||||
* @returns {{konzerte:Array, ohneTermine:Array<string>}}
|
* @returns {{konzerte:Array, ohneTermine:Array<string>}}
|
||||||
*/
|
*/
|
||||||
async function kommendeKonzerte(kuenstler, apiKey, tage = 365) {
|
async function kommendeKonzerte(kuenstler, apiKey, tage = 0) {
|
||||||
const grenze = Date.now() + tage * 24 * 60 * 60 * 1000;
|
// Kein Fenster als Vorgabe: Ticketmaster liefert ohnehin nur Anstehendes, und bei Konzerten
|
||||||
|
// will man ALLES sehen, was angekuendigt ist — eine Tagesgrenze schneidet nur willkuerlich ab.
|
||||||
|
const grenze = tage > 0 ? Date.now() + tage * 24 * 60 * 60 * 1000 : Infinity;
|
||||||
const ohneTermine = [];
|
const ohneTermine = [];
|
||||||
|
|
||||||
const proKuenstler = await inHaeppchen(kuenstler, GLEICHZEITIG, async (k) => {
|
const proKuenstler = await inHaeppchen(kuenstler, GLEICHZEITIG, async (k) => {
|
||||||
|
|||||||
@@ -265,7 +265,10 @@ app.post('/api/artist-concerts', async (req, res) => {
|
|||||||
if (!key) return res.json({ konzerte: [], ohneTermine: [], keinSchluessel: true });
|
if (!key) return res.json({ konzerte: [], ohneTermine: [], keinSchluessel: true });
|
||||||
|
|
||||||
const artists = Array.isArray(req.body?.artists) ? req.body.artists : [];
|
const artists = Array.isArray(req.body?.artists) ? req.body.artists : [];
|
||||||
const days = Math.min(Math.max(parseInt(req.body?.days, 10) || 365, 1), 365);
|
// Ohne `days` gibt es KEIN Fenster — Konzerte sind ohnehin nur Zukunft, und dort will man
|
||||||
|
// alles Angekuendigte sehen. Ein mitgeschicktes Fenster wird weiterhin beachtet.
|
||||||
|
const roh = parseInt(req.body?.days, 10);
|
||||||
|
const days = Number.isFinite(roh) && roh > 0 ? Math.min(roh, 3650) : 0;
|
||||||
if (!artists.length) return res.json({ konzerte: [], ohneTermine: [] });
|
if (!artists.length) return res.json({ konzerte: [], ohneTermine: [] });
|
||||||
// Obergrenze, damit ein kaputter Client nicht hunderte Ticketmaster-Aufrufe ausloest.
|
// Obergrenze, damit ein kaputter Client nicht hunderte Ticketmaster-Aufrufe ausloest.
|
||||||
if (artists.length > 300) return res.status(400).json({ error: 'Zu viele Künstler (max. 300)' });
|
if (artists.length > 300) return res.status(400).json({ error: 'Zu viele Künstler (max. 300)' });
|
||||||
|
|||||||
+15
-9
@@ -11,7 +11,6 @@ import { navigate, _navGoBack } from './navigation.js';
|
|||||||
// Die Deezer-Auflösung macht das Backend, weil dort auch die Künstler-Pins liegen.
|
// Die Deezer-Auflösung macht das Backend, weil dort auch die Künstler-Pins liegen.
|
||||||
|
|
||||||
let _tage = 90;
|
let _tage = 90;
|
||||||
let _tageKonzerte = 365; // Konzerte schaut man in die Weite an, nicht auf 90 Tage
|
|
||||||
let _reiter = 'releases';
|
let _reiter = 'releases';
|
||||||
let _laeuft = false;
|
let _laeuft = false;
|
||||||
|
|
||||||
@@ -26,14 +25,18 @@ export function showArtistNewsTab(reiter) {
|
|||||||
? 'Konzerte <em>deiner Künstler</em>'
|
? 'Konzerte <em>deiner Künstler</em>'
|
||||||
: 'Neu von <em>deinen Künstlern</em>';
|
: 'Neu von <em>deinen Künstlern</em>';
|
||||||
}
|
}
|
||||||
|
// Das Zeitfenster gilt nur fuer die Veroeffentlichungen. Konzerte sind ohnehin Zukunft, und
|
||||||
|
// dort will man alles Angekuendigte sehen — eine Tagesgrenze schnitte nur willkuerlich ab.
|
||||||
|
const tageReihe = document.getElementById('artist-news-sort');
|
||||||
|
if (tageReihe) tageReihe.style.display = _reiter === 'konzerte' ? 'none' : '';
|
||||||
if (_reiter === 'konzerte') loadKonzerte();
|
if (_reiter === 'konzerte') loadKonzerte();
|
||||||
else loadArtistNews();
|
else loadArtistNews();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Zeitfenster setzen — es gilt je Reiter, weil es in verschiedene Richtungen zeigt. */
|
/** Zeitfenster setzen — gibt es nur bei den Veroeffentlichungen. */
|
||||||
export function setArtistNewsDays(tage) {
|
export function setArtistNewsDays(tage) {
|
||||||
if (_reiter === 'konzerte') { _tageKonzerte = tage; loadKonzerte(); }
|
_tage = tage;
|
||||||
else { _tage = tage; loadArtistNews(); }
|
loadArtistNews();
|
||||||
}
|
}
|
||||||
|
|
||||||
function _markiereTage(tage) {
|
function _markiereTage(tage) {
|
||||||
@@ -44,6 +47,8 @@ function _markiereTage(tage) {
|
|||||||
export async function loadArtistNews(tage = _tage) {
|
export async function loadArtistNews(tage = _tage) {
|
||||||
_tage = tage;
|
_tage = tage;
|
||||||
_reiter = 'releases';
|
_reiter = 'releases';
|
||||||
|
const tageReihe = document.getElementById('artist-news-sort');
|
||||||
|
if (tageReihe) tageReihe.style.display = '';
|
||||||
// Die Seite haengt an den Favoriten (Knopf "✨ Neu") und nicht mehr an der Seitenleiste,
|
// Die Seite haengt an den Favoriten (Knopf "✨ Neu") und nicht mehr an der Seitenleiste,
|
||||||
// deshalb braucht sie einen Weg zurueck wie jede andere Unterseite.
|
// deshalb braucht sie einen Weg zurueck wie jede andere Unterseite.
|
||||||
const zurueck = document.getElementById('artist-news-back-btn');
|
const zurueck = document.getElementById('artist-news-back-btn');
|
||||||
@@ -196,12 +201,12 @@ function _zeile(rel, schonDa) {
|
|||||||
// Gegenstück zur Release-Zeitleiste. Die Liste läuft NACH VORN: das nächste Konzert zuerst.
|
// Gegenstück zur Release-Zeitleiste. Die Liste läuft NACH VORN: das nächste Konzert zuerst.
|
||||||
// Die Termine kommen über das Backend von Ticketmaster, gecacht für alle Geräte gemeinsam.
|
// Die Termine kommen über das Backend von Ticketmaster, gecacht für alle Geräte gemeinsam.
|
||||||
|
|
||||||
export async function loadKonzerte(tage = _tageKonzerte) {
|
export async function loadKonzerte() {
|
||||||
_tageKonzerte = tage;
|
|
||||||
_reiter = 'konzerte';
|
_reiter = 'konzerte';
|
||||||
const zurueck = document.getElementById('artist-news-back-btn');
|
const zurueck = document.getElementById('artist-news-back-btn');
|
||||||
if (zurueck) zurueck.onclick = () => _navGoBack();
|
if (zurueck) zurueck.onclick = () => _navGoBack();
|
||||||
_markiereTage(tage);
|
const tageReihe = document.getElementById('artist-news-sort');
|
||||||
|
if (tageReihe) tageReihe.style.display = 'none';
|
||||||
|
|
||||||
const el = document.getElementById('artist-news-list');
|
const el = document.getElementById('artist-news-list');
|
||||||
if (!el || _laeuft) return;
|
if (!el || _laeuft) return;
|
||||||
@@ -226,7 +231,8 @@ export async function loadKonzerte(tage = _tageKonzerte) {
|
|||||||
const res = await fetch(`${S.cfg.backendUrl}/api/artist-concerts`, {
|
const res = await fetch(`${S.cfg.backendUrl}/api/artist-concerts`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ artists: kuenstler, days: tage }),
|
// Ohne `days`: das Backend liefert alles Angekuendigte.
|
||||||
|
body: JSON.stringify({ artists: kuenstler }),
|
||||||
});
|
});
|
||||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||||
const { konzerte = [], keinSchluessel } = await res.json();
|
const { konzerte = [], keinSchluessel } = await res.json();
|
||||||
@@ -240,7 +246,7 @@ export async function loadKonzerte(tage = _tageKonzerte) {
|
|||||||
if (!konzerte.length) {
|
if (!konzerte.length) {
|
||||||
const leer = document.createElement('div');
|
const leer = document.createElement('div');
|
||||||
leer.className = 'empty-state';
|
leer.className = 'empty-state';
|
||||||
leer.innerHTML = `<div class="icon">🎪</div><p>Keine Termine in den nächsten ${tage} Tagen</p>`
|
leer.innerHTML = '<div class="icon">🎪</div><p>Keine anstehenden Termine</p>'
|
||||||
+ '<p style="font-size:12px;color:var(--text3);margin-top:6px">Gesucht wird weltweit über den Künstlernamen.</p>';
|
+ '<p style="font-size:12px;color:var(--text3);margin-top:6px">Gesucht wird weltweit über den Künstlernamen.</p>';
|
||||||
el.appendChild(leer);
|
el.appendChild(leer);
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in new issue
Block a user