fronde 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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