mtg_card_maker 0.1.0 → 0.2.1

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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +48 -0
  3. data/LICENSE.txt +59 -14
  4. data/README.md +257 -73
  5. data/lib/mtg_card_maker/base_card.rb +24 -3
  6. data/lib/mtg_card_maker/cli.rb +69 -66
  7. data/lib/mtg_card_maker/color_scheme.rb +18 -23
  8. data/lib/mtg_card_maker/css_service.rb +72 -0
  9. data/lib/mtg_card_maker/fonts/GoudyBookletter1911.ttf +0 -0
  10. data/lib/mtg_card_maker/fonts/OFL.txt +92 -0
  11. data/lib/mtg_card_maker/fonts/goudy_bookletter_base64.txt +1 -0
  12. data/lib/mtg_card_maker/icon_filename_service.rb +118 -0
  13. data/lib/mtg_card_maker/icon_service.rb +87 -25
  14. data/lib/mtg_card_maker/icons/black.svg +6 -1
  15. data/lib/mtg_card_maker/icons/blue.svg +6 -1
  16. data/lib/mtg_card_maker/icons/colorless.svg +6 -1
  17. data/lib/mtg_card_maker/icons/double-digit.svg +6 -0
  18. data/lib/mtg_card_maker/icons/energy.svg +26 -0
  19. data/lib/mtg_card_maker/icons/green.svg +6 -1
  20. data/lib/mtg_card_maker/icons/hybrid/2-black.svg +19 -0
  21. data/lib/mtg_card_maker/icons/hybrid/2-blue.svg +19 -0
  22. data/lib/mtg_card_maker/icons/hybrid/2-green.svg +19 -0
  23. data/lib/mtg_card_maker/icons/hybrid/2-red.svg +19 -0
  24. data/lib/mtg_card_maker/icons/hybrid/2-white.svg +19 -0
  25. data/lib/mtg_card_maker/icons/hybrid/black-blue.svg +19 -0
  26. data/lib/mtg_card_maker/icons/hybrid/black-green.svg +19 -0
  27. data/lib/mtg_card_maker/icons/hybrid/black-red.svg +19 -0
  28. data/lib/mtg_card_maker/icons/hybrid/black-white.svg +19 -0
  29. data/lib/mtg_card_maker/icons/hybrid/blue-black.svg +19 -0
  30. data/lib/mtg_card_maker/icons/hybrid/blue-green.svg +19 -0
  31. data/lib/mtg_card_maker/icons/hybrid/blue-red.svg +19 -0
  32. data/lib/mtg_card_maker/icons/hybrid/blue-white.svg +19 -0
  33. data/lib/mtg_card_maker/icons/hybrid/colorless-black.svg +19 -0
  34. data/lib/mtg_card_maker/icons/hybrid/colorless-blue.svg +19 -0
  35. data/lib/mtg_card_maker/icons/hybrid/colorless-green.svg +19 -0
  36. data/lib/mtg_card_maker/icons/hybrid/colorless-red.svg +19 -0
  37. data/lib/mtg_card_maker/icons/hybrid/colorless-white.svg +19 -0
  38. data/lib/mtg_card_maker/icons/hybrid/green-black.svg +19 -0
  39. data/lib/mtg_card_maker/icons/hybrid/green-blue.svg +19 -0
  40. data/lib/mtg_card_maker/icons/hybrid/green-red.svg +19 -0
  41. data/lib/mtg_card_maker/icons/hybrid/green-white.svg +19 -0
  42. data/lib/mtg_card_maker/icons/hybrid/red-black.svg +19 -0
  43. data/lib/mtg_card_maker/icons/hybrid/red-blue.svg +19 -0
  44. data/lib/mtg_card_maker/icons/hybrid/red-green.svg +19 -0
  45. data/lib/mtg_card_maker/icons/hybrid/red-white.svg +19 -0
  46. data/lib/mtg_card_maker/icons/hybrid/white-black.svg +19 -0
  47. data/lib/mtg_card_maker/icons/hybrid/white-blue.svg +19 -0
  48. data/lib/mtg_card_maker/icons/hybrid/white-green.svg +19 -0
  49. data/lib/mtg_card_maker/icons/hybrid/white-red.svg +19 -0
  50. data/lib/mtg_card_maker/icons/phyrexian/black-blue.svg +19 -0
  51. data/lib/mtg_card_maker/icons/phyrexian/black-green.svg +19 -0
  52. data/lib/mtg_card_maker/icons/phyrexian/black-red.svg +19 -0
  53. data/lib/mtg_card_maker/icons/phyrexian/black-white.svg +19 -0
  54. data/lib/mtg_card_maker/icons/phyrexian/black.svg +6 -0
  55. data/lib/mtg_card_maker/icons/phyrexian/blue-black.svg +19 -0
  56. data/lib/mtg_card_maker/icons/phyrexian/blue-green.svg +19 -0
  57. data/lib/mtg_card_maker/icons/phyrexian/blue-red.svg +19 -0
  58. data/lib/mtg_card_maker/icons/phyrexian/blue-white.svg +19 -0
  59. data/lib/mtg_card_maker/icons/phyrexian/blue.svg +6 -0
  60. data/lib/mtg_card_maker/icons/phyrexian/colorless.svg +6 -0
  61. data/lib/mtg_card_maker/icons/phyrexian/green-black.svg +19 -0
  62. data/lib/mtg_card_maker/icons/phyrexian/green-blue.svg +19 -0
  63. data/lib/mtg_card_maker/icons/phyrexian/green-red.svg +19 -0
  64. data/lib/mtg_card_maker/icons/phyrexian/green-white.svg +19 -0
  65. data/lib/mtg_card_maker/icons/phyrexian/green.svg +6 -0
  66. data/lib/mtg_card_maker/icons/phyrexian/red-black.svg +19 -0
  67. data/lib/mtg_card_maker/icons/phyrexian/red-blue.svg +19 -0
  68. data/lib/mtg_card_maker/icons/phyrexian/red-green.svg +19 -0
  69. data/lib/mtg_card_maker/icons/phyrexian/red-white.svg +19 -0
  70. data/lib/mtg_card_maker/icons/phyrexian/red.svg +6 -0
  71. data/lib/mtg_card_maker/icons/phyrexian/white-black.svg +19 -0
  72. data/lib/mtg_card_maker/icons/phyrexian/white-blue.svg +19 -0
  73. data/lib/mtg_card_maker/icons/phyrexian/white-green.svg +19 -0
  74. data/lib/mtg_card_maker/icons/phyrexian/white-red.svg +19 -0
  75. data/lib/mtg_card_maker/icons/phyrexian/white.svg +6 -0
  76. data/lib/mtg_card_maker/icons/red.svg +6 -1
  77. data/lib/mtg_card_maker/icons/single-digit.svg +6 -0
  78. data/lib/mtg_card_maker/icons/snow.svg +24 -0
  79. data/lib/mtg_card_maker/icons/tap.svg +1 -0
  80. data/lib/mtg_card_maker/icons/tap_legacy.svg +45 -0
  81. data/lib/mtg_card_maker/icons/untap.svg +1 -0
  82. data/lib/mtg_card_maker/icons/white.svg +6 -1
  83. data/lib/mtg_card_maker/icons/x.svg +6 -0
  84. data/lib/mtg_card_maker/layer_config.rb +21 -46
  85. data/lib/mtg_card_maker/layers/border_layer.rb +4 -5
  86. data/lib/mtg_card_maker/layers/frame_layer.rb +1 -1
  87. data/lib/mtg_card_maker/layers/name_layer.rb +16 -8
  88. data/lib/mtg_card_maker/layers/power_layer.rb +1 -3
  89. data/lib/mtg_card_maker/layers/text_box_layer.rb +205 -51
  90. data/lib/mtg_card_maker/layers/type_line_layer.rb +2 -4
  91. data/lib/mtg_card_maker/logger.rb +62 -0
  92. data/lib/mtg_card_maker/mana_cost.rb +59 -128
  93. data/lib/mtg_card_maker/sprite_sheet_assets.rb +10 -55
  94. data/lib/mtg_card_maker/sprite_sheet_builder.rb +20 -8
  95. data/lib/mtg_card_maker/sprite_sheet_service.rb +22 -9
  96. data/lib/mtg_card_maker/svg_gradient_service.rb +11 -11
  97. data/lib/mtg_card_maker/symbol_replacement_service.rb +102 -0
  98. data/lib/mtg_card_maker/text_rendering_service.rb +7 -3
  99. data/lib/mtg_card_maker/version.rb +2 -2
  100. data/lib/mtg_card_maker.rb +9 -78
  101. metadata +79 -12
  102. data/lib/mtg_card_maker/fonts/Goudy Mediaeval DemiBold.ttf +0 -0
  103. data/lib/mtg_card_maker/fonts/goudy_base64.txt +0 -1
