fronde 0.3.4 → 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.
- checksums.yaml +4 -4
- data/bin/fronde +15 -30
- data/lib/ext/nil_time.rb +25 -0
- data/lib/ext/r18n.rb +37 -0
- data/lib/ext/time.rb +39 -0
- data/lib/ext/time_no_time.rb +23 -0
- data/lib/fronde/cli/commands.rb +97 -104
- data/lib/fronde/cli/data/Rakefile +8 -0
- data/lib/fronde/cli/data/config.yml +13 -0
- data/lib/fronde/cli/data/gitignore +6 -0
- data/lib/fronde/cli/data/zsh_completion +37 -0
- data/lib/fronde/cli/helpers.rb +55 -0
- data/lib/fronde/cli/opt_parse.rb +140 -0
- data/lib/fronde/cli/throbber.rb +110 -0
- data/lib/fronde/cli.rb +42 -42
- data/lib/fronde/config/data/org-config.el +25 -0
- data/lib/fronde/config/data/ox-fronde.el +158 -0
- data/lib/fronde/config/data/themes/umaneti/css/htmlize.css +364 -0
- data/lib/fronde/config/data/themes/umaneti/css/style.css +250 -0
- data/lib/fronde/config/data/themes/umaneti/img/bottom.png +0 -0
- data/lib/fronde/config/data/themes/umaneti/img/content.png +0 -0
- data/lib/fronde/config/data/themes/umaneti/img/tic.png +0 -0
- data/lib/fronde/config/data/themes/umaneti/img/top.png +0 -0
- data/lib/fronde/config/helpers.rb +62 -0
- data/lib/fronde/config/lisp.rb +80 -0
- data/lib/fronde/config.rb +148 -98
- data/lib/fronde/emacs.rb +23 -20
- data/lib/fronde/index/atom_generator.rb +55 -66
- data/lib/fronde/index/data/all_tags.org +19 -0
- data/lib/fronde/index/data/template.org +26 -0
- data/lib/fronde/index/data/template.xml +37 -0
- data/lib/fronde/index/org_generator.rb +72 -88
- data/lib/fronde/index.rb +57 -86
- data/lib/fronde/org/file.rb +299 -0
- data/lib/fronde/org/file_extracter.rb +101 -0
- data/lib/fronde/org.rb +105 -0
- data/lib/fronde/preview.rb +43 -39
- data/lib/fronde/slug.rb +54 -0
- data/lib/fronde/source/gemini.rb +34 -0
- data/lib/fronde/source/html.rb +67 -0
- data/lib/fronde/source.rb +209 -0
- data/lib/fronde/sync/neocities.rb +220 -0
- data/lib/fronde/sync/rsync.rb +46 -0
- data/lib/fronde/sync.rb +32 -0
- data/lib/fronde/templater.rb +101 -71
- data/lib/fronde/version.rb +1 -1
- data/lib/tasks/cli.rake +33 -0
- data/lib/tasks/org.rake +58 -43
- data/lib/tasks/site.rake +66 -31
- data/lib/tasks/sync.rake +37 -40
- data/lib/tasks/tags.rake +11 -7
- data/locales/en.yml +61 -14
- data/locales/fr.yml +69 -14
- metadata +77 -95
- data/lib/fronde/config/lisp_config.rb +0 -340
- data/lib/fronde/config/org-config.el +0 -19
- data/lib/fronde/config/ox-fronde.el +0 -121
- data/lib/fronde/org_file/class_methods.rb +0 -72
- data/lib/fronde/org_file/extracter.rb +0 -72
- data/lib/fronde/org_file/htmlizer.rb +0 -43
- data/lib/fronde/org_file.rb +0 -298
- data/lib/fronde/utils.rb +0 -229
@@ -0,0 +1,37 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<feed xmlns="http://www.w3.org/2005/Atom"
|
3
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
4
|
+
xml:lang="{{ lang }}">
|
5
|
+
|
6
|
+
<title>{{ title | escape }}</title>
|
7
|
+
<link href="{{ domain }}/feeds/{{ slug }}.xml" rel="self" type="application/atom+xml"/>
|
8
|
+
<link href="{{ tagurl }}" rel="alternate" type="text/html" title="{{ title }}"/>
|
9
|
+
<updated>{{ upddate }}</updated>
|
10
|
+
<author><name>{{ author }}</name></author>
|
11
|
+
<id>urn:md5:{{ domain | md5 }}</id>
|
12
|
+
<generator uri="https://git.umaneti.net/fronde/about/">Fronde</generator>
|
13
|
+
|
14
|
+
{%- for article in entries %}
|
15
|
+
|
16
|
+
<entry>
|
17
|
+
<title>{{ article.title | escape }}</title>
|
18
|
+
<link href="{{ article.url }}" rel="alternate"
|
19
|
+
type="{{ publication_format }}"
|
20
|
+
title="{{ article.title }}"/>
|
21
|
+
<id>urn:md5:{{ article.timekey | md5 }}</id>
|
22
|
+
<published>{{ article.published_xml }}</published>
|
23
|
+
<updated>{{ article.updated_xml }}</updated>
|
24
|
+
<author><name>{{ article.author | escape }}</name></author>
|
25
|
+
{%- for keyword in article.keywords %}
|
26
|
+
<dc:subject>{{ keyword | escape }}</dc:subject>
|
27
|
+
{%- endfor %}
|
28
|
+
{%- if publication_format == 'text/html' %}
|
29
|
+
<content type="html">
|
30
|
+
{%- else %}
|
31
|
+
<content>
|
32
|
+
{%- endif %}
|
33
|
+
{{- article.published_body | escape -}}
|
34
|
+
</content>
|
35
|
+
</entry>
|
36
|
+
{%- endfor %}
|
37
|
+
</feed>
|
@@ -1,114 +1,98 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
using TimePatch
|
4
|
+
|
3
5
|
module Fronde
|
4
|
-
#
|
5
|
-
# index.
|
6
|
-
|
7
|
-
def
|
8
|
-
|
6
|
+
# Reopen Index class to embed methods responsible for generating an
|
7
|
+
# org file for a given index.
|
8
|
+
class Index
|
9
|
+
def blog_home_page
|
10
|
+
org_index @project['title'], '__HOME_PAGE__', @entries.map(&:to_h)
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_org(index_name = 'index')
|
9
14
|
return all_tags_index if index_name == 'index'
|
10
|
-
|
11
|
-
|
15
|
+
|
16
|
+
org_index(
|
17
|
+
@tags_names[index_name], index_name,
|
18
|
+
(@index[index_name] || []).map(&:to_h)
|
19
|
+
)
|
12
20
|
end
|
13
21
|
alias_method :to_s, :to_org
|
14
22
|
|
15
23
|
def write_org(index_name)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
content = to_org index_name
|
20
|
-
orgdest = "tags/#{slug}.org"
|
21
|
-
File.write(orgdest, content)
|
24
|
+
slug = Slug.slug index_name
|
25
|
+
orgdest = "#{@project['path']}/tags/#{slug}.org"
|
26
|
+
File.write orgdest, to_org(index_name)
|
22
27
|
end
|
23
28
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
content += org_articles(@projects[project_name])
|
29
|
+
def write_all_org(verbose: true)
|
30
|
+
FileUtils.mkdir_p "#{@project['path']}/tags"
|
31
|
+
@index.each_key do |tag|
|
32
|
+
write_org(tag)
|
33
|
+
warn R18n.t.fronde.index.index_generated(tag: tag) if verbose
|
30
34
|
end
|
31
|
-
|
35
|
+
write_blog_home_page(verbose)
|
32
36
|
end
|
33
37
|
|
34
|
-
|
35
|
-
Fronde::Config.sources.each do |project|
|
36
|
-
next unless project['is_blog']
|
37
|
-
next unless Dir.exist?(project['path'])
|
38
|
-
warn "Generated blog home for #{project['name']}" if verbose
|
39
|
-
orgdest = format('%<root>s/index.org', root: project['path'])
|
40
|
-
File.write(orgdest, to_org(project['name'], is_project: true))
|
41
|
-
end
|
42
|
-
end
|
38
|
+
private
|
43
39
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
40
|
+
# Render an Org index file.
|
41
|
+
#
|
42
|
+
# @param title [String] the title of the current org index
|
43
|
+
# @param slug [String] the slug of the current org index
|
44
|
+
# @param entries [Array] the article to list in this file
|
45
|
+
# @return [String] the org file content as a String
|
46
|
+
def org_index(title, slug, entries)
|
47
|
+
entries.map! do |article|
|
48
|
+
published = article['published']
|
49
|
+
unless published == ''
|
50
|
+
article['published'] = R18n.t.fronde.index.published_on published
|
54
51
|
end
|
52
|
+
article
|
55
53
|
end
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
54
|
+
Config::Helpers.render_liquid_template(
|
55
|
+
File.read(File.expand_path('./data/template.org', __dir__)),
|
56
|
+
'title' => title,
|
57
|
+
'slug' => slug,
|
58
|
+
'project_path' => @project.public_absolute_path,
|
59
|
+
'project_type' => @project.type,
|
60
|
+
'domain' => Fronde::CONFIG.get('domain'),
|
61
|
+
'lang' => Fronde::CONFIG.get('lang'),
|
62
|
+
'author' => Fronde::CONFIG.get('author'),
|
63
|
+
'unsorted' => R18n.t.fronde.index.unsorted,
|
64
|
+
'entries' => entries
|
65
|
+
)
|
64
66
|
end
|
65
67
|
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
#+title: #{title}
|
74
|
-
#+author: #{Fronde::Config.get('author')}
|
75
|
-
#+language: #{Fronde::Config.get('lang')}
|
76
|
-
HEADER
|
77
|
-
end
|
78
|
-
|
79
|
-
def org_articles(articles_list)
|
80
|
-
last_year = nil
|
81
|
-
articles_list.map do |article|
|
82
|
-
year_title = ''
|
83
|
-
year = article.timekey.slice(0, 4)
|
84
|
-
if year != last_year
|
85
|
-
year_title = format("\n%<title>s\n", title: org_title(year))
|
86
|
-
last_year = year
|
68
|
+
def all_tags_index
|
69
|
+
indexes = sort_tags_by_name_and_weight.map do |title, tags|
|
70
|
+
all_tags = tags.map do |tag|
|
71
|
+
{
|
72
|
+
'slug' => tag, 'title' => @tags_names[tag],
|
73
|
+
'weight' => @index[tag].length
|
74
|
+
}
|
87
75
|
end
|
88
|
-
|
76
|
+
{ 'title' => R18n.t.fronde.index.send(title), 'tags' => all_tags }
|
89
77
|
end
|
78
|
+
Config::Helpers.render_liquid_template(
|
79
|
+
File.read(File.expand_path('./data/all_tags.org', __dir__)),
|
80
|
+
'title' => R18n.t.fronde.index.all_tags,
|
81
|
+
'lang' => Fronde::CONFIG.get('lang'),
|
82
|
+
'author' => Fronde::CONFIG.get('author'),
|
83
|
+
'domain' => Fronde::CONFIG.get('domain'),
|
84
|
+
'project_path' => @project.public_absolute_path,
|
85
|
+
'project_type' => @project.type,
|
86
|
+
'indexes' => indexes
|
87
|
+
)
|
90
88
|
end
|
91
89
|
|
92
|
-
def
|
93
|
-
|
94
|
-
if
|
95
|
-
|
96
|
-
published = R18n.t.fronde.index.published_on art_date
|
97
|
-
line += " / #{published}"
|
90
|
+
def write_blog_home_page(verbose)
|
91
|
+
orgdest = format('%<root>s/index.org', root: @project['path'])
|
92
|
+
if verbose
|
93
|
+
warn R18n.t.fronde.org.generate_blog_index(name: @project['name'])
|
98
94
|
end
|
99
|
-
|
100
|
-
line
|
101
|
-
end
|
102
|
-
|
103
|
-
def org_title(year, html_class = 'index-year')
|
104
|
-
year = R18n.t.fronde.index.unsorted if year == '0000'
|
105
|
-
<<~ENDPROP
|
106
|
-
* #{year}
|
107
|
-
:PROPERTIES:
|
108
|
-
:HTML_CONTAINER_CLASS: #{html_class}
|
109
|
-
:UNNUMBERED: notoc
|
110
|
-
:END:
|
111
|
-
ENDPROP
|
95
|
+
File.write(orgdest, blog_home_page)
|
112
96
|
end
|
113
97
|
end
|
114
98
|
end
|
data/lib/fronde/index.rb
CHANGED
@@ -1,11 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
require 'fronde/org_file'
|
7
|
-
require 'fronde/index/atom_generator'
|
8
|
-
require 'fronde/index/org_generator'
|
3
|
+
require_relative 'slug'
|
4
|
+
require_relative 'config'
|
5
|
+
require_relative 'org/file'
|
9
6
|
|
10
7
|
module Fronde
|
11
8
|
# Generates website indexes and atom feeds for all the org documents
|
@@ -13,118 +10,92 @@ module Fronde
|
|
13
10
|
class Index
|
14
11
|
attr_reader :date
|
15
12
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
def initialize
|
20
|
-
@pubdir = Fronde::Config.get('public_folder')
|
13
|
+
def initialize(project)
|
14
|
+
@project = project
|
21
15
|
@index = { 'index' => [] }
|
22
|
-
@
|
16
|
+
@entries = []
|
23
17
|
@tags_names = {}
|
24
|
-
@date =
|
25
|
-
|
26
|
-
|
18
|
+
@date = Time.now
|
19
|
+
generate_feeds if @project.blog?
|
20
|
+
sort_feeds!
|
27
21
|
end
|
28
22
|
|
29
|
-
def
|
30
|
-
@index.keys.reject { |
|
23
|
+
def all_tags
|
24
|
+
@index.keys.reject { |tag| tag == 'index' }
|
31
25
|
end
|
32
26
|
|
33
27
|
def empty?
|
34
28
|
@index['index'].empty?
|
35
29
|
end
|
36
30
|
|
37
|
-
def
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
31
|
+
def sort_by(kind)
|
32
|
+
accepted_values = %i[name weight]
|
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
|
43
38
|
end
|
44
|
-
|
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
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
return
|
53
|
-
|
54
|
-
|
46
|
+
class << self
|
47
|
+
def all_blog_index(&block)
|
48
|
+
all_blogs = CONFIG.sources.filter_map do |project|
|
49
|
+
Index.new(project) if project.blog?
|
50
|
+
end
|
51
|
+
return all_blogs unless block
|
52
|
+
|
53
|
+
all_blogs.each(&block)
|
55
54
|
end
|
56
|
-
raise ArgumentError, "#{kind} not in [:name, :weight]"
|
57
55
|
end
|
58
56
|
|
59
57
|
private
|
60
58
|
|
61
|
-
def
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
Dir.glob(file_pattern, base: project['path']).map do |s|
|
70
|
-
org_file = File.join(project['path'], s)
|
71
|
-
next if exclude_file?(org_file, project)
|
72
|
-
add_to_indexes(
|
73
|
-
Fronde::OrgFile.new(org_file, project: project)
|
74
|
-
)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
59
|
+
def generate_feeds
|
60
|
+
file_pattern = '**/*.org'
|
61
|
+
Dir.glob(file_pattern, base: @project['path']).map do |index_file|
|
62
|
+
# Obviously don't parse tags
|
63
|
+
next if index_file.start_with?('tags/')
|
64
|
+
|
65
|
+
org_file = File.join(@project['path'], index_file)
|
66
|
+
next if @project.exclude_file? org_file
|
78
67
|
|
79
|
-
|
80
|
-
|
81
|
-
@projects[project['name']] ||= []
|
82
|
-
@projects[project['name']] << article
|
68
|
+
add_to_indexes(Org::File.new(org_file))
|
69
|
+
end
|
83
70
|
end
|
84
71
|
|
85
72
|
def add_to_indexes(article)
|
86
73
|
@index['index'] << article
|
87
|
-
|
88
|
-
article.keywords.each do |
|
89
|
-
slug =
|
90
|
-
@tags_names[slug] =
|
74
|
+
@entries << article
|
75
|
+
article.keywords.each do |tag|
|
76
|
+
slug = Slug.slug tag
|
77
|
+
@tags_names[slug] = tag # Overwrite is permitted
|
91
78
|
@index[slug] ||= []
|
92
79
|
@index[slug] << article
|
93
80
|
end
|
94
81
|
end
|
95
82
|
|
96
|
-
def
|
97
|
-
@index.
|
98
|
-
|
99
|
-
end
|
100
|
-
@projects.each do |k, i|
|
101
|
-
@projects[k] = i.sort { |a, b| b.timekey <=> a.timekey }
|
83
|
+
def sort_feeds!
|
84
|
+
@index.transform_values! do |articles|
|
85
|
+
articles.sort_by(&:timekey).reverse
|
102
86
|
end
|
87
|
+
@entries = @entries.sort_by(&:timekey).reverse
|
103
88
|
end
|
104
89
|
|
105
90
|
def sort_tags_by_name_and_weight
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
end
|
112
|
-
tags_sorted
|
113
|
-
end
|
114
|
-
|
115
|
-
def exclude_file?(file_path, project)
|
116
|
-
# Obviously excluding index itself for blogs
|
117
|
-
return true if file_path == File.join(project['path'], 'index.org')
|
118
|
-
return false unless project['exclude']
|
119
|
-
file_path.match? project['exclude']
|
120
|
-
end
|
121
|
-
|
122
|
-
def save?
|
123
|
-
return true unless empty?
|
124
|
-
Fronde::Config.sources.each do |project|
|
125
|
-
return true if project['is_blog'] && Dir.exist?(project['path'])
|
126
|
-
end
|
127
|
-
false
|
91
|
+
all_keys = all_tags
|
92
|
+
{
|
93
|
+
by_name: all_keys.sort,
|
94
|
+
by_weight: all_keys.sort_by { @index[_1].length }.reverse
|
95
|
+
}
|
128
96
|
end
|
129
97
|
end
|
130
98
|
end
|
99
|
+
|
100
|
+
require_relative 'index/org_generator'
|
101
|
+
require_relative 'index/atom_generator'
|