solara 0.4.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/solara/lib/.DS_Store +0 -0
  3. data/solara/lib/core/.DS_Store +0 -0
  4. data/solara/lib/core/brands/brand_switcher.rb +58 -1
  5. data/solara/lib/core/dashboard/brand/BrandDetail.js +34 -2
  6. data/solara/lib/core/dashboard/brand/BrandDetailController.js +23 -233
  7. data/solara/lib/core/dashboard/brand/BrandDetailModel.js +13 -5
  8. data/solara/lib/core/dashboard/brand/BrandDetailView.js +16 -200
  9. data/solara/lib/core/dashboard/brand/SectionsFormManager.js +232 -0
  10. data/solara/lib/core/dashboard/brand/brand.html +187 -177
  11. data/solara/lib/core/dashboard/brand/source/BrandLocalSource.js +2 -5
  12. data/solara/lib/core/dashboard/brand/source/BrandRemoteSource.js +36 -133
  13. data/solara/lib/core/dashboard/brands/Brands.js +31 -0
  14. data/solara/lib/core/dashboard/brands/BrandsController.js +0 -5
  15. data/solara/lib/core/dashboard/brands/BrandsView.js +2 -2
  16. data/solara/lib/core/dashboard/brands/brands.html +71 -52
  17. data/solara/lib/core/dashboard/component/AliasesBottomSheet.js +6 -6
  18. data/solara/lib/core/dashboard/component/BrandOptionsBottomSheet.js +4 -4
  19. data/solara/lib/core/dashboard/component/ConfirmationDialog.js +15 -10
  20. data/solara/lib/core/dashboard/component/EditJsonSheet.js +160 -0
  21. data/solara/lib/core/dashboard/component/MessageBottomSheet.js +5 -5
  22. data/solara/lib/core/dashboard/component/OnboardBrandBottomSheet.js +5 -3
  23. data/solara/lib/core/dashboard/handler/base_handler.rb +1 -0
  24. data/solara/lib/core/dashboard/handler/edit_section_handler.rb +1 -5
  25. data/solara/lib/core/doctor/schema/brand_configurations.json +0 -8
  26. data/solara/lib/core/doctor/schema/platform/global/resources_manifest.json +30 -0
  27. data/solara/lib/core/doctor/schema/platform/json_manifest.json +57 -0
  28. data/solara/lib/core/doctor/validator/template/android_template_validation_config.yml +35 -1
  29. data/solara/lib/core/doctor/validator/template/flutter_template_validation_config.yml +30 -1
  30. data/solara/lib/core/doctor/validator/template/ios_template_validation_config.yml +35 -1
  31. data/solara/lib/core/doctor/validator/template/template_validator.rb +9 -9
  32. data/solara/lib/core/scripts/brand_config_manager.rb +1 -1
  33. data/solara/lib/core/scripts/brand_configurations_manager.rb +41 -0
  34. data/solara/lib/core/scripts/code_generator.rb +342 -118
  35. data/solara/lib/core/scripts/file_path.rb +21 -1
  36. data/solara/lib/core/scripts/gitignore_manager.rb +11 -3
  37. data/solara/lib/core/scripts/json_manifest_processor.rb +95 -0
  38. data/solara/lib/core/scripts/platform/ios/infoplist_string_catalog_manager.rb +11 -1
  39. data/solara/lib/core/scripts/resource_manifest_processor.rb +151 -0
  40. data/solara/lib/core/scripts/solara_status_manager.rb +1 -1
  41. data/solara/lib/core/scripts/theme_generator.rb +21 -242
  42. data/solara/lib/core/solara_configurator.rb +1 -1
  43. data/solara/lib/core/template/brands/global/resources_manifest.json +10 -0
  44. data/solara/lib/core/template/brands/json/Json-Manifest.md +61 -0
  45. data/solara/lib/core/template/brands/json/json_manifest.json +18 -0
  46. data/solara/lib/core/template/brands/shared/theme.json +213 -29
  47. data/solara/lib/core/template/config/android_template_config.json +50 -0
  48. data/solara/lib/core/template/config/flutter_template_config.json +35 -0
  49. data/solara/lib/core/template/config/ios_template_config.json +50 -0
  50. data/solara/lib/core/template/configurations.json +46 -0
  51. data/solara/lib/core/template/project_template_generator.rb +2 -0
  52. data/solara/lib/solara/version.rb +1 -1
  53. data/solara/lib/solara.rb +19 -0
  54. metadata +13 -4
  55. data/solara/lib/core/dashboard/component/AddFieldSheet.js +0 -175
  56. data/solara/lib/core/dashboard/handler/brand_configurations_manager.rb +0 -73
