solara 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/solara/lib/core/.DS_Store +0 -0
  3. data/solara/lib/core/aliases/alias_generator.rb +1 -0
  4. data/solara/lib/core/aliases/alias_generator_manager.rb +2 -1
  5. data/solara/lib/core/aliases/solara_terminal_setup.rb +1 -1
  6. data/solara/lib/core/brands/brand_font_switcher.rb +154 -0
  7. data/solara/lib/core/brands/brand_onboarder.rb +8 -6
  8. data/solara/lib/core/brands/brand_switcher.rb +232 -166
  9. data/solara/lib/core/brands/brands_manager.rb +15 -39
  10. data/solara/lib/core/dashboard/brand/BrandDetail.js +19 -0
  11. data/solara/lib/core/dashboard/brand/BrandDetailController.js +50 -8
  12. data/solara/lib/core/dashboard/brand/BrandDetailModel.js +9 -30
  13. data/solara/lib/core/dashboard/brand/BrandDetailView.js +49 -3
  14. data/solara/lib/core/dashboard/brand/InfoPlistStringCatalogManager.js +19 -0
  15. data/solara/lib/core/dashboard/brand/brand.html +209 -62
  16. data/solara/lib/core/dashboard/brand/source/BrandLocalSource.js +1 -1
  17. data/solara/lib/core/dashboard/brand/source/BrandRemoteSource.js +38 -53
  18. data/solara/lib/core/dashboard/brands/BrandsController.js +6 -5
  19. data/solara/lib/core/dashboard/brands/BrandsModel.js +2 -2
  20. data/solara/lib/core/dashboard/brands/BrandsView.js +2 -2
  21. data/solara/lib/core/dashboard/brands/brands.html +3 -1
  22. data/solara/lib/core/dashboard/component/AliasesBottomSheet.js +7 -5
  23. data/solara/lib/core/dashboard/dashboard_manager.rb +2 -0
  24. data/solara/lib/core/dashboard/dashboard_server.rb +1 -3
  25. data/solara/lib/core/dashboard/handler/brand_alisases_handler.rb +4 -11
  26. data/solara/lib/core/dashboard/handler/brand_configurations_manager.rb +11 -11
  27. data/solara/lib/core/dashboard/handler/{brand_configurations_handler.rb → brand_details_handler.rb} +4 -4
  28. data/solara/lib/core/dashboard/handler/brands_handler.rb +1 -1
  29. data/solara/lib/core/dashboard/handler/edit_section_handler.rb +8 -8
  30. data/solara/lib/core/doctor/brand_doctor.rb +31 -31
  31. data/solara/lib/core/doctor/doctor_manager.rb +0 -1
  32. data/solara/lib/core/doctor/project_doctor.rb +0 -1
  33. data/solara/lib/core/doctor/schema/platform/android/android_config.json +0 -4
  34. data/solara/lib/core/doctor/schema/platform/ios/InfoPlist.xcstrings +15 -0
  35. data/solara/lib/core/doctor/schema/platform/ios/ios_config.json +0 -5
  36. data/solara/lib/core/doctor/schema/platform/shared/brand_config.json +9 -0
  37. data/solara/lib/core/doctor/schema/platform/shared/theme.json +94 -9
  38. data/solara/lib/core/doctor/validator/brand_settings_validator.rb +6 -0
  39. data/solara/lib/core/doctor/validator/brand_settings_validator_manager.rb +9 -21
  40. data/solara/lib/core/doctor/validator/template/android_template_validation_config.yml +22 -4
  41. data/solara/lib/core/doctor/validator/template/flutter_template_validation_config.yml +22 -6
  42. data/solara/lib/core/doctor/validator/template/ios_template_validation_config.yml +22 -4
  43. data/solara/lib/core/scripts/brand_config_generator.rb +1 -0
  44. data/solara/lib/core/scripts/brand_config_manager.rb +2 -4
  45. data/solara/lib/core/scripts/brand_exporter.rb +1 -1
  46. data/solara/lib/core/scripts/brand_importer.rb +2 -3
  47. data/solara/lib/core/scripts/brand_offboarder.rb +5 -0
  48. data/solara/lib/core/scripts/brand_resources_manager.rb +127 -54
  49. data/solara/lib/core/scripts/directory_creator.rb +2 -2
  50. data/solara/lib/core/scripts/file_manager.rb +53 -19
  51. data/solara/lib/core/scripts/file_path.rb +175 -30
  52. data/solara/lib/core/scripts/folder_copier.rb +3 -7
  53. data/solara/lib/core/scripts/gitignore_manager.rb +21 -10
  54. data/solara/lib/core/scripts/interactive_file_system_validator.rb +8 -2
  55. data/solara/lib/core/scripts/platform/android/android_manifest_switcher.rb +3 -3
  56. data/solara/lib/core/scripts/platform/android/android_strings_switcher.rb +26 -24
  57. data/solara/lib/core/scripts/platform/android/gradle_switcher.rb +7 -6
  58. data/solara/lib/core/scripts/platform/ios/infoplist_string_catalog_manager.rb +123 -0
  59. data/solara/lib/core/scripts/platform/ios/infoplist_switcher.rb +59 -0
  60. data/solara/lib/core/scripts/platform/ios/ios_plist_manager.rb +11 -20
  61. data/solara/lib/core/scripts/platform/ios/plist_font_manager.rb +33 -0
  62. data/solara/lib/core/scripts/platform/ios/xcconfig_generator.rb +15 -3
  63. data/solara/lib/core/scripts/platform/ios/xcode_asset_manager.rb +2 -3
  64. data/solara/lib/core/scripts/platform/ios/xcode_project_manager.rb +80 -1
  65. data/solara/lib/core/scripts/platform/ios/xcode_project_switcher.rb +15 -34
  66. data/solara/lib/core/scripts/solara_logger.rb +10 -0
  67. data/solara/lib/core/scripts/solara_settings_manager.rb +26 -1
  68. data/solara/lib/core/scripts/strings_xml_manager.rb +17 -2
  69. data/solara/lib/core/scripts/theme_generator.rb +133 -130
  70. data/solara/lib/core/scripts/yaml_manager.rb +23 -0
  71. data/solara/lib/core/solara_configurator.rb +1 -1
  72. data/solara/lib/core/template/brands/android/android_config.json +0 -1
  73. data/solara/lib/core/template/brands/android/res/values/strings.xml +4 -0
  74. data/solara/lib/core/template/brands/ios/InfoPlist.xcstrings +30 -0
  75. data/solara/lib/core/template/brands/ios/ios_config.json +1 -2
  76. data/solara/lib/core/template/brands/shared/brand_config.json +1 -0
  77. data/solara/lib/core/template/brands/shared/theme.json +3 -3
  78. data/solara/lib/core/template/config/android_template_config.json +11 -1
  79. data/solara/lib/core/template/config/flutter_template_config.json +12 -2
  80. data/solara/lib/core/template/config/ios_template_config.json +11 -1
  81. data/solara/lib/core/template/project_template_generator.rb +8 -3
  82. data/solara/lib/solara/version.rb +1 -1
  83. data/solara/lib/solara.rb +8 -4
  84. data/solara/lib/solara_initializer.rb +5 -2
  85. data/solara/lib/solara_manager.rb +1 -1
  86. metadata +62 -43
  87. data/solara/lib/core/dashboard/handler/brand_section_handler.rb +0 -20
  88. data/solara/lib/core/doctor/validator/directory_structure_validator.rb +0 -38
  89. data/solara/lib/core/doctor/validator/file_structure_validator.rb +0 -37
  90. data/solara/lib/core/scripts/platform/ios/ios_file_path_manager.rb +0 -109
  91. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/.DS_Store +0 -0
  92. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/100.png +0 -0
  93. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/102.png +0 -0
  94. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/1024.png +0 -0
  95. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/114.png +0 -0
  96. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/120.png +0 -0
  97. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/128.png +0 -0
  98. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/144.png +0 -0
  99. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/152.png +0 -0
  100. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/16.png +0 -0
  101. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/167.png +0 -0
  102. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/172.png +0 -0
  103. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/180.png +0 -0
  104. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/196.png +0 -0
  105. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/20.png +0 -0
  106. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/216.png +0 -0
  107. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/256.png +0 -0
  108. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/29.png +0 -0
  109. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/32.png +0 -0
  110. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/40.png +0 -0
  111. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/48.png +0 -0
  112. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/50.png +0 -0
  113. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/512.png +0 -0
  114. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/55.png +0 -0
  115. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/57.png +0 -0
  116. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/58.png +0 -0
  117. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/60.png +0 -0
  118. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/64.png +0 -0
  119. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/66.png +0 -0
  120. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/72.png +0 -0
  121. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/76.png +0 -0
  122. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/80.png +0 -0
  123. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/87.png +0 -0
  124. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/88.png +0 -0
  125. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/92.png +0 -0
  126. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/Contents.json +0 -0
