solara 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (175) hide show
  1. checksums.yaml +7 -0
  2. data/bin/solara +18 -0
  3. data/solara/lib/.DS_Store +0 -0
  4. data/solara/lib/core/.DS_Store +0 -0
  5. data/solara/lib/core/aliases/alias_generator.rb +128 -0
  6. data/solara/lib/core/aliases/alias_generator_manager.rb +28 -0
  7. data/solara/lib/core/aliases/solara_terminal_setup.rb +103 -0
  8. data/solara/lib/core/brands/brand_onboarder.rb +46 -0
  9. data/solara/lib/core/brands/brand_switcher.rb +204 -0
  10. data/solara/lib/core/brands/brands_manager.rb +154 -0
  11. data/solara/lib/core/dashboard/.DS_Store +0 -0
  12. data/solara/lib/core/dashboard/brand/.DS_Store +0 -0
  13. data/solara/lib/core/dashboard/brand/BrandDetail.js +11 -0
  14. data/solara/lib/core/dashboard/brand/BrandDetailController.js +361 -0
  15. data/solara/lib/core/dashboard/brand/BrandDetailModel.js +155 -0
  16. data/solara/lib/core/dashboard/brand/BrandDetailView.js +245 -0
  17. data/solara/lib/core/dashboard/brand/brand.html +477 -0
  18. data/solara/lib/core/dashboard/brand/source/BrandLocalSource.js +123 -0
  19. data/solara/lib/core/dashboard/brand/source/BrandRemoteSource.js +260 -0
  20. data/solara/lib/core/dashboard/brands/Brands.js +10 -0
  21. data/solara/lib/core/dashboard/brands/BrandsController.js +155 -0
  22. data/solara/lib/core/dashboard/brands/BrandsModel.js +136 -0
  23. data/solara/lib/core/dashboard/brands/BrandsView.js +136 -0
  24. data/solara/lib/core/dashboard/brands/brands.html +345 -0
  25. data/solara/lib/core/dashboard/component/AddFieldSheet.js +212 -0
  26. data/solara/lib/core/dashboard/component/AliasesBottomSheet.js +128 -0
  27. data/solara/lib/core/dashboard/component/BrandOptionsBottomSheet.js +130 -0
  28. data/solara/lib/core/dashboard/component/ConfirmationDialog.js +103 -0
  29. data/solara/lib/core/dashboard/component/MessageBottomSheet.js +80 -0
  30. data/solara/lib/core/dashboard/component/OnboardBrandBottomSheet.js +214 -0
  31. data/solara/lib/core/dashboard/dashboard_manager.rb +19 -0
  32. data/solara/lib/core/dashboard/dashboard_server.rb +132 -0
  33. data/solara/lib/core/dashboard/handler/base_handler.rb +25 -0
  34. data/solara/lib/core/dashboard/handler/brand_alisases_handler.rb +33 -0
  35. data/solara/lib/core/dashboard/handler/brand_configurations_handler.rb +18 -0
  36. data/solara/lib/core/dashboard/handler/brand_configurations_manager.rb +73 -0
  37. data/solara/lib/core/dashboard/handler/brand_icon_handler.rb +20 -0
  38. data/solara/lib/core/dashboard/handler/brand_section_handler.rb +20 -0
  39. data/solara/lib/core/dashboard/handler/brands_handler.rb +14 -0
  40. data/solara/lib/core/dashboard/handler/current_brand_handler.rb +18 -0
  41. data/solara/lib/core/dashboard/handler/doctor_handler.rb +39 -0
  42. data/solara/lib/core/dashboard/handler/edit_section_handler.rb +55 -0
  43. data/solara/lib/core/dashboard/handler/offboard_brand_handler.rb +34 -0
  44. data/solara/lib/core/dashboard/handler/onboard_brand_handler.rb +53 -0
  45. data/solara/lib/core/dashboard/handler/redirect_handler.rb +12 -0
  46. data/solara/lib/core/dashboard/handler/switch_handler.rb +25 -0
  47. data/solara/lib/core/dashboard/index.html +36 -0
  48. data/solara/lib/core/dashboard/local.html +41 -0
  49. data/solara/lib/core/dashboard/res/favicon/android-chrome-192x192.png +0 -0
  50. data/solara/lib/core/dashboard/res/favicon/android-chrome-512x512.png +0 -0
  51. data/solara/lib/core/dashboard/res/favicon/apple-touch-icon.png +0 -0
  52. data/solara/lib/core/dashboard/res/favicon/favicon-16x16.png +0 -0
  53. data/solara/lib/core/dashboard/res/favicon/favicon-32x32.png +0 -0
  54. data/solara/lib/core/dashboard/res/favicon/favicon.ico +0 -0
  55. data/solara/lib/core/dashboard/res/favicon/site.webmanifest +1 -0
  56. data/solara/lib/core/dashboard/solara.png +0 -0
  57. data/solara/lib/core/doctor/brand_doctor.rb +94 -0
  58. data/solara/lib/core/doctor/doctor_manager.rb +35 -0
  59. data/solara/lib/core/doctor/project_doctor.rb +8 -0
  60. data/solara/lib/core/doctor/schema/brand_configurations.json +60 -0
  61. data/solara/lib/core/doctor/schema/platform/android/android_config.json +23 -0
  62. data/solara/lib/core/doctor/schema/platform/android/android_signing.json +23 -0
  63. data/solara/lib/core/doctor/schema/platform/ios/ios_config.json +27 -0
  64. data/solara/lib/core/doctor/schema/platform/ios/ios_signing.json +27 -0
  65. data/solara/lib/core/doctor/schema/platform/shared/theme.json +48 -0
  66. data/solara/lib/core/doctor/validator/brand_settings_validator.rb +55 -0
  67. data/solara/lib/core/doctor/validator/brand_settings_validator_manager.rb +82 -0
  68. data/solara/lib/core/doctor/validator/directory_structure_validator.rb +38 -0
  69. data/solara/lib/core/doctor/validator/file_structure_validator.rb +37 -0
  70. data/solara/lib/core/doctor/validator/json_file_validator.rb +21 -0
  71. data/solara/lib/core/doctor/validator/json_schema_validator.rb +32 -0
  72. data/solara/lib/core/doctor/validator/project_filesystem_validator.rb +70 -0
  73. data/solara/lib/core/doctor/validator/template/android_template_validation_config.yml +51 -0
  74. data/solara/lib/core/doctor/validator/template/flutter_template_validation_config.yml +53 -0
  75. data/solara/lib/core/doctor/validator/template/ios_template_validation_config.yml +51 -0
  76. data/solara/lib/core/doctor/validator/template/template_validator.rb +108 -0
  77. data/solara/lib/core/doctor/validator/validation_strategy.rb +7 -0
  78. data/solara/lib/core/scripts/brand_config_generator.rb +245 -0
  79. data/solara/lib/core/scripts/brand_config_manager.rb +90 -0
  80. data/solara/lib/core/scripts/brand_exporter.rb +38 -0
  81. data/solara/lib/core/scripts/brand_importer.rb +84 -0
  82. data/solara/lib/core/scripts/brand_offboarder.rb +19 -0
  83. data/solara/lib/core/scripts/brand_resources_manager.rb +77 -0
  84. data/solara/lib/core/scripts/directory_creator.rb +22 -0
  85. data/solara/lib/core/scripts/file_manager.rb +90 -0
  86. data/solara/lib/core/scripts/file_path.rb +327 -0
  87. data/solara/lib/core/scripts/folder_copier.rb +41 -0
  88. data/solara/lib/core/scripts/gitignore_manager.rb +54 -0
  89. data/solara/lib/core/scripts/interactive_file_system_validator.rb +110 -0
  90. data/solara/lib/core/scripts/platform/android/android_manifest_switcher.rb +24 -0
  91. data/solara/lib/core/scripts/platform/android/android_strings_switcher.rb +39 -0
  92. data/solara/lib/core/scripts/platform/android/gradle_switcher.rb +233 -0
  93. data/solara/lib/core/scripts/platform/android/properties_generator.rb +31 -0
  94. data/solara/lib/core/scripts/platform/ios/ios_file_path_manager.rb +109 -0
  95. data/solara/lib/core/scripts/platform/ios/ios_plist_manager.rb +42 -0
  96. data/solara/lib/core/scripts/platform/ios/xcconfig_generator.rb +44 -0
  97. data/solara/lib/core/scripts/platform/ios/xcode_asset_manager.rb +56 -0
  98. data/solara/lib/core/scripts/platform/ios/xcode_project_manager.rb +82 -0
  99. data/solara/lib/core/scripts/platform/ios/xcode_project_switcher.rb +130 -0
  100. data/solara/lib/core/scripts/project_settings_manager.rb +39 -0
  101. data/solara/lib/core/scripts/solara_logger.rb +103 -0
  102. data/solara/lib/core/scripts/solara_settings_manager.rb +73 -0
  103. data/solara/lib/core/scripts/solara_status_manager.rb +55 -0
  104. data/solara/lib/core/scripts/solara_version_manager.rb +42 -0
  105. data/solara/lib/core/scripts/strings_xml_manager.rb +22 -0
  106. data/solara/lib/core/scripts/terminal_input_manager.rb +22 -0
  107. data/solara/lib/core/scripts/theme_generator.rb +250 -0
  108. data/solara/lib/core/scripts/yaml_manager.rb +72 -0
  109. data/solara/lib/core/solara_configurator.rb +15 -0
  110. data/solara/lib/core/template/brands/android/android_config.json +8 -0
  111. data/solara/lib/core/template/brands/android/android_signing.json +6 -0
  112. data/solara/lib/core/template/brands/android/res/.DS_Store +0 -0
  113. data/solara/lib/core/template/brands/android/res/mipmap-hdpi/ic_launcher.png +0 -0
  114. data/solara/lib/core/template/brands/android/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  115. data/solara/lib/core/template/brands/android/res/mipmap-mdpi/ic_launcher.png +0 -0
  116. data/solara/lib/core/template/brands/android/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  117. data/solara/lib/core/template/brands/android/res/mipmap-xhdpi/ic_launcher.png +0 -0
  118. data/solara/lib/core/template/brands/android/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  119. data/solara/lib/core/template/brands/android/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  120. data/solara/lib/core/template/brands/android/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  121. data/solara/lib/core/template/brands/android/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  122. data/solara/lib/core/template/brands/android/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  123. data/solara/lib/core/template/brands/brands.json +4 -0
  124. data/solara/lib/core/template/brands/ios/assets/.DS_Store +0 -0
  125. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/100.png +0 -0
  126. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/102.png +0 -0
  127. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/1024.png +0 -0
  128. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/114.png +0 -0
  129. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/120.png +0 -0
  130. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/128.png +0 -0
  131. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/144.png +0 -0
  132. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/152.png +0 -0
  133. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/16.png +0 -0
  134. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/167.png +0 -0
  135. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/172.png +0 -0
  136. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/180.png +0 -0
  137. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/196.png +0 -0
  138. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/20.png +0 -0
  139. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/216.png +0 -0
  140. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/256.png +0 -0
  141. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/29.png +0 -0
  142. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/32.png +0 -0
  143. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/40.png +0 -0
  144. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/48.png +0 -0
  145. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/50.png +0 -0
  146. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/512.png +0 -0
  147. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/55.png +0 -0
  148. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/57.png +0 -0
  149. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/58.png +0 -0
  150. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/60.png +0 -0
  151. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/64.png +0 -0
  152. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/66.png +0 -0
  153. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/72.png +0 -0
  154. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/76.png +0 -0
  155. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/80.png +0 -0
  156. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/87.png +0 -0
  157. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/88.png +0 -0
  158. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/92.png +0 -0
  159. data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/Contents.json +1 -0
  160. data/solara/lib/core/template/brands/ios/ios_config.json +7 -0
  161. data/solara/lib/core/template/brands/ios/ios_signing.json +7 -0
  162. data/solara/lib/core/template/brands/shared/.DS_Store +0 -0
  163. data/solara/lib/core/template/brands/shared/brand_config.json +2 -0
  164. data/solara/lib/core/template/brands/shared/theme.json +46 -0
  165. data/solara/lib/core/template/config/android_template_config.json +57 -0
  166. data/solara/lib/core/template/config/flutter_template_config.json +62 -0
  167. data/solara/lib/core/template/config/ios_template_config.json +57 -0
  168. data/solara/lib/core/template/project_template_generator.rb +63 -0
  169. data/solara/lib/platform_detector.rb +84 -0
  170. data/solara/lib/solara/cli.rb +5 -0
  171. data/solara/lib/solara/version.rb +3 -0
  172. data/solara/lib/solara.rb +238 -0
  173. data/solara/lib/solara_initializer.rb +44 -0
  174. data/solara/lib/solara_manager.rb +73 -0
  175. metadata +346 -0
