solara 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/brand/BrandDetail.js +34 -2
- data/solara/lib/core/dashboard/brand/BrandDetailController.js +23 -233
- data/solara/lib/core/dashboard/brand/BrandDetailModel.js +13 -5
- data/solara/lib/core/dashboard/brand/BrandDetailView.js +16 -200
- data/solara/lib/core/dashboard/brand/SectionsFormManager.js +232 -0
- data/solara/lib/core/dashboard/brand/brand.html +187 -177
- 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}")
|
@@ -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,7 +75,7 @@ class BrandDetailController {
|
|
80
75
|
|
81
76
|
async addNewBrand() {
|
82
77
|
this.view.showOnboardBrandForm(async (key, name) => {
|
83
|
-
const configurations = await this.model.
|
78
|
+
const configurations = await this.model.createNewBrandConfigurations()
|
84
79
|
await this.addBrand(key, name, configurations)
|
85
80
|
})
|
86
81
|
}
|
@@ -97,10 +92,10 @@ class BrandDetailController {
|
|
97
92
|
await this.onLoadSections(response.result);
|
98
93
|
const {isCurrentBrand, contentChanged} = await this.model.fetchCurrentBrand();
|
99
94
|
|
100
|
-
if (
|
95
|
+
if (isCurrentBrand) {
|
96
|
+
this.view.setupSyncBrandButton(contentChanged ? '#ff4136' : '#4A90E2');
|
97
|
+
} else {
|
101
98
|
this.view.showSwitchButton();
|
102
|
-
} else if (contentChanged) {
|
103
|
-
this.view.showApplyChangesButton();
|
104
99
|
}
|
105
100
|
|
106
101
|
await this.checkBrandHealth();
|
@@ -128,7 +123,12 @@ class BrandDetailController {
|
|
128
123
|
window.location.href = `../brands/brands.html?source=${this.model.source}`;
|
129
124
|
});
|
130
125
|
|
131
|
-
document.getElementById('
|
126
|
+
document.getElementById('syncBrandButton').addEventListener(
|
127
|
+
'click',
|
128
|
+
async () => {
|
129
|
+
await this.switchToBrand()
|
130
|
+
await this.view.toast("Synced successfully")
|
131
|
+
});
|
132
132
|
document.getElementById('switchButton').addEventListener('click', () => this.switchToBrand());
|
133
133
|
|
134
134
|
this.view.exportBrandBtn.addEventListener('click', () => this.exportBrand());
|
@@ -141,188 +141,37 @@ class BrandDetailController {
|
|
141
141
|
|
142
142
|
const sectionItems = configuraationsResult.configurations
|
143
143
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
this.createSection(
|
151
|
-
sectionData.key,
|
152
|
-
sectionData,
|
153
|
-
new InfoPlistStringCatalogManager(sectionData.content).extractLocalizations(),
|
154
|
-
sectionData.name,
|
155
|
-
sectionData.inputType)
|
156
|
-
} else {
|
157
|
-
this.createSection(sectionData.key, sectionData, sectionData.content, sectionData.name, sectionData.inputType)
|
158
|
-
}
|
159
|
-
}
|
144
|
+
this.view.sectionsFormManager.display(
|
145
|
+
sectionItems,
|
146
|
+
(section, container) => {
|
147
|
+
this.onSectionChanged(section, container)
|
148
|
+
})
|
149
|
+
|
160
150
|
} catch (error) {
|
161
151
|
console.error('Error loading configurations:', error);
|
162
152
|
alert(error.message);
|
163
153
|
}
|
164
154
|
}
|
165
155
|
|
166
|
-
|
167
|
-
this.
|
168
|
-
sectionData,
|
169
|
-
sectionData.content.colors,
|
170
|
-
'Theme Colors',
|
171
|
-
'color',
|
172
|
-
'colors')
|
173
|
-
this.createSection(`${sectionData.key}_typography`,
|
174
|
-
sectionData,
|
175
|
-
sectionData.content.typography,
|
176
|
-
'Theme Typography',
|
177
|
-
'text',
|
178
|
-
'typography')
|
179
|
-
this.createSection(`${sectionData.key}_spacing`,
|
180
|
-
sectionData,
|
181
|
-
sectionData.content.spacing,
|
182
|
-
'Theme Spacing', 'text',
|
183
|
-
'spacing')
|
184
|
-
this.createSection(
|
185
|
-
`${sectionData.key}_borderRadius`,
|
186
|
-
sectionData,
|
187
|
-
sectionData.content.borderRadius,
|
188
|
-
'Theme Border Radius',
|
189
|
-
'text',
|
190
|
-
'borderRadius')
|
191
|
-
this.createSection(
|
192
|
-
`${sectionData.key}_elevation`,
|
193
|
-
sectionData,
|
194
|
-
sectionData.content.elevation,
|
195
|
-
'Theme Elevation',
|
196
|
-
'text',
|
197
|
-
'elevation')
|
198
|
-
}
|
199
|
-
|
200
|
-
createSection(id, sectionData, content, sectionName, inputType, propertiesGroupName = null) {
|
201
|
-
const sectionElement = this.view.createSection(sectionData.key, sectionName, inputType);
|
202
|
-
sectionElement.id = id;
|
203
|
-
sectionElement.dataset.propertiesGroupName = propertiesGroupName
|
204
|
-
|
205
|
-
this.view.sectionsContainer.appendChild(sectionElement);
|
206
|
-
|
207
|
-
this.view.populateJsonFields(sectionData, sectionElement, content, inputType);
|
156
|
+
async onSectionChanged(section, container) {
|
157
|
+
if (this.model.isRemote()) return
|
208
158
|
|
209
|
-
const addButton = document.createElement('button');
|
210
|
-
addButton.textContent = 'Add Field';
|
211
|
-
addButton.className = 'add-field-btn';
|
212
|
-
addButton.onclick = () => this.addNewField(sectionData, sectionElement, inputType);
|
213
|
-
sectionElement.appendChild(addButton);
|
214
|
-
}
|
215
|
-
|
216
|
-
async onSectionChanged(sectionItem, sectionElement) {
|
217
159
|
try {
|
218
|
-
|
219
|
-
await this.model.saveSection(sectionItem, configuration);
|
220
|
-
this.view.showApplyChangesButton();
|
160
|
+
await this.model.saveSection(container.dataset.key, section.content);
|
221
161
|
await this.checkBrandHealth();
|
162
|
+
await this.switchToBrand(true)
|
222
163
|
} catch (error) {
|
223
164
|
console.error('Error saving section:', error);
|
224
165
|
alert(error.message);
|
225
166
|
}
|
226
167
|
}
|
227
168
|
|
228
|
-
|
229
|
-
const data = {};
|
230
|
-
const level = container.dataset.level
|
231
|
-
|
232
|
-
const jsonObjects = container.querySelectorAll(`.json-object-${level}`);
|
233
|
-
jsonObjects.forEach(jsonObject => {
|
234
|
-
const jsonObjectLabel = jsonObject.querySelector('label').textContent;
|
235
|
-
data[jsonObjectLabel] = this.collectJsonData(jsonObject);
|
236
|
-
|
237
|
-
});
|
238
|
-
|
239
|
-
const group = container.querySelectorAll(`.json-array-${level}`);
|
240
|
-
group.forEach(arrayItem => {
|
241
|
-
const label = arrayItem.querySelector('label').textContent;
|
242
|
-
const items = arrayItem.querySelectorAll(`.json-array-item-${level}`);
|
243
|
-
const indexed = arrayItem.querySelectorAll(`.json-array-item-indexed-${level}`).length !== 0;
|
244
|
-
|
245
|
-
data[label] = Array.from(items).map((item, index) => {
|
246
|
-
const values = this.collectJsonData(item)
|
247
|
-
if (indexed) {
|
248
|
-
return values[index]
|
249
|
-
}
|
250
|
-
return values;
|
251
|
-
});
|
252
|
-
});
|
253
|
-
|
254
|
-
const result = this.collectJsonFields(container, level);
|
255
|
-
|
256
|
-
Object.keys(data).forEach(key => {
|
257
|
-
result[key] = data[key];
|
258
|
-
});
|
259
|
-
return result
|
260
|
-
}
|
261
|
-
|
262
|
-
collectJsonFields(container, level) {
|
263
|
-
const result = {};
|
264
|
-
|
265
|
-
const inputFields = container.querySelectorAll(`.json-field-${level}`);
|
266
|
-
inputFields.forEach(inputField => {
|
267
|
-
const values = this.getInputFieldsData(inputField);
|
268
|
-
Object.keys(values).forEach(key => {
|
269
|
-
result[key] = values[key];
|
270
|
-
});
|
271
|
-
})
|
272
|
-
return result
|
273
|
-
}
|
274
|
-
|
275
|
-
getInputFieldsData(container) {
|
276
|
-
const data = {};
|
277
|
-
|
278
|
-
const inputs = container.querySelectorAll('input');
|
279
|
-
inputs.forEach(input => {
|
280
|
-
if (input.type === 'checkbox') {
|
281
|
-
data[input.id] = input.checked;
|
282
|
-
} else {
|
283
|
-
let value = input.value;
|
284
|
-
if (input.type === 'color') {
|
285
|
-
value = `#${value.substring(1).toUpperCase()}`;
|
286
|
-
} else if (!isNaN(value) && value.trim() !== '') {
|
287
|
-
// Convert to number if it's a valid number string
|
288
|
-
value = parseFloat(value);
|
289
|
-
}
|
290
|
-
data[input.id] = value;
|
291
|
-
}
|
292
|
-
});
|
293
|
-
|
294
|
-
return data;
|
295
|
-
}
|
296
|
-
|
297
|
-
addNewField(sectionItem, sectionElement, inputType) {
|
298
|
-
this.view.showAddFieldForm(sectionItem, sectionElement, inputType);
|
299
|
-
}
|
300
|
-
|
301
|
-
deleteField(sectionItem, fieldContainer) {
|
302
|
-
this.view.showConfirmationDialog(
|
303
|
-
'Are you sure you want to delete this item?',
|
304
|
-
() => {
|
305
|
-
const sectionElement = fieldContainer.closest('.section');
|
306
|
-
fieldContainer.remove();
|
307
|
-
this.onSectionChanged(sectionItem, sectionElement);
|
308
|
-
}
|
309
|
-
);
|
310
|
-
}
|
311
|
-
|
312
|
-
getArrayValue(container) {
|
313
|
-
const arrayItems = container.querySelectorAll('.array-item-input');
|
314
|
-
return Array.from(arrayItems).map(item => item.value);
|
315
|
-
}
|
316
|
-
|
317
|
-
async switchToBrand() {
|
169
|
+
async switchToBrand(silentError = false) {
|
318
170
|
try {
|
319
171
|
await this.model.switchToBrand();
|
320
|
-
const applyChangesButton = document.getElementById('applyChangesButton');
|
321
|
-
applyChangesButton.style.display = 'none';
|
322
|
-
location.reload();
|
323
172
|
} catch (error) {
|
324
173
|
console.error('Error switching to brand:', error);
|
325
|
-
alert(error.message);
|
174
|
+
if (!silentError) alert(error.message);
|
326
175
|
}
|
327
176
|
}
|
328
177
|
|
@@ -350,72 +199,13 @@ class BrandDetailController {
|
|
350
199
|
}
|
351
200
|
}
|
352
201
|
|
353
|
-
async getSectionData(sectionKey) {
|
354
|
-
try {
|
355
|
-
const container = this.view.sectionsContainer;
|
356
|
-
|
357
|
-
const sectionElements = Array.from(container.querySelectorAll('.section'))
|
358
|
-
.filter(element => element.dataset.key === sectionKey);
|
359
|
-
|
360
|
-
if (sectionElements.length === 1) {
|
361
|
-
return this.collectJsonData(sectionElements[0])
|
362
|
-
}
|
363
|
-
|
364
|
-
const configurations = sectionElements.map(sectionElement => {
|
365
|
-
const propertiesGroupName = sectionElement.dataset.propertiesGroupName;
|
366
|
-
const config = this.collectJsonData(sectionElement);
|
367
|
-
|
368
|
-
if (propertiesGroupName !== "null") {
|
369
|
-
return {[propertiesGroupName]: config};
|
370
|
-
} else {
|
371
|
-
return config;
|
372
|
-
}
|
373
|
-
});
|
374
|
-
|
375
|
-
return configurations.reduce((acc, config) => {
|
376
|
-
const key = Object.keys(config)[0]; // Get the key from the configuration item
|
377
|
-
acc[key] = config[key]; // Assign the value to the dynamic object
|
378
|
-
return acc;
|
379
|
-
}, {});
|
380
|
-
|
381
|
-
} catch (error) {
|
382
|
-
console.error('Error downloading brand:', error);
|
383
|
-
alert(error.message);
|
384
|
-
}
|
385
|
-
}
|
386
|
-
|
387
202
|
async exportBrand() {
|
388
203
|
try {
|
389
|
-
const
|
204
|
+
const result = this.view.sectionsFormManager.data();
|
390
205
|
|
391
206
|
const brandKey = this.view.sectionsContainer.dataset.brandKey;
|
392
207
|
const brandName = this.view.sectionsContainer.dataset.brandName;
|
393
208
|
|
394
|
-
const sectionElements = Array.from(sectionsContainer.querySelectorAll('.section'));
|
395
|
-
|
396
|
-
const uniqueSections = new Map();
|
397
|
-
|
398
|
-
// The theme section has been divided into multiple categories (e.g., colors, typography).
|
399
|
-
// In the getSectionData function, we merge these sections. To prevent duplication when
|
400
|
-
// processing the sections, we will ensure that each section key is processed only once.
|
401
|
-
await Promise.all(sectionElements.map(async sectionElement => {
|
402
|
-
const key = sectionElement.dataset.key;
|
403
|
-
// Check if the key already exists in the map
|
404
|
-
if (!uniqueSections.has(key)) {
|
405
|
-
const configurations = await this.getSectionData(key);
|
406
|
-
uniqueSections.set(
|
407
|
-
key, {
|
408
|
-
key: key,
|
409
|
-
name: sectionElement.dataset.name,
|
410
|
-
inputType: sectionElement.dataset.inputType,
|
411
|
-
content: configurations
|
412
|
-
});
|
413
|
-
}
|
414
|
-
}));
|
415
|
-
|
416
|
-
// Convert the map values to an array
|
417
|
-
const result = Array.from(uniqueSections.values());
|
418
|
-
|
419
209
|
this.model.exportBrand(brandKey, brandName, result);
|
420
210
|
|
421
211
|
} catch (error) {
|
@@ -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) {
|