discourse_theme 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b049cb77cb8542cd1991928a60dab7567f11e8a89c8c4ddaba8e297c05938f6c
4
- data.tar.gz: c799d67427d340e1ce920c8deaebd9ae34b0af598905bf6176421ed816c3eade
3
+ metadata.gz: 0a1f5b1cee83b53b139cb01af57e7e7ea7687cd1a97cc55ef293703d5500f17c
4
+ data.tar.gz: c67b2363cba3ab789eb20f987775c90f0821105dbbf32ddf3a7e564e77d35d7f
5
5
  SHA512:
6
- metadata.gz: 6936df70b44ba83c191cb2b37a0897fa9caaf00614e3d1caa70d9f033e796eba29b8c9276e90ec8b9523af200d1f18b053c06957cefa3a6b3ab435a91b748c87
7
- data.tar.gz: 0d7f183e24fb26fefed3000b4b7d681bfb51326dd1c7a9e5693fcc940dd077eb5bf31a79fa6ec287a76dd4989c60e135e3b23fb08dbce26a953aefd26d5486d4
6
+ metadata.gz: a93ecd60d0cab2284697e183595fe5caf76c0a137e476551461ee189a81382ec9ea34480b1c3ac78058641aa4ca391d4fd567373bf81c700cc5843a90685aa6a
7
+ data.tar.gz: eefffe552afaf7a461c55a04258714a2204be39b0190c4337f2ed928ffd8ed15e27fd09c9b6f5889fb1e5e4c0162810b850194819542daaa9cef7187072c731c
@@ -1,38 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module DiscourseTheme
3
3
  class Cli
4
-
5
- @@prompt = ::TTY::Prompt.new(help_color: :cyan)
6
- @@pastel = Pastel.new
7
-
8
- def self.yes?(message)
9
- @@prompt.yes?(@@pastel.cyan("? ") + message)
10
- end
11
-
12
- def self.ask(message, default: nil)
13
- @@prompt.ask(@@pastel.cyan("? ") + message, default: default)
14
- end
15
-
16
- def self.select(message, options)
17
- @@prompt.select(@@pastel.cyan("? ") + message, options)
18
- end
19
-
20
- def self.info(message)
21
- puts @@pastel.blue("i ") + message
22
- end
23
-
24
- def self.progress(message)
25
- puts @@pastel.yellow("» ") + message
26
- end
27
-
28
- def self.error(message)
29
- puts @@pastel.red("✘ #{message}")
30
- end
31
-
32
- def self.success(message)
33
- puts @@pastel.green("✔ #{message}")
34
- end
35
-
36
4
  SETTINGS_FILE = File.expand_path("~/.discourse_theme")
37
5
 
38
6
  def usage
@@ -63,11 +31,7 @@ module DiscourseTheme
63
31
  if command == "new"
64
32
  raise DiscourseTheme::ThemeError.new "'#{dir} is not empty" if Dir.exists?(dir) && !Dir.empty?(dir)
65
33
  DiscourseTheme::Scaffold.generate(dir)
66
- if Cli.yes?("Would you like to start 'watching' this theme?")
67
- args[0] = "watch"
68
- Cli.progress "Running discourse_theme #{args.join(' ')}"
69
- run(args)
70
- end
34
+ watch_theme?(args)
71
35
  elsif command == "watch"
72
36
  raise DiscourseTheme::ThemeError.new "'#{dir} does not exist" unless Dir.exists?(dir)
73
37
  client = DiscourseTheme::Client.new(dir, settings, reset: reset)
@@ -81,13 +45,13 @@ module DiscourseTheme
81
45
  options["Create and sync with a new theme"] = :create
82
46
  options["Select a different theme"] = :select
83
47
 
84
- choice = Cli.select('How would you like to sync this theme?', options.keys)
48
+ choice = UI.select('How would you like to sync this theme?', options.keys)
85
49
 
86
50
  if options[choice] == :create
