solara 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/solara/lib/.DS_Store +0 -0
- data/solara/lib/core/.DS_Store +0 -0
- data/solara/lib/core/brands/brand_switcher.rb +58 -1
- data/solara/lib/core/dashboard/.DS_Store +0 -0
- data/solara/lib/core/dashboard/brand/BrandDetail.js +34 -2
- data/solara/lib/core/dashboard/brand/BrandDetailController.js +23 -206
- data/solara/lib/core/dashboard/brand/BrandDetailModel.js +13 -5
- data/solara/lib/core/dashboard/brand/BrandDetailView.js +16 -178
- data/solara/lib/core/dashboard/brand/SectionsFormManager.js +232 -0
- data/solara/lib/core/dashboard/brand/brand.html +199 -199
- data/solara/lib/core/dashboard/brand/source/BrandLocalSource.js +2 -5
- data/solara/lib/core/dashboard/brand/source/BrandRemoteSource.js +36 -133
- data/solara/lib/core/dashboard/brands/Brands.js +31 -0
- data/solara/lib/core/dashboard/brands/BrandsController.js +0 -5
- data/solara/lib/core/dashboard/brands/BrandsView.js +2 -2
- data/solara/lib/core/dashboard/brands/brands.html +71 -52
- data/solara/lib/core/dashboard/component/AliasesBottomSheet.js +6 -6
- data/solara/lib/core/dashboard/component/BrandOptionsBottomSheet.js +4 -4
- data/solara/lib/core/dashboard/component/ConfirmationDialog.js +15 -10
- data/solara/lib/core/dashboard/component/EditJsonSheet.js +160 -0
- data/solara/lib/core/dashboard/component/MessageBottomSheet.js +5 -5
- data/solara/lib/core/dashboard/component/OnboardBrandBottomSheet.js +5 -3
- data/solara/lib/core/dashboard/handler/base_handler.rb +1 -0
- data/solara/lib/core/dashboard/handler/edit_section_handler.rb +1 -5
- data/solara/lib/core/doctor/schema/brand_configurations.json +0 -8
- data/solara/lib/core/doctor/schema/platform/global/resources_manifest.json +30 -0
- data/solara/lib/core/doctor/schema/platform/json_manifest.json +57 -0
- data/solara/lib/core/doctor/validator/template/android_template_validation_config.yml +35 -1
- data/solara/lib/core/doctor/validator/template/flutter_template_validation_config.yml +30 -1
- data/solara/lib/core/doctor/validator/template/ios_template_validation_config.yml +35 -1
- data/solara/lib/core/doctor/validator/template/template_validator.rb +9 -9
- data/solara/lib/core/scripts/brand_config_manager.rb +1 -1
- data/solara/lib/core/scripts/brand_configurations_manager.rb +41 -0
- data/solara/lib/core/scripts/code_generator.rb +342 -118
- data/solara/lib/core/scripts/file_path.rb +21 -1
- data/solara/lib/core/scripts/gitignore_manager.rb +11 -3
- data/solara/lib/core/scripts/json_manifest_processor.rb +95 -0
- data/solara/lib/core/scripts/platform/ios/infoplist_string_catalog_manager.rb +11 -1
- data/solara/lib/core/scripts/resource_manifest_processor.rb +151 -0
- data/solara/lib/core/scripts/solara_status_manager.rb +1 -1
- data/solara/lib/core/scripts/theme_generator.rb +21 -242
- data/solara/lib/core/solara_configurator.rb +1 -1
- data/solara/lib/core/template/brands/global/resources_manifest.json +10 -0
- data/solara/lib/core/template/brands/json/Json-Manifest.md +61 -0
- data/solara/lib/core/template/brands/json/json_manifest.json +18 -0
- data/solara/lib/core/template/brands/shared/theme.json +213 -29
- data/solara/lib/core/template/config/android_template_config.json +50 -0
- data/solara/lib/core/template/config/flutter_template_config.json +35 -0
- data/solara/lib/core/template/config/ios_template_config.json +50 -0
- data/solara/lib/core/template/configurations.json +46 -0
- data/solara/lib/core/template/project_template_generator.rb +2 -0
- data/solara/lib/solara/version.rb +1 -1
- data/solara/lib/solara.rb +19 -0
- metadata +13 -4
- data/solara/lib/core/dashboard/component/AddFieldSheet.js +0 -175
- data/solara/lib/core/dashboard/handler/brand_configurations_manager.rb +0 -73
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 714797cd507e354e49c4a1981a516f6ad3e659797ba40b6040c7e7a6f30f11aa
|
4
|
+
data.tar.gz: 3b3d4ed6c116abea9dd15c2db4b5df308320649be4381623e3c7a3c863ef0385
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b4c46c3f893d95eddbde530e7d83fe340ce36698974880073b3517779bb8e39b31813863c13f7743e821936b814e6d7f5d42337c10b3ef37a4cd6767732f5a20
|
7
|
+
data.tar.gz: 750e7851fa9584bb85b00b5f01e48ea246892914f1bbfafeb7a2b18db8e138d0da5f8fd2a2253434bed1dd6b6d9b0c6911dcaec908714e96ff69c894653490b8
|
data/solara/lib/.DS_Store
CHANGED
Binary file
|
data/solara/lib/core/.DS_Store
CHANGED
Binary file
|
@@ -30,6 +30,9 @@ class BrandSwitcher
|
|
30
30
|
def switch
|
31
31
|
BrandFontSwitcher.new(@brand_key).switch
|
32
32
|
|
33
|
+
ResourceManifestSwitcher.new(@brand_key).switch
|
34
|
+
JsonManifestSwitcher.new(@brand_key).switch
|
35
|
+
|
33
36
|
case @platform
|
34
37
|
when Platform::Flutter
|
35
38
|
IOSBrandSwitcher.new(@brand_key).switch
|
@@ -42,6 +45,60 @@ class BrandSwitcher
|
|
42
45
|
else
|
43
46
|
raise ArgumentError, "Invalid platform: #{@platform}"
|
44
47
|
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
class ResourceManifestSwitcher
|
54
|
+
def initialize(brand_key)
|
55
|
+
@brand_key = brand_key
|
56
|
+
end
|
57
|
+
|
58
|
+
def switch
|
59
|
+
Solara.logger.start_step("Process resource manifest: #{FilePath.resources_manifest}")
|
60
|
+
brand_resource_copier = ResourceManifestProcessor.new(@brand_key)
|
61
|
+
brand_resource_copier.copy
|
62
|
+
Solara.logger.debug("#{@brand_key} resources copied successfully according to the manifest: #{FilePath.resources_manifest}.")
|
63
|
+
Solara.logger.end_step("Process resource manifest: #{FilePath.resources_manifest}")
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
class JsonManifestSwitcher
|
69
|
+
def initialize(brand_key)
|
70
|
+
@brand_key = brand_key
|
71
|
+
@manifest_path = FilePath.brand_json_dir(brand_key)
|
72
|
+
end
|
73
|
+
|
74
|
+
def switch
|
75
|
+
Solara.logger.start_step("Process JSON manifest: #{@manifest_path}")
|
76
|
+
|
77
|
+
|
78
|
+
case SolaraSettingsManager.instance.platform
|
79
|
+
when Platform::Flutter
|
80
|
+
process_maifest(Language::Dart, FilePath.flutter_lib_artifacts)
|
81
|
+
process_maifest(Language::Dart, FilePath.brand_global_json_dir)
|
82
|
+
when Platform::IOS
|
83
|
+
process_maifest(Language::Swift, FilePath.ios_project_root_artifacts)
|
84
|
+
process_maifest(Language::Swift, FilePath.brand_global_json_dir)
|
85
|
+
when Platform::Android
|
86
|
+
process_maifest(Language::Kotlin, FilePath.android_project_java_artifacts )
|
87
|
+
process_maifest(Language::Kotlin, FilePath.brand_global_json_dir)
|
88
|
+
else
|
89
|
+
raise ArgumentError, "Invalid platform: #{@platform}"
|
90
|
+
end
|
91
|
+
|
92
|
+
Solara.logger.end_step("Process JSON manifest: #{@manifest_path}")
|
93
|
+
end
|
94
|
+
|
95
|
+
def process_maifest(language, output_path)
|
96
|
+
processor = JsonManifestProcessor.new(
|
97
|
+
@manifest_path,
|
98
|
+
language,
|
99
|
+
output_path
|
100
|
+
)
|
101
|
+
processor.process
|
45
102
|
end
|
46
103
|
end
|
47
104
|
|
@@ -225,7 +282,7 @@ class ThemeSwitcher
|
|
225
282
|
def generate_theme(name, language, platform)
|
226
283
|
Solara.logger.start_step("Generate #{name} for #{platform}")
|
227
284
|
|
228
|
-
theme_manager =
|
285
|
+
theme_manager = ThemeGenerator.new(FilePath.brand_theme(@brand_key))
|
229
286
|
theme_manager.generate(language, FilePath.generated_config(name, platform))
|
230
287
|
|
231
288
|
Solara.logger.end_step("Generate #{name} for #{platform}")
|
Binary file
|
@@ -2,6 +2,37 @@ import BrandDetailModel from './BrandDetailModel.js';
|
|
2
2
|
import BrandDetailView from './BrandDetailView.js';
|
3
3
|
import BrandDetailController from './BrandDetailController.js';
|
4
4
|
|
5
|
+
const modeToggle = document.getElementById('modeToggle');
|
6
|
+
const body = document.body;
|
7
|
+
const icon = modeToggle.querySelector('i');
|
8
|
+
|
9
|
+
function applyMode(mode) {
|
10
|
+
if (mode === 'dark') {
|
11
|
+
body.classList.add('dark-mode');
|
12
|
+
icon.classList.remove('fa-sun');
|
13
|
+
icon.classList.add('fa-moon');
|
14
|
+
} else {
|
15
|
+
body.classList.remove('dark-mode');
|
16
|
+
icon.classList.remove('fa-moon');
|
17
|
+
icon.classList.add('fa-sun');
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
const savedMode = localStorage.getItem('mode');
|
22
|
+
if (savedMode) {
|
23
|
+
applyMode(savedMode);
|
24
|
+
} else {
|
25
|
+
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
26
|
+
applyMode(systemPrefersDark ? 'dark' : 'light');
|
27
|
+
}
|
28
|
+
|
29
|
+
modeToggle.addEventListener('click', () => {
|
30
|
+
const currentMode = body.classList.contains('dark-mode') ? 'dark' : 'light';
|
31
|
+
const newMode = currentMode === 'dark' ? 'light' : 'dark';
|
32
|
+
applyMode(newMode);
|
33
|
+
localStorage.setItem('mode', newMode);
|
34
|
+
});
|
35
|
+
|
5
36
|
window.onload = function () {
|
6
37
|
document.getElementById('loadingOverlay').style.display = 'none';
|
7
38
|
};
|
@@ -20,10 +51,11 @@ window.addEventListener('scroll', function () {
|
|
20
51
|
}
|
21
52
|
lastScrollTop = scrollTop;
|
22
53
|
});
|
23
|
-
|
54
|
+
|
24
55
|
document.addEventListener('DOMContentLoaded', async () => {
|
25
56
|
const model = new BrandDetailModel();
|
26
57
|
const view = new BrandDetailView(model);
|
27
58
|
const controller = new BrandDetailController(model, view);
|
28
59
|
await controller.initializeApp();
|
29
|
-
});
|
60
|
+
});
|
61
|
+
|
@@ -1,15 +1,10 @@
|
|
1
1
|
import {DataSource} from './BrandDetailModel.js';
|
2
|
-
import InfoPlistStringCatalogManager from "./InfoPlistStringCatalogManager.js";
|
3
2
|
|
4
3
|
class BrandDetailController {
|
5
4
|
constructor(model, view) {
|
6
5
|
this.model = model;
|
7
6
|
this.view = view;
|
8
|
-
this.onSectionChanged = this.onSectionChanged.bind(this);
|
9
|
-
this.deleteField = this.deleteField.bind(this);
|
10
7
|
this.initializeEventListeners();
|
11
|
-
this.view.setOnSectionChangedHandler(this.onSectionChanged.bind(this));
|
12
|
-
this.view.setOnDeleteFieldHandler(this.deleteField.bind(this));
|
13
8
|
}
|
14
9
|
|
15
10
|
async initializeApp() {
|
@@ -80,8 +75,7 @@ class BrandDetailController {
|
|
80
75
|
|
81
76
|
async addNewBrand() {
|
82
77
|
this.view.showOnboardBrandForm(async (key, name) => {
|
83
|
-
const configurations = await this.model.
|
84
|
-
console.log(configurations)
|
78
|
+
const configurations = await this.model.createNewBrandConfigurations()
|
85
79
|
await this.addBrand(key, name, configurations)
|
86
80
|
})
|
87
81
|
}
|
@@ -98,10 +92,10 @@ class BrandDetailController {
|
|
98
92
|
await this.onLoadSections(response.result);
|
99
93
|
const {isCurrentBrand, contentChanged} = await this.model.fetchCurrentBrand();
|
100
94
|
|
101
|
-
if (
|
95
|
+
if (isCurrentBrand) {
|
96
|
+
this.view.setupSyncBrandButton(contentChanged ? '#ff4136' : '#4A90E2');
|
97
|
+
} else {
|
102
98
|
this.view.showSwitchButton();
|
103
|
-
} else if (contentChanged) {
|
104
|
-
this.view.showApplyChangesButton();
|
105
99
|
}
|
106
100
|
|
107
101
|
await this.checkBrandHealth();
|
@@ -129,7 +123,12 @@ class BrandDetailController {
|
|
129
123
|
window.location.href = `../brands/brands.html?source=${this.model.source}`;
|
130
124
|
});
|
131
125
|
|
132
|
-
document.getElementById('
|
126
|
+
document.getElementById('syncBrandButton').addEventListener(
|
127
|
+
'click',
|
128
|
+
async () => {
|
129
|
+
await this.switchToBrand()
|
130
|
+
await this.view.toast("Synced successfully")
|
131
|
+
});
|
133
132
|
document.getElementById('switchButton').addEventListener('click', () => this.switchToBrand());
|
134
133
|
|
135
134
|
this.view.exportBrandBtn.addEventListener('click', () => this.exportBrand());
|
@@ -142,155 +141,37 @@ class BrandDetailController {
|
|
142
141
|
|
143
142
|
const sectionItems = configuraationsResult.configurations
|
144
143
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
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)
|
158
|
-
} else {
|
159
|
-
this.createSection(sectionInfo.key, sectionInfo, sectionInfo.content, sectionInfo.name, sectionInfo.inputType)
|
160
|
-
}
|
161
|
-
}
|
144
|
+
this.view.sectionsFormManager.display(
|
145
|
+
sectionItems,
|
146
|
+
(section, container) => {
|
147
|
+
this.onSectionChanged(section, container)
|
148
|
+
})
|
149
|
+
|
162
150
|
} catch (error) {
|
163
151
|
console.error('Error loading configurations:', error);
|
164
152
|
alert(error.message);
|
165
153
|
}
|
166
154
|
}
|
167
155
|
|
168
|
-
|
169
|
-
this.
|
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')
|
200
|
-
}
|
201
|
-
|
202
|
-
createSection(id, sectionInfo, content, sectionName, inputType, propertiesGroupName = null) {
|
203
|
-
const sectionElement = this.view.createSection(sectionInfo.key, sectionName, inputType);
|
204
|
-
sectionElement.id = id;
|
205
|
-
sectionElement.dataset.propertiesGroupName = propertiesGroupName
|
206
|
-
|
207
|
-
this.view.sectionsContainer.appendChild(sectionElement);
|
208
|
-
|
209
|
-
console.log('Section element created:', sectionElement);
|
210
|
-
|
211
|
-
this.view.populateSection(sectionInfo, sectionElement, content, inputType);
|
212
|
-
|
213
|
-
const addButton = document.createElement('button');
|
214
|
-
addButton.textContent = 'Add Field';
|
215
|
-
addButton.className = 'add-field-btn';
|
216
|
-
addButton.onclick = () => this.addNewField(sectionInfo, sectionElement, inputType);
|
217
|
-
sectionElement.appendChild(addButton);
|
218
|
-
}
|
156
|
+
async onSectionChanged(section, container) {
|
157
|
+
if (this.model.isRemote()) return
|
219
158
|
|
220
|
-
async onSectionChanged(sectionItem, sectionElement) {
|
221
159
|
try {
|
222
|
-
|
223
|
-
await this.model.saveSection(sectionItem, configuration);
|
224
|
-
this.view.showApplyChangesButton();
|
160
|
+
await this.model.saveSection(container.dataset.key, section.content);
|
225
161
|
await this.checkBrandHealth();
|
162
|
+
await this.switchToBrand(true)
|
226
163
|
} catch (error) {
|
227
164
|
console.error('Error saving section:', error);
|
228
165
|
alert(error.message);
|
229
166
|
}
|
230
167
|
}
|
231
168
|
|
232
|
-
|
233
|
-
const configuration = {};
|
234
|
-
const inputs = sectionElement.querySelectorAll('input:not(.array-item-input)');
|
235
|
-
inputs.forEach(input => {
|
236
|
-
const keys = input.id.split('.');
|
237
|
-
let current = configuration;
|
238
|
-
for (let i = 0; i < keys.length - 1; i++) {
|
239
|
-
if (!current[keys[i]]) {
|
240
|
-
current[keys[i]] = {};
|
241
|
-
}
|
242
|
-
current = current[keys[i]];
|
243
|
-
}
|
244
|
-
const lastKey = keys[keys.length - 1];
|
245
|
-
|
246
|
-
if (input.classList.contains('array-input')) {
|
247
|
-
const arrayItemsContainer = input.closest('.input-wrapper').querySelector('.array-items-container');
|
248
|
-
current[lastKey] = this.getArrayValue(arrayItemsContainer);
|
249
|
-
} else if (input.type === 'checkbox') {
|
250
|
-
current[lastKey] = input.checked;
|
251
|
-
} else {
|
252
|
-
let value = input.value;
|
253
|
-
if (input.type === 'color') {
|
254
|
-
value = `#${value.substring(1).toUpperCase()}`;
|
255
|
-
} else if (!isNaN(value) && value.trim() !== '') {
|
256
|
-
// Convert to number if it's a valid number string
|
257
|
-
value = parseFloat(value);
|
258
|
-
}
|
259
|
-
current[lastKey] = value;
|
260
|
-
}
|
261
|
-
});
|
262
|
-
return configuration;
|
263
|
-
}
|
264
|
-
|
265
|
-
addNewField(sectionItem, sectionElement, inputType) {
|
266
|
-
this.view.showAddFieldForm(sectionItem, sectionElement, inputType);
|
267
|
-
}
|
268
|
-
|
269
|
-
deleteField(sectionItem, fieldContainer) {
|
270
|
-
this.view.showConfirmationDialog(
|
271
|
-
'Are you sure you want to delete this item?',
|
272
|
-
() => {
|
273
|
-
const sectionElement = fieldContainer.closest('.section');
|
274
|
-
fieldContainer.remove();
|
275
|
-
this.onSectionChanged(sectionItem, sectionElement);
|
276
|
-
}
|
277
|
-
);
|
278
|
-
}
|
279
|
-
|
280
|
-
getArrayValue(container) {
|
281
|
-
const arrayItems = container.querySelectorAll('.array-item-input');
|
282
|
-
return Array.from(arrayItems).map(item => item.value);
|
283
|
-
}
|
284
|
-
|
285
|
-
async switchToBrand() {
|
169
|
+
async switchToBrand(silentError = false) {
|
286
170
|
try {
|
287
171
|
await this.model.switchToBrand();
|
288
|
-
const applyChangesButton = document.getElementById('applyChangesButton');
|
289
|
-
applyChangesButton.style.display = 'none';
|
290
|
-
location.reload();
|
291
172
|
} catch (error) {
|
292
173
|
console.error('Error switching to brand:', error);
|
293
|
-
alert(error.message);
|
174
|
+
if (!silentError) alert(error.message);
|
294
175
|
}
|
295
176
|
}
|
296
177
|
|
@@ -318,76 +199,13 @@ class BrandDetailController {
|
|
318
199
|
}
|
319
200
|
}
|
320
201
|
|
321
|
-
async getSectionData(sectionKey) {
|
322
|
-
try {
|
323
|
-
const container = this.view.sectionsContainer;
|
324
|
-
|
325
|
-
const sectionElements = Array.from(container.querySelectorAll('.section'))
|
326
|
-
.filter(element => element.dataset.key === sectionKey);
|
327
|
-
|
328
|
-
if (sectionElements.length === 1) {
|
329
|
-
return this.getSectionConfiguration(sectionElements[0])
|
330
|
-
}
|
331
|
-
|
332
|
-
const configurations = sectionElements.map(sectionElement => {
|
333
|
-
const propertiesGroupName = sectionElement.dataset.propertiesGroupName;
|
334
|
-
const config = this.getSectionConfiguration(sectionElement);
|
335
|
-
|
336
|
-
if (propertiesGroupName !== "null") {
|
337
|
-
return {[propertiesGroupName]: config};
|
338
|
-
} else {
|
339
|
-
return config;
|
340
|
-
}
|
341
|
-
});
|
342
|
-
|
343
|
-
const result = configurations.reduce((acc, config) => {
|
344
|
-
const key = Object.keys(config)[0]; // Get the key from the configuration item
|
345
|
-
acc[key] = config[key]; // Assign the value to the dynamic object
|
346
|
-
return acc;
|
347
|
-
}, {});
|
348
|
-
|
349
|
-
const json = JSON.stringify(result, null, 2); // Pretty-printing JSON
|
350
|
-
console.log(json);
|
351
|
-
return result;
|
352
|
-
|
353
|
-
} catch (error) {
|
354
|
-
console.error('Error downloading brand:', error);
|
355
|
-
alert(error.message);
|
356
|
-
}
|
357
|
-
}
|
358
|
-
|
359
202
|
async exportBrand() {
|
360
203
|
try {
|
361
|
-
const
|
204
|
+
const result = this.view.sectionsFormManager.data();
|
362
205
|
|
363
206
|
const brandKey = this.view.sectionsContainer.dataset.brandKey;
|
364
207
|
const brandName = this.view.sectionsContainer.dataset.brandName;
|
365
208
|
|
366
|
-
const sectionElements = Array.from(sectionsContainer.querySelectorAll('.section'));
|
367
|
-
|
368
|
-
const uniqueSections = new Map();
|
369
|
-
|
370
|
-
// The theme section has been divided into multiple categories (e.g., colors, typography).
|
371
|
-
// In the getSectionData function, we merge these sections. To prevent duplication when
|
372
|
-
// processing the sections, we will ensure that each section key is processed only once.
|
373
|
-
await Promise.all(sectionElements.map(async sectionElement => {
|
374
|
-
const key = sectionElement.dataset.key;
|
375
|
-
// Check if the key already exists in the map
|
376
|
-
if (!uniqueSections.has(key)) {
|
377
|
-
const configurations = await this.getSectionData(key);
|
378
|
-
uniqueSections.set(
|
379
|
-
key, {
|
380
|
-
key: key,
|
381
|
-
name: sectionElement.dataset.name,
|
382
|
-
inputType: sectionElement.dataset.inputType,
|
383
|
-
content: configurations
|
384
|
-
});
|
385
|
-
}
|
386
|
-
}));
|
387
|
-
|
388
|
-
// Convert the map values to an array
|
389
|
-
const result = Array.from(uniqueSections.values());
|
390
|
-
|
391
209
|
this.model.exportBrand(brandKey, brandName, result);
|
392
210
|
|
393
211
|
} catch (error) {
|
@@ -399,5 +217,4 @@ class BrandDetailController {
|
|
399
217
|
}
|
400
218
|
|
401
219
|
|
402
|
-
|
403
220
|
export default BrandDetailController;
|
@@ -17,6 +17,14 @@ class BrandDetailModel {
|
|
17
17
|
this.source = sourceFromUrl === DataSource.LOCAL ? DataSource.LOCAL : DataSource.REMOTE;
|
18
18
|
}
|
19
19
|
|
20
|
+
isLocal() {
|
21
|
+
return this.source === DataSource.LOCAL
|
22
|
+
}
|
23
|
+
|
24
|
+
isRemote() {
|
25
|
+
return this.source === DataSource.REMOTE
|
26
|
+
}
|
27
|
+
|
20
28
|
getQueryFromUrl(name) {
|
21
29
|
return this.localSource.getQueryFromUrl(name);
|
22
30
|
}
|
@@ -29,10 +37,10 @@ class BrandDetailModel {
|
|
29
37
|
return await this.localSource.fetchCurrentBrand(this.brandKey);
|
30
38
|
}
|
31
39
|
|
32
|
-
async saveSection(
|
40
|
+
async saveSection(key, configuration) {
|
33
41
|
switch (this.source) {
|
34
42
|
case DataSource.LOCAL:
|
35
|
-
return await this.localSource.saveSection(
|
43
|
+
return await this.localSource.saveSection(key, configuration, this.brandKey);
|
36
44
|
case DataSource.REMOTE:
|
37
45
|
// Saving is not supported remotely. Instead, user can export the brand.
|
38
46
|
return
|
@@ -48,7 +56,7 @@ class BrandDetailModel {
|
|
48
56
|
async checkBrandHealth() {
|
49
57
|
switch (this.source) {
|
50
58
|
case DataSource.LOCAL:
|
51
|
-
|
59
|
+
return await this.localSource.checkBrandHealth(this.brandKey);
|
52
60
|
case DataSource.REMOTE:
|
53
61
|
// Checking health is not supported remotely yet.
|
54
62
|
return
|
@@ -57,8 +65,8 @@ class BrandDetailModel {
|
|
57
65
|
}
|
58
66
|
}
|
59
67
|
|
60
|
-
async
|
61
|
-
return await this.remoteSource.
|
68
|
+
async createNewBrandConfigurations() {
|
69
|
+
return await this.remoteSource.createNewBrandConfigurations();
|
62
70
|
}
|
63
71
|
|
64
72
|
async createBrandConfigurationsFromDirectory(dirHandle) {
|