fronde 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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ext/r18n.rb +20 -0
  3. data/lib/ext/time.rb +6 -16
  4. data/lib/ext/time_no_time.rb +23 -0
  5. data/lib/fronde/cli/commands.rb +16 -12
  6. data/lib/fronde/cli/data/gitignore +0 -1
  7. data/lib/fronde/cli/opt_parse.rb +4 -7
  8. data/lib/fronde/cli/throbber.rb +24 -13
  9. data/lib/fronde/cli.rb +3 -2
  10. data/lib/fronde/config/data/org-config.el +3 -2
  11. data/lib/fronde/config/data/ox-fronde.el +72 -35
  12. data/lib/fronde/config/data/themes/umaneti/css/htmlize.css +364 -0
  13. data/lib/fronde/config/data/themes/umaneti/css/style.css +250 -0
  14. data/lib/fronde/config/data/themes/umaneti/img/bottom.png +0 -0
  15. data/lib/fronde/config/data/themes/umaneti/img/content.png +0 -0
  16. data/lib/fronde/config/data/themes/umaneti/img/tic.png +0 -0
  17. data/lib/fronde/config/data/themes/umaneti/img/top.png +0 -0
  18. data/lib/fronde/config/helpers.rb +0 -18
  19. data/lib/fronde/config/lisp.rb +13 -3
  20. data/lib/fronde/config.rb +40 -26
  21. data/lib/fronde/emacs.rb +1 -1
  22. data/lib/fronde/index/data/all_tags.org +6 -1
  23. data/lib/fronde/index/data/template.org +8 -4
  24. data/lib/fronde/index/org_generator.rb +2 -0
  25. data/lib/fronde/index.rb +12 -15
  26. data/lib/fronde/org/file.rb +39 -27
  27. data/lib/fronde/org/file_extracter.rb +15 -12
  28. data/lib/fronde/org.rb +11 -9
  29. data/lib/fronde/slug.rb +39 -12
  30. data/lib/fronde/source/gemini.rb +0 -5
  31. data/lib/fronde/source/html.rb +5 -5
  32. data/lib/fronde/source.rb +13 -8
  33. data/lib/fronde/sync/neocities.rb +220 -0
  34. data/lib/fronde/sync/rsync.rb +46 -0
  35. data/lib/fronde/sync.rb +32 -0
  36. data/lib/fronde/templater.rb +18 -11
  37. data/lib/fronde/version.rb +1 -1
  38. data/lib/tasks/org.rake +12 -17
  39. data/lib/tasks/site.rake +10 -13
  40. data/lib/tasks/sync.rake +13 -36
  41. data/lib/tasks/tags.rake +2 -2
  42. data/locales/en.yml +1 -0
  43. data/locales/fr.yml +1 -0
  44. metadata +49 -10
data/lib/fronde/config.rb CHANGED
@@ -39,16 +39,16 @@ module Fronde
39
39
 
40
40
  def initialize
41
41
  @default_settings = {
42
- 'author' => (ENV['USER'] || ''),
42
+ 'author' => ENV['USER'] || '',
43
43
  'domain' => '',
44
44
  'lang' => Fronde::Config::Helpers.extract_lang_from_env('en'),
45
45
  'html_public_folder' => 'public_html',
46
46
  'gemini_public_folder' => 'public_gmi',
47
47
  'templates' => [], 'theme' => 'default'
48
48
  }.freeze
49
- @org_version = @sources = nil
50
- @config = load_settings
51
49
  # Do not load sources now to avoid dependency loop on config
50
+ @sources = nil
51
+ @config = load_settings
52
52
  end
53
53
 
54
54
  include Fronde::Config::Lisp
@@ -93,7 +93,7 @@ module Fronde
93
93
  def reset
94
94
  # Reload config, taking default settings into account
95
95
  @config = load_settings
96
- @org_version = @sources = nil
96
+ @sources = nil
97
97
  @sources = load_sources