@@ -21,7 +21,7 @@ module MtgCardMaker
21
21
  # --rules-text "Lightning Bolt deals 3 damage to any target." --color red
22
22
  #
23
23
  # @since 0.1.0
24
- class CLI < Thor # rubocop:disable Metrics/ClassLength
24
+ class CLI < Thor
25
25
  package_name 'mtg_card_maker'
26
26
  map 'a' => :add_card
27
27
  map 'ac' => :add_card
@@ -30,6 +30,9 @@ module MtgCardMaker
30
30
  map 'gcs'=> :generate_sprite
31
31
  map 'gs' => :generate_sprite
32
32
 
33
+ # Fail on misspelled options (for example --nmae) instead of ignoring them
34
+ check_unknown_options!
35
+
33
36
  def self.exit_on_failure?
34
37
  true
35
38
  end
@@ -39,11 +42,11 @@ module MtgCardMaker
39
42
  # @return [Hash] the card option definitions for Thor
40
43
  def self.card_options
41
44
  {
42
- name: { type: :string, required: true, desc: 'Card name' },
45
+ name: { type: :string, desc: 'Card name (warns when omitted)' },
43
46
  mana_cost: { type: :string, aliases: ['mana', 'cost'], desc: 'Mana cost (e.g., "2RR", "XG")' },
44
- type_line: { type: :string, required: true, aliases: ['type'],
45
- desc: 'Card type & subtype (e.g., "Creature - Dragon", "Instant")' },
46
- rules_text: { type: :string, required: true, aliases: ['rules'], desc: 'Card rules text' },
47
+ type_line: { type: :string, aliases: ['type'],
48
+ desc: 'Card type & subtype (e.g., "Creature - Dragon", "Instant"; warns when omitted)' },
49
+ rules_text: { type: :string, aliases: ['rules'], desc: 'Card rules text (optional)' },
47
50
  flavor_text: { type: :string, aliases: ['flavor'], desc: 'Flavor text (optional)' },
48
51
  power: { type: :string, desc: 'Power (for creatures)' },
49
52
  toughness: { type: :string, desc: 'Toughness (for creatures)' },
@@ -51,16 +54,17 @@ module MtgCardMaker
51
54
  color: { type: :string,
52
55
  default: 'colorless',
53
56
  desc: 'Card color (white, blue, black, red, green, colorless)' },
54
- art: { type: :string, aliases: ['artwork', 'image'], desc: 'Image URL or path for card artwork' }
57
+ art: { type: :string, aliases: ['artwork', 'image'], desc: 'Image URL or path for card artwork' },
58
+ embed_font: { type: :boolean, default: true, desc: 'Embed font as base64 in SVG' }
55
59
  }
