Themes: make 'description' and 'title' optional if there is a single theme and it can be reused from this single theme

This commit is contained in:
Pieter Vander Vennet 2025-07-05 04:38:56 +02:00
parent 54e1f5d44c
commit c7b905d1fb
4 changed files with 37 additions and 7 deletions

View file

@ -617,6 +617,33 @@ class OrderTheme extends DesugaringStep<ThemeConfigJson>{
return Utils.reorder(json, OrderTheme.themeAttributesOrder) return Utils.reorder(json, OrderTheme.themeAttributesOrder)
} }
} }
class DeriveDescription extends DesugaringStep<ThemeConfigJson> {
private readonly _key: string
private readonly _sourceKey: "name"
constructor(key: "icon" | "description" | "title", sourceKey?: "name") {
super("DeriveDescription", "If a single layer and no description is given, steal the description from the layer")
this._key = key
this._sourceKey = sourceKey
}
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
if (json[this._key]) {
return json
}
const msg = "This theme has no "+this._key+". If there is only a single layer, we can steal it from this layer though. Current layers are "+json.layers.map(l => l["id"]).join("; ")
if (json.layers.length !== 1) {
context.err(msg)
}
const l = <LayerConfigJson> json.layers[0] // Already expanded
context.info(`Added '${this._key}' to theme ${json.id} based on single layer`)
return {
...json,
[this._key]: l[this._sourceKey ?? this._key],
}
}
}
export class PrepareTheme extends Fuse<ThemeConfigJson> { export class PrepareTheme extends Fuse<ThemeConfigJson> {
private state: DesugaringContext private state: DesugaringContext
@ -632,6 +659,9 @@ export class PrepareTheme extends Fuse<ThemeConfigJson> {
new PreparePersonalTheme(state), new PreparePersonalTheme(state),
new WarnForUnsubstitutedLayersInTheme(), new WarnForUnsubstitutedLayersInTheme(),
new On("layers", new Concat(new SubstituteLayer(state))), new On("layers", new Concat(new SubstituteLayer(state))),
new DeriveDescription( "description"),
new DeriveDescription( "icon"),
new DeriveDescription( "title", "name"),
new SetDefault("socialImage", "assets/SocialImage.png", true), new SetDefault("socialImage", "assets/SocialImage.png", true),
// We expand all tagrenderings first... // We expand all tagrenderings first...

View file

@ -35,6 +35,9 @@ export class ValidateTheme extends DesugaringStep<ThemeConfigJson> {
} }
convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson { convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
if (!json.title) {
context.enter("title").err(`The theme ${json.id} does not have a title defined.`)
}
const theme = new ThemeConfig(json, this._isBuiltin) const theme = new ThemeConfig(json, this._isBuiltin)
{ {
// Legacy format checks // Legacy format checks
@ -55,9 +58,7 @@ export class ValidateTheme extends DesugaringStep<ThemeConfigJson> {
} }
} }
} }
if (!json.title) {
context.enter("title").err(`The theme ${json.id} does not have a title defined.`)
}
if (!json.icon) { if (!json.icon) {
context.enter("icon").err("A theme should have an icon") context.enter("icon").err("A theme should have an icon")
} }

View file

@ -56,10 +56,11 @@ export interface ThemeConfigJson {
/** /**
* question: How would you describe this theme? * question: How would you describe this theme?
* The description, as shown in the welcome message and the more-screen * The description, as shown in the welcome message and the more-screen
* ifunset: reuse the description of the only layer
* group: basic * group: basic
* *
*/ */
description: Translatable description?: Translatable
/** /**
* A short description, showed as social description and in the 'more theme'-buttons. * A short description, showed as social description and in the 'more theme'-buttons.

View file

@ -132,9 +132,7 @@ export default class ThemeConfig implements ThemeInformation {
} }
const context = this.id const context = this.id
this.credits = Array.isArray(json.credits) ? json.credits.join("; ") : json.credits this.credits = Array.isArray(json.credits) ? json.credits.join("; ") : json.credits
if (!json.title) {
throw `The theme ${json.id} does not have a title defined.`
}
this.language = json.mustHaveLanguage ?? Object.keys(json.title) this.language = json.mustHaveLanguage ?? Object.keys(json.title)
{ {