98
98
  end
99
99
 
@@ -109,7 +109,7 @@ module Fronde
109
109
  # @return [Fronde::Config::Store] self
110
110
  def load_test(config)
111
111
  @config = @default_settings.merge config
112
- @org_version = @sources = nil
112
+ @sources = nil
113
113
  @sources = load_sources
114
114
  self
115
115
  end
@@ -148,26 +148,48 @@ module Fronde
148
148
  end
149
149
  end
150
150
 
151
+ def check_duplicate_and_warn(collection, source, type)
152
+ path = source['path']
153
+ return path unless collection[type].has_key?(path)
154
+
155
+ warn(
156
+ R18n.t.fronde.error.source.duplicate(
157
+ source: source['name'], type: type
158
+ )
159
+ )
160
+ end
161
+
151
162
  def remove_duplicate(sources)
152
163
  check_paths = {}
153
164
  sources.each do |source|
154
165
  type = source.type
155
166
  check_paths[type] ||= {}
156
- path = source['path']
167
+ path = check_duplicate_and_warn check_paths, source, type
157
168
  # Avoid duplicate
158
- if check_paths[type].has_key?(path)
159
- warn(
160
- R18n.t.fronde.error.source.duplicate(
161
- source: source['name'], type: type
162
- )
163
- )
164
- next
165
- end
169
+ next unless path
170
+
166
171
  check_paths[type][path] = source
167
172
  end
168
173
  check_paths
169
174
  end
170
175
 
176
+ def filter_possible_matchs(path, other_paths_list)
177
+ other_paths_list.select do |other_path|
178
+ path != other_path && other_path.start_with?(path)
179
+ end
180
+ end
181
+
182
+ def warn_on_existing_inclusion(type, other, possible_matchs, sources)
183
+ possible_matchs.each do |match|
184
+ warn(
185
+ R18n.t.fronde.error.source.inclusion(
186
+ source: sources[match]['title'],
187
+ other_source: other, type: type
188
+ )
189
+ )
190
+ end
191
+ end
192
+
171
193
  def remove_inclusion(check_paths)
172
194
  check_paths.map do |type, sources_by_path|
173
195
  skip_paths = []
@@ -183,21 +205,13 @@ module Fronde
183
205
  next source unless source.recursive?
184
206
 
185
207
  # Ensure that the current source does not embed another one
186
- possible_matchs = sorted_paths.select do |other_path|
187
- path != other_path && other_path.start_with?(path)
188
- end
208
+ possible_matchs = filter_possible_matchs path, sorted_paths
189
209
  next source if possible_matchs.empty?
190
210
 
191
211
  skip_paths += possible_matchs
192
- possible_matchs.each do |match|
193
- other_source = sources_by_path[match]
194
- warn(
195
- R18n.t.fronde.error.source.inclusion(
196
- source: other_source['title'], type: type,
197
- other_source: source['title']
198
- )
199
- )
200
- end
212
+ warn_on_existing_inclusion(
213
+ type, source['title'], possible_matchs, sources_by_path
214
+ )
201
215
  end
202
216
  end.flatten
203
217
  end
data/lib/fronde/emacs.rb CHANGED
@@ -23,7 +23,7 @@ module Fronde
23
23
  warn cmd
24
24
  return system(cmd, exception: true)
25
25
  end
26
- system cmd, out: '/dev/null', err: '/dev/null', exception: true
26
+ system cmd, out: File::NULL, err: File::NULL, exception: true
27
27
  end
28
28
 
29
29
  def build_command(org_action)
@@ -4,11 +4,16 @@
4
4
  {% for index in indexes %}
5
5
  * {{ index.title }}
6
6
  :PROPERTIES:
7
- :HTML_CONTAINER_CLASS: index-tags
7
+ {%- if project_type == 'html' %}
8
+ :HTML_CONTAINER_CLASS: index-tags{% endif %}
8
9
  :UNNUMBERED: notoc