56
60
  end
57
61
 
58
62
  # Generate a single MTG card with specified parameters
59
63
  #
60
- # @option options [String] :name the card name (required)
64
+ # @option options [String] :name the card name (optional, warns when omitted)
61
65
  # @option options [String] :mana_cost the mana cost in MTG notation
62
- # @option options [String] :type_line the card type (required)
63
- # @option options [String] :rules_text the card rules (required)
66
+ # @option options [String] :type_line the card type (optional, warns when omitted)
67
+ # @option options [String] :rules_text the card rules text (optional)
64
68
  # @option options [String] :flavor_text the flavor text
65
69
  # @option options [String] :power the power value for creatures
66
70
  # @option options [String] :toughness the toughness value for creatures
@@ -80,7 +84,7 @@ module MtgCardMaker
80
84
  config = config.transform_keys(&:to_sym)
81
85
  card = BaseCard.new(config)
82
86
  card.save(options[:output])
83
- puts "✨ Generated #{options[:output]}! ✨"
87
+ logger.success("Generated #{options[:output]}!")
84
88
  end
85
89
 
86
90
  # @!method generate_sprite(yaml_file, output_file)
@@ -89,17 +93,11 @@ module MtgCardMaker
89
93
  option :cards_per_row, type: :numeric, default: 4, desc: 'Number of cards per row in sprite'