87
51
  theme_id = nil
88
52
  elsif options[choice] == :select
89
53
  themes = render_theme_list(theme_list)
90
- choice = Cli.select('Which theme would you like to sync with?', themes)
54
+ choice = UI.select('Which theme would you like to sync with?', themes)
91
55
  theme_id = extract_theme_id(choice)
92
56
  theme = theme_list.find { |t| t["id"] == theme_id }
93
57
  end
@@ -102,27 +66,26 @@ module DiscourseTheme
102
66
  options["Yes"] = :sync
103
67
  options["No"] = :none
104
68
  options = options.sort_by { |_, b| b == components.to_sym ? 0 : 1 }.to_h if components
105
- choice = Cli.select('Would you like to update child theme components?', options.keys)
69
+ choice = UI.select('Would you like to update child theme components?', options.keys)
106
70
  settings.components = components = options[choice].to_s
107
71
  end
108
72
 
109
73
  uploader = DiscourseTheme::Uploader.new(dir: dir, client: client, theme_id: theme_id, components: components)
110
74
 
111
- Cli.progress "Uploading theme from #{dir}"
75
+ UI.progress "Uploading theme from #{dir}"
112
76
  settings.theme_id = theme_id = uploader.upload_full_theme
113
77
 
114
- Cli.success "Theme uploaded (id:#{theme_id})"
115
- Cli.info "Preview: #{client.root}/?preview_theme_id=#{theme_id}"
78
+ UI.success "Theme uploaded (id:#{theme_id})"
79
+ UI.info "Preview: #{client.root}/?preview_theme_id=#{theme_id}"
116
80
  if client.is_theme_creator
117
- Cli.info "Manage: #{client.root}/my/themes"
81
+ UI.info "Manage: #{client.root}/my/themes"
118
82
  else
119
- Cli.info "Manage: #{client.root}/admin/customize/themes/#{theme_id}"
83
+ UI.info "Manage: #{client.root}/admin/customize/themes/#{theme_id}"
120
84
  end
121
85
  watcher = DiscourseTheme::Watcher.new(dir: dir, uploader: uploader)
122
86
 
123
- Cli.progress "Watching for changes in #{dir}..."
87
+ UI.progress "Watching for changes in #{dir}..."
124
88
  watcher.watch
125
-
126
89
  elsif command == "download"
127
90
  client = DiscourseTheme::Client.new(dir, settings, reset: reset)
128
91
  downloader = DiscourseTheme::Downloader.new(dir: dir, client: client)
@@ -130,33 +93,39 @@ module DiscourseTheme
130
93
  FileUtils.mkdir_p dir unless Dir.exists?(dir)
131
94
  raise DiscourseTheme::ThemeError.new "'#{dir} is not empty" unless Dir.empty?(dir)
132
95
 
133
- Cli.progress "Loading theme list..."
96
+ UI.progress "Loading theme list..."
134
97
  themes = render_theme_list(client.get_themes_list)
135
98
 
136
- choice = Cli.select('Which theme would you like to download?', themes)
99
+ choice = UI.select('Which theme would you like to download?', themes)
137
100
  theme_id = extract_theme_id(choice)
138
101
 
139
- Cli.progress "Downloading theme into #{dir}"
102
+ UI.progress "Downloading theme into #{dir}"
140
103
 
141
104
  downloader.download_theme(theme_id)
142
105
  settings.theme_id = theme_id
143
106
 
144
- Cli.success "Theme downloaded"
107
+ UI.success "Theme downloaded"
145
108
 
146
- if Cli.yes?("Would you like to start 'watching' this theme?")
147
- args[0] = "watch"
148
- Cli.progress "Running discourse_theme #{args.join(' ')}"
149
- run(args)
150
- end
109
+ watch_theme?(args)
151
110
  else
152
111
  usage
153
112
  end
154
113
 
155
- Cli.progress "Exiting..."
114
+ UI.progress "Exiting..."
156
115
  rescue DiscourseTheme::ThemeError => e