@@ -99,6 +99,14 @@ module FilePath
99
99
  File.join(brands, brand_key)
100
100
  end
101
101
 
102
+ def self.brand_json_dir(brand_key, platform = nil)
103
+ File.join(brand(brand_key), platform || SolaraSettingsManager.instance.platform, 'json')
104
+ end
105
+
106
+ def self.brand_global_json_dir
107
+ File.join(global, 'json')
108
+ end
109
+
102
110
  def self.android_config(brand_key)
103
111
  File.join(android_brand_root(brand_key), 'android_config.json')
104
112
  end
@@ -116,7 +124,15 @@ module FilePath
116
124
  end
117
125
 
118
126
  def self.brand_fonts
119
- File.join(solara_brand, 'global', 'fonts')
127
+ File.join(global, 'fonts')
128
+ end
129
+
130
+ def self.resources_manifest
131
+ File.join(global, 'resources_manifest.json')
132
+ end
133
+
134
+ def self.global
135
+ File.join(solara_brand, 'global')
120
136
  end
121
137
 
122
138
  def self.brand_config(brand_key)
@@ -287,6 +303,10 @@ module FilePath
287
303
  File.join(root, 'core', 'template')
288
304
  end
289
305
 
306
+ def self.brand_configurations
307
+ File.join(solara_template, 'configurations.json')
308
+ end
309
+
290
310
  def self.solara_aliases_json
291
311
  File.join(dot_solara, 'aliases', 'aliases.json')
292
312
  end
@@ -4,7 +4,7 @@ class GitignoreManager
4
4
  create_gitignore_if_not_exists
5
5
  end
6
6
 
7
- def self.ignore
7
+ def self.ignore_common_files
8
8
  Solara.logger.start_step("Exclude Brand-Generated Files and Folders from Git")
9
9
 
