mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	feat(web): custom stylesheets (#4602)
* add initial ui and api definitions for stylesheets * proper saving * make custom css work * add textarea * rebuild api * run prettier * add typecast * update typings * move css accordion to be sorted alphabetically * set content-type properly * rename stylesheets to theme * fix server test
This commit is contained in:
		
							
								
								
									
										19
									
								
								cli/src/api/open-api/api.ts
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										19
									
								
								cli/src/api/open-api/api.ts
									
									
									
										generated
									
									
									
								
							@@ -3307,6 +3307,12 @@ export interface SystemConfigDto {
 | 
				
			|||||||
     * @memberof SystemConfigDto
 | 
					     * @memberof SystemConfigDto
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    'storageTemplate': SystemConfigStorageTemplateDto;
 | 
					    'storageTemplate': SystemConfigStorageTemplateDto;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * @type {SystemConfigThemeDto}
 | 
				
			||||||
 | 
					     * @memberof SystemConfigDto
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    'theme': SystemConfigThemeDto;
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 
 | 
					     * 
 | 
				
			||||||
     * @type {SystemConfigThumbnailDto}
 | 
					     * @type {SystemConfigThumbnailDto}
 | 
				
			||||||
@@ -3741,6 +3747,19 @@ export interface SystemConfigTemplateStorageOptionDto {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    'yearOptions': Array<string>;
 | 
					    'yearOptions': Array<string>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @export
 | 
				
			||||||
 | 
					 * @interface SystemConfigThemeDto
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export interface SystemConfigThemeDto {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * @type {string}
 | 
				
			||||||
 | 
					     * @memberof SystemConfigThemeDto
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    'customCss': string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 
 | 
					 * 
 | 
				
			||||||
 * @export
 | 
					 * @export
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								mobile/openapi/.openapi-generator/FILES
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3
									
								
								mobile/openapi/.openapi-generator/FILES
									
									
									
										generated
									
									
									
								
							@@ -135,6 +135,7 @@ doc/SystemConfigPasswordLoginDto.md
 | 
				
			|||||||
doc/SystemConfigReverseGeocodingDto.md
 | 
					doc/SystemConfigReverseGeocodingDto.md
 | 
				
			||||||
doc/SystemConfigStorageTemplateDto.md
 | 
					doc/SystemConfigStorageTemplateDto.md
 | 
				
			||||||
doc/SystemConfigTemplateStorageOptionDto.md
 | 
					doc/SystemConfigTemplateStorageOptionDto.md
 | 
				
			||||||
 | 
					doc/SystemConfigThemeDto.md
 | 
				
			||||||
doc/SystemConfigThumbnailDto.md
 | 
					doc/SystemConfigThumbnailDto.md
 | 
				
			||||||
doc/SystemConfigTrashDto.md
 | 
					doc/SystemConfigTrashDto.md
 | 
				
			||||||
doc/TagApi.md
 | 
					doc/TagApi.md
 | 
				
			||||||
@@ -302,6 +303,7 @@ lib/model/system_config_password_login_dto.dart
 | 
				
			|||||||
lib/model/system_config_reverse_geocoding_dto.dart
 | 
					lib/model/system_config_reverse_geocoding_dto.dart
 | 
				
			||||||
lib/model/system_config_storage_template_dto.dart
 | 
					lib/model/system_config_storage_template_dto.dart
 | 
				
			||||||
lib/model/system_config_template_storage_option_dto.dart
 | 
					lib/model/system_config_template_storage_option_dto.dart
 | 
				
			||||||
 | 
					lib/model/system_config_theme_dto.dart
 | 
				
			||||||
lib/model/system_config_thumbnail_dto.dart
 | 
					lib/model/system_config_thumbnail_dto.dart
 | 
				
			||||||
lib/model/system_config_trash_dto.dart
 | 
					lib/model/system_config_trash_dto.dart
 | 
				
			||||||
lib/model/tag_response_dto.dart
 | 
					lib/model/tag_response_dto.dart
 | 
				
			||||||
@@ -456,6 +458,7 @@ test/system_config_password_login_dto_test.dart
 | 
				
			|||||||
test/system_config_reverse_geocoding_dto_test.dart
 | 
					test/system_config_reverse_geocoding_dto_test.dart
 | 
				
			||||||
test/system_config_storage_template_dto_test.dart
 | 
					test/system_config_storage_template_dto_test.dart
 | 
				
			||||||
test/system_config_template_storage_option_dto_test.dart
 | 
					test/system_config_template_storage_option_dto_test.dart
 | 
				
			||||||
 | 
					test/system_config_theme_dto_test.dart
 | 
				
			||||||
test/system_config_thumbnail_dto_test.dart
 | 
					test/system_config_thumbnail_dto_test.dart
 | 
				
			||||||
test/system_config_trash_dto_test.dart
 | 
					test/system_config_trash_dto_test.dart
 | 
				
			||||||
test/tag_api_test.dart
 | 
					test/tag_api_test.dart
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								mobile/openapi/README.md
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								mobile/openapi/README.md
									
									
									
										generated
									
									
									
								
							@@ -318,6 +318,7 @@ Class | Method | HTTP request | Description
 | 
				
			|||||||
 - [SystemConfigReverseGeocodingDto](doc//SystemConfigReverseGeocodingDto.md)
 | 
					 - [SystemConfigReverseGeocodingDto](doc//SystemConfigReverseGeocodingDto.md)
 | 
				
			||||||
 - [SystemConfigStorageTemplateDto](doc//SystemConfigStorageTemplateDto.md)
 | 
					 - [SystemConfigStorageTemplateDto](doc//SystemConfigStorageTemplateDto.md)
 | 
				
			||||||
 - [SystemConfigTemplateStorageOptionDto](doc//SystemConfigTemplateStorageOptionDto.md)
 | 
					 - [SystemConfigTemplateStorageOptionDto](doc//SystemConfigTemplateStorageOptionDto.md)
 | 
				
			||||||
 | 
					 - [SystemConfigThemeDto](doc//SystemConfigThemeDto.md)
 | 
				
			||||||
 - [SystemConfigThumbnailDto](doc//SystemConfigThumbnailDto.md)
 | 
					 - [SystemConfigThumbnailDto](doc//SystemConfigThumbnailDto.md)
 | 
				
			||||||
 - [SystemConfigTrashDto](doc//SystemConfigTrashDto.md)
 | 
					 - [SystemConfigTrashDto](doc//SystemConfigTrashDto.md)
 | 
				
			||||||
 - [TagResponseDto](doc//TagResponseDto.md)
 | 
					 - [TagResponseDto](doc//TagResponseDto.md)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								mobile/openapi/doc/SystemConfigDto.md
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								mobile/openapi/doc/SystemConfigDto.md
									
									
									
										generated
									
									
									
								
							@@ -16,6 +16,7 @@ Name | Type | Description | Notes
 | 
				
			|||||||
**passwordLogin** | [**SystemConfigPasswordLoginDto**](SystemConfigPasswordLoginDto.md) |  | 
 | 
					**passwordLogin** | [**SystemConfigPasswordLoginDto**](SystemConfigPasswordLoginDto.md) |  | 
 | 
				
			||||||
**reverseGeocoding** | [**SystemConfigReverseGeocodingDto**](SystemConfigReverseGeocodingDto.md) |  | 
 | 
					**reverseGeocoding** | [**SystemConfigReverseGeocodingDto**](SystemConfigReverseGeocodingDto.md) |  | 
 | 
				
			||||||
**storageTemplate** | [**SystemConfigStorageTemplateDto**](SystemConfigStorageTemplateDto.md) |  | 
 | 
					**storageTemplate** | [**SystemConfigStorageTemplateDto**](SystemConfigStorageTemplateDto.md) |  | 
 | 
				
			||||||
 | 
					**theme** | [**SystemConfigThemeDto**](SystemConfigThemeDto.md) |  | 
 | 
				
			||||||
**thumbnail** | [**SystemConfigThumbnailDto**](SystemConfigThumbnailDto.md) |  | 
 | 
					**thumbnail** | [**SystemConfigThumbnailDto**](SystemConfigThumbnailDto.md) |  | 
 | 
				
			||||||
**trash** | [**SystemConfigTrashDto**](SystemConfigTrashDto.md) |  | 
 | 
					**trash** | [**SystemConfigTrashDto**](SystemConfigTrashDto.md) |  | 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										15
									
								
								mobile/openapi/doc/SystemConfigThemeDto.md
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								mobile/openapi/doc/SystemConfigThemeDto.md
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					# openapi.model.SystemConfigThemeDto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Load the model package
 | 
				
			||||||
 | 
					```dart
 | 
				
			||||||
 | 
					import 'package:openapi/api.dart';
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Properties
 | 
				
			||||||
 | 
					Name | Type | Description | Notes
 | 
				
			||||||
 | 
					------------ | ------------- | ------------- | -------------
 | 
				
			||||||
 | 
					**customCss** | **String** |  | 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								mobile/openapi/lib/api.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								mobile/openapi/lib/api.dart
									
									
									
										generated
									
									
									
								
							@@ -163,6 +163,7 @@ part 'model/system_config_password_login_dto.dart';
 | 
				
			|||||||
part 'model/system_config_reverse_geocoding_dto.dart';
 | 
					part 'model/system_config_reverse_geocoding_dto.dart';
 | 
				
			||||||
part 'model/system_config_storage_template_dto.dart';
 | 
					part 'model/system_config_storage_template_dto.dart';
 | 
				
			||||||
part 'model/system_config_template_storage_option_dto.dart';
 | 
					part 'model/system_config_template_storage_option_dto.dart';
 | 
				
			||||||
 | 
					part 'model/system_config_theme_dto.dart';
 | 
				
			||||||
part 'model/system_config_thumbnail_dto.dart';
 | 
					part 'model/system_config_thumbnail_dto.dart';
 | 
				
			||||||
part 'model/system_config_trash_dto.dart';
 | 
					part 'model/system_config_trash_dto.dart';
 | 
				
			||||||
part 'model/tag_response_dto.dart';
 | 
					part 'model/tag_response_dto.dart';
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								mobile/openapi/lib/api_client.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								mobile/openapi/lib/api_client.dart
									
									
									
										generated
									
									
									
								
							@@ -417,6 +417,8 @@ class ApiClient {
 | 
				
			|||||||
          return SystemConfigStorageTemplateDto.fromJson(value);
 | 
					          return SystemConfigStorageTemplateDto.fromJson(value);
 | 
				
			||||||
        case 'SystemConfigTemplateStorageOptionDto':
 | 
					        case 'SystemConfigTemplateStorageOptionDto':
 | 
				
			||||||
          return SystemConfigTemplateStorageOptionDto.fromJson(value);
 | 
					          return SystemConfigTemplateStorageOptionDto.fromJson(value);
 | 
				
			||||||
 | 
					        case 'SystemConfigThemeDto':
 | 
				
			||||||
 | 
					          return SystemConfigThemeDto.fromJson(value);
 | 
				
			||||||
        case 'SystemConfigThumbnailDto':
 | 
					        case 'SystemConfigThumbnailDto':
 | 
				
			||||||
          return SystemConfigThumbnailDto.fromJson(value);
 | 
					          return SystemConfigThumbnailDto.fromJson(value);
 | 
				
			||||||
        case 'SystemConfigTrashDto':
 | 
					        case 'SystemConfigTrashDto':
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								mobile/openapi/lib/model/system_config_dto.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										10
									
								
								mobile/openapi/lib/model/system_config_dto.dart
									
									
									
										generated
									
									
									
								
							@@ -21,6 +21,7 @@ class SystemConfigDto {
 | 
				
			|||||||
    required this.passwordLogin,
 | 
					    required this.passwordLogin,
 | 
				
			||||||
    required this.reverseGeocoding,
 | 
					    required this.reverseGeocoding,
 | 
				
			||||||
    required this.storageTemplate,
 | 
					    required this.storageTemplate,
 | 
				
			||||||
 | 
					    required this.theme,
 | 
				
			||||||
    required this.thumbnail,
 | 
					    required this.thumbnail,
 | 
				
			||||||
    required this.trash,
 | 
					    required this.trash,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
@@ -41,6 +42,8 @@ class SystemConfigDto {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  SystemConfigStorageTemplateDto storageTemplate;
 | 
					  SystemConfigStorageTemplateDto storageTemplate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  SystemConfigThemeDto theme;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  SystemConfigThumbnailDto thumbnail;
 | 
					  SystemConfigThumbnailDto thumbnail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  SystemConfigTrashDto trash;
 | 
					  SystemConfigTrashDto trash;
 | 
				
			||||||
@@ -55,6 +58,7 @@ class SystemConfigDto {
 | 
				
			|||||||
     other.passwordLogin == passwordLogin &&
 | 
					     other.passwordLogin == passwordLogin &&
 | 
				
			||||||
     other.reverseGeocoding == reverseGeocoding &&
 | 
					     other.reverseGeocoding == reverseGeocoding &&
 | 
				
			||||||
     other.storageTemplate == storageTemplate &&
 | 
					     other.storageTemplate == storageTemplate &&
 | 
				
			||||||
 | 
					     other.theme == theme &&
 | 
				
			||||||
     other.thumbnail == thumbnail &&
 | 
					     other.thumbnail == thumbnail &&
 | 
				
			||||||
     other.trash == trash;
 | 
					     other.trash == trash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -69,11 +73,12 @@ class SystemConfigDto {
 | 
				
			|||||||
    (passwordLogin.hashCode) +
 | 
					    (passwordLogin.hashCode) +
 | 
				
			||||||
    (reverseGeocoding.hashCode) +
 | 
					    (reverseGeocoding.hashCode) +
 | 
				
			||||||
    (storageTemplate.hashCode) +
 | 
					    (storageTemplate.hashCode) +
 | 
				
			||||||
 | 
					    (theme.hashCode) +
 | 
				
			||||||
    (thumbnail.hashCode) +
 | 
					    (thumbnail.hashCode) +
 | 
				
			||||||
    (trash.hashCode);
 | 
					    (trash.hashCode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String toString() => 'SystemConfigDto[ffmpeg=$ffmpeg, job=$job, machineLearning=$machineLearning, map=$map, oauth=$oauth, passwordLogin=$passwordLogin, reverseGeocoding=$reverseGeocoding, storageTemplate=$storageTemplate, thumbnail=$thumbnail, trash=$trash]';
 | 
					  String toString() => 'SystemConfigDto[ffmpeg=$ffmpeg, job=$job, machineLearning=$machineLearning, map=$map, oauth=$oauth, passwordLogin=$passwordLogin, reverseGeocoding=$reverseGeocoding, storageTemplate=$storageTemplate, theme=$theme, thumbnail=$thumbnail, trash=$trash]';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Map<String, dynamic> toJson() {
 | 
					  Map<String, dynamic> toJson() {
 | 
				
			||||||
    final json = <String, dynamic>{};
 | 
					    final json = <String, dynamic>{};
 | 
				
			||||||
@@ -85,6 +90,7 @@ class SystemConfigDto {
 | 
				
			|||||||
      json[r'passwordLogin'] = this.passwordLogin;
 | 
					      json[r'passwordLogin'] = this.passwordLogin;
 | 
				
			||||||
      json[r'reverseGeocoding'] = this.reverseGeocoding;
 | 
					      json[r'reverseGeocoding'] = this.reverseGeocoding;
 | 
				
			||||||
      json[r'storageTemplate'] = this.storageTemplate;
 | 
					      json[r'storageTemplate'] = this.storageTemplate;
 | 
				
			||||||
 | 
					      json[r'theme'] = this.theme;
 | 
				
			||||||
      json[r'thumbnail'] = this.thumbnail;
 | 
					      json[r'thumbnail'] = this.thumbnail;
 | 
				
			||||||
      json[r'trash'] = this.trash;
 | 
					      json[r'trash'] = this.trash;
 | 
				
			||||||
    return json;
 | 
					    return json;
 | 
				
			||||||
@@ -106,6 +112,7 @@ class SystemConfigDto {
 | 
				
			|||||||
        passwordLogin: SystemConfigPasswordLoginDto.fromJson(json[r'passwordLogin'])!,
 | 
					        passwordLogin: SystemConfigPasswordLoginDto.fromJson(json[r'passwordLogin'])!,
 | 
				
			||||||
        reverseGeocoding: SystemConfigReverseGeocodingDto.fromJson(json[r'reverseGeocoding'])!,
 | 
					        reverseGeocoding: SystemConfigReverseGeocodingDto.fromJson(json[r'reverseGeocoding'])!,
 | 
				
			||||||
        storageTemplate: SystemConfigStorageTemplateDto.fromJson(json[r'storageTemplate'])!,
 | 
					        storageTemplate: SystemConfigStorageTemplateDto.fromJson(json[r'storageTemplate'])!,
 | 
				
			||||||
 | 
					        theme: SystemConfigThemeDto.fromJson(json[r'theme'])!,
 | 
				
			||||||
        thumbnail: SystemConfigThumbnailDto.fromJson(json[r'thumbnail'])!,
 | 
					        thumbnail: SystemConfigThumbnailDto.fromJson(json[r'thumbnail'])!,
 | 
				
			||||||
        trash: SystemConfigTrashDto.fromJson(json[r'trash'])!,
 | 
					        trash: SystemConfigTrashDto.fromJson(json[r'trash'])!,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@@ -163,6 +170,7 @@ class SystemConfigDto {
 | 
				
			|||||||
    'passwordLogin',
 | 
					    'passwordLogin',
 | 
				
			||||||
    'reverseGeocoding',
 | 
					    'reverseGeocoding',
 | 
				
			||||||
    'storageTemplate',
 | 
					    'storageTemplate',
 | 
				
			||||||
 | 
					    'theme',
 | 
				
			||||||
    'thumbnail',
 | 
					    'thumbnail',
 | 
				
			||||||
    'trash',
 | 
					    'trash',
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										98
									
								
								mobile/openapi/lib/model/system_config_theme_dto.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								mobile/openapi/lib/model/system_config_theme_dto.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// AUTO-GENERATED FILE, DO NOT MODIFY!
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// @dart=2.12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ignore_for_file: unused_element, unused_import
 | 
				
			||||||
 | 
					// ignore_for_file: always_put_required_named_parameters_first
 | 
				
			||||||
 | 
					// ignore_for_file: constant_identifier_names
 | 
				
			||||||
 | 
					// ignore_for_file: lines_longer_than_80_chars
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					part of openapi.api;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SystemConfigThemeDto {
 | 
				
			||||||
 | 
					  /// Returns a new [SystemConfigThemeDto] instance.
 | 
				
			||||||
 | 
					  SystemConfigThemeDto({
 | 
				
			||||||
 | 
					    required this.customCss,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  String customCss;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  bool operator ==(Object other) => identical(this, other) || other is SystemConfigThemeDto &&
 | 
				
			||||||
 | 
					     other.customCss == customCss;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  int get hashCode =>
 | 
				
			||||||
 | 
					    // ignore: unnecessary_parenthesis
 | 
				
			||||||
 | 
					    (customCss.hashCode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String toString() => 'SystemConfigThemeDto[customCss=$customCss]';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Map<String, dynamic> toJson() {
 | 
				
			||||||
 | 
					    final json = <String, dynamic>{};
 | 
				
			||||||
 | 
					      json[r'customCss'] = this.customCss;
 | 
				
			||||||
 | 
					    return json;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Returns a new [SystemConfigThemeDto] instance and imports its values from
 | 
				
			||||||
 | 
					  /// [value] if it's a [Map], null otherwise.
 | 
				
			||||||
 | 
					  // ignore: prefer_constructors_over_static_methods
 | 
				
			||||||
 | 
					  static SystemConfigThemeDto? fromJson(dynamic value) {
 | 
				
			||||||
 | 
					    if (value is Map) {
 | 
				
			||||||
 | 
					      final json = value.cast<String, dynamic>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return SystemConfigThemeDto(
 | 
				
			||||||
 | 
					        customCss: mapValueOfType<String>(json, r'customCss')!,
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static List<SystemConfigThemeDto> listFromJson(dynamic json, {bool growable = false,}) {
 | 
				
			||||||
 | 
					    final result = <SystemConfigThemeDto>[];
 | 
				
			||||||
 | 
					    if (json is List && json.isNotEmpty) {
 | 
				
			||||||
 | 
					      for (final row in json) {
 | 
				
			||||||
 | 
					        final value = SystemConfigThemeDto.fromJson(row);
 | 
				
			||||||
 | 
					        if (value != null) {
 | 
				
			||||||
 | 
					          result.add(value);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return result.toList(growable: growable);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static Map<String, SystemConfigThemeDto> mapFromJson(dynamic json) {
 | 
				
			||||||
 | 
					    final map = <String, SystemConfigThemeDto>{};
 | 
				
			||||||
 | 
					    if (json is Map && json.isNotEmpty) {
 | 
				
			||||||
 | 
					      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
				
			||||||
 | 
					      for (final entry in json.entries) {
 | 
				
			||||||
 | 
					        final value = SystemConfigThemeDto.fromJson(entry.value);
 | 
				
			||||||
 | 
					        if (value != null) {
 | 
				
			||||||
 | 
					          map[entry.key] = value;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return map;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // maps a json object with a list of SystemConfigThemeDto-objects as value to a dart map
 | 
				
			||||||
 | 
					  static Map<String, List<SystemConfigThemeDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
 | 
				
			||||||
 | 
					    final map = <String, List<SystemConfigThemeDto>>{};
 | 
				
			||||||
 | 
					    if (json is Map && json.isNotEmpty) {
 | 
				
			||||||
 | 
					      // ignore: parameter_assignments
 | 
				
			||||||
 | 
					      json = json.cast<String, dynamic>();
 | 
				
			||||||
 | 
					      for (final entry in json.entries) {
 | 
				
			||||||
 | 
					        map[entry.key] = SystemConfigThemeDto.listFromJson(entry.value, growable: growable,);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return map;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// The list of required keys that must be present in a JSON.
 | 
				
			||||||
 | 
					  static const requiredKeys = <String>{
 | 
				
			||||||
 | 
					    'customCss',
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										5
									
								
								mobile/openapi/test/system_config_dto_test.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										5
									
								
								mobile/openapi/test/system_config_dto_test.dart
									
									
									
										generated
									
									
									
								
							@@ -56,6 +56,11 @@ void main() {
 | 
				
			|||||||
      // TODO
 | 
					      // TODO
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // SystemConfigThemeDto theme
 | 
				
			||||||
 | 
					    test('to test the property `theme`', () async {
 | 
				
			||||||
 | 
					      // TODO
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // SystemConfigThumbnailDto thumbnail
 | 
					    // SystemConfigThumbnailDto thumbnail
 | 
				
			||||||
    test('to test the property `thumbnail`', () async {
 | 
					    test('to test the property `thumbnail`', () async {
 | 
				
			||||||
      // TODO
 | 
					      // TODO
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										27
									
								
								mobile/openapi/test/system_config_theme_dto_test.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								mobile/openapi/test/system_config_theme_dto_test.dart
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// AUTO-GENERATED FILE, DO NOT MODIFY!
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// @dart=2.12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ignore_for_file: unused_element, unused_import
 | 
				
			||||||
 | 
					// ignore_for_file: always_put_required_named_parameters_first
 | 
				
			||||||
 | 
					// ignore_for_file: constant_identifier_names
 | 
				
			||||||
 | 
					// ignore_for_file: lines_longer_than_80_chars
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:openapi/api.dart';
 | 
				
			||||||
 | 
					import 'package:test/test.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// tests for SystemConfigThemeDto
 | 
				
			||||||
 | 
					void main() {
 | 
				
			||||||
 | 
					  // final instance = SystemConfigThemeDto();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  group('test SystemConfigThemeDto', () {
 | 
				
			||||||
 | 
					    // String customCss
 | 
				
			||||||
 | 
					    test('to test the property `customCss`', () async {
 | 
				
			||||||
 | 
					      // TODO
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -8060,6 +8060,9 @@
 | 
				
			|||||||
          "storageTemplate": {
 | 
					          "storageTemplate": {
 | 
				
			||||||
            "$ref": "#/components/schemas/SystemConfigStorageTemplateDto"
 | 
					            "$ref": "#/components/schemas/SystemConfigStorageTemplateDto"
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
 | 
					          "theme": {
 | 
				
			||||||
 | 
					            "$ref": "#/components/schemas/SystemConfigThemeDto"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
          "thumbnail": {
 | 
					          "thumbnail": {
 | 
				
			||||||
            "$ref": "#/components/schemas/SystemConfigThumbnailDto"
 | 
					            "$ref": "#/components/schemas/SystemConfigThumbnailDto"
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
@@ -8077,7 +8080,8 @@
 | 
				
			|||||||
          "storageTemplate",
 | 
					          "storageTemplate",
 | 
				
			||||||
          "job",
 | 
					          "job",
 | 
				
			||||||
          "thumbnail",
 | 
					          "thumbnail",
 | 
				
			||||||
          "trash"
 | 
					          "trash",
 | 
				
			||||||
 | 
					          "theme"
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "type": "object"
 | 
					        "type": "object"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
@@ -8404,6 +8408,17 @@
 | 
				
			|||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "type": "object"
 | 
					        "type": "object"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					      "SystemConfigThemeDto": {
 | 
				
			||||||
 | 
					        "properties": {
 | 
				
			||||||
 | 
					          "customCss": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "required": [
 | 
				
			||||||
 | 
					          "customCss"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "type": "object"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      "SystemConfigThumbnailDto": {
 | 
					      "SystemConfigThumbnailDto": {
 | 
				
			||||||
        "properties": {
 | 
					        "properties": {
 | 
				
			||||||
          "colorspace": {
 | 
					          "colorspace": {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					import { IsString } from 'class-validator';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class SystemConfigThemeDto {
 | 
				
			||||||
 | 
					  @IsString()
 | 
				
			||||||
 | 
					  customCss!: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -9,6 +9,7 @@ import { SystemConfigOAuthDto } from './system-config-oauth.dto';
 | 
				
			|||||||
import { SystemConfigPasswordLoginDto } from './system-config-password-login.dto';
 | 
					import { SystemConfigPasswordLoginDto } from './system-config-password-login.dto';
 | 
				
			||||||
import { SystemConfigReverseGeocodingDto } from './system-config-reverse-geocoding.dto';
 | 
					import { SystemConfigReverseGeocodingDto } from './system-config-reverse-geocoding.dto';
 | 
				
			||||||
import { SystemConfigStorageTemplateDto } from './system-config-storage-template.dto';
 | 
					import { SystemConfigStorageTemplateDto } from './system-config-storage-template.dto';
 | 
				
			||||||
 | 
					import { SystemConfigThemeDto } from './system-config-theme.dto';
 | 
				
			||||||
import { SystemConfigThumbnailDto } from './system-config-thumbnail.dto';
 | 
					import { SystemConfigThumbnailDto } from './system-config-thumbnail.dto';
 | 
				
			||||||
import { SystemConfigTrashDto } from './system-config-trash.dto';
 | 
					import { SystemConfigTrashDto } from './system-config-trash.dto';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -62,6 +63,11 @@ export class SystemConfigDto implements SystemConfig {
 | 
				
			|||||||
  @ValidateNested()
 | 
					  @ValidateNested()
 | 
				
			||||||
  @IsObject()
 | 
					  @IsObject()
 | 
				
			||||||
  trash!: SystemConfigTrashDto;
 | 
					  trash!: SystemConfigTrashDto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Type(() => SystemConfigThemeDto)
 | 
				
			||||||
 | 
					  @ValidateNested()
 | 
				
			||||||
 | 
					  @IsObject()
 | 
				
			||||||
 | 
					  theme!: SystemConfigThemeDto;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function mapConfig(config: SystemConfig): SystemConfigDto {
 | 
					export function mapConfig(config: SystemConfig): SystemConfigDto {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -114,6 +114,9 @@ export const defaults = Object.freeze<SystemConfig>({
 | 
				
			|||||||
    enabled: true,
 | 
					    enabled: true,
 | 
				
			||||||
    days: 30,
 | 
					    days: 30,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  theme: {
 | 
				
			||||||
 | 
					    customCss: '',
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export enum FeatureFlag {
 | 
					export enum FeatureFlag {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -115,6 +115,9 @@ const updatedConfig = Object.freeze<SystemConfig>({
 | 
				
			|||||||
    enabled: true,
 | 
					    enabled: true,
 | 
				
			||||||
    days: 10,
 | 
					    days: 10,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  theme: {
 | 
				
			||||||
 | 
					    customCss: '',
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe(SystemConfigService.name, () => {
 | 
					describe(SystemConfigService.name, () => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -90,6 +90,8 @@ export enum SystemConfigKey {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  TRASH_ENABLED = 'trash.enabled',
 | 
					  TRASH_ENABLED = 'trash.enabled',
 | 
				
			||||||
  TRASH_DAYS = 'trash.days',
 | 
					  TRASH_DAYS = 'trash.days',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  THEME_CUSTOM_CSS = 'theme.customCss',
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export enum TranscodePolicy {
 | 
					export enum TranscodePolicy {
 | 
				
			||||||
@@ -221,4 +223,7 @@ export interface SystemConfig {
 | 
				
			|||||||
    enabled: boolean;
 | 
					    enabled: boolean;
 | 
				
			||||||
    days: number;
 | 
					    days: number;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					  theme: {
 | 
				
			||||||
 | 
					    customCss: string;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								web/src/api/open-api/api.ts
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										19
									
								
								web/src/api/open-api/api.ts
									
									
									
										generated
									
									
									
								
							@@ -3307,6 +3307,12 @@ export interface SystemConfigDto {
 | 
				
			|||||||
     * @memberof SystemConfigDto
 | 
					     * @memberof SystemConfigDto
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    'storageTemplate': SystemConfigStorageTemplateDto;
 | 
					    'storageTemplate': SystemConfigStorageTemplateDto;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * @type {SystemConfigThemeDto}
 | 
				
			||||||
 | 
					     * @memberof SystemConfigDto
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    'theme': SystemConfigThemeDto;
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 
 | 
					     * 
 | 
				
			||||||
     * @type {SystemConfigThumbnailDto}
 | 
					     * @type {SystemConfigThumbnailDto}
 | 
				
			||||||
@@ -3741,6 +3747,19 @@ export interface SystemConfigTemplateStorageOptionDto {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    'yearOptions': Array<string>;
 | 
					    'yearOptions': Array<string>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @export
 | 
				
			||||||
 | 
					 * @interface SystemConfigThemeDto
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export interface SystemConfigThemeDto {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * @type {string}
 | 
				
			||||||
 | 
					     * @memberof SystemConfigThemeDto
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    'customCss': string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 
 | 
					 * 
 | 
				
			||||||
 * @export
 | 
					 * @export
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					  import { quintOut } from 'svelte/easing';
 | 
				
			||||||
 | 
					  import { fly } from 'svelte/transition';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  export let value: string;
 | 
				
			||||||
 | 
					  export let label = '';
 | 
				
			||||||
 | 
					  export let desc = '';
 | 
				
			||||||
 | 
					  export let required = false;
 | 
				
			||||||
 | 
					  export let disabled = false;
 | 
				
			||||||
 | 
					  export let isEdited = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleInput = (e: Event) => {
 | 
				
			||||||
 | 
					    value = (e.target as HTMLInputElement).value;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="mb-4 w-full">
 | 
				
			||||||
 | 
					  <div class={`flex h-[26px] place-items-center gap-1`}>
 | 
				
			||||||
 | 
					    <label class={`immich-form-label text-sm`} for={label}>{label}</label>
 | 
				
			||||||
 | 
					    {#if required}
 | 
				
			||||||
 | 
					      <div class="text-red-400">*</div>
 | 
				
			||||||
 | 
					    {/if}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {#if isEdited}
 | 
				
			||||||
 | 
					      <div
 | 
				
			||||||
 | 
					        transition:fly={{ x: 10, duration: 200, easing: quintOut }}
 | 
				
			||||||
 | 
					        class="rounded-full bg-orange-100 px-2 text-[10px] text-orange-900"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        Unsaved change
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    {/if}
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  {#if desc}
 | 
				
			||||||
 | 
					    <p class="immich-form-label pb-2 text-sm" id="{label}-desc">
 | 
				
			||||||
 | 
					      {desc}
 | 
				
			||||||
 | 
					    </p>
 | 
				
			||||||
 | 
					  {:else}
 | 
				
			||||||
 | 
					    <slot name="desc" />
 | 
				
			||||||
 | 
					  {/if}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <textarea
 | 
				
			||||||
 | 
					    class="immich-form-input w-full pb-2"
 | 
				
			||||||
 | 
					    aria-describedby={desc ? `${label}-desc` : undefined}
 | 
				
			||||||
 | 
					    aria-labelledby="{label}-label"
 | 
				
			||||||
 | 
					    id={label}
 | 
				
			||||||
 | 
					    name={label}
 | 
				
			||||||
 | 
					    {required}
 | 
				
			||||||
 | 
					    {value}
 | 
				
			||||||
 | 
					    on:input={handleInput}
 | 
				
			||||||
 | 
					    {disabled}
 | 
				
			||||||
 | 
					  />
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
@@ -0,0 +1,98 @@
 | 
				
			|||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					  import {
 | 
				
			||||||
 | 
					    notificationController,
 | 
				
			||||||
 | 
					    NotificationType,
 | 
				
			||||||
 | 
					  } from '$lib/components/shared-components/notification/notification';
 | 
				
			||||||
 | 
					  import { handleError } from '$lib/utils/handle-error';
 | 
				
			||||||
 | 
					  import { api, SystemConfigThemeDto } from '@api';
 | 
				
			||||||
 | 
					  import { isEqual } from 'lodash-es';
 | 
				
			||||||
 | 
					  import { fade } from 'svelte/transition';
 | 
				
			||||||
 | 
					  import SettingButtonsRow from '../setting-buttons-row.svelte';
 | 
				
			||||||
 | 
					  import SettingTextarea from '../setting-textarea.svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  export let themeConfig: SystemConfigThemeDto; // this is the config that is being edited
 | 
				
			||||||
 | 
					  export let disabled = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let savedConfig: SystemConfigThemeDto;
 | 
				
			||||||
 | 
					  let defaultConfig: SystemConfigThemeDto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async function getConfigs() {
 | 
				
			||||||
 | 
					    [savedConfig, defaultConfig] = await Promise.all([
 | 
				
			||||||
 | 
					      api.systemConfigApi.getConfig().then((res) => res.data.theme),
 | 
				
			||||||
 | 
					      api.systemConfigApi.getDefaults().then((res) => res.data.theme),
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async function saveSetting() {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data: current } = await api.systemConfigApi.getConfig();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const { data: updated } = await api.systemConfigApi.updateConfig({
 | 
				
			||||||
 | 
					        systemConfigDto: {
 | 
				
			||||||
 | 
					          ...current,
 | 
				
			||||||
 | 
					          theme: themeConfig,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      themeConfig = { ...updated.theme };
 | 
				
			||||||
 | 
					      savedConfig = { ...updated.theme };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      notificationController.show({ message: 'Theme saved', type: NotificationType.Info });
 | 
				
			||||||
 | 
					    } catch (error) {
 | 
				
			||||||
 | 
					      handleError(error, 'Unable to save settings');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async function reset() {
 | 
				
			||||||
 | 
					    const { data: resetConfig } = await api.systemConfigApi.getConfig();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    themeConfig = { ...resetConfig.theme };
 | 
				
			||||||
 | 
					    savedConfig = { ...resetConfig.theme };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    notificationController.show({
 | 
				
			||||||
 | 
					      message: 'Reset theme to the recent saved theme',
 | 
				
			||||||
 | 
					      type: NotificationType.Info,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async function resetToDefault() {
 | 
				
			||||||
 | 
					    const { data: configs } = await api.systemConfigApi.getDefaults();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    themeConfig = { ...configs.theme };
 | 
				
			||||||
 | 
					    defaultConfig = { ...configs.theme };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    notificationController.show({
 | 
				
			||||||
 | 
					      message: 'Reset theme to default',
 | 
				
			||||||
 | 
					      type: NotificationType.Info,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div>
 | 
				
			||||||
 | 
					  {#await getConfigs() then}
 | 
				
			||||||
 | 
					    <div in:fade={{ duration: 500 }}>
 | 
				
			||||||
 | 
					      <form autocomplete="off" on:submit|preventDefault>
 | 
				
			||||||
 | 
					        <div class="ml-4 mt-4 flex flex-col gap-4">
 | 
				
			||||||
 | 
					          <div class="ml-4">
 | 
				
			||||||
 | 
					            <SettingTextarea
 | 
				
			||||||
 | 
					              {disabled}
 | 
				
			||||||
 | 
					              label="Custom CSS"
 | 
				
			||||||
 | 
					              desc="Cascading Style Sheets allow the design of Immich to be customized."
 | 
				
			||||||
 | 
					              bind:value={themeConfig.customCss}
 | 
				
			||||||
 | 
					              required={true}
 | 
				
			||||||
 | 
					              isEdited={themeConfig.customCss !== savedConfig.customCss}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <SettingButtonsRow
 | 
				
			||||||
 | 
					              on:reset={reset}
 | 
				
			||||||
 | 
					              on:save={saveSetting}
 | 
				
			||||||
 | 
					              on:reset-to-default={resetToDefault}
 | 
				
			||||||
 | 
					              showResetToDefault={!isEqual(savedConfig, defaultConfig)}
 | 
				
			||||||
 | 
					              {disabled}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </form>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  {/await}
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
@@ -67,6 +67,7 @@
 | 
				
			|||||||
<svelte:head>
 | 
					<svelte:head>
 | 
				
			||||||
  <title>{$page.data.meta?.title || 'Web'} - Immich</title>
 | 
					  <title>{$page.data.meta?.title || 'Web'} - Immich</title>
 | 
				
			||||||
  <link rel="manifest" href="/manifest.json" />
 | 
					  <link rel="manifest" href="/manifest.json" />
 | 
				
			||||||
 | 
					  <link rel="stylesheet" href="/custom.css" />
 | 
				
			||||||
  <meta name="theme-color" content="currentColor" />
 | 
					  <meta name="theme-color" content="currentColor" />
 | 
				
			||||||
  <FaviconHeader />
 | 
					  <FaviconHeader />
 | 
				
			||||||
  <AppleHeader />
 | 
					  <AppleHeader />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@
 | 
				
			|||||||
  import StorageTemplateSettings from '$lib/components/admin-page/settings/storage-template/storage-template-settings.svelte';
 | 
					  import StorageTemplateSettings from '$lib/components/admin-page/settings/storage-template/storage-template-settings.svelte';
 | 
				
			||||||
  import ThumbnailSettings from '$lib/components/admin-page/settings/thumbnail/thumbnail-settings.svelte';
 | 
					  import ThumbnailSettings from '$lib/components/admin-page/settings/thumbnail/thumbnail-settings.svelte';
 | 
				
			||||||
  import TrashSettings from '$lib/components/admin-page/settings/trash-settings/trash-settings.svelte';
 | 
					  import TrashSettings from '$lib/components/admin-page/settings/trash-settings/trash-settings.svelte';
 | 
				
			||||||
 | 
					  import ThemeSettings from '$lib/components/admin-page/settings/theme/theme-settings.svelte';
 | 
				
			||||||
  import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
 | 
					  import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
 | 
				
			||||||
  import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
 | 
					  import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
 | 
				
			||||||
  import { downloadManager } from '$lib/stores/download';
 | 
					  import { downloadManager } from '$lib/stores/download';
 | 
				
			||||||
@@ -96,6 +97,10 @@
 | 
				
			|||||||
        />
 | 
					        />
 | 
				
			||||||
      </SettingAccordion>
 | 
					      </SettingAccordion>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <SettingAccordion title="Theme Settings" subtitle="Manage customization of the Immich web interface">
 | 
				
			||||||
 | 
					        <ThemeSettings disabled={$featureFlags.configFile} themeConfig={configs.theme} />
 | 
				
			||||||
 | 
					      </SettingAccordion>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <SettingAccordion title="Thumbnail Settings" subtitle="Manage the resolution of thumbnail sizes">
 | 
					      <SettingAccordion title="Thumbnail Settings" subtitle="Manage the resolution of thumbnail sizes">
 | 
				
			||||||
        <ThumbnailSettings disabled={$featureFlags.configFile} thumbnailConfig={configs.thumbnail} />
 | 
					        <ThumbnailSettings disabled={$featureFlags.configFile} thumbnailConfig={configs.thumbnail} />
 | 
				
			||||||
      </SettingAccordion>
 | 
					      </SettingAccordion>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								web/src/routes/custom.css/+server.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								web/src/routes/custom.css/+server.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					import { RequestHandler, text } from '@sveltejs/kit';
 | 
				
			||||||
 | 
					export const GET = (async ({ locals: { api } }) => {
 | 
				
			||||||
 | 
					  const { customCss } = await api.systemConfigApi.getConfig().then((res) => res.data.theme);
 | 
				
			||||||
 | 
					  return text(customCss, {
 | 
				
			||||||
 | 
					    headers: {
 | 
				
			||||||
 | 
					      'Content-Type': 'text/css',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}) satisfies RequestHandler;
 | 
				
			||||||
		Reference in New Issue
	
	Block a user