9
10
  :END:
10
11
 
11
12
  {% for tag in index.tags -%}
13
+ {%- if project_type == 'gemini' -%}
14
+ [[{{ domain }}{{ project_path }}tags/{{ tag.slug }}.gmi][{{ tag.title }} ({{ tag.weight }})]]
15
+ {%- else -%}
12
16
  - [[{{ domain }}{{ project_path }}tags/{{ tag.slug }}.html][{{ tag.title }}]] ({{ tag.weight }})
17
+ {%- endif %}
13
18
  {% endfor %}
14
19
  {%- endfor -%}
@@ -1,22 +1,26 @@
1
1
  #+title: {{ title }}
2
2
  #+author: {{ author }}
3
3
  #+language: {{ lang }}
4
- {%- unless slug == '__HOME_PAGE__' %}
4
+ {%- if project_type == 'html' and slug != '__HOME_PAGE__' %}
5
5
  #+html_head_extra: <link rel="alternate" type="application/atom+xml" title="{{ title }}" href="{{ domain }}{{ project_path }}feeds/{{ slug }}.xml" />
6
- {% endunless -%}
6
+ {% endif -%}
7
7
  {%- assign last_year = 0 -%}
8
8
  {% for article in entries %}
9
9
  {% assign cur_year = article.timekey | slice: 0, 4 %}
10
10
  {%- unless cur_year == last_year %}
11
11
  * {% if cur_year == "0000" %}{{ unsorted }}{% else %}{{ cur_year }}{% endif %}
12
12
  :PROPERTIES:
13
- :HTML_CONTAINER_CLASS: index-year
13
+ {%- if project_type == 'html' %}
14
+ :HTML_CONTAINER_CLASS: index-year{% endif %}
14
15
  :UNNUMBERED: notoc
15
16
  :END:
16
17
  {% assign last_year = cur_year %}
17
18
  {% endunless -%}
19
+ {%- if project_type == 'gemini' -%}
20
+ [[{{ article.url }}][{% if article.published != '' %}{{ article.published_gemini_index }} {% endif %}{{ article.title }}]]
21
+ {%- else -%}
18
22
  - *[[{{ article.url }}][{{ article.title }}]]*
19
23
  {%- if article.published != '' %} / {{ article.published }}{% endif -%}
20
24
  {%- if article.excerpt != '' %} \\
21
- {{ article.excerpt }}{% endif %}
25
+ {{ article.excerpt }}{% endif %}{% endif %}
22
26
  {%- endfor %}
@@ -56,6 +56,7 @@ module Fronde
56
56
  'title' => title,
57
57
  'slug' => slug,
58
58
  'project_path' => @project.public_absolute_path,
59
+ 'project_type' => @project.type,
59
60
  'domain' => Fronde::CONFIG.get('domain'),
60
61
  'lang' => Fronde::CONFIG.get('lang'),
61
62
  'author' => Fronde::CONFIG.get('author'),
@@ -81,6 +82,7 @@ module Fronde
81
82
  'author' => Fronde::CONFIG.get('author'),
82
83
  'domain' => Fronde::CONFIG.get('domain'),
83
84
  'project_path' => @project.public_absolute_path,
85
+ 'project_type' => @project.type,
84
86
  'indexes' => indexes
85
87
  )
86
88
  end
data/lib/fronde/index.rb CHANGED
@@ -30,26 +30,23 @@ module Fronde
30
30
 
31
31
  def sort_by(kind)
32
32
  accepted_values = %i[name weight]