10
10
  items = [
@@ -29,7 +29,7 @@ class GitignoreManager
29
29
 
30
30
  def add_items(items)
31
31
  items.each do |item|
32
- add_item(item)
32
+ add_item(FileManager.get_relative_path_to_root(item))
33
33
  end
34
34
  end
35
35
 
@@ -39,7 +39,15 @@ class GitignoreManager
39
39
  if existing_items.include?(item)
40
40
  Solara.logger.debug("'#{item}' already exists in .gitignore")
41
41
  else
42
- File.open(@gitignore_path, 'a') do |file|
42
+ File.open(@gitignore_path, 'a+') do |file|
43
+ # Move the file pointer to the beginning to check the last character
44
+ file.seek(0, IO::SEEK_END)
45
+ if file.size > 0
46
+ # Only add a new line if the last character is not a newline
47
+ file.seek(-1, IO::SEEK_END)
48
+ last_char = file.getc
49
+ file.puts if last_char != "\n"
50
+ end
43
51
  file.puts(item)
44
52
  end
45
53
  Solara.logger.debug("Added '#{item}' to .gitignore")
@@ -0,0 +1,95 @@
1
+ require 'json'
2
+
3
+ class JsonManifestProcessor
4
+
5
+ def initialize(json_path, language, output_path)
6
+ @json_path = json_path
7
+ @language = language
8
+ @output_path = output_path
9
+ end
10
+
11
+ def process
12
+ manifest = read_json
13
+ process_files(manifest)
14
+ end
15
+
16
+ private
17
+
18
+ def process_files(manifest)
19
+ manifest['files'].each do |file|
20
+ generate_code(file)
21
+ end
22
+ end
23
+
24
+ def generate_code(file)
25
+ return unless file['generate']['enabled']
26
+
27
+ file_name = file['fileName']
28
+ class_name = file['generate']['className']
29
+
30
+ puts "generate_code: file_name = #{file_name}, class_name = #{class_name}"
31
+ return if file_name.empty? || class_name.empty?
32
+ puts "generate_code: file_name = #{file_name}, class_name = #{class_name}"
33
+
34
+ custom_class_names = convert_to_map(file['generate']['customClassNames'])
35
+
36
+ file_path = File.join(@json_path, file_name)
37
+ code_generator = CodeGenerator.new(
38
+ json: JSON.parse(File.read(file_path)),
39
+ language: @language ,
40
+ parent_class_name: class_name,
41
+ custom_types: custom_class_names
42
+ )
43
+
44
+ generated_code = code_generator.generate
45
+
46
+ output_path = File.join(@output_path, gnerated_filename(class_name))
47
+ write_to_file(output_path, generated_code)
48
+ end
49
+
50
+ def gnerated_filename(class_name)
51
+ case SolaraSettingsManager.instance.platform
52
+ when Platform::Flutter
53
+ "#{to_snake_case(class_name)}.dart"
54
+ when Platform::IOS
55
+ "#{class_name}.swift"
56
+ when Platform::Android
57
+ "#{class_name}.kt"
58
+ else
59
+ raise ArgumentError, "Invalid platform: #{@platform}"
60
+ end
61
+ end
62
+
63
+ def to_snake_case(string)
64
+ string.gsub(/[A-Z]/) { |match| "_#{match.downcase}" }.sub(/^_/, '')
65
+ end
66
+
67
+ def write_to_file(output, content)
68
+ puts "generate_code: output = #{output}, content = #{content}"
69
+ File.write(output, content)
70
+ Solara.logger.debug("Genrated #{output}")
71
+ rescue StandardError => e
72
+ Solara.logger.debug("Error writing to file #{file_name}: #{e.message}")
73
+ end
74
+
75
+ def convert_to_map(custom_class_names)
76
+ custom_class_names.each_with_object({}) do |item, result|
77
+ result[item['generatedName']] = item['customName']
78
+ end
79
+ end
80
+
81
+ def read_json
82
+ mainfest_path = File.join(@json_path, 'json_manifest.json')
83
+ JSON.parse(File.read(mainfest_path))
84
+ rescue JSON::ParserError => e
85
+ Solara.logger.debug("Error parsing JSON: #{e.message}")
86
+ {}
87
+ rescue Errno::ENOENT => e
88
+ Solara.logger.debug("Error reading file: #{e.message}")
89
+ {}
90
+ rescue StandardError => e
91
+ Solara.logger.debug("Unexpected error: #{e.message}")
92
+ {}
93
+ end
94
+
95
+ end
@@ -2,12 +2,22 @@ require 'json'
2
2
 
3
3
  module StringCatalogUtils
4
4
  def load_string_catalog(path)
5
+ @path = path
5
6
  JSON.parse(File.read(path))
6
7
  end
7
8
 
8
9
  def get_value(data, key, target, language)
9
10
  lang = language || data['sourceLanguage']
10
- data['strings'][key]['localizations'][lang]['stringUnit'][target]
11
+ localizations = data.dig('strings', key, 'localizations', lang)
12
+
13
+ unless localizations && localizations['stringUnit']
14
+ error_message = "The default language is #{lang}, but no localizations are available for key '#{key}'. Please address this issue in {@path}. You can easily open the file in Xcode to make the necessary adjustments."
15
+ Solara.logger.fatal(error_message)
16
+ exit 1
17
+ end
18
+
19
+ string_unit = localizations['stringUnit']
20
+ string_unit[target]
11
21
  end
12
22
 
13
23
  def has_value?(data, key, language)
@@ -0,0 +1,151 @@
1
+ require 'json'
2
+ require 'fileutils'
3
+
4
+ class ResourceManifestProcessor
5
+ def initialize(brand_key)
6
+ @brand_key = brand_key
7
+ @manifest_file = FilePath.resources_manifest
8
+ @config = load_manifest_file
9
+ end
10
+
11
+ def copy
12
+ @base_source_path = FilePath.brands
13
+ @base_destination_path = FilePath.project_root
14
+ @config['files'].each do |item|
15
+ process_file_item(item)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def clean(item, src, dst)
22
+ paths = destinations(item, src, dst)
23
+ paths.each do |path|
24
+ File.delete(path) if File.exist?(path)
25
+ end
26
+ end
27
+
28
+ def process_file_item(item)
29
+ src = resolve_source_path(@brand_key, item['source'], @base_source_path)
30
+ dst = File.join(@base_destination_path, item['destination'])
31
+
32
+ clean(item, src, dst)
33
+
34
+ return skip_empty_paths(item) if empty_paths?(item)
35
+
36
+ check_mandatory_file(item, src, dst)
37
+
38
+ if File.exist?(src)
39
+ copy_file(src, dst)
40
+ git_ignore(destinations(item, src, dst))
41
+ else
42
+ log_file_not_found(item)
43
+ end
44
+ end
45
+
46
+ def destinations(item, src, dst, visited = {})
47
+ return [] if visited[src]
48
+
49
+ visited[src] = true # Mark the current source as visited
50
+
51
+ if File.file?(src)
52
+ if File.directory?(dst)
53
+ return [File.join(dst, File.basename(src))]
54
+ else
55
+ return [dst]
56
+ end
57
+ elsif File.directory?(src)
58
+ return destinations_of_directory_contents(src, dst)
59
+ end
60
+
61
+ if !item['mandatory'] && !File.file?(src)
62
+ return get_optional_resource_destination(item, dst, visited)
63
+ end
64
+
65
+ []
66
+ end
67
+
68
+ def get_optional_resource_destination(item, dst, visited)
69
+ return [] if item['mandatory']
70
+ keys = BrandsManager.instance.brands_list.map { |brand| brand['key'] }
71
+ keys.each do |key|
72
+ src = resolve_source_path(key, item['source'], @base_source_path)
73
+ result = destinations(item, src, dst, visited)
74
+ return result unless result.empty?
75
+ end
76
+ []
77
+ end
78
+
79
+ def destinations_of_directory_contents(src_dir, dst_dir)
80
+ items = []
81
+ Dir.foreach(src_dir) do |file|
82
+ next if file == '.' || file == '..'
83
+ full_dst_path = File.join(dst_dir, file)
84
+ items << full_dst_path
85
+ end
86
+ items
87
+ end
88
+
89
+ def git_ignore(files)
90
+ files.each do |file|
91
+ GitignoreManager.new(FilePath.project_root).add_items([file])
92
+ end
93
+ end
94
+
95
+ def resolve_source_path(brand_key, source, base_source_path)
96
+ source.gsub(/\{.*?\}/, brand_key).prepend(base_source_path + '/')
97
+ end
98
+
99
+ def empty_paths?(item)
100
+ item['source'].empty? || item['destination'].empty?
101
+ end
102
+
103
+ def skip_empty_paths(item)
104
+ Solara.logger.debug("Skipped (empty source or destination) for #{@brand_key}: #{item['source']} -> #{item['destination']}")
105
+ end
106
+
107
+ def check_mandatory_file(item, src, dst)
108
+ if item['mandatory'] && !File.exist?(src)
109
+ Solara.logger.fatal("Mandatory resource file/folder not found for #{@brand_key}: #{src}. Please add the resource or mark it as not mandatory in #{FilePath.resources_manifest}.")
110
+ exit 1
111
+ end
112
+
113
+ end
114
+
115
+ def copy_file(src, dst)
116
+ if File.directory?(src)
117
+ FileUtils.mkdir_p(dst)
118
+ FileUtils.cp_r(File.join(src, '.'), dst)
119
+ else
120
+ FileUtils.mkdir_p(File.dirname(dst))
121
+ FileUtils.cp(src, dst)
122
+ end
123
+ Solara.logger.debug("Copied resource for #{@brand_key}: #{File.basename(src)} to #{File.basename(dst)}")
124
+ end
125
+
126
+ def log_file_not_found(item)
127
+ Solara.logger.debug("Skipped resource (not found) for #{@brand_key}: #{item['source']}")
128
+ end
129
+
130
+ def load_manifest_file
131
+ validate_manifest_file_existence
132
+ parse_manifest_file
133
+ end
134
+
135
+ def validate_manifest_file_existence
136
+ unless File.exist?(@manifest_file)
137
+ Solara.logger.fatal("Brand switch copy manifest not found for #{@brand_key}: #{@manifest_file}")
138
+ exit 1
139
+ end
140
+ end
141
+
142
+ def parse_manifest_file
143
+ begin
144
+ JSON.parse(File.read(@manifest_file))
145
+ rescue JSON::ParserError => e
146
+ Solara.logger.fatal("Invalid brand switch copy manifest for #{@brand_key}: #{e.message}")
147
+ exit 1
148
+ end
149
+ end
150
+
151
+ end
@@ -37,7 +37,7 @@ class SolaraStatusManager
37
37
 
38
38
  solara dashboard -k #{current_brand['key']}
39
39
 
40
- Then, click the "Apply Changes" button.
40
+ Then, click the "Sync" button.
41
41
  MESSAGE
42
42
  Solara.logger.info(message)
43
43
  end
@@ -1,253 +1,32 @@
1
1
  require 'json'
2
2
  require 'fileutils'
3
3
 
4
- class ThemeGeneratorManager
4
+ class ThemeGenerator
5
5
  def initialize(input_path)
6
6
  @input_path = input_path
7
7
  end
8
8
 
9
9
  def generate(language, output_path)
10
- case language.downcase
11
- when 'kotlin'
12
- generator = KotlinThemeGenerator.new(@input_path, output_path)
13
- when 'swift'
14
- generator = SwiftThemeGenerator.new(@input_path, output_path)
15
- when 'dart'
16
- generator = DartThemeGenerator.new(@input_path, output_path)
17
- else
18
- Solara.logger.fatal("Unsupported language: #{language}")
19
- return
20
- end
21
-
22
- generator.generate
23
- end
24
- end
25
-
26
- class ThemeGenerator
27
- def initialize(input_path, output_path)
28
- @theme = JSON.parse(File.read(input_path))
29
- @output_path = output_path
30
- end
31
-
32
- def write_to_file(code)
33
- FileUtils.mkdir_p(File.dirname(@output_path))
34
- File.write(@output_path, code)
35
- Solara.logger.debug("Generated theme file: #{@output_path}")
36
- end
37
- end
38
-
39
- class KotlinThemeGenerator < ThemeGenerator
40
- def generate
41
- code = "import android.graphics.Color\n\n"
42
- code += "object BrandTheme {\n"
43
- code += generate_colors
44
- code += generate_typography
45
- code += generate_spacing
46
- code += generate_border_radius
47
- code += generate_elevation
48
- code += "}"
49
- write_to_file(code)
50
- end
51
-
52
- private
53
-
54
- def generate_colors
55
- code = " object Colors {\n"
56
- @theme['colors'].each do |name, value|
57
- code += " val #{name} = Color.parseColor(\"#{value}\")\n"
58
- end
59
- code + " }\n\n"
60
- end
61
-
62
- def generate_typography
63
- code = " object Typography {\n"
64
- code += " object FontFamily {\n"
65
- @theme['typography']['fontFamily'].each do |name, value|
66
- code += " val #{name} = \"#{value}\"\n"
67
- end
68
- code += " }\n\n"
69
- code += " object FontSize {\n"
70
- @theme['typography']['fontSize'].each do |name, value|
71
- code += " val #{name} = #{value}\n"
72
- end
73
- code += " }\n"
74
- code + " }\n\n"
75
- end
76
-
77
- def generate_spacing
78
- code = " object Spacing {\n"
79
- @theme['spacing'].each do |name, value|
80
- code += " val #{name} = #{value}\n"
81
- end
82
- code + " }\n\n"
83
- end
84
-
85
- def generate_border_radius
86
- code = " object BorderRadius {\n"
87
- @theme['borderRadius'].each do |name, value|
88
- code += " val #{name} = #{value}\n"
89
- end
90
- code + " }\n\n"
91
- end
92
-
93
- def generate_elevation
94
- code = " object Elevation {\n"
95
- @theme['elevation'].each do |name, value|
96
- code += " val #{name} = #{value}\n"
97
- end
98
- code + " }\n"
99
- end
100
- end
101
-
102
- class SwiftThemeGenerator < ThemeGenerator
103
- def generate
104
- code = "import UIKit\n\n"
105
- code += "struct BrandTheme {\n"
106
- code += generate_colors
107
- code += generate_typography
108
- code += generate_spacing
109
- code += generate_border_radius
110
- code += generate_elevation
111
- code += "}\n\n"
112
- code += generate_colors_hex_extension
113
- write_to_file(code)
114
- end
115
-
116
- private
117
-
118
- def generate_colors
119
- code = " struct Colors {\n"
120
- @theme['colors'].each do |name, value|
121
- code += " static let #{name} = UIColor(hex: \"#{value}\")\n"
122
- end
123
- code + " }\n\n"
124
- end
125
-
126
- def generate_colors_hex_extension
127
- <<-SWIFT
128
- extension UIColor {
129
- convenience init(hex: String) {
130
- let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
131
- var int: UInt64 = 0
132
- Scanner(string: hex).scanHexInt64(&int)
133
- let a, r, g, b: UInt64
134
- switch hex.count {
135
- case 3: // RGB (12-bit)
136
- (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
137
- case 6: // RGB (24-bit)
138
- (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
139
- case 8: // ARGB (32-bit)
140
- (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
141
- default:
142
- (a, r, g, b) = (255, 255, 255, 0)
10
+ config_generator = CodeGenerator.new(
11
+ json: JSON.parse(File.read(@input_path)),
12
+ language: language,
13
+ parent_class_name: 'BrandTheme',
14
+ custom_types: {
15
+ "BrandThemeColorSchemes" => "BrandColorScheme",
16
+ "BrandThemeTypography" => "BrandTypography",
17
+ "BrandThemeSpacing" => "BrandSpacing",
18
+ "BrandThemeBorderRadius" => "BrandBorderRadius",
19
+ "BrandThemeElevation" => "BrandElevation",
20
+ "BrandThemeOpacity" => "BrandOpacity",
21
+ "BrandThemeAnimation" => "BrandAnimation",
22
+ "BrandThemeBreakpoints" => "BrandBreakpoints",
23
+ "BrandThemeColorSchemesLight" => "BrandLightColorScheme",
24
+ "BrandThemeColorSchemesDark" => "BrandDarkColorScheme",
143
25
  }
144
-
145
- self.init(
146
- red: CGFloat(r) / 255,
147
- green: CGFloat(g) / 255,
148
- blue: CGFloat(b) / 255,
149
- alpha: CGFloat(a) / 255
150
- )
151
- }
152
- }
153
- SWIFT
154
- end
155
-
156
- def generate_typography
157
- code = " struct Typography {\n"
158
- code += " struct FontFamily {\n"
159
- @theme['typography']['fontFamily'].each do |name, value|
160
- code += " static let #{name} = \"#{value}\"\n"
161
- end
162
- code += " }\n\n"
163
- code += " struct FontSize {\n"
164
- @theme['typography']['fontSize'].each do |name, value|
165
- code += " static let #{name}: CGFloat = #{value}\n"
166
- end
167
- code += " }\n"
168
- code + " }\n\n"
169
- end
170
-
171
- def generate_spacing
172
- code = " struct Spacing {\n"
173
- @theme['spacing'].each do |name, value|
174
- code += " static let #{name}: CGFloat = #{value}\n"
175
- end
176
- code + " }\n\n"
177
- end
178
-
179
- def generate_border_radius
180
- code = " struct BorderRadius {\n"
181
- @theme['borderRadius'].each do |name, value|
182
- code += " static let #{name}: CGFloat = #{value}\n"
183
- end
184
- code + " }\n\n"
185
- end
186
-
187
- def generate_elevation
188
- code = " struct Elevation {\n"
189
- @theme['elevation'].each do |name, value|
190
- code += " static let #{name}: CGFloat = #{value}\n"
191
- end
192
- code + " }\n"
26
+ )
27
+ content = config_generator.generate
28
+ FileManager.create_file_if_not_exist(output_path)
29
+ File.write(output_path, content)
30
+ Solara.logger.debug("Generated theme file: #{output_path}")
193
31
  end
194
32
  end
195
-
196
- class DartThemeGenerator < ThemeGenerator
197
- def generate
198
- code = "import 'package:flutter/material.dart';\n\n"
199
- code += generate_colors
200
- code += generate_typography
201
- code += generate_spacing
202
- code += generate_border_radius
203
- code += generate_elevation
204
- write_to_file(code)
205
- end
206
-
207
- private
208
-
209
- def generate_colors
210
- code = " class BrandColors {\n"
211
- @theme['colors'].each do |name, value|
212
- code += " static const Color #{name} = Color(0xFF#{value[1..-1]});\n"
213
- end
214
- code + " }\n\n"
215
- end
216
-
217
- def generate_typography
218
- code = " class FontFamily {\n"
219
- @theme['typography']['fontFamily'].each do |name, value|
220
- code += " static const String #{name} = '#{value}';\n"
221
- end
222
- code += " }\n\n"
223
- code += " class FontSize {\n"
224
- @theme['typography']['fontSize'].each do |name, value|
225
- code += " static const double #{name} = #{value};\n"
226
- end
227
- code + " }\n\n"
228
- end
229
-
230
- def generate_spacing
231
- code = " class Spacing {\n"
232
- @theme['spacing'].each do |name, value|
233
- code += " static const double #{name} = #{value};\n"
234
- end
235
- code + " }\n\n"
236
- end
237
-
238
- def generate_border_radius
239
- code = " class BorderRadius {\n"
240
- @theme['borderRadius'].each do |name, value|
241
- code += " static const double #{name} = #{value};\n"
242
- end
243
- code += " }\n\n"
244
- end
245
-
246
- def generate_elevation
247
- code = " class Elevation {\n"
248
- @theme['elevation'].each do |name, value|
249
- code += " static const double #{name} = #{value};\n"
250
- end
251
- code + " }\n"
252
- end
253
- end
@@ -7,7 +7,7 @@ class SolaraConfigurator
7
7
  end
8
8
 
9
9
  def start
10
- GitignoreManager.ignore
10
+ GitignoreManager.ignore_common_files
11
11
  AliasManager.new.start
12
12
  end
13
13
 
@@ -0,0 +1,10 @@
1
+ {
2
+ "description": "This file outlines the resources to be transferred from the brand source to the codebase during the switching process.",
3
+ "files": [
4
+ {
5
+ "source": "",
6
+ "destination": "",
7
+ "mandatory": true
8
+ }
9
+ ]
10
+ }