90
94
  option :spacing, type: :numeric, default: 30, desc: 'Spacing between cards in pixels'
91
95
  def generate_sprite(yaml_file, output_file)
92
- validate_yaml_file(yaml_file)
93
-
94
- begin
95
- config = load_yaml_config(yaml_file)
96
- sprite_service = create_sprite_service
97
- process_sprite_generation(config, sprite_service, output_file)
98
- rescue Psych::SyntaxError => e
99
- handle_yaml_error(e)
100
- rescue StandardError => e
101
- handle_general_error(e)
102
- end
96
+ abort "❌ YAML file not found: #{yaml_file}" unless File.exist?(yaml_file)
97
+
98
+ config = validate_yaml(yaml_file)
99
+ sprite_service = create_sprite_service
100
+ process_sprite_generation(config, sprite_service, output_file)
103
101
  end
104
102
 
105
103
  # @!method add_card(yaml_file)
@@ -107,11 +105,8 @@ module MtgCardMaker
107
105
  desc 'add_card YAML_FILE [OPTIONS]', 'Add a new card configuration to YAML file'
108
106
  card_options.each { |option, config| option option, config }
109
107
  def add_card(yaml_file)
110
- # Create directory if it doesn't exist
111
- FileUtils.mkdir_p(File.dirname(yaml_file))
112
-
113
- # Load existing config or create new one
114
- config = File.exist?(yaml_file) ? YAML.safe_load_file(yaml_file) : {}
108
+ # Create directory and load/validate config
109
+ config = create_directory_and_load_config(yaml_file)
115
110
 
116
111
  # Generate a unique key for the card
117
112
  card_key = generate_card_key(options[:name], config)
@@ -124,47 +119,40 @@ module MtgCardMaker
124
119
 
125
120
  # Save back to file
126
121
  File.write(yaml_file, config.to_yaml)
127
- puts "✨ Added card '#{options[:name]}' to #{yaml_file}! ✨"
128
- puts "🎴 Key: #{card_key}"
122
+ logger.success("Added card '#{options[:name] || card_key}' to #{yaml_file}!")
123
+ logger.info("🎴 Key: #{card_key}")
129
124
  end
130
125
 
131
126
  private
132
127
 
133
- def validate_yaml_file(yaml_file)
134
- return if File.exist?(yaml_file)
135
-
136
- warn "❌ YAML file not found: #{yaml_file}"
137
- exit 1
128
+ def logger
129
+ @logger ||= MtgCardMaker::Logger.new
138
130
  end
139
131
 
140
132
  def process_sprite_generation(config, sprite_service, output_file)
141
133
  if sprite_service.create_sprite_sheet(config, output_file)
142
134
  display_success_message(config, sprite_service, output_file)
143
135
  else
144
- warn '❌ Failed to generate sprite sheet'
136
+ logger.error('Failed to generate sprite sheet')
145
137
  exit 1
146
138
  end
147
139
  end
148
140
 
149
141
  def handle_yaml_error(error)
150
- warn "❌ Invalid YAML syntax: #{error.message}"
142
+ logger.error("Invalid YAML syntax: #{error.message}")
151
143
  exit 1
152
144
  end
153
145
 
154
146
  def handle_general_error(error)
155
- warn "💥 Error: #{error.message}"
147
+ logger.error(error.message)
156
148
  exit 1
157
149
  end
158
150
 
159
151
  def display_success_message(config, sprite_service, output_file)
160
- puts "✨ Generated #{output_file}! ✨"
152
+ logger.success("Generated #{output_file}!")
161
153
  width, height = sprite_service.sprite_dimensions(config.length)