33
- if accepted_values.include?(kind)
34
- tags_sorted = sort_tags_by_name_and_weight["by_#{kind}".to_sym]
35
- # Reverse in order to have most important or A near next prompt
36
- # and avoid to scroll to find the beginning of the list.
37
- return tags_sorted.map do |tag|
38
- @tags_names[tag] + " (#{@index[tag].length})"
39
- end.reverse
33
+ unless accepted_values.include?(kind)
34
+ error_msg = R18n.t.fronde.error.index.wrong_sort_kind(
35
+ kind: kind, accepted_values: accepted_values.inspect
36
+ )
37
+ raise ArgumentError, error_msg
40
38
  end
41
- error_msg = R18n.t.fronde.error.index.wrong_sort_kind(
42
- kind: kind, accepted_values: accepted_values.inspect
43
- )
44
- raise ArgumentError, error_msg
39
+ sort_tags_by_name_and_weight[:"by_#{kind}"].map do |tag|
40
+ @tags_names[tag] + " (#{@index[tag].length})"
41
+ end.reverse
42
+ # Reverse in order to have most important or A near next prompt
43
+ # and avoid to scroll to find the beginning of the list.
45
44
  end
46
45
 
47
46
  class << self
48
- def all_html_blog_index(&block)
47
+ def all_blog_index(&block)
49
48
  all_blogs = CONFIG.sources.filter_map do |project|
50
- next unless project['type'] == 'html' && project.blog?
51
-
52
- Index.new(project)
49
+ Index.new(project) if project.blog?
53
50
  end
54
51
  return all_blogs unless block
55
52
 
@@ -118,41 +118,53 @@ module Fronde
118
118
  #
119
119
  # *** Format:
120
120
  #
121
- # - %a :: the raw author name
121
+ # - %a :: the raw author name.
122
122
  # - %A :: the HTML rendering of the author name, equivalent to
123
- # ~<span class="author">%a</span>~
123
+ # ~<span class="author">%a</span>~.
124
124
  # - %d :: the ~:short~ date HTML representation, equivalent
125
- # to ~<time datetime="%I">%i</time>~
126
- # - %D :: the ~:full~ date and time HTML representation
127
- # - %i :: the raw ~:short~ date and time
128
- # - %I :: the raw ~:iso8601~ date and time
129
- # - %k :: the keywords separated by a comma
130
- # - %K :: the HTML list rendering of the keywords
131
- # - %l :: the lang of the document
125
+ # to ~<time datetime="%I">%i</time>~.
126
+ # - %D :: the ~:full~ date and time HTML representation.
127
+ # - %F :: the ~link~ HTML tag for the main Atom feed of the
128
+ # current file source.
129
+ # - %h :: the declared host/domain name, taken from the
130
+ # {Fronde::Config#settings}.
131
+ # - %i :: the raw ~:short~ date and time.
132
+ # - %I :: the raw ~:iso8601~ date and time.
133
+ # - %k :: the document keywords separated by commas.
134
+ # - %K :: the HTML list rendering of the keywords.
135
+ # - %l :: the lang of the document.
132
136
  # - %L :: the license information, taken from the
133
- # {Fronde::Config#settings}
134
- # - %n :: the Fronde name and version
135
- # - %N :: the Fronde name and version with a link to the project
136
- # home on the name
137
- # - %s :: the subtitle of the document
138
- # - %t :: the title of the document
139
- # - %u :: the URL to the related published HTML document
140
- # - %x :: the raw description (eXcerpt)
137
+ # {Fronde::Config#settings}.
138
+ # - %n :: the fronde name and version.
139
+ # - %N :: the fronde name and version with a link to the project
140
+ # home on the name.
141
+ # - %o :: the theme name (~o~ as in Outfit) of the current file source.
142
+ # - %s :: the subtitle of the document (from ~#+subtitle:~).
143
+ # - %t :: the title of the document (from ~#+title:~).
144
+ # - %u :: the URL to the related published HTML document.
145
+ # - %x :: the raw description (~x~ as in eXcerpt) of the document
146
+ # (from ~#+description:~).
141
147
  # - %X :: the description, enclosed in an HTML ~p~ tag, equivalent