157
- Cli.error "#{e.message}"
116
+ UI.error "#{e.message}"
158
117
  rescue Interrupt, TTY::Reader::InputInterrupt => e
159
- Cli.error "Interrupted"
118
+ UI.error "Interrupted"
119
+ end
120
+
121
+ private
122
+
123
+ def watch_theme?(args)
124
+ if UI.yes?("Would you like to start 'watching' this theme?")
125
+ args[0] = "watch"
126
+ UI.progress "Running discourse_theme #{args.join(' ')}"
127
+ run(args)
128
+ end
160
129
  end
161
130
 
162
131
  def render_theme_list(themes)
@@ -14,8 +14,8 @@ module DiscourseTheme
14
14
  @is_theme_creator = !!(THEME_CREATOR_REGEX =~ @url)
15
15
 
16
16
  if !self.class.has_needed_version?(discourse_version, "2.3.0.beta1")
17
- Cli.info "discourse_theme is designed for Discourse 2.3.0.beta1 or above"
18
- Cli.info "download will not function, and syncing destination will be unpredictable"
17
+ UI.info "discourse_theme is designed for Discourse 2.3.0.beta1 or above"
18
+ UI.info "download will not function, and syncing destination will be unpredictable"
19
19
  end
20
20
  end
21
21
 
@@ -142,26 +142,26 @@ module DiscourseTheme
142
142
  def guess_url(settings)
143
143
  url = ENV['DISCOURSE_URL']
144
144
  if url
145
- Cli.progress "Using #{url} from DISCOURSE_URL"
145
+ UI.progress "Using #{url} from DISCOURSE_URL"
146
146
  end
147
147
 
148
148
  if !url && settings.url
149
149
  url = settings.url
150
- Cli.progress "Using #{url} from #{DiscourseTheme::Cli::SETTINGS_FILE}"
150
+ UI.progress "Using #{url} from #{DiscourseTheme::Cli::SETTINGS_FILE}"
151
151
  end
152
152
 
153
153
  if !url || @reset
154
- url = Cli.ask("What is the root URL of your Discourse site?", default: url).strip
154
+ url = UI.ask("What is the root URL of your Discourse site?", default: url).strip
155
155
  url = "http://#{url}" unless url =~ /^https?:\/\//
156
156
 
157
157
  # maybe this is an HTTPS redirect
158
158
  uri = URI.parse(url)
159
159
  if URI::HTTP === uri && uri.port == 80 && is_https_redirect?(url)
160
- Cli.info "Detected that #{url} should be accessed over https"
160
+ UI.info "Detected that #{url} should be accessed over https"
161
161
  url = url.sub("http", "https")
162
162
  end
163
163
 
164
- if Cli.yes?("Would you like this site name stored in #{DiscourseTheme::Cli::SETTINGS_FILE}?")
164
+ if UI.yes?("Would you like this site name stored in #{DiscourseTheme::Cli::SETTINGS_FILE}?")
165
165
  settings.url = url
166
166
  else
167
167
  settings.url = nil
@@ -174,17 +174,17 @@ module DiscourseTheme
174
174
  def guess_api_key(settings)
175
175
  api_key = ENV['DISCOURSE_API_KEY']
176
176
  if api_key
177
- Cli.progress "Using api key from DISCOURSE_API_KEY"
177
+ UI.progress "Using api key from DISCOURSE_API_KEY"
178
178
  end
179
179
 
180
180
  if !api_key && settings.api_key
181
181
  api_key = settings.api_key
182
- Cli.progress "Using api key from #{DiscourseTheme::Cli::SETTINGS_FILE}"
182
+ UI.progress "Using api key from #{DiscourseTheme::Cli::SETTINGS_FILE}"
183
183
  end
184
184
 
185
185
  if !api_key || @reset