162
- puts "📏 Sprite dimensions: #{width}x#{height} pixels"
163
- puts "🎨 Contains #{config.length} cards"
164
- end
165
-
166
- def load_yaml_config(yaml_file)
167
- YAML.safe_load_file(yaml_file)
154
+ logger.info("📏 Sprite dimensions: #{width}x#{height} pixels")
155
+ logger.info("🎨 Contains #{config.length} cards")
168
156
  end
169
157
 
170
158
  def create_sprite_service
@@ -175,29 +163,25 @@ module MtgCardMaker
175
163
  end
176
164
 
177
165
  def build_card_config_from_options
178
- config = build_required_config
179
- add_optional_fields(config)
180
- config
166
+ build_base_config.tap { |config| add_optional_fields(config) }
181
167
  end
182
168
 
183
- def build_required_config
184
- {
185
- 'name' => options[:name],
186
- 'type_line' => options[:type_line],
187
- 'rules_text' => process_newlines(options[:rules_text])
188
- }
169
+ def build_base_config
170
+ { 'name' => options[:name], 'type_line' => options[:type_line] }.compact
189
171
  end
190
172
 
191
173
  def add_optional_fields(config)
192
- optional_fields = %w[mana_cost power toughness border_color color art]
174
+ optional_fields = %w[mana_cost power toughness border_color color art embed_font]
193
175
  optional_fields.each do |field|
194
- config[field] = options[field.to_sym] if options[field.to_sym]
176
+ config[field] = options[field.to_sym] if options.key?(field.to_sym)
195
177
  end
196
178
 
197
- # Handle flavor_text separately to process newlines
198
- return unless options[:flavor_text]
179
+ add_text_fields(config)
180
+ end
199
181
 
200
- config['flavor_text'] = process_newlines(options[:flavor_text])
182
+ # Text fields are handled separately to process newlines
183
+ def add_text_fields(config)
184
+ %i[rules_text flavor_text].each { |f| config[f.to_s] = process_newlines(options[f]) if options[f] }
201
185
  end
202
186
 
203
187
  def process_newlines(text)
@@ -205,17 +189,36 @@ module MtgCardMaker
205
189
  text.gsub('\\n', "\n")
206
190
  end
207
191
 
208
- def generate_card_key(name, existing_config)
209
- base_key = name.downcase.gsub(/[^a-z0-9]/, '_').squeeze('_').chomp('_')
192
+ def create_directory_and_load_config(yaml_file)
193
+ # Create directory if it doesn't exist
194
+ FileUtils.mkdir_p(File.dirname(yaml_file))
195
+
196
+ # Load and validate config
197
+ validate_yaml(yaml_file)
198
+ end
199
+
200
+ def validate_yaml(yaml_file)
201
+ return {} unless File.exist?(yaml_file)
202
+
203
+ YAML.safe_load_file(yaml_file) || {}
204
+ rescue Psych::SyntaxError => e
205
+ logger.error("Invalid YAML syntax: #{e.message}")
206
+ exit 1
207
+ rescue StandardError => e
208
+ logger.error("Error reading YAML file: #{e.message}")
209
+ exit 1
210
+ end
211
+
212
+ def generate_card_key(name, config)
213
+ base_key = name.to_s.downcase.gsub(/[^a-z0-9]/, '_').squeeze('_').chomp('_')
214
+ base_key = 'card' if base_key.empty?
210
215
 
211
216
  # If key already exists, append a number
212
- if existing_config.key?(base_key)
213
- counter = 1
214
- counter += 1 while existing_config.key?("#{base_key}_#{counter}")
215
- "#{base_key}_#{counter}"
216
- else
217
- base_key
218
- end
217
+ return base_key unless config.key?(base_key)
218
+
219
+ counter = 1
220
+ counter += 1 while config.key?("#{base_key}_#{counter}")
221
+ "#{base_key}_#{counter}"
219
222
  end
220
223
  end
221
224
  end
@@ -17,14 +17,14 @@ module MtgCardMaker
17
17
  # colorless_scheme = MtgCardMaker::ColorScheme.colorless
18
18
  #
19
19
  # @since 0.1.0
20
- class ColorScheme # rubocop:disable Metrics/ClassLength
20
+ class ColorScheme
21
21
  # Predefined color schemes for all MTG colors and card types