142
- # to ~<p>%x</p>~
148
+ # to ~<p>%x</p>~.
143
149
  #
144
150
  # @example
145
151
  # org_file.format("Article written by %a the %d")
146
152
  # => "Article written by Alice Smith the Wednesday 3rd July"
147
153
  #
148
154
  # @return [String] the given ~string~ after replacement occurs
149
- # rubocop:disable Metrics/MethodLength
150
155
  # rubocop:disable Layout/LineLength
151
156
  def format(string)
157
+ project_data = @project.to_h
158
+ # NOTE: The following keycode are reserved by Org itself:
159
+ # %a (author), %c (creator), %C (input-file), %d (date),
160
+ # %e (email), %s (subtitle), %t (title), %T (timestamp),
161
+ # %v (html validation link)
152
162
  string.gsub('%a', @data[:author])
153
163
  .gsub('%A', "<span class=\"author\">#{@data[:author]}</span>")
154
164
  .gsub('%d', @data[:date].l18n_short_date_html)
155
165
  .gsub('%D', @data[:date].l18n_long_date_html)
166
+ .gsub('%F', project_data['atom_feed'] || '')
167
+ .gsub('%h', project_data['domain'] || '')
156
168
  .gsub('%i', @data[:date].l18n_short_date_string)
157
169
  .gsub('%I', @data[:date].xmlschema)
158
170
  .gsub('%k', @data[:keywords].join(', '))
@@ -161,6 +173,7 @@ module Fronde
161
173
  .gsub('%L', Fronde::CONFIG.get('license', '').gsub(/\s+/, ' ').strip)
162
174
  .gsub('%n', "Fronde #{Fronde::VERSION}")
163
175
  .gsub('%N', "<a href=\"https://git.umaneti.net/fronde/about/\">Fronde</a> #{Fronde::VERSION}")
176
+ .gsub('%o', project_data['theme'] || '')
164
177
  .gsub('%s', @data[:subtitle])
165
178
  .gsub('%t', @data[:title])
166
179
  .gsub('%u', @data[:url] || '')
@@ -168,7 +181,6 @@ module Fronde
168
181
  .gsub('%X', "<p>#{@data[:excerpt]}</p>")
169
182
  end
170
183
  # rubocop:enable Layout/LineLength
171
- # rubocop:enable Metrics/MethodLength
172
184
 
173
185
  # Writes the current Org::File content to the underlying file.
174
186
  #
@@ -215,6 +227,7 @@ module Fronde
215
227
  data['published_body'] = extract_published_body
216
228
  pub_date = @data[:date]
217
229
  data['published'] = pub_date.l18n_long_date_string(with_year: false)
230
+ data['published_gemini_index'] = pub_date.strftime('%Y-%m-%d')
218
231
  data['published_xml'] = pub_date.xmlschema
219
232
  data['updated_xml'] = @data[:updated]&.xmlschema
220
233
  data
@@ -228,8 +241,10 @@ module Fronde
228
241
  else
229
242
  source = find_source_for_publication_file
230
243
  end