186
- api_key = Cli.ask("What is your API key?", default: api_key).strip
187
- if Cli.yes?("Would you like this API key stored in #{DiscourseTheme::Cli::SETTINGS_FILE}?")
186
+ api_key = UI.ask("What is your API key?", default: api_key).strip
187
+ if UI.yes?("Would you like this API key stored in #{DiscourseTheme::Cli::SETTINGS_FILE}?")
188
188
  settings.api_key = api_key
189
189
  else
190
190
  settings.api_key = nil
@@ -1,75 +1,128 @@
1
1
  # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
2
5
  module DiscourseTheme
3
6
  class Scaffold
4
7
 
5
8
  BLANK_FILES = %w{
6
9
  common/common.scss
7
- common/header.html
8
- common/after_header.html
9
- common/footer.html
10
- common/head_tag.html
11
- common/body_tag.html
12
- common/embedded.scss
13
-
14
- desktop/desktop.scss
15
- desktop/header.html
16
- desktop/after_header.html
17
- desktop/footer.html
18
- desktop/head_tag.html
19
- desktop/body_tag.html
20
-
21
- mobile/mobile.scss
22
- mobile/header.html
23
- mobile/after_header.html
24
- mobile/footer.html
25
- mobile/head_tag.html
26
- mobile/body_tag.html
27
-
28
- locales/en.yml
29
10
 
30
11
  settings.yml
31
12
  }
32
13
 
