hyde-fonts 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ef7f7a15334f4df1f96be84e4c34b6e5b63500170c559ec590e36379c03695f3
4
+ data.tar.gz: f3cfdf6988e1de02511abce55f29c39a940c4090140c323971fda3aa8ca2005d
5
+ SHA512:
6
+ metadata.gz: 07d8d6fdd0a29e3d458d40ec1ccff14d4952b94891b3c5aee73405d626943e894e38b8a3b9182241e6b4e7e12d25dda210f5407e3b28fa196d9ada950f29c14f
7
+ data.tar.gz: 65ccfe4b9510c92d7a05b700f4dbb84ac1fe456fa2893f58637c9d2c87a72c30c1b52b8ef66909f78613be732705041f9c533c2d2d2b885dcb4ac0e19e8e05cc
@@ -0,0 +1,24 @@
1
+ module Hyde
2
+ class FontData
3
+ attr_reader :faces
4
+
5
+ def initialize(data)
6
+ @data = data
7
+ @faces = []
8
+ @sizes = []
9
+
10
+ return unless @data
11
+
12
+ parse_faces
13
+ end
14
+
15
+ def parse_faces
16
+
17
+ for face in @data['faces'] do
18
+ faces.push(Hyde::FontFace.new(face))
19
+ end
20
+
21
+ return faces
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,38 @@
1
+ module Hyde
2
+ class FontFace
3
+ attr_reader :provider
4
+ attr_accessor :css
5
+
6
+ def initialize(face)
7
+ @name = face['name']
8
+ @provider = face['provider']
9
+ @weights = face['weights']
10
+ @variants = parse_variants
11
+ @css = []
12
+ end
13
+
14
+ def sort_variants
15
+ @variants.sort do |a, b|
16
+ (a.italic == b.italic) ? a.weight <=> b.weight : a.italic <=> b.italic
17
+ end
18
+ end
19
+
20
+ def to_s
21
+ variants = sort_variants.map { |variant| variant.to_s }
22
+
23
+ @name + ':ital,wght@' + variants.join(';')
24
+ end
25
+
26
+ private
27
+
28
+ def parse_variants
29
+ variants = []
30
+
31
+ for variant in @weights
32
+ variants.push(Hyde::FontVariant.new(weight: variant['value'], italic: variant['italic']))
33
+ end
34
+
35
+ return variants
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,28 @@
1
+ module Hyde
2
+ class FontRuleset
3
+ attr_reader :filename, :char_set, :family, :style, :weight, :uri, :format, :ruleset, :local_rule_set
4
+
5
+ def initialize(raw_css_ruleset)
6
+ @ruleset = raw_css_ruleset
7
+
8
+ /\/\* (?'character_set'.*) \*\// =~ raw_css_ruleset
9
+ /^\s*font-family:\s'(?'family'[\w]*)';$/ =~ raw_css_ruleset
10
+ /^\s*font-style:\s(?'style'[\w]*);$/ =~ raw_css_ruleset
11
+ /^\s*font-weight:\s(?'weight'[\w]*);$/ =~ raw_css_ruleset
12
+ /\s\ssrc:\surl\((?'uri'.*)\)\s.*\('(?'format'.*)'\);$$/ =~ raw_css_ruleset
13
+
14
+ @char_set = character_set
15
+ @family = family
16
+ @style = style
17
+ @weight = weight
18
+ @uri = URI(uri)
19
+ @format = format
20
+
21
+ @filename = [@family, @style, @weight, @char_set + '.' + @format].join('_')
22
+ end
23
+
24
+ def local_ruleset(path)
25
+ @ruleset.gsub(/(?<=url\().*(?=\)\s)/, '/' + File.join(path, @filename))
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ module Hyde
2
+ class FontVariant
3
+ attr_reader :italic, :weight
4
+
5
+ def initialize(weight:, italic:)
6
+ @weight = weight
7
+ @italic = 0
8
+
9
+ if italic == true
10
+ @italic = 1
11
+ end
12
+ end
13
+
14
+ def to_s
15
+ @italic.to_s + ',' + @weight.to_s
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,33 @@
1
+ module Hyde
2
+ # Alternative class for jekyll's static files
3
+ # this allows the creation of files without a source file
4
+
5
+ class GeneratedCssFile < Jekyll::StaticFile
6
+ attr_accessor :file_contents
7
+ attr_reader :generator, :x
8
+
9
+ def initialize(site, dir, name)
10
+ @site = site
11
+ @dir = dir
12
+ @name = name
13
+ @relative_path = File.join(*[@dir, @name].compact)
14
+ @extname = File.extname(@name)
15
+ @type = @collection&.label&.to_sym
16
+ @generator = 'hyde_fonts'
17
+ end
18
+
19
+ def write(dest)
20
+ dest_path = destination(dest)
21
+ return false if File.exist?(dest_path)
22
+
23
+ FileUtils.mkdir_p(File.dirname(dest_path))
24
+ FileUtils.rm(dest_path) if File.exist?(dest_path)
25
+
26
+ File.open(dest_path, 'w') do |output_file|
27
+ output_file << file_contents
28
+ end
29
+
30
+ true
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,34 @@
1
+ module Hyde
2
+ # Alternative class for jekyll's static files
3
+ # this allows the creation of files without a source file
4
+
5
+ class GeneratedFontFile < Jekyll::StaticFile
6
+ attr_accessor :file_contents
7
+ attr_reader :generator, :dest_path
8
+
9
+ def initialize(site, dir, name)
10
+ @site = site
11
+ @dir = dir
12
+ @name = name
13
+ @relative_path = File.join(*[@dir, @name].compact)
14
+ @extname = File.extname(@name)
15
+ @type = @collection&.label&.to_sym
16
+ @generator = 'hyde_fonts'
17
+ @dest_path = ''
18
+ end
19
+
20
+ def write(dest)
21
+ return false if File.exist?(dest_path)
22
+
23
+ @dest_path = destination(dest)
24
+ FileUtils.mkdir_p(File.dirname(dest_path))
25
+ FileUtils.rm(dest_path) if File.exist?(dest_path)
26
+
27
+ File.open(dest_path, 'w') do |output_file|
28
+ output_file << file_contents
29
+ end
30
+
31
+ true
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,111 @@
1
+ require 'jekyll'
2
+ require_relative 'font_data.rb'
3
+ require_relative 'font_face.rb'
4
+ require_relative 'font_ruleset.rb'
5
+ require_relative 'font_variant.rb'
6
+ require_relative 'generated_css_file.rb'
7
+ require_relative 'generated_font_file.rb'
8
+ require_relative 'provider_google.rb'
9
+
10
+ module Jekyll
11
+ class HydeFontsTag < Liquid::Tag
12
+ def initialize(tag_name, text, tokens)
13
+ super
14
+
15
+ @tag_name = tag_name
16
+ @text = text.strip
17
+ @tokens = tokens
18
+ end
19
+
20
+ def render(context)
21
+ config = context.registers[:site].config['hyde_fonts']
22
+ return unless config['enable'] == true
23
+
24
+ file = context.registers[:site].static_files.find { |file|
25
+ file.is_a?(Hyde::GeneratedCssFile)
26
+ }
27
+
28
+ if @text == 'inline'
29
+ file.file_contents
30
+ else
31
+ "<link href='" + file.relative_path + "' rel='stylesheet'>"
32
+ end
33
+ end
34
+ end
35
+
36
+ Liquid::Template.register_tag('hyde_fonts', Jekyll::HydeFontsTag)
37
+
38
+ class HydeFontsGenerator < Generator
39
+ def generate(site)
40
+ Hyde::Fonts.new(site).generate()
41
+ end
42
+ end
43
+ end
44
+
45
+ module Hyde
46
+ class Fonts
47
+ @@config = {
48
+ "data_path" => 'fonts',
49
+ "file_output_path" => 'assets/fonts',
50
+ "css_output_name" => 'fonts.css',
51
+ "css_minify" => true,
52
+ "enable" => true,
53
+ "fetch_fonts" => true,
54
+ "keep_files" => false
55
+ }
56
+
57
+ def initialize(site)
58
+ @site = site
59
+ @config = site.config.dig('hyde_fonts') || @@config
60
+
61
+ if config('keep_files') == true
62
+ @site.config['keep_files'].push(config('file_output_path'))
63
+ end
64
+
65
+ if site.config.dig('hyde_fonts').nil?
66
+ @site.config['hyde_fonts'] = @config
67
+ end
68
+ end
69
+
70
+ def generate
71
+ # get faces from jekyll data file
72
+ font_data = Hyde::FontData.new(data)
73
+
74
+ # handle font providers
75
+ for face in font_data.faces
76
+ case face.provider
77
+ when 'google'
78
+ Hyde::FontProviderGoogle.new(@site, @config).fetch(face)
79
+ when 'local'
80
+ # TODO handle local fonts
81
+ # Hyde::FontProviderLocal.new(@site, @config).fetch(face)
82
+ end
83
+ end
84
+
85
+ css = font_data.faces.map { |face| face.css }
86
+ # generate static file containing face css rulesets
87
+ css_file = Hyde::GeneratedCssFile.new(@site, config('file_output_path'), config('css_output_name'))
88
+ css_file.file_contents = minify(css.join("\n"))
89
+
90
+ @site.static_files << css_file
91
+ end
92
+
93
+ private
94
+
95
+ def config(*keys)
96
+ @config.dig(*keys)
97
+ end
98
+
99
+ def data
100
+ @site.data.dig(config('data_path'), 'fonts')
101
+ end
102
+
103
+ def minify(css)
104
+ return css if config('css_minify') == false
105
+
106
+ converter_config = { 'sass' => { 'style' => 'compressed' } }
107
+
108
+ Jekyll::Converters::Scss.new(converter_config).convert(css)
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,71 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+
4
+ module Hyde
5
+ class FontProviderGoogle
6
+ def initialize(site, config)
7
+ @site = site
8
+ @config = config
9
+ end
10
+
11
+ def fetch(face)
12
+ @face = face
13
+
14
+ begin
15
+ uri_payload = Net::HTTP.get(face_uri, {
16
+ "User-Agent": 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/117.0'
17
+ })
18
+ rescue
19
+ Jekyll.logger.warn('Fonts Warning:', 'Unable to reach Google Fonts service.')
20
+ return
21
+ end
22
+
23
+ rulesets = parse_css_payload(uri_payload)
24
+
25
+ # TODO if @config['fetch_fonts'] is false, don't download the files
26
+
27
+ for ruleset in rulesets
28
+ fetch_font_from_ruleset(ruleset)
29
+ face.css.push(rewrite_ruleset_to_local(ruleset))
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def face_uri
36
+ google_uri_base = 'https://fonts.googleapis.com/css2'
37
+ params = [['display', 'swap']]
38
+ params.push(['family', @face.to_s])
39
+
40
+ uri = google_uri_base + '?' + params.map { |param| param.join('=') }.join('&')
41
+
42
+ URI(uri)
43
+ end
44
+
45
+ def parse_css_payload(css)
46
+ css.scan(/\/\*[^}]*}/).map do |raw_ruleset|
47
+ Hyde::FontRuleset.new(raw_ruleset)
48
+ end
49
+ end
50
+
51
+ def fetch_font_from_ruleset(ruleset)
52
+ filename = ruleset.filename
53
+ file = Hyde::GeneratedFontFile.new(@site, @config['file_output_path'], filename)
54
+
55
+ destination_fname = file.destination('./')
56
+
57
+ if @config['keep_files'] == true
58
+ return if File.exist?(destination_fname)
59
+ end
60
+
61
+ font_uri_payload = Net::HTTP.get(ruleset.uri)
62
+ file.file_contents = font_uri_payload
63
+
64
+ @site.static_files << file
65
+ end
66
+
67
+ def rewrite_ruleset_to_local(ruleset)
68
+ ruleset.local_ruleset(@config['file_output_path'])
69
+ end
70
+ end
71
+ end
data/lib/hyde_fonts.rb ADDED
@@ -0,0 +1,8 @@
1
+ module Hyde
2
+ class Fonts
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
6
+
7
+ require_relative './hyde_fonts/hyde_fonts.rb'
8
+
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hyde-fonts
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Gregory Daynes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-12-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jekyll
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '5.0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '4.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5.0'
33
+ description: Hyde Fonts is a plugin for Jekyll to make adding Google fonts based on
34
+ configuration.
35
+ email: email@gregdaynes.com
36
+ executables: []
37
+ extensions: []
38
+ extra_rdoc_files: []
39
+ files:
40
+ - lib/hyde_fonts.rb
41
+ - lib/hyde_fonts/font_data.rb
42
+ - lib/hyde_fonts/font_face.rb
43
+ - lib/hyde_fonts/font_ruleset.rb
44
+ - lib/hyde_fonts/font_variant.rb
45
+ - lib/hyde_fonts/generated_css_file.rb
46
+ - lib/hyde_fonts/generated_font_file.rb
47
+ - lib/hyde_fonts/hyde_fonts.rb
48
+ - lib/hyde_fonts/provider_google.rb
49
+ homepage: https://gregdaynes.com
50
+ licenses:
51
+ - MIT
52
+ metadata: {}
53
+ post_install_message:
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubygems_version: 3.4.6
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: Plugin for jekyll to manage google fonts
72
+ test_files: []