231
- warn R18n.t.fronde.error.org_file.no_project(file: @file) unless source
232
- source
244
+ return source if source
245
+
246
+ short_file = @file.sub(/^#{Dir.pwd}/, '.')
247
+ warn R18n.t.fronde.error.org_file.no_project(file: short_file)
233
248
  end
234
249
 
235
250
  def find_source_for_org_file
@@ -250,20 +265,17 @@ module Fronde
250
265
  def init_empty_file
251
266
  @data = {
252
267
  title: @options[:title] || '', subtitle: '', excerpt: '',
253
- date: Time.now,
254
268
  author: @options[:author] || Fronde::CONFIG.get('author'),
255
- keywords: [],
256
269
  lang: @options[:lang] || Fronde::CONFIG.get('lang'),
257
- pub_file: nil, url: nil
270
+ date: Time.now, keywords: [], pub_file: nil, url: nil
258
271
  }
259
- body = @options[:content] || ''
260
272
  @data[:content] = @options[:raw_content] || <<~ORG
261
273
  #+title: #{@data[:title]}
262
274
  #+date: <#{@data[:date].strftime('%Y-%m-%d %a. %H:%M:%S')}>
263
275
  #+author: #{@data[:author]}
264
276
  #+language: #{@data[:lang]}
265
277
 
266
- #{body}
278
+ #{@options[:content]}
267
279
  ORG
268
280
  end
269
281
 
@@ -2,6 +2,8 @@
2
2
 
3
3
  using TimePatch
4
4
 
5
+ require_relative '../../ext/time_no_time'
6
+
5
7
  module Fronde
6
8
  module Org
7
9
  # This module holds extracter methods for the {Fronde::Org::File}
@@ -14,7 +16,7 @@ module Fronde
14
16
  def extract_data
15
17
  @data = { content: ::File.read(@file), pub_file: nil, url: nil }
16
18
  %i[title subtitle date author keywords lang excerpt].each do |param|
17
- @data[param] = send("extract_#{param}".to_sym)
19
+ @data[param] = send(:"extract_#{param}")
18
20
  end
19
21
  return unless @project
20
22
 
@@ -29,22 +31,19 @@ module Fronde
29
31
  match = daterx.match(@data[:content])
30
32
  return NilTime.new if match.nil?
31
33
 
32
- notime = match[2].nil?
33
- if notime
34
- time = '00:00:00'
35
- else
36
- time = "#{match[2]}:#{match[3] || '00'}"
37
- end
38
- date = Time.strptime("#{match[1]} #{time}", '%Y-%m-%d %H:%M:%S')
39
- date.no_time = notime
40
- date
34
+ return TimeNoTime.parse_no_time(match[1]) if match[2].nil?
35
+
36
+ Time.strptime(
37
+ "#{match[1]} #{match[2]}:#{match[3] || '00'}",
38
+ '%Y-%m-%d %H:%M:%S'
39
+ )
41
40
  end
42
41
 
43
42
  def extract_title
44
43
  match = /^#\+title:(.+)$/i.match(@data[:content])
45
44
  if match.nil?
46
45
  # Avoid to leak absolute path
47
- project_relative_path = @file.sub(/^#{Dir.pwd}\//, '')
46
+ project_relative_path = @file.sub %r{^#{Dir.pwd}/}, ''
48
47
  return project_relative_path
49
48
  end
50
49
  match[1].strip
@@ -81,13 +80,17 @@ module Fronde
81
80
  # Always return something, even when not published yet
82
81
  return @data[:excerpt] unless pub_file && @project
83
82
 
84
- project_type = @project['type']
83
+ project_type = @project.type
85
84
  pub_folder = Fronde::CONFIG.get("#{project_type}_public_folder")
86
85
  file_name = pub_folder + pub_file
87
86
  return @data[:excerpt] unless ::File.exist? file_name
88
87
 
89
88
  return ::File.read(file_name) if project_type == 'gemini'
90
89
 
90
+ read_html_body file_name
91
+ end
92
+
93
+ def read_html_body(file_name)
91
94
  dom = ::File.open(file_name, 'r') { |file| Nokogiri::HTML file }
92
95
  body = dom.css('div#content')
93
96
  body.css('header').unlink # Remove the main title
data/lib/fronde/org.rb CHANGED
@@ -55,23 +55,25 @@ module Fronde
55
55
  # @param destination [String] where to save the org-mode tarball
56
56
  # @return [String] the downloaded org-mode version
57
57
  def download(destination = 'var/tmp')
58
- # Remove version number in dest file to allow easy rake file
59
- # task naming
60
- dest_file = ::File.expand_path('org.tar.gz', destination)
61
58
  org_last_version = last_version(force: false, cookie_dir: destination)
62
59
  tarball = "org-mode-release_#{org_last_version}.tar.gz"
63
60
  uri = URI("https://git.savannah.gnu.org/cgit/emacs/org-mode.git/snapshot/#{tarball}")
64
61
  # Will crash on purpose if anything goes wrong
65
62
  Net::HTTP.start(uri.host) do |http|
66
- request = Net::HTTP::Get.new uri
63
+ fetch_org_tarball http, Net::HTTP::Get.new(uri), destination
64
+ end
65
+ org_last_version
66
+ end
67
67
 
68
- http.request request do |response|
69
- ::File.open(dest_file, 'w') do |io|
70
- response.read_body { |chunk| io.write chunk }
71
- end
68
+ def fetch_org_tarball(http, request, destination)
69
+ # Remove version number in dest file to allow easy rake file
70
+ # task naming
71
+ dest_file = ::File.expand_path('org.tar.gz', destination)
72
+ http.request request do |response|
73
+ ::File.open(dest_file, 'w') do |io|
74
+ response.read_body { |chunk| io.write chunk }
72
75
  end
73
76
  end
74
- org_last_version
75
77
  end
76
78
 
77
79
  def make_org_cmd(org_dir, target, verbose: false)
data/lib/fronde/slug.rb CHANGED
@@ -5,23 +5,50 @@ module Fronde
5
5
  module Slug
6
6
  class << self
7
7
  def slug(title)
8
- title.downcase.tr(' ', '-')
8
+ title.downcase
9
9
  .encode('ascii', fallback: ->(k) { translit(k) })
10
- .gsub(/[^\w-]/, '').delete_suffix('-')
10
+ .encode('utf-8') # Convert back to utf-8 string
11
+ .gsub(/[^\w-]/, '-')
12
+ .squeeze('-')
13
+ .delete_suffix('-')
11
14
  end
12
15
 
16
+ # rubocop:disable Metrics/CyclomaticComplexity
17
+ # rubocop:disable Metrics/MethodLength
13
18
  def translit(char)
14
- return 'a' if %w[á à â ä ǎ ã å].include?(char)
15
- return 'e' if %w[é è ê ë ě ẽ].include?(char)
16
- return 'i' if %w[í ì î ï ǐ ĩ].include?(char)
17
- return 'o' if %w[ó ò ô ö ǒ õ].include?(char)
18
- return 'u' if %w[ú ù û ü ǔ ũ].include?(char)
19
- return 'y' if %w[ý ŷ ÿ ỹ].include?(char)
20
- return 'c' if char == 'ç'
21
- return 'n' if char == 'ñ'
22
-
23
- '-'
19
+ case char
20
+ when 'á', 'à', 'â', 'ä', 'ǎ', 'ã', 'å'
21
+ 'a'
22
+ when 'é', 'è', 'ê', 'ë', 'ě', 'ẽ', '€'
23
+ 'e'
24
+ when 'í', 'ì', 'î', 'ï', 'ǐ', 'ĩ'
25
+ 'i'
26
+ when 'ó', 'ò', 'ô', 'ö', 'ǒ', 'õ', 'ø'
27
+ 'o'
28
+ when 'ú', 'ù', 'û', 'ü', 'ǔ', 'ũ'
29
+ 'u'
30
+ when 'ý', 'ỳ', 'ŷ', 'ÿ', 'ỹ'
31
+ 'y'
32
+ when 'ç', '©', '🄯'
33
+ 'c'
34
+ when 'ñ'
35
+ 'n'
36
+ when 'ß'
37
+ 'ss'
38
+ when 'œ'
39
+ 'oe'
40
+ when 'æ'
41
+ 'ae'
42
+ when '®'
43
+ 'r'
44
+ when '™'
45
+ 'tm'
46
+ else
47
+ '-'
48
+ end
24
49
  end
50
+ # rubocop:enable Metrics/CyclomaticComplexity
51
+ # rubocop:enable Metrics/MethodLength
25
52
  end
26
53
  end
27
54
  end
@@ -4,11 +4,6 @@ module Fronde
4
4
  class Source
5
5
  # Specific settings for Gemini {Fronde::Source}
6
6
  class Gemini < Source
7
- def blog?
8
- # TODO: See how to support blog/indexes with gemini
9
- false
10
- end
11
-
12
7
  class << self
13
8
  def org_default_postamble
14
9
  format(
@@ -40,12 +40,12 @@ module Fronde
40
40
  super
41
41
  end
42
42
 
43
- def org_default_options # rubocop:disable Metrics/MethodLength
43
+ def org_default_options
44
44
  defaults = {
45
45
  'publishing-function' => 'org-html-publish-to-html',
46
46
  'html-head-include-default-style' => 't',
47
47
  'html-head-include-scripts' => 't',
48
- 'html-head' => '{{ atom_feed }}',
48
+ 'html-head' => '%F',
49
49
  'html-postamble' => Html.org_default_postamble
50
50
  }
51
51
  return defaults if @config['theme'] == 'default'
@@ -55,10 +55,10 @@ module Fronde
55
55
  'html-head-include-scripts' => 'nil',
56
56
  'html-head' => <<~HTMLHEAD
57
57
  <link rel="stylesheet" type="text/css" media="screen"
58
- href="{{ domain }}/assets/{{ theme }}/css/style.css">
58
+ href="%h/assets/%o/css/style.css">
59
59
  <link rel="stylesheet" type="text/css" media="screen"
60
- href="{{ domain }}/assets/{{ theme }}/css/htmlize.css">
61
- {{ atom_feed }}
60
+ href="%h/assets/%o/css/htmlize.css">
61
+ %F
62
62
  HTMLHEAD
63
63
  )
64
64
  end
data/lib/fronde/source.rb CHANGED
@@ -147,7 +147,7 @@ module Fronde
147
147
 
148
148
  def clean_config
149
149
  fill_in_specific_config
150
- @config['name'] ||= @config['path'].sub(/^[.~]*\//, '').tr('/.', '-')
150
+ @config['name'] ||= @config['path'].sub(%r{^[.~]*/}, '').tr('/.', '-')
151
151
  @config['title'] ||= @config['path']
152
152
  @config['target'] ||= File.basename(@config['path']).delete_prefix '.'
153
153
  @config['target'] = '' if @config['target'] == '.'
@@ -168,12 +168,16 @@ module Fronde
168
168
  end
169
169
 
170
170
  def render_heading
171
- heading_key = "#{@config['type']}-head"
172
- heading = @config.dig 'org-options', heading_key
173
- @config['org-options'][heading_key] = \
174
- Config::Helpers.render_liquid_template(
175
- heading, to_h
176
- )
171
+ %w[head head-extra preamble postamble].each do |kind|
172
+ heading_key = "#{@config['type']}-#{kind}"
173
+ heading = @config.dig 'org-options', heading_key
174
+ next unless heading
175
+
176
+ @config['org-options'][heading_key] =
177
+ heading.gsub('%F', @config['atom_feed'])
178
+ .gsub('%h', @config['domain'])
179
+ .gsub('%o', @config['theme'])
180
+ end
177
181
  end
178
182
 
179
183
  def org_project_config
@@ -181,7 +185,8 @@ module Fronde
181
185
  'base-directory' => @config['path'],
182
186
  'base-extension' => 'org',
183
187
  'publishing-directory' => publication_path,
184
- 'recursive' => @config['recursive']
188
+ 'recursive' => @config['recursive'],
189
+ 'fronde-base-uri' => "#{@config['domain']}#{public_absolute_path}"
185
190
  }.merge(@config['org-options'])
186
191
  exclude = @config['exclude']
187
192
  attributes['exclude'] = exclude if exclude