33
- ABOUT_JSON = <<~STR
34
- {
35
- "name": "#NAME#",
36
- "about_url": null,
37
- "license_url": null,
38
- "assets": {
39
- },
40
- "color_schemes": {
41
- }
14
+ ABOUT_JSON = {
15
+ about_url: nil,
16
+ license_url: nil,
17
+ assets: {}
42
18
  }
43
- STR
44
19
 
45
20
  HELP = <<~STR
46
21
  Are you a bit lost? Be sure to read https://meta.discourse.org/t/how-to-develop-custom-themes/60848
47
22
  STR
48
23
 
49
24
  GIT_IGNORE = <<~STR
50
- .discourse-site
51
- HELP
52
- STR
25
+ .discourse-site
26
+ node_modules
27
+ HELP
28
+ STR
29
+
30
+ API_INITIALIZER = <<~STR
31
+ import { apiInitializer } from "discourse/lib/api";
32
+
33
+ export default apiInitializer("0.11.1", api => {
34
+ console.log("hello world from api initializer!");
35
+ });
36
+ STR
37
+
38
+ PACKAGE_JSON = <<~STR
39
+ {
40
+ "author": "#AUTHOR",
41
+ "license": "MIT",
42
+ "devDependencies": {
43
+ "eslint-config-discourse": "latest"
44
+ }
45
+ }
46
+ STR
47
+
48
+ ESLINT_RC = <<~STR
49
+ {
50
+ "extends": "eslint-config-discourse"
51
+ }
52
+ STR
53
+
54
+ TEMPLATE_LINT_RC = <<~STR
55
+ module.exports = {
56
+ plugins: ["ember-template-lint-plugin-discourse"],
57
+ extends: "discourse:recommended",
58
+ };
59
+ STR
60
+
61
+ EN_YML = <<~YAML
62
+ en:
63
+ #my_locale_key: My Translation
64
+ theme_metadata:
65
+ description: "#DESCRIPTION"
66
+ settings:
67
+ # my_setting_name: My Setting Description
68
+ YAML
53
69
 
54
70
  def self.generate(dir)
55
- Cli.progress "Generating a scaffold theme at #{dir}"
71
+ UI.progress "Generating a scaffold theme at #{dir}"
56
72
 
57
- name = Cli.ask("What would you like to call your theme?").strip
73
+ name = UI.ask("What would you like to call your theme?").strip
74
+ is_component = UI.yes?("Is this a component?")
58
75
 
59
76
  FileUtils.mkdir_p dir
60
77
  Dir.chdir dir do
61
- File.write('about.json', ABOUT_JSON.sub("#NAME#", name))
78
+ UI.info "Creating about.json"
79
+ about_template = ABOUT_JSON.dup
80
+ about_template[:name] = name
81
+ if is_component
82
+ about_template[:component] = true
83
+ else
84
+ about_template[:color_schemes] = {}
85
+ end
86
+ File.write('about.json', JSON.pretty_generate(about_template))
87
+
88
+ UI.info "Creating HELP"
62
89
  File.write('HELP', HELP)
90
+
91
+ UI.info "Creating package.json"
92
+ author = UI.ask("Who is authoring the theme?").strip
93
+ File.write('package.json', PACKAGE_JSON.sub("#AUTHOR", author))
94
+
95
+ UI.info "Creating .template-lintrc.js"
96
+ File.write('.template-lintrc.js', TEMPLATE_LINT_RC)
97
+
98
+ UI.info "Creating .eslintrc"
99
+ File.write('.eslintrc', ESLINT_RC)
100
+
101
+ UI.info "Creating .gitignore"
63
102
  File.write('.gitignore', GIT_IGNORE)
64
103
 
104
+ locale = "locales/en.yml"
105
+ UI.info "Creating #{locale}"
106
+ FileUtils.mkdir_p(File.dirname(locale))
107
+ description = UI.ask("How would you describe this theme?").strip
108
+ File.write(locale, EN_YML.sub("#DESCRIPTION", description))
109
+
110
+ initializer = "javascripts/discourse/api-initializers/#{name}.js"
111
+ UI.info "Creating #{initializer}"
112
+ FileUtils.mkdir_p(File.dirname(initializer))
113
+ File.write(initializer, API_INITIALIZER)
114
+
65
115
  BLANK_FILES.each do |f|
66
- Cli.info "Creating #{f}"
116
+ UI.info "Creating #{f}"
67
117
  FileUtils.mkdir_p File.dirname(f)
68
118
  FileUtils.touch f
69
119
  end
70
120
 
71
- Cli.info "Initializing git repo"
121
+ UI.info "Initializing git repo"
72
122
  puts `git init .`
123
+
124
+ UI.info "Installing dependencies"
125
+ puts `yarn`
73
126
  end
74
127
  end
75
128
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+ module DiscourseTheme
3
+ class UI
4
+ @@prompt = ::TTY::Prompt.new(help_color: :cyan)
5
+ @@pastel = Pastel.new
6
+
7
+ def self.yes?(message)
8
+ @@prompt.yes?(@@pastel.cyan("? ") + message)
9
+ end
10
+
11
+ def self.ask(message, default: nil)
12
+ @@prompt.ask(@@pastel.cyan("? ") + message, default: default)
13
+ end
14
+
15
+ def self.select(message, options)
16
+ @@prompt.select(@@pastel.cyan("? ") + message, options)
17
+ end
18
+
19
+ def self.info(message)
20
+ puts @@pastel.blue("i ") + message
21
+ end
22
+
23
+ def self.progress(message)
24
+ puts @@pastel.yellow("» ") + message
25
+ end
26
+
27
+ def self.error(message)
28
+ puts @@pastel.red("✘ #{message}")
29
+ end
30
+
31
+ def self.success(message)
32
+ puts @@pastel.green("✔ #{message}")
33
+ end
34
+ end
35
+ end
@@ -34,9 +34,9 @@ module DiscourseTheme
34
34
  json["theme"]["theme_fields"].each do |row|
35
35
  if (error = row["error"]) && error.length > 0
36
36
  count += 1
37
- Cli.error ""
38
- Cli.error "Error in #{row["target"]} #{row["name"]}: #{row["error"]}"
39
- Cli.error ""
37
+ UI.error ""
38
+ UI.error "Error in #{row["target"]} #{row["name"]}: #{row["error"]}"
39
+ UI.error ""
40
40
  end
41
41
  end
42
42
  count
@@ -59,7 +59,7 @@ module DiscourseTheme
59
59
  response = @client.update_theme(@theme_id, args)
60
60
  json = JSON.parse(response.body)
61
61
  if diagnose_errors(json) != 0
62
- Cli.error "(end of errors)"
62
+ UI.error "(end of errors)"
63
63
  end
64
64
  end
65
65
 
@@ -73,7 +73,7 @@ module DiscourseTheme
73
73
  json = JSON.parse(response.body)
74
74
  @theme_id = json["theme"]["id"]
75
75
  if diagnose_errors(json) != 0
76
- Cli.error "(end of errors)"
76
+ UI.error "(end of errors)"
77
77
  end
78
78
  @theme_id
79
79
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module DiscourseTheme
3
- VERSION = "0.4.1"
3
+ VERSION = "0.5.0"
4
4
  end
@@ -23,7 +23,7 @@ module DiscourseTheme
23
23
  (resolved = resolve_file(modified[0]))
24
24
 
25
25
  target, name, type_id = resolved
26
- Cli.progress "Fast updating #{target}.scss"
26
+ UI.progress "Fast updating #{target}.scss"
27
27
 
28
28
  @uploader.upload_theme_field(
29
29
  target: target,
@@ -34,17 +34,17 @@ module DiscourseTheme
34
34
  else
35
35
  count = modified.length + added.length + removed.length
36
36
  if count > 1
37
- Cli.progress "Detected changes in #{count} files, uploading theme"
37
+ UI.progress "Detected changes in #{count} files, uploading theme"
38
38
  else
39
39
  filename = modified[0] || added[0] || removed[0]
40
- Cli.progress "Detected changes in #{filename.gsub(@dir, '')}, uploading theme"
40
+ UI.progress "Detected changes in #{filename.gsub(@dir, '')}, uploading theme"
41
41
  end
42
42
  @uploader.upload_full_theme
43
43
  end
44
- Cli.success "Done! Watching for changes..."
44
+ UI.success "Done! Watching for changes..."
45
45
  rescue DiscourseTheme::ThemeError => e
46
- Cli.error "#{e.message}"
47
- Cli.progress "Watching for changes..."
46
+ UI.error "#{e.message}"
47
+ UI.progress "Watching for changes..."
48
48
  end
49
49
  end
50
50
 
@@ -16,6 +16,7 @@ require 'tty/prompt'
16
16
 
17
17
  require 'discourse_theme/version'
18
18
  require 'discourse_theme/config'
19
+ require 'discourse_theme/ui'
19
20
  require 'discourse_theme/cli'
20
21
  require 'discourse_theme/client'
21
22
  require 'discourse_theme/downloader'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: discourse_theme
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-11 00:00:00.000000000 Z
11
+ date: 2021-05-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitar
@@ -217,6 +217,7 @@ files:
217
217
  - lib/discourse_theme/config.rb
218
218
  - lib/discourse_theme/downloader.rb
219
219
  - lib/discourse_theme/scaffold.rb
220
+ - lib/discourse_theme/ui.rb
220
221
  - lib/discourse_theme/uploader.rb
221
222
  - lib/discourse_theme/version.rb
222
223
  - lib/discourse_theme/watcher.rb
@@ -224,7 +225,7 @@ homepage: https://github.com/discourse/discourse_theme
224
225
  licenses:
225
226
  - MIT
226
227
  metadata: {}
227
- post_install_message:
228
+ post_install_message:
228
229
  rdoc_options: []
229
230
  require_paths:
230
231
  - lib
@@ -239,8 +240,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
239
240
  - !ruby/object:Gem::Version
240
241
  version: '0'
241
242
  requirements: []
242
- rubygems_version: 3.1.4
243
- signing_key:
243
+ rubygems_version: 3.0.3
244
+ signing_key:
244
245
  specification_version: 4
245
246
  summary: CLI helper for creating Discourse themes
246
247
  test_files: []