@@ -0,0 +1,477 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Solara Dashboard</title>
7
+ <link rel="icon" href="../res/favicon/favicon.ico" type="image/x-icon">
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css">
9
+ <style>
10
+ :root {
11
+ --primary-color: #4A90E2;
12
+ --secondary-color: #50E3C2;
13
+ --background-color: #F5F7FA;
14
+ --text-color: #333;
15
+ --border-color: #E1E4E8;
16
+ --delete-color: #dc3545;
17
+ --field-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
18
+ }
19
+ body {
20
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
21
+ background-color: var(--background-color);
22
+ color: var(--text-color);
23
+ line-height: 1.6;
24
+ margin: 0;
25
+ padding-top: 110px;
26
+ }
27
+ .container {
28
+ max-width: 1000px;
29
+ margin: 0 auto;
30
+ padding: 20px;
31
+ }
32
+
33
+ h1 {
34
+ margin: 0;
35
+ font-size: 2.5em;
36
+ }
37
+ .section {
38
+ background-color: white;
39
+ border-radius: 8px;
40
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
41
+ margin-bottom: 30px;
42
+ padding: 20px;
43
+ }
44
+ h2 {
45
+ color: var(--primary-color);
46
+ border-bottom: 2px solid var(--border-color);
47
+ padding-bottom: 10px;
48
+ margin-top: 0;
49
+ }
50
+ .input-group {
51
+ margin-bottom: 25px;
52
+ display: flex;
53
+ align-items: center;
54
+ background-color: white;
55
+ border-radius: 8px;
56
+ box-shadow: var(--field-shadow);
57
+ padding: 10px;
58
+ transition: box-shadow 0.3s ease;
59
+ }
60
+ .input-group:hover {
61
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
62
+ }
63
+ label {
64
+ display: inline-block;
65
+ margin-right: 10px;
66
+ font-weight: bold;
67
+ min-width: 250px;
68
+ flex-shrink: 0;
69
+ }
70
+ .input-wrapper {
71
+ display: flex;
72
+ align-items: center;
73
+ flex-grow: 1;
74
+ }
75
+ input, select {
76
+ flex-grow: 1;
77
+ padding: 10px;
78
+ border: 1px solid var(--border-color);
79
+ border-radius: 4px;
80
+ font-size: 16px;
81
+ }
82
+ input[type="color"] {
83
+ height: 50px;
84
+ padding: 2px;
85
+ }
86
+ button {
87
+ background-color: var(--secondary-color);
88
+ color: white;
89
+ padding: 12px 20px;
90
+ border: none;
91
+ border-radius: 4px;
92
+ cursor: pointer;
93
+ font-size: 18px;
94
+ transition: background-color 0.3s ease;
95
+ }
96
+ button:hover {
97
+ background-color: #3CC2A3;
98
+ }
99
+
100
+ .save-section-btn {
101
+ background-color: #28a745;
102
+ margin-top: 10px;
103
+ margin-right: 10px;
104
+ }
105
+ .save-section-btn:hover {
106
+ background-color: #218838;
107
+ }
108
+ .button-group {
109
+ display: flex;
110
+ justify-content: flex-start;
111
+ margin-top: 20px;
112
+ }
113
+ .delete-icon {
114
+ color: var(--delete-color);
115
+ cursor: pointer;
116
+ font-weight: bold;
117
+ font-size: 20px;
118
+ line-height: 1;
119
+ padding: 10px 15px;
120
+ margin-left: 10px;
121
+ border-radius: 4px;
122
+ transition: background-color 0.3s ease;
123
+ }
124
+ .delete-icon:hover {
125
+ color: #fff;
126
+ background-color: var(--delete-color);
127
+ }
128
+ .section-title-container {
129
+ margin-bottom: 1em;
130
+ }
131
+ .section-title-container h2 {
132
+ margin-bottom: 0.2em;
133
+ }
134
+ .section-subtitle {
135
+ font-size: 0.9em;
136
+ color: #666;
137
+ margin-bottom: 32px;
138
+ }
139
+
140
+ @media (max-width: 768px) {
141
+ .container {
142
+ padding: 10px;
143
+ }
144
+ .input-group {
145
+ flex-direction: column;
146
+ align-items: flex-start;
147
+ }
148
+ label {
149
+ margin-bottom: 5px;
150
+ }
151
+ .input-wrapper {
152
+ width: 100%;
153
+ }
154
+ }
155
+
156
+
157
+ .array-input-container {
158
+ display: flex;
159
+ align-items: center;
160
+ margin-bottom: 5px;
161
+ width: 100%;
162
+ }
163
+
164
+ .array-input {
165
+ flex-grow: 1;
166
+ margin-right: 8px;
167
+ }
168
+
169
+ .add-array-item {
170
+ background-color: #4CAF50;
171
+ color: white;
172
+ border: none;
173
+ padding: 5px 10px;
174
+ border-radius: 4px;
175
+ cursor: pointer;
176
+ }
177
+
178
+ .array-items-container {
179
+ margin-top: 5px;
180
+ width: 100%;
181
+ }
182
+
183
+ .array-item {
184
+ display: flex;
185
+ align-items: center;
186
+ margin-bottom: 5px;
187
+ }
188
+
189
+ .array-item-input {
190
+ flex-grow: 1;
191
+ margin: 16px;
192
+ }
193
+
194
+ .delete-array-item {
195
+ background-color: #f44336;
196
+ color: white;
197
+ border: none;
198
+ padding: 2px 6px;
199
+ border-radius: 4px;
200
+ cursor: pointer;
201
+ }
202
+ .logo {
203
+ width: 75px;
204
+ height: 75px;
205
+ margin-right: 20px;
206
+ filter: drop-shadow(3px 3px 3px rgba(0, 0, 0, 0.3));
207
+ transition: transform 0.3s ease;
208
+ }
209
+ .logo:hover {
210
+ transform: scale(1.1);
211
+ }
212
+
213
+ .header-container {
214
+ display: flex;
215
+ align-items: center;
216
+ justify-content: center;
217
+ }
218
+
219
+ header {
220
+ background-color: var(--primary-color);
221
+ color: white;
222
+ text-align: center;
223
+ padding: 10px 0;
224
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
225
+ display: flex;
226
+ justify-content: center;
227
+ align-items: center;
228
+ position: fixed;
229
+ top: 0;
230
+ left: 0;
231
+ right: 0;
232
+ z-index: 1000;
233
+ transition: transform 0.3s ease;
234
+ }
235
+ .scroll-up header {
236
+ transform: translateY(0);
237
+ }
238
+ .scroll-down header {
239
+ transform: translateY(-100%);
240
+ }
241
+ .logo {
242
+ width: 50px;
243
+ height: 50px;
244
+ margin-right: 20px;
245
+ filter: drop-shadow(3px 3px 3px rgba(0, 0, 0, 0.3));
246
+ transition: transform 0.3s ease;
247
+ }
248
+ .logo:hover {
249
+ transform: scale(1.1);
250
+ }
251
+ h1 {
252
+ margin: 0;
253
+ font-size: 2.5em;
254
+ }
255
+
256
+ .action-buttons {
257
+ position: fixed;
258
+ top: 100px;
259
+ left: 20px;
260
+ display: flex;
261
+ flex-direction: column;
262
+ gap: 20px;
263
+ z-index: 1000;
264
+ }
265
+
266
+ .action-buttons button {
267
+ min-width: 250px;
268
+ background-color: var(--primary-color);
269
+ color: white;
270
+ padding: 12px 10px;
271
+ border: none;
272
+ border-radius: 4px;
273
+ cursor: pointer;
274
+ font-size: 18px;
275
+ transition: background-color 0.3s ease, opacity 0.3s ease;
276
+ }
277
+
278
+ .action-buttons button:hover {
279
+ background-color: #3A7BC8;
280
+ }
281
+
282
+ #switchButton {
283
+ display: none;
284
+ }
285
+
286
+ #applyChangesButton {
287
+ display: none;
288
+ }
289
+
290
+
291
+ #error-button {
292
+ position: fixed;
293
+ bottom: 20px;
294
+ right: 20px;
295
+ background-color: #ff4136;
296
+ color: white;
297
+ border: none;
298
+ border-radius: 50%;
299
+ width: 60px;
300
+ height: 60px;
301
+ font-size: 24px;
302
+ cursor: pointer;
303
+ justify-content: center;
304
+ align-items: center;
305
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
306
+ transition: transform 0.2s;
307
+ display: none;
308
+ }
309
+
310
+ #error-button:hover {
311
+ transform: scale(1.1);
312
+ }
313
+
314
+ .count {
315
+ position: absolute;
316
+ top: -5px;
317
+ right: -5px;
318
+ background-color: #ffdc00;
319
+ color: #111;
320
+ border-radius: 50%;
321
+ width: 24px;
322
+ height: 24px;
323
+ font-size: 14px;
324
+ font-weight: bold;
325
+ display: flex;
326
+ justify-content: center;
327
+ align-items: center;
328
+ }
329
+
330
+ .add-brand-container {
331
+ position: fixed;
332
+ top: 50%;
333
+ left: 50%;
334
+ transform: translate(-50%, -50%);
335
+ text-align: center;
336
+ background-color: white;
337
+ padding: 40px;
338
+ border-radius: 20px;
339
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
340
+ z-index: 999;
341
+ animation: fadeIn 0.5s ease-out;
342
+ }
343
+
344
+ @keyframes fadeIn {
345
+ from {
346
+ opacity: 0;
347
+ transform: translate(-50%, -60%);
348
+ }
349
+ to {
350
+ opacity: 1;
351
+ transform: translate(-50%, -50%);
352
+ }
353
+ }
354
+
355
+ .add-brand-container img {
356
+ width: 150px;
357
+ height: 150px;
358
+ margin-bottom: 20px;
359
+ }
360
+
361
+ .add-brand-container h2 {
362
+ font-size: 18px;
363
+ color: #333;
364
+ margin-bottom: 30px;
365
+ animation: slideDown 0.5s ease-out 0.3s both;
366
+ }
367
+
368
+ .add-brand-container button {
369
+ display: block;
370
+ width: 200px;
371
+ margin: 20px auto;
372
+ padding: 15px;
373
+ font-size: 18px;
374
+ background-color: var(--primary-color);
375
+ color: white;
376
+ border: none;
377
+ border-radius: 8px;
378
+ cursor: pointer;
379
+ transition: background-color 0.3s ease, transform 0.2s ease;
380
+ opacity: 0;
381
+ animation: fadeInButton 0.5s ease-out forwards;
382
+ }
383
+
384
+ .add-brand-container button:hover {
385
+ background-color: #3A7BC8;
386
+ transform: scale(1.05);
387
+ }
388
+
389
+ .button-message {
390
+ font-size: 18px;
391
+ color: #666;
392
+ margin-bottom: 5px;
393
+ opacity: 0;
394
+ animation: fadeInMessage 0.5s ease-out forwards;
395
+ }
396
+
397
+ @keyframes slideDown {
398
+ from {
399
+ opacity: 0;
400
+ transform: translateY(-20px);
401
+ }
402
+ to {
403
+ opacity: 1;
404
+ transform: translateY(0);
405
+ }
406
+ }
407
+
408
+ @keyframes fadeInButton {
409
+ to {
410
+ opacity: 1;
411
+ }
412
+ }
413
+
414
+ @keyframes fadeInMessage {
415
+ to {
416
+ opacity: 1;
417
+ }
418
+ }
419
+
420
+
421
+ /* Hide the brand-details-container by default */
422
+ #brand-details-container {
423
+ display: none;
424
+ }
425
+ </style>
426
+ </head>
427
+ <body>
428
+
429
+ <header>
430
+ <div class="header-container">
431
+ <img class="logo" src="../solara.png" alt="Splash Image">
432
+ <h1><span id="brandNametitle"></span></h1>
433
+ </div>
434
+
435
+ </header>
436
+
437
+ <div id="add-brand-container" class="add-brand-container">
438
+ <img src="../solara.png" alt="Solara Logo">
439
+ <h2>Solara simplifies the management of your brand configurations, allowing you to access and update them anytime, anywhere.</h2>
440
+ <div class="button-message">You can select a JSON file containing brand configurations that were exported using Solara.</div>
441
+ <button id="uploadJsonBtn" style=" animation-delay: 0.5s;">Upload JSON</button>
442
+ <div class="button-message" style=" animation-delay: 0.7s;">Alternatively, upload from a folder that includes the brand's JSON files.</div>
443
+ <button id="uploadBrandBtn" style=" animation-delay: 0.9s;">Upload Folder</button>
444
+ <div class="button-message" style=" animation-delay: 1.1s;">You also have the option to create new brand configurations.</div>
445
+ <button id="newBrandBtn" style=" animation-delay: 1.3s;">New Brand</button>
446
+ </div>
447
+
448
+ <onboard-bottom-sheet id="onboardBottomSheet"></onboard-bottom-sheet>
449
+
450
+ <div id="brand-details-container">
451
+ <button id="error-button">
452
+ ⚠️
453
+ <span class="count">5</span>
454
+ </button>
455
+
456
+ <div class="action-buttons">
457
+ <button id="allBrandsButton">All Brands</button>
458
+ <button id="switchButton">Switch</button>
459
+ <button id="applyChangesButton">Apply Changes</button>
460
+ <button id="exportBrandBtn">Export</button>
461
+ </div>
462
+
463
+ <div class="container">
464
+ <div id="sections"></div>
465
+ </div>
466
+
467
+ <add-field-sheet id="addFieldSheet"></add-field-sheet>
468
+
469
+ <message-bottom-sheet id="messageBottomSheet"></message-bottom-sheet>
470
+
471
+ <confirmation-dialog id="confirmationDialog"></confirmation-dialog>
472
+ </div>
473
+
474
+ <script type="module" src="BrandDetail.js"></script>
475
+
476
+ </body>
477
+ </html>
@@ -0,0 +1,123 @@
1
+ class BrandLocalSource {
2
+ constructor() {
3
+ this.savingInProgress = false;
4
+ }
5
+
6
+ getQueryFromUrl(name) {
7
+ const urlParams = new URLSearchParams(window.location.search);
8
+ return urlParams.get(name);
9
+ }
10
+
11
+ async fetchBrandDetails(brandKey) {
12
+ try {
13
+ if (!brandKey) {
14
+ throw new Error('No brand_key provided in URL');
15
+ }
16
+
17
+ const url = `/configurations?brand_key=${encodeURIComponent(brandKey)}`;
18
+ console.log('Fetching configurations from:', url);
19
+
20
+ const response = await fetch(url);
21
+ const result = await response.json();
22
+ if (!response.ok) {
23
+ throw new Error(result.error);
24
+ }
25
+ return result;
26
+ } catch (error) {
27
+ console.error('Error fetching configurations:', error);
28
+ throw error;
29
+ }
30
+ }
31
+
32
+ async fetchCurrentBrand(brandKey) {
33
+ try {
34
+ const response = await fetch('/brand/current');
35
+ let result = await response.json();
36
+ if (!response.ok) {
37
+ throw new Error(result.error);
38
+ }
39
+ let isCurrentBrand = result.key === brandKey;
40
+ return {isCurrentBrand: isCurrentBrand, contentChanged: result.content_changed};
41
+ } catch (error) {
42
+ console.error('Error fetching current brand:', error);
43
+ throw error;
44
+ }
45
+ }
46
+
47
+ async saveSection(sectionItem, configuration, brandKey) {
48
+ if (this.savingInProgress) return;
49
+ this.savingInProgress = true;
50
+
51
+ const dataToSend = {
52
+ brand_key: brandKey,
53
+ key: sectionItem.key,
54
+ data: configuration
55
+ };
56
+
57
+ try {
58
+ const response = await fetch(`/section/edit`, {
59
+ method: 'POST',
60
+ headers: {
61
+ 'Content-Type': 'application/json'
62
+ },
63
+ body: JSON.stringify(dataToSend)
64
+ });
65
+
66
+ const result = await response.json();
67
+
68
+ if (!response.ok) {
69
+ throw new Error(result.error);
70
+ }
71
+
72
+ console.log(`${sectionItem.name} configuration saved successfully!`);
73
+ return true;
74
+ } catch (error) {
75
+ console.error('Error saving configuration:', error);
76
+ throw error;
77
+ } finally {
78
+ this.savingInProgress = false;
79
+ }
80
+ }
81
+
82
+ async switchToBrand(brandKey) {
83
+ try {
84
+ const response = await fetch('/switch', {
85
+ method: 'POST',
86
+ headers: {
87
+ 'Content-Type': 'application/json',
88
+ },
89
+ body: JSON.stringify({brand_key: brandKey}),
90
+ });
91
+
92
+ const result = await response.json();
93
+
94
+ if (!response.ok) {
95
+ throw new Error(result.error);
96
+ }
97
+
98
+ console.log('Switch to brand result:', result);
99
+ return true;
100
+ } catch (error) {
101
+ console.error('Error switching to brand:', error);
102
+ throw error;
103
+ }
104
+ }
105
+
106
+ async checkBrandHealth(brandKey) {
107
+ try {
108
+ const response = await fetch(`/brand/doctor?brand_key=${encodeURIComponent(brandKey)}`);
109
+ const result = await response.json();
110
+
111
+ if (!response.ok) {
112
+ throw new Error(result.error);
113
+ }
114
+
115
+ return result.result;
116
+ } catch (error) {
117
+ console.error('Error calling doctor API:', error);
118
+ throw error;
119
+ }
120
+ }
121
+ }
122
+
123
+ export default BrandLocalSource;