diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 5848714b7fd..eb11dc37d19 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -54,7 +54,7 @@ jobs:
### In cases where you want to specify the cache key, enable the above 2 inputs
### Follows the format here https://github.com/actions/cache
#
- custom_opts: '--future --config _config.yml,_only_latest_guides_config.yml'
+ custom_opts: '--future --config _config.yml,_only_latest_guides_config.yml,_nosocialimages_config.yml'
### If you need to specify any Jekyll build options, enable the above input
### Flags accepted can be found here https://jekyllrb.com/docs/configuration/options/#build-command-options
diff --git a/Gemfile b/Gemfile
index af8e1eeab01..c69cf3492ac 100644
--- a/Gemfile
+++ b/Gemfile
@@ -35,3 +35,9 @@ gem "wdm", "~> 0.1.0" if Gem.win_platform?
gem "webrick", "~> 1.7"
+
+# Used in _plugins/social_images.rb
+gem "chunky_png", "~> 1.4.0"
+gem 'rsvg2', '~> 4.1.7'
+gem "cairo", "~> 1.17.9"
+gem "rake", "~> 13.0.1"
diff --git a/Gemfile.lock b/Gemfile.lock
index 0ae6c30f375..7fe8e531f30 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,19 +1,38 @@
GEM
remote: https://rubygems.org/
specs:
- addressable (2.8.0)
- public_suffix (>= 2.0.2, < 5.0)
- asciidoctor (2.0.15)
+ addressable (2.8.4)
+ public_suffix (>= 2.0.2, < 6.0)
+ asciidoctor (2.0.20)
+ cairo (1.17.9)
+ native-package-installer (>= 1.0.3)
+ pkg-config (>= 1.2.2)
+ red-colors
+ cairo-gobject (4.1.7)
+ cairo (>= 1.16.2)
+ glib2 (= 4.1.7)
+ chunky_png (1.4.0)
colorator (1.1.0)
- concurrent-ruby (1.1.8)
- em-websocket (0.5.2)
+ concurrent-ruby (1.2.2)
+ em-websocket (0.5.3)
eventmachine (>= 0.12.9)
- http_parser.rb (~> 0.6.0)
+ http_parser.rb (~> 0)
eventmachine (1.2.7)
- ffi (1.15.0)
+ ffi (1.15.5)
+ fiddle (1.1.1)
forwardable-extended (2.6.0)
- http_parser.rb (0.6.0)
- i18n (1.8.10)
+ gdk_pixbuf2 (4.1.7)
+ gio2 (= 4.1.7)
+ gio2 (4.1.7)
+ fiddle
+ gobject-introspection (= 4.1.7)
+ glib2 (4.1.7)
+ native-package-installer (>= 1.0.3)
+ pkg-config (>= 1.3.5)
+ gobject-introspection (4.1.7)
+ glib2 (= 4.1.7)
+ http_parser.rb (0.8.0)
+ i18n (1.14.1)
concurrent-ruby (~> 1.0)
jekyll (4.1.1)
addressable (~> 2.4)
@@ -35,57 +54,70 @@ GEM
jekyll-asciidoc (3.0.0)
asciidoctor (>= 1.5.0)
jekyll (>= 3.0.0)
- jekyll-feed (0.15.1)
+ jekyll-feed (0.17.0)
jekyll (>= 3.7, < 5.0)
jekyll-paginate-v2 (3.0.0)
jekyll (>= 3.0, < 5.0)
- jekyll-sass-converter (2.1.0)
+ jekyll-sass-converter (2.2.0)
sassc (> 2.0.1, < 3.0)
- jekyll-seo-tag (2.7.1)
+ jekyll-seo-tag (2.8.0)
jekyll (>= 3.8, < 5.0)
jekyll-watch (2.2.1)
listen (~> 3.0)
- kramdown (2.3.1)
+ kramdown (2.4.0)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liquid (4.0.4)
- listen (3.5.1)
+ listen (3.8.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
+ matrix (0.4.2)
mercenary (0.4.0)
minima (2.5.1)
jekyll (>= 3.5, < 5.0)
jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1)
+ native-package-installer (1.1.5)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
- public_suffix (4.0.6)
- rb-fsevent (0.11.0)
+ pkg-config (1.5.1)
+ public_suffix (5.0.1)
+ rake (13.0.6)
+ rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
+ red-colors (0.3.0)
+ matrix
rexml (3.2.5)
- rouge (3.26.0)
+ rouge (3.30.0)
+ rsvg2 (4.1.7)
+ cairo-gobject (= 4.1.7)
+ gdk_pixbuf2 (= 4.1.7)
safe_yaml (1.0.5)
sassc (2.4.0)
ffi (~> 1.9)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
- unicode-display_width (1.7.0)
- webrick (1.7.0)
+ unicode-display_width (1.8.0)
+ webrick (1.8.1)
PLATFORMS
ruby
DEPENDENCIES
+ cairo (~> 1.17.9)
+ chunky_png (~> 1.4.0)
jekyll (~> 4.1.1)
jekyll-archives
jekyll-asciidoc
jekyll-feed (~> 0.6)
jekyll-paginate-v2
minima (~> 2.0)
+ rake (~> 13.0.1)
+ rsvg2 (~> 4.1.7)
tzinfo-data
webrick (~> 1.7)
BUNDLED WITH
- 2.2.16
+ 2.4.10
diff --git a/_layouts/base.html b/_layouts/base.html
index 85ffc2ce424..7b0686330f2 100755
--- a/_layouts/base.html
+++ b/_layouts/base.html
@@ -35,7 +35,7 @@
-
+
{% if page.layout == 'guides' or page.layout == 'guides-index' %}
{%assign canonical_url = page.url | replace_regex: '^/version/[^/]+', '' %}
{% else %}
diff --git a/_nosocialimages_config.yml b/_nosocialimages_config.yml
new file mode 100644
index 00000000000..6025b9970b2
--- /dev/null
+++ b/_nosocialimages_config.yml
@@ -0,0 +1 @@
+skip_social_images: true
\ No newline at end of file
diff --git a/_plugins/assets/quarkus_card_blank.png b/_plugins/assets/quarkus_card_blank.png
new file mode 100644
index 00000000000..4b74b1102e0
Binary files /dev/null and b/_plugins/assets/quarkus_card_blank.png differ
diff --git a/_plugins/social_images.rb b/_plugins/social_images.rb
new file mode 100644
index 00000000000..a2ae5be2172
--- /dev/null
+++ b/_plugins/social_images.rb
@@ -0,0 +1,154 @@
+require 'chunky_png'
+require 'cairo'
+require 'rsvg2'
+
+module Jekyll
+ # Generates social images for blog posts and guides
+ module SocialImages
+ def social_image(text, page_path)
+ # If text is not empty, return it
+ if text.nil? || text.empty?
+ if File.exist?("./assets/images/social/#{File.basename(page_path, '.adoc')}.png")
+ return "/assets/images/social/#{File.basename(page_path, '.adoc')}.png"
+ else
+ return "/assets/images/quarkus_card.png"
+ end
+ else
+ text
+ end
+ end
+ end
+
+ class GenerateSocialImagesGenerator < Generator
+ def generate(site)
+ # Check if skip_social_images is set to true
+ # If so, skip generating social images
+ # This is useful when running the site locally
+ if site.config['skip_social_images']
+ Jekyll.logger.info('Skipping social image generation')
+ return
+ end
+ generate_images(Dir.glob(File.join(site.source, '_posts', '*.adoc')), site)
+ generate_images(Dir.glob(File.join(site.source, '_guides', '*.adoc')), site)
+ end
+
+ def split_text_into_lines(text)
+ lines = []
+ words = text.split(' ')
+ current_line = ''
+
+ words.each do |word|
+ if current_line.length + word.length <= 32
+ current_line += (current_line == '' ? '' : ' ') + word
+ else
+ lines.push(current_line)
+ current_line = word
+ end
+ end
+
+ lines.push(current_line) unless current_line.empty?
+
+ lines
+ end
+
+ private
+
+ def generate_images(files, site)
+ output_dir = 'assets/images/social'
+ FileUtils.mkdir_p(File.join(site.source, output_dir))
+
+ files.each do |guide_file|
+ basename = File.basename(guide_file, '.adoc')
+ if basename.start_with?('_')
+ next
+ end
+ title = extract_title(guide_file)
+ # Skip if title is empty
+ if (title.nil? || title.empty?)
+ next
+ end
+ output_file = File.join(site.source, output_dir, "#{basename}.png")
+ # Skip if the file already exists
+ if File.exist?(output_file)
+ next
+ end
+
+ Jekyll.logger.info("Generating social image for '#{title}' in #{output_file}")
+
+ # Generate the SVG image
+ svg_image_str = generate_svg_string(title)
+
+ # Create a Cairo surface and context for the PNG image (must be smaller than 600x330)
+ surface = Cairo::ImageSurface.new(Cairo::FORMAT_ARGB32, 600, 250)
+ context = Cairo::Context.new(surface)
+
+ # Load and render the SVG onto the Cairo context
+ svg = RSVG::Handle.new_from_data(svg_image_str)
+ context.render_rsvg_handle(svg)
+
+ # Save the Cairo surface to a PNG file
+ b = StringIO.new
+ surface.write_to_png(b)
+
+ # Compose the generated image with the template image
+ png_image = ChunkyPNG::Image.from_file('_plugins/assets/quarkus_card_blank.png')
+ # Change the last parameters to change the position of the generated image
+ png_image.compose!(ChunkyPNG::Image.from_blob(b.string), 0, 80)
+
+ # Save the composed image to the output file
+ png_image.save(output_file)
+ end
+ end
+
+ def generate_svg_string(title)
+ idx = 90
+ font_size = 30
+ tspan_elements = ''
+ # Sanitize title
+ title = title.gsub(/&/, '&')
+ title = title.gsub(/, '<')
+ title = title.gsub(/>/, '>')
+
+ split_text_into_lines(title).each_with_index do |line, index|
+ tspan_elements += "#{line}"
+ idx += font_size + 10
+ end
+ "
+
+ "
+ end
+
+ def extract_title(adoc_file)
+ line_nr = 0
+ File.readlines(adoc_file).each do |line|
+ if line_nr == 0
+ # If line does not start with --- break
+ unless line.strip.start_with?('---')
+ break
+ end
+ end
+ if line_nr > 0 && line.strip.start_with?('---')
+ break;
+ end
+ if line.strip.start_with?('title:')
+ title = line.strip.sub('title:', '').strip
+ # Remove quotes
+ title = title.gsub(/\A[\"']|[\"']\z/, '')
+ return title
+ end
+ line_nr += 1
+ end
+ doc = Asciidoctor.load_file(adoc_file, header_only: true, logger: NullLogger.new)
+ doc.doctitle
+ end
+ end
+end
+
+Liquid::Template.register_filter(Jekyll::SocialImages)