22
22
  # @return [Hash] the predefined color scheme configurations
23
23
  SCHEMES = {
24
24
  colorless: {
25
25
  frame_gradient: ['#8B8B8B', '#6B6B6B', '#4A4A4A'],
26
26
  name_gradient: ['#F5F5F5', '#E8E8E8', '#D4D4D4'],
27
- description_gradient: ['#F5F5F5', '#E8E8E8', '#D4D4D4'],
27
+ text_box_gradient: ['#F5F5F5', '#E8E8E8', '#D4D4D4'],
28
28
  card_gradient: ['#3D3D3D', '#111', '#1A1A1A'],
29
29
  primary: '#8B8B8B',
30
30
  background: '#E8E8E8',
@@ -37,7 +37,7 @@ module MtgCardMaker
37
37
  white: {
38
38
  frame_gradient: ['#FFF9C4', '#F5F5F5', '#BDB76B'],
39
39
  name_gradient: ['#FFFFFF', '#FFF9C4', '#E0E0E0'],
40
- description_gradient: ['#FFFFFF', '#F5F5F5', '#E0E0E0'],
40
+ text_box_gradient: ['#FFFFFF', '#F5F5F5', '#E0E0E0'],
41
41
  card_gradient: ['#D7CCC8', '#BCAAA4', '#8D6E63'],
42
42
  primary: '#8B8B8B',
43
43
  background: '#FFFFFF',
@@ -47,7 +47,7 @@ module MtgCardMaker
47
47
  blue: {
48
48
  frame_gradient: ['#42A5F5', '#1565C0', '#263238'],
49
49
  name_gradient: ['#E3F2FD', '#BBDEFB', '#90CAF9'],
50
- description_gradient: ['#F3F8FF', '#E3F2FD', '#BBDEFB'],
50
+ text_box_gradient: ['#F3F8FF', '#E3F2FD', '#BBDEFB'],
51
51
  card_gradient: ['#546E7A', '#37474F', '#263238'],
52
52
  primary: '#42A5F5',
53
53
  background: '#E3F2FD',
@@ -57,7 +57,7 @@ module MtgCardMaker
57
57
  black: {
58
58
  frame_gradient: ['#424242', '#212121', '#000'],
59
59
  name_gradient: ['#E0E0E0', '#BDBDBD', '#9E9E9E'],
60
- description_gradient: ['#F5F5F5', '#E0E0E0', '#BDBDBD'],
60
+ text_box_gradient: ['#F5F5F5', '#E0E0E0', '#BDBDBD'],
61
61
  card_gradient: ['#424242', '#212121', '#000'],
62
62
  primary: '#424242',
63
63
  background: '#E0E0E0',
@@ -67,7 +67,7 @@ module MtgCardMaker
67
67
  red: {
68
68
  frame_gradient: ['#F44336', '#D32F2F', '#B71C1C'],
69
69
  name_gradient: ['#FFEBEE', '#FFCDD2', '#EF9A9A'],
70
- description_gradient: ['#FFEBEE', '#FFCDD2', '#EF9A9A'],
70
+ text_box_gradient: ['#FFEBEE', '#FFCDD2', '#EF9A9A'],
71
71
  card_gradient: ['#8D6E63', '#6D4C41', '#4E342E'],
72
72
  primary: '#F44336',
73
73
  background: '#FFEBEE',
@@ -77,7 +77,7 @@ module MtgCardMaker
77
77
  green: {
78
78
  frame_gradient: ['#4CAF50', '#388E3C', '#2E7D32'],
79
79
  name_gradient: ['#E8F5E8', '#C8E6C9', '#A5D6A7'],
80
- description_gradient: ['#F1F8E9', '#E8F5E8', '#C8E6C9'],
80
+ text_box_gradient: ['#F1F8E9', '#E8F5E8', '#C8E6C9'],
81
81
  card_gradient: ['#6D4C41', '#5D4037', '#4E342E'],
82
82
  primary: '#4CAF50',
83
83
  background: '#E8F5E8',
@@ -87,7 +87,7 @@ module MtgCardMaker
87
87
  gold: {
88
88
  frame_gradient: ['#FFD700', '#FFA500', '#FF8C00'],
89
89
  name_gradient: ['#F5DEB3', '#E1C16E', '#C9A13B'],
90
- description_gradient: ['#FFF8DC', '#FFE4B5', '#FFDAB9'],
90
+ text_box_gradient: ['#FFF8DC', '#FFE4B5', '#FFDAB9'],
91
91
  card_gradient: ['#8B7355', '#6B4423', '#4A2C0A'],
92
92
  primary: '#FFD700',
93
93
  background: '#FFF8DC',
@@ -100,7 +100,7 @@ module MtgCardMaker
100
100
  artifact: {
101
101
  frame_gradient: ['#D2B48C', '#BC8F8F', '#A0522D'],
102
102
  name_gradient: ['#F5F5DC', '#DEB887', '#CD853F'],
103
- description_gradient: ['#F5F5DC', '#DEB887', '#CD853F'],
103
+ text_box_gradient: ['#F5F5DC', '#DEB887', '#CD853F'],
104
104
  card_gradient: ['#8B7355', '#6B4423', '#4A2C0A'],
105
105
  primary: '#D2B48C',
106
106
  background: '#F5F5DC',
@@ -169,21 +169,21 @@ module MtgCardMaker
169
169
  config[:name_gradient]
170
170
  end
171
171
 
172
- # Description gradient colors
173
- def description_gradient_start
174
- config[:description_gradient][0]
172
+ # Text box gradient colors
173
+ def text_box_gradient_start
174
+ config[:text_box_gradient][0]
175
175
  end
176
176
 
177
- def description_gradient_middle
178
- config[:description_gradient][1]
177
+ def text_box_gradient_middle
178
+ config[:text_box_gradient][1]
179
179
  end
180
180
 
181
- def description_gradient_end
182
- config[:description_gradient][2]
181
+ def text_box_gradient_end
182
+ config[:text_box_gradient][2]
183
183
  end
184
184
 
185
- def description_gradient_colors
186
- config[:description_gradient]
185
+ def text_box_gradient_colors
186
+ config[:text_box_gradient]
187
187
  end
188
188
 
189
189
  # Card gradient colors
@@ -296,10 +296,5 @@ module MtgCardMaker
296
296
  def self.artifact
297
297
  new(:artifact)
298
298
  end
299
-
300
- # @return [ColorScheme] a silver color scheme
301
- def self.silver
302
- new(:silver)
303
- end
304
299
  end
305
300
  end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MtgCardMaker
4
+ # Service class for managing CSS styles used across the application
5
+ class CssService
6
+ class << self
7
+ # Generate the font face declaration
8
+ #
9
+ # @param embed [Boolean] whether to embed the font as base64
10
+ # @return [String] the font face CSS
11
+ def font_face(embed: false)
12
+ return '' unless embed
13
+
14
+ font_path = File.join(__dir__, 'fonts', 'goudy_bookletter_base64.txt')
15
+ base64_font_data = File.read(font_path).strip
16
+ <<~CSS
17
+ @font-face {
18
+ font-family: 'Goudy Bookletter 1911';
19
+ src: url(data:font/truetype;charset=utf-8;base64,#{base64_font_data}) format('truetype');
20
+ }
21
+ CSS
22
+ end
23
+
24
+ # Generate all CSS classes
25
+ #
26
+ # @return [String] the CSS classes
27
+ def css_classes(embed: false)
28
+ <<~CSS
29
+ /* Font Classes */
30
+ .card-name, .card-type {
31
+ font-family: #{font_family(embed)};
32
+ font-weight: #{font_weight(embed)};
33
+ }
34
+
35
+ .card-rules-text, .mana-cost-text {
36
+ font-family: serif;
37
+ }
38
+
39
+ .card-flavor-text {
40
+ font-family: serif;
41
+ font-style: italic;
42
+ }
43
+
44
+ .card-power-toughness {
45
+ font-family: serif;
46
+ font-weight: bold;
47
+ }
48
+
49
+ .card-copyright {
50
+ font-family: sans-serif;
51
+ }
52
+ CSS
53
+ end
54
+
55
+ def font_family(embed)
56
+ embed ? "'Goudy Bookletter 1911', serif" : 'serif'
57
+ end
58
+
59
+ def font_weight(embed)
60
+ embed ? 'normal' : 'bold'
61
+ end
62
+
63
+ # Generate complete CSS styles
64
+ #
65
+ # @param embed [Boolean] whether to embed the font as base64
66
+ # @return [String] the complete CSS styles
67
+ def complete_styles(embed: false)
68
+ font_face(embed: embed) + css_classes(embed: embed)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,92 @@
1
+ Copyright (c) 2010, Barry Schwartz (crudfactory.com)
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ http://scripts.sil.org/OFL
6
+
7
+ -----------------------------------------------------------
8
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
9
+ -----------------------------------------------------------
10
+
11
+ PREAMBLE
12
+ The goals of the Open Font License (OFL) are to stimulate worldwide
13
+ development of collaborative font projects, to support the font creation
14
+ efforts of academic and linguistic communities, and to provide a free and
15
+ open framework in which fonts may be shared and improved in partnership
16
+ with others.
17
+
18
+ The OFL allows the licensed fonts to be used, studied, modified and
19
+ redistributed freely as long as they are not sold by themselves. The
20
+ fonts, including any derivative works, can be bundled, embedded,
21
+ redistributed and/or sold with any software provided that any reserved
22
+ names are not used by derivative works. The fonts and derivatives,
23
+ however, cannot be released under any other type of license. The
24
+ requirement for fonts to remain under this license does not apply
25
+ to any document created using the fonts or their derivatives.
26
+
27
+ DEFINITIONS
28
+ "Font Software" refers to the set of files released by the Copyright
29
+ Holder(s) under this license and clearly marked as such. This may
30
+ include source files, build scripts and documentation.
31
+
32
+ "Reserved Font Name" refers to any names specified as such after the
33
+ copyright statement(s).
34
+
35
+ "Original Version" refers to the collection of Font Software components as
36
+ distributed by the Copyright Holder(s).
37
+
38
+ "Modified Version" refers to any derivative made by adding to, deleting,
39
+ or substituting -- in part or in whole -- any of the components of the
40
+ Original Version, by changing formats or by porting the Font Software to a
41
+ new environment.
42
+
43
+ "Author" refers to any designer, engineer, programmer, technical
44
+ writer or other person who contributed to the Font Software.
45
+
46
+ PERMISSION & CONDITIONS
47
+ Permission is hereby granted, free of charge, to any person obtaining
48
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
49
+ redistribute, and sell modified and unmodified copies of the Font
50
+ Software, subject to the following conditions:
51
+
52
+ 1) Neither the Font Software nor any of its individual components,
53
+ in Original or Modified Versions, may be sold by itself.
54
+
55
+ 2) Original or Modified Versions of the Font Software may be bundled,
56
+ redistributed and/or sold with any software, provided that each copy
57
+ contains the above copyright notice and this license. These can be
58
+ included either as stand-alone text files, human-readable headers or
59
+ in the appropriate machine-readable metadata fields within text or
60
+ binary files as long as those fields can be easily viewed by the user.
61
+
62
+ 3) No Modified Version of the Font Software may use the Reserved Font
63
+ Name(s) unless explicit written permission is granted by the corresponding
64
+ Copyright Holder. This restriction only applies to the primary font name as
65
+ presented to the users.
66
+
67
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
68
+ Software shall not be used to promote, endorse or advertise any
69
+ Modified Version, except to acknowledge the contribution(s) of the
70
+ Copyright Holder(s) and the Author(s) or with their explicit written
71
+ permission.
72
+
73
+ 5) The Font Software, modified or unmodified, in part or in whole,
74
+ must be distributed entirely under this license, and must not be
75
+ distributed under any other license. The requirement for fonts to
76
+ remain under this license does not apply to any document created
77
+ using the Font Software.
78
+
79
+ TERMINATION
80
+ This license becomes null and void if any of the above conditions are
81
+ not met.
82
+
83
+ DISCLAIMER
84
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
85
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
86
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
87
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
88
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
89
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
90
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
91
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
92
+ OTHER DEALINGS IN THE FONT SOFTWARE.