@@ -5,25 +5,22 @@ require 'rubygems'
5
5
  class BrandsManager
6
6
  include Singleton
7
7
 
8
+ # Class method to access the singleton instance
9
+ def self.instance
10
+ @instance ||= new
11
+ end
12
+
8
13
  def initialize
9
14
  brands_list_path = FilePath.brands_list
10
15
  @brands_list = JSON.parse(File.read(brands_list_path))
11
16
  end
12
17
 
13
- def first_brand
14
- brands_list.first
15
- end
16
-
17
18
  def first_brand_key
18
19
  brands_list.first["key"]
19
20
  rescue
20
21
  nil
21
22
  end
22
23
 
23
- def brand_name(brand_key)
24
- brand_data(brand_key)["name"]
25
- end
26
-
27
24
  def brand_with_configurations(brand_key)
28
25
  configurations = BrandConfigurationsManager.new(brand_key).create
29
26
  {
@@ -41,17 +38,8 @@ class BrandsManager
41
38
  @brands_list["brands"]
42
39
  end
43
40
 
44
- def find(brand_key)
45
- brands = brands_list
46
- brands.find { |b| b["key"] == brand_key }
47
- end
48
-
49
- def brands_json
50
- @brands_list
51
- end
52
-
53
41
  def exists(brand_key)
54
- !brand_data(brand_key).nil?
42
+ !brand_data(brand_key).nil? && File.exist?(FilePath.brand(brand_key))
55
43
  end
56
44
 
57
45
  def add_brand(brand_name, brand_key)
@@ -59,11 +47,11 @@ class BrandsManager
59
47
  existing_brand = brand_data(brand_key)
60
48
  if existing_brand
61
49
  update_brand(brands_list.index(existing_brand), brand)
62
- Solara.logger.debug("#{brand_name} Brand updated in the list.")
50
+ Solara.logger.debug("#{brand_name} Brand updated in the brands list.")
63
51
  else
64
52
  brands_list.push(brand)
65
53
  save_brands_list
66
- Solara.logger.debug("#{brand_name} added to the list.")
54
+ Solara.logger.debug("#{brand_name} added to the brands list.")
67
55
  end
68
56
  end
69
57
 
@@ -71,13 +59,6 @@ class BrandsManager
71
59
  JSON.parse(File.read(FilePath.current_brand))
72
60
  end
73
61
 
74
- def current_brand_content_changed(brand_key)
75
- unless is_current_brand(brand_key)
76
- return false
77
- end
78
- current_brand['content_changed'] == true
79
- end
80
-
81
62
  def set_current_brand_content_changed(brand_key, changed)
82
63
  unless is_current_brand(brand_key)
83
64
  return false
@@ -85,7 +66,7 @@ class BrandsManager
85
66
  Solara.logger.debug("")
86
67
  brand = current_brand
87
68
  brand['content_changed'] = changed
88
- save_current_brand_date(brand)
69
+ save_current_brand_data(brand)
89
70
  Solara.logger.debug("#{brand_key} changed saved to current_brand.json.")
90
71
  end
91
72
 
@@ -95,17 +76,17 @@ class BrandsManager
95
76
 
96
77
  def save_current_brand(brand_key)
97
78
  brand = brand_data(brand_key)
98
- save_current_brand_date(brand)
79
+ save_current_brand_data(brand)
99
80
  Solara.logger.debug("#{brand_key} saved as current brand.")
100
81
  end
101
82
 
102
- def save_current_brand_date(brand_data)
103
- current_brand = FilePath.current_brand
83
+ def save_current_brand_data(brand_data)
84
+ path = FilePath.current_brand
104
85
 
105
86
  # Create the file if it doesn't exist
106
- FileUtils.touch(current_brand) unless File.exist?(current_brand)
87
+ FileUtils.touch(path) unless File.exist?(path)
107
88
 
108
- File.open(current_brand, 'w') do |file|
89
+ File.open(path, 'w') do |file|
109
90
  file.write(JSON.pretty_generate(brand_data))
110
91
  end
111
92
 
@@ -128,7 +109,7 @@ class BrandsManager
128
109
  if index
129
110
  brand_dir = FilePath.brand(brand_key)
130
111
  remove_brand(index)
131
- FileUtils.rm_rf(brand_dir)
112
+ FileManager.delete_if_exists(brand_dir)
132
113
  save_brands_list
133
114
  Solara.logger.debug("Brand removed.")
134
115
  else
@@ -136,11 +117,6 @@ class BrandsManager
136
117
  end
137
118
  end
138
119
 
139
- # Class method to access the singleton instance
140
- def self.instance
141
- @instance ||= new
142
- end
143
-
144
120
  private
145
121
 
146
122
  def save_brands_list
@@ -3,6 +3,25 @@ import BrandDetailModel from './BrandDetailModel.js';
3
3
  import BrandDetailView from './BrandDetailView.js';
4
4
  import BrandDetailController from './BrandDetailController.js';
5
5
 
6
+ window.onload = function () {
7
+ document.getElementById('loadingOverlay').style.display = 'none';
8
+ };
9
+
10
+ let lastScrollTop = 0;
11
+ const header = document.getElementById('header');
12
+
13
+ window.addEventListener('scroll', function () {
14
+ let scrollTop = window.pageYOffset || document.documentElement.scrollTop;
15
+ if (scrollTop > lastScrollTop) {
16
+ // Scrolling down
17
+ header.classList.add('scroll-down');
18
+ } else {
19
+ // Scrolling up
20
+ header.classList.remove('scroll-down');
21
+ }
22
+ lastScrollTop = scrollTop;
23
+ });
24
+
6
25
  document.addEventListener('DOMContentLoaded', async () => {
7
26
  const model = new BrandDetailModel();
8
27
  const view = new BrandDetailView(model);
@@ -1,4 +1,5 @@
1
1
  import {DataSource} from './BrandDetailModel.js';
2
+ import InfoPlistStringCatalogManager from "./InfoPlistStringCatalogManager.js";
2
3
 
3
4
  class BrandDetailController {
4
5
  constructor(model, view) {
@@ -112,8 +113,11 @@ class BrandDetailController {
112
113
 
113
114
  async onLoadSections(configuraationsResult) {
114
115
  try {
116
+ this.view.addBrandOverlay.style.display = 'none'
117
+ this.view.header.style.display = 'flex';
115
118
  this.view.updateAppNameTitle(`${configuraationsResult.brand.key} (${configuraationsResult.brand.name})`);
116
119
  await this.showSections(configuraationsResult);
120
+ this.view.showIndex();
117
121
  } catch (error) {
118
122
  console.error('Error initializing app:', error);
119
123
  alert(error.message);
@@ -142,10 +146,17 @@ class BrandDetailController {
142
146
  const sectionInfo = sectionItems[i];
143
147
  console.log('Processing section:', i, sectionInfo);
144
148
 
145
- if (sectionInfo.key === 'theme') {
149
+ if (sectionInfo.key === 'theme.json') {
146
150
  this.createThemeSections(sectionInfo)
151
+ } else if (sectionInfo.key === 'InfoPlist.xcstrings') {
152
+ this.createSection(
153
+ sectionInfo.key,
154
+ sectionInfo,
155
+ new InfoPlistStringCatalogManager(sectionInfo.content).extractLocalizations(),
156
+ sectionInfo.name,
157
+ sectionInfo.inputType)
147
158
  } else {
148
- this.createSection(sectionInfo, sectionInfo.content, sectionInfo.name, sectionInfo.inputType)
159
+ this.createSection(sectionInfo.key, sectionInfo, sectionInfo.content, sectionInfo.name, sectionInfo.inputType)
149
160
  }
150
161
  }
151
162
  } catch (error) {
@@ -155,15 +166,42 @@ class BrandDetailController {
155
166
  }
156
167
 
157
168
  createThemeSections(sectionInfo) {
158
- this.createSection(sectionInfo, sectionInfo.content.colors, 'Theme Colors', 'color', 'colors')
159
- this.createSection(sectionInfo, sectionInfo.content.typography, 'Theme Typography', 'text', 'typography')
160
- this.createSection(sectionInfo, sectionInfo.content.spacing, 'Theme Spacing', 'text', 'spacing')
161
- this.createSection(sectionInfo, sectionInfo.content.borderRadius, 'Theme Border Radius', 'text', 'borderRadius')
162
- this.createSection(sectionInfo, sectionInfo.content.elevation, 'Theme Elevation', 'text', 'elevation')
169
+ this.createSection(`${sectionInfo.key}_colors`,
170
+ sectionInfo,
171
+ sectionInfo.content.colors,
172
+ 'Theme Colors',
173
+ 'color',
174
+ 'colors')
175
+ this.createSection(`${sectionInfo.key}_typography`,
176
+ sectionInfo,
177
+ sectionInfo.content.typography,
178
+ 'Theme Typography',
179
+ 'text',
180
+ 'typography')
181
+ this.createSection(`${sectionInfo.key}_spacing`,
182
+ sectionInfo,
183
+ sectionInfo.content.spacing,
184
+ 'Theme Spacing', 'text',
185
+ 'spacing')
186
+ this.createSection(
187
+ `${sectionInfo.key}_borderRadius`,
188
+ sectionInfo,
189
+ sectionInfo.content.borderRadius,
190
+ 'Theme Border Radius',
191
+ 'text',
192
+ 'borderRadius')
193
+ this.createSection(
194
+ `${sectionInfo.key}_elevation`,
195
+ sectionInfo,
196
+ sectionInfo.content.elevation,
197
+ 'Theme Elevation',
198
+ 'text',
199
+ 'elevation')
163
200
  }
164
201
 
165
- createSection(sectionInfo, content, sectionName, inputType, propertiesGroupName = null) {
202
+ createSection(id, sectionInfo, content, sectionName, inputType, propertiesGroupName = null) {
166
203
  const sectionElement = this.view.createSection(sectionInfo.key, sectionName, inputType);
204
+ sectionElement.id = id;
167
205
  sectionElement.dataset.propertiesGroupName = propertiesGroupName
168
206
 
169
207
  this.view.sectionsContainer.appendChild(sectionElement);
@@ -208,6 +246,8 @@ class BrandDetailController {
208
246
  if (input.classList.contains('array-input')) {
209
247
  const arrayItemsContainer = input.closest('.input-wrapper').querySelector('.array-items-container');
210
248
  current[lastKey] = this.getArrayValue(arrayItemsContainer);
249
+ } else if (input.type === 'checkbox') {
250
+ current[lastKey] = input.checked;
211
251
  } else {
212
252
  let value = input.value;
213
253
  if (input.type === 'color') {
@@ -358,4 +398,6 @@ class BrandDetailController {
358
398
 
359
399
  }
360
400
 
401
+
402
+
361
403
  export default BrandDetailController;
@@ -14,9 +14,7 @@ class BrandDetailModel {
14
14
  this.brandKey = this.getQueryFromUrl('brand_key');
15
15
 
16
16
  const sourceFromUrl = this.getQueryFromUrl('source');
17
- // TODO: uncomment
18
- this.source = sourceFromUrl === DataSource.LOCAL ? DataSource.LOCAL : DataSource.REMOTE;
19
- // this.source = DataSource.REMOTE;
17
+ this.source = sourceFromUrl === DataSource.LOCAL ? DataSource.LOCAL : DataSource.REMOTE;
20
18
  }
21
19
 
22
20
  getQueryFromUrl(name) {
@@ -24,25 +22,11 @@ class BrandDetailModel {
24
22
  }
25
23
 
26
24
  async fetchBrandDetails() {
27
- switch (this.source) {
28
- case DataSource.LOCAL:
29
- return await this.localSource.fetchBrandDetails(this.brandKey);
30
- case DataSource.REMOTE:
31
- return await this.remoteSource.fetchBrandDetails(this.brandKey);
32
- default:
33
- throw new Error('Unknown data source');
34
- }
25
+ return await this.localSource.fetchBrandDetails(this.brandKey);
35
26
  }
36
27
 
37
28
  async fetchCurrentBrand() {
38
- switch (this.source) {
39
- case DataSource.LOCAL:
40
- return await this.localSource.fetchCurrentBrand(this.brandKey);
41
- case DataSource.REMOTE:
42
- return await this.remoteSource.fetchCurrentBrand(this.brandKey);
43
- default:
44
- throw new Error('Unknown data source');
45
- }
29
+ return await this.localSource.fetchCurrentBrand(this.brandKey);
46
30
  }
47
31
 
48
32
  async saveSection(sectionItem, configuration) {
@@ -50,29 +34,24 @@ class BrandDetailModel {
50
34
  case DataSource.LOCAL:
51
35
  return await this.localSource.saveSection(sectionItem, configuration, this.brandKey);
52
36
  case DataSource.REMOTE:
53
- return await this.remoteSource.saveSection(sectionItem, configuration, this.brandKey);
37
+ // Saving is not supported remotely. Instead, user can export the brand.
38
+ return
54
39
  default:
55
40
  throw new Error('Unknown data source');
56
41
  }
57
42
  }
58
43
 
59
44
  async switchToBrand() {
60
- switch (this.source) {
61
- case DataSource.LOCAL:
62
- return await this.localSource.switchToBrand(this.brandKey);
63
- case DataSource.REMOTE:
64
- return await this.remoteSource.switchToBrand(this.brandKey);
65
- default:
66
- throw new Error('Unknown data source');
67
- }
45
+ return await this.localSource.switchToBrand(this.brandKey);
68
46
  }
69
47
 
70
48
  async checkBrandHealth() {
71
49
  switch (this.source) {
72
50
  case DataSource.LOCAL:
73
- return await this.localSource.checkBrandHealth(this.brandKey);
51
+ return await this.localSource.checkBrandHealth(this.brandKey);
74
52
  case DataSource.REMOTE:
75
- return await this.remoteSource.checkBrandHealth(this.brandKey);
53
+ // Checking health is not supported remotely yet.
54
+ return
76
55
  default:
77
56
  throw new Error('Unknown data source');
78
57
  }
@@ -7,7 +7,11 @@ import '../component/MessageBottomSheet.js';
7
7
  class BrandDetailView {
8
8
  constructor(model) {
9
9
  this.model = model;
10
+
11
+ this.header = document.getElementById('header');
12
+
10
13
  this.brandDetailsContainer = document.getElementById('brand-details-container');
14
+ this.addBrandOverlay = document.getElementById('add-brand-overlay');
11
15
  this.addBrandContainer = document.getElementById('add-brand-container');
12
16
 
13
17
  this.sectionsContainer = document.getElementById('sections');
@@ -38,11 +42,15 @@ class BrandDetailView {
38
42
  }
39
43
 
40
44
  async setupLocal() {
45
+ this.addBrandOverlay.style.display = 'none'
46
+ this.header.style.display = 'flex'
41
47
  this.allBrandsButton.style.display = 'block'
42
48
  this.toggleAddBrandContainer(false);
43
49
  }
44
50
 
45
51
  async setupRemote() {
52
+ this.addBrandOverlay.style.display = 'flex'
53
+ this.header.style.display = 'none'
46
54
  this.allBrandsButton.style.display = 'none'
47
55
  this.toggleAddBrandContainer(true);
48
56
  }
@@ -76,7 +84,7 @@ class BrandDetailView {
76
84
 
77
85
  const subtitleElement = document.createElement('p');
78
86
  subtitleElement.className = 'section-subtitle';
79
- subtitleElement.textContent = `${key}.json`;
87
+ subtitleElement.textContent = key;
80
88
  titleContainer.appendChild(subtitleElement);
81
89
 
82
90
  section.appendChild(titleContainer);
@@ -90,10 +98,12 @@ class BrandDetailView {
90
98
  sectionElement.appendChild(this.createInputField(sectionItem, key, value, 'array'));
91
99
  } else if (typeof value === 'object' && value !== null) {
92
100
  for (const [subKey, subValue] of Object.entries(value)) {
93
- sectionElement.appendChild(this.createInputField(sectionItem, `${key}.${subKey}`, subValue, inputType));
101
+ const subInputType = subValue === true || subValue === false ? 'boolean' : inputType;
102
+ sectionElement.appendChild(this.createInputField(sectionItem, `${key}.${subKey}`, subValue, subInputType));
94
103
  }
95
104
  } else {
96
- sectionElement.appendChild(this.createInputField(sectionItem, key, value, inputType));
105
+ const fieldInputType = value === true || value === false ? 'boolean' : inputType;
106
+ sectionElement.appendChild(this.createInputField(sectionItem, key, value, fieldInputType));
97
107
  }
98
108
  }
99
109
  }
@@ -142,11 +152,30 @@ class BrandDetailView {
142
152
  input.value = '';
143
153
  });
144
154
 
155
+ } else if (inputType === 'boolean') {
156
+ const checkbox = document.createElement('input');
157
+ checkbox.type = 'checkbox';
158
+ checkbox.id = key;
159
+ checkbox.checked = value;
160
+
161
+ const checkboxLabel = document.createElement('label');
162
+ checkboxLabel.className = 'checkbox-label';
163
+ checkboxLabel.htmlFor = key;
164
+ checkboxLabel.textContent = value ? 'True' : 'False';
165
+
166
+ checkbox.addEventListener('change', () => {
167
+ checkboxLabel.textContent = checkbox.checked ? 'True' : 'False';
168
+ this.onSectionChanged(sectionItem, container.closest('.section'));
169
+ });
170
+
171
+ inputWrapper.appendChild(checkbox);
172
+ inputWrapper.appendChild(checkboxLabel);
145
173
  } else {
146
174
  const input = document.createElement('input');
147
175
  input.type = inputType;
148
176
  input.id = key;
149
177
 
178
+ console.log(value)
150
179
  if (inputType === 'color') {
151
180
  input.value = value.startsWith('#') ? value : `#${value.substring(4)}`;
152
181
  } else {
@@ -236,6 +265,23 @@ class BrandDetailView {
236
265
  this.onboardSheet.show('Brand Details', 'Add Brand', onSubmit);
237
266
  }
238
267
 
268
+ showIndex() {
269
+ const sectionsContainer = this.sectionsContainer;
270
+ const sectionElements = Array.from(sectionsContainer.querySelectorAll('.section'));
271
+
272
+ const indexElement = document.getElementById('index');
273
+
274
+ // Clear existing items if needed
275
+ indexElement.innerHTML = '';
276
+
277
+ sectionElements.forEach(sectionElement => {
278
+ const newItem = document.createElement('li');
279
+ newItem.classList.add('index-item');
280
+ newItem.innerHTML = `<a href="#${sectionElement.id}">${sectionElement.dataset.name}</a>`;
281
+ indexElement.appendChild(newItem);
282
+ });
283
+ }
284
+
239
285
  async hideOnboardBrandForm() {
240
286
  this.onboardSheet.hide();
241
287
  }
@@ -0,0 +1,19 @@
1
+ class InfoPlistStringCatalogManager {
2
+ constructor(jsonData) {
3
+ this.data = jsonData;
4
+ this.localizations = {};
5
+ this.extractLocalizations();
6
+ }
7
+
8
+ extractLocalizations() {
9
+ for (const [key, details] of Object.entries(this.data.strings)) {
10
+ for (const [lang, localization] of Object.entries(details.localizations)) {
11
+ const formattedKey = `${key}.${lang}`;
12
+ this.localizations[formattedKey] = localization.stringUnit.value;
13
+ }
14
+ }
15
+ return this.localizations
16
+ }
17
+ }
18
+
19
+ export default InfoPlistStringCatalogManager;