2021-12-11 22:18:48 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
namespace :tanuki_emoji do
|
|
|
|
desc 'Generates Emoji aliases fixtures'
|
|
|
|
task aliases: :environment do
|
2022-05-07 20:08:51 +05:30
|
|
|
ALLOWED_ALIASES = [':)', ':('].freeze
|
2021-12-11 22:18:48 +05:30
|
|
|
aliases = {}
|
|
|
|
|
|
|
|
TanukiEmoji.index.all.each do |emoji|
|
|
|
|
emoji.aliases.each do |emoji_alias|
|
|
|
|
aliases[TanukiEmoji::Character.format_name(emoji_alias)] = emoji.name
|
|
|
|
end
|
2022-05-07 20:08:51 +05:30
|
|
|
|
|
|
|
emoji.ascii_aliases.intersection(ALLOWED_ALIASES).each do |ascii_alias|
|
|
|
|
# We add an extra space at the end so that when a user types ":) "
|
|
|
|
# we'd still match this alias and not show "cocos (keeling) islands" as the first result.
|
|
|
|
# The initial ":" is ignored when matching because it's our emoji prefix in Markdown.
|
|
|
|
aliases[ascii_alias + ' '] = emoji.name
|
|
|
|
end
|
2021-12-11 22:18:48 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
aliases_json_file = File.join(Rails.root, 'fixtures', 'emojis', 'aliases.json')
|
|
|
|
File.open(aliases_json_file, 'w') do |handle|
|
|
|
|
handle.write(Gitlab::Json.pretty_generate(aliases, indent: ' ', space: '', space_before: ''))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
desc 'Generates Emoji SHA256 digests'
|
|
|
|
task digests: :environment do
|
|
|
|
require 'digest/sha2'
|
|
|
|
|
|
|
|
digest_emoji_map = {}
|
|
|
|
emojis_map = {}
|
|
|
|
|
|
|
|
TanukiEmoji.index.all.each do |emoji|
|
|
|
|
emoji_path = Gitlab::Emoji.emoji_public_absolute_path.join("#{emoji.name}.png")
|
|
|
|
|
|
|
|
digest_entry = {
|
|
|
|
category: emoji.category,
|
|
|
|
moji: emoji.codepoints,
|
|
|
|
description: emoji.description,
|
|
|
|
unicodeVersion: emoji.unicode_version,
|
|
|
|
digest: Digest::SHA256.file(emoji_path).hexdigest
|
|
|
|
}
|
|
|
|
|
|
|
|
digest_emoji_map[emoji.name] = digest_entry
|
|
|
|
|
|
|
|
# Our new map is only characters to make the json substantially smaller
|
|
|
|
emoji_entry = {
|
|
|
|
c: emoji.category,
|
|
|
|
e: emoji.codepoints,
|
|
|
|
d: emoji.description,
|
|
|
|
u: emoji.unicode_version
|
|
|
|
}
|
|
|
|
|
|
|
|
emojis_map[emoji.name] = emoji_entry
|
|
|
|
end
|
|
|
|
|
|
|
|
digests_json = File.join(Rails.root, 'fixtures', 'emojis', 'digests.json')
|
|
|
|
File.open(digests_json, 'w') do |handle|
|
|
|
|
handle.write(Gitlab::Json.pretty_generate(digest_emoji_map))
|
|
|
|
end
|
|
|
|
|
|
|
|
emojis_json = Gitlab::Emoji.emoji_public_absolute_path.join('emojis.json')
|
|
|
|
File.open(emojis_json, 'w') do |handle|
|
|
|
|
handle.write(Gitlab::Json.pretty_generate(emojis_map))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
desc 'Import emoji assets from TanukiEmoji to versioned folder'
|
|
|
|
task import: :environment do
|
|
|
|
require 'mini_magick'
|
|
|
|
|
|
|
|
# Setting to the same size as previous gemojione images
|
|
|
|
EMOJI_SIZE = 64
|
|
|
|
|
|
|
|
emoji_dir = Gitlab::Emoji.emoji_public_absolute_path
|
|
|
|
|
|
|
|
puts "Importing emojis into: #{emoji_dir} ..."
|
|
|
|
|
|
|
|
# Re-create the assets folder and copy emojis renaming them to use name instead of unicode hex
|
|
|
|
FileUtils.rm_rf(emoji_dir) if Dir.exist?(emoji_dir)
|
|
|
|
FileUtils.mkdir_p(emoji_dir, mode: 0700)
|
|
|
|
|
|
|
|
TanukiEmoji.index.all.each do |emoji|
|
|
|
|
source = File.join(TanukiEmoji.images_path, emoji.image_name)
|
|
|
|
destination = File.join(emoji_dir, "#{emoji.name}.png")
|
|
|
|
|
|
|
|
FileUtils.cp(source, destination)
|
|
|
|
resize!(destination, EMOJI_SIZE)
|
|
|
|
print emoji.codepoints
|
|
|
|
end
|
|
|
|
|
|
|
|
puts
|
|
|
|
puts 'Done!'
|
|
|
|
end
|
|
|
|
|
|
|
|
# This task will generate a standard and Retina sprite of all of the current
|
|
|
|
# TanukiEmoji Emojis, with the accompanying SCSS map.
|
|
|
|
#
|
|
|
|
# It will not appear in `rake -T` output, and the dependent gems are not
|
|
|
|
# included in the Gemfile by default, because this task will only be needed
|
|
|
|
# occasionally, such as when new Emojis are added to TanukiEmoji.
|
|
|
|
task sprite: :environment do
|
|
|
|
begin
|
|
|
|
require 'sprite_factory'
|
|
|
|
# Sprite-Factory still requires rmagick, but maybe could be migrated to support minimagick
|
|
|
|
# Upstream issue: https://github.com/jakesgordon/sprite-factory/issues/47#issuecomment-929302890
|
|
|
|
require 'rmagick'
|
|
|
|
rescue LoadError
|
|
|
|
# noop
|
|
|
|
end
|
|
|
|
|
|
|
|
check_requirements!
|
|
|
|
|
|
|
|
SIZE = 20
|
|
|
|
RETINA = SIZE * 2
|
|
|
|
|
|
|
|
# Update these values to the width and height of the spritesheet when
|
|
|
|
# new emoji are added.
|
|
|
|
SPRITESHEET_WIDTH = 860
|
|
|
|
SPRITESHEET_HEIGHT = 840
|
|
|
|
|
|
|
|
emoji_dir = Gitlab::Emoji.emoji_public_absolute_path
|
|
|
|
|
|
|
|
puts "Preparing sprites for regular size: #{SIZE}px..."
|
|
|
|
|
|
|
|
Dir.mktmpdir do |tmpdir|
|
|
|
|
FileUtils.cp_r(File.join(emoji_dir, '.'), tmpdir)
|
|
|
|
|
|
|
|
Dir.chdir(tmpdir) do
|
|
|
|
Dir["**/*.png"].each do |png|
|
|
|
|
tmp_image_path = File.join(tmpdir, png)
|
|
|
|
resize!(tmp_image_path, SIZE)
|
|
|
|
print '.'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
puts ' Done!'
|
|
|
|
|
|
|
|
puts "\n"
|
|
|
|
|
|
|
|
style_path = Rails.root.join(*%w(app assets stylesheets emoji_sprites.scss))
|
|
|
|
|
|
|
|
print 'Compiling sprites regular sprites... '
|
|
|
|
|
|
|
|
# Combine the resized assets into a packed sprite and re-generate the SCSS
|
|
|
|
SpriteFactory.cssurl = "image-url('$IMAGE')"
|
|
|
|
SpriteFactory.run!(tmpdir, {
|
|
|
|
output_style: style_path,
|
|
|
|
output_image: "app/assets/images/emoji.png",
|
2022-10-11 01:57:18 +05:30
|
|
|
selector: '.emoji-',
|
|
|
|
style: :scss,
|
|
|
|
nocomments: true,
|
|
|
|
pngcrush: true,
|
|
|
|
layout: :packed
|
2021-12-11 22:18:48 +05:30
|
|
|
})
|
|
|
|
|
|
|
|
# SpriteFactory's SCSS is a bit too verbose for our purposes here, so
|
|
|
|
# let's simplify it
|
|
|
|
system(%Q(sed -i '' "s/width: #{SIZE}px; height: #{SIZE}px; background: image-url('emoji.png')/background-position:/" #{style_path}))
|
|
|
|
system(%Q(sed -i '' "s/ no-repeat//" #{style_path}))
|
|
|
|
system(%Q(sed -i '' "s/ 0px/ 0/g" #{style_path}))
|
|
|
|
|
|
|
|
# Append a generic rule that applies to all Emojis
|
|
|
|
File.open(style_path, 'a') do |f|
|
|
|
|
f.puts
|
|
|
|
f.puts <<-CSS.strip_heredoc
|
|
|
|
.emoji-icon {
|
|
|
|
background-image: image-url('emoji.png');
|
|
|
|
background-repeat: no-repeat;
|
|
|
|
color: transparent;
|
|
|
|
text-indent: -99em;
|
|
|
|
height: #{SIZE}px;
|
|
|
|
width: #{SIZE}px;
|
|
|
|
|
|
|
|
/* stylelint-disable media-feature-name-no-vendor-prefix */
|
|
|
|
@media only screen and (-webkit-min-device-pixel-ratio: 2),
|
|
|
|
only screen and (min--moz-device-pixel-ratio: 2),
|
|
|
|
only screen and (-o-min-device-pixel-ratio: 2/1),
|
|
|
|
only screen and (min-device-pixel-ratio: 2),
|
|
|
|
only screen and (min-resolution: 192dpi),
|
|
|
|
only screen and (min-resolution: 2dppx) {
|
|
|
|
background-image: image-url('emoji@2x.png');
|
|
|
|
background-size: #{SPRITESHEET_WIDTH}px #{SPRITESHEET_HEIGHT}px;
|
|
|
|
}
|
|
|
|
/* stylelint-enable media-feature-name-no-vendor-prefix */
|
|
|
|
}
|
|
|
|
CSS
|
|
|
|
end
|
|
|
|
end
|
|
|
|
puts 'Done!'
|
|
|
|
|
|
|
|
puts "\n"
|
|
|
|
|
|
|
|
puts "Preparing sprites for HiDPI size: #{RETINA}px..."
|
|
|
|
|
|
|
|
# Now do it again but for Retina
|
|
|
|
Dir.mktmpdir do |tmpdir|
|
|
|
|
# Copy the TanukiEmoji assets to the temporary folder for resizing
|
|
|
|
FileUtils.cp_r(File.join(emoji_dir, '.'), tmpdir)
|
|
|
|
|
|
|
|
Dir.chdir(tmpdir) do
|
|
|
|
Dir["**/*.png"].each do |png|
|
|
|
|
tmp_image_path = File.join(tmpdir, png)
|
|
|
|
resize!(tmp_image_path, RETINA)
|
|
|
|
print '.'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
puts ' Done!'
|
|
|
|
|
|
|
|
puts "\n"
|
|
|
|
|
|
|
|
print 'Compiling HiDPI sprites...'
|
|
|
|
|
|
|
|
# Combine the resized assets into a packed sprite and re-generate the SCSS
|
|
|
|
SpriteFactory.run!(tmpdir, {
|
|
|
|
output_image: "app/assets/images/emoji@2x.png",
|
2022-10-11 01:57:18 +05:30
|
|
|
style: false,
|
|
|
|
nocomments: true,
|
|
|
|
pngcrush: true,
|
|
|
|
layout: :packed
|
2021-12-11 22:18:48 +05:30
|
|
|
})
|
|
|
|
end
|
|
|
|
|
|
|
|
puts ' Done!'
|
|
|
|
end
|
|
|
|
|
|
|
|
def check_requirements!
|
|
|
|
unless defined?(Magick)
|
|
|
|
puts <<~MSG
|
|
|
|
This task is disabled by default and should only be run when the TanukiEmoji
|
|
|
|
gem is updated with new Emojis.
|
|
|
|
|
|
|
|
To enable this task, *temporarily* add the following lines to Gemfile and
|
|
|
|
re-bundle:
|
|
|
|
|
|
|
|
gem 'rmagick', '~> 3.2'
|
|
|
|
|
|
|
|
It depends on ImageMagick 6, which can be installed via HomeBrew with:
|
|
|
|
|
|
|
|
brew unlink imagemagick
|
|
|
|
brew install imagemagick@6 && brew link imagemagick@6 --force
|
|
|
|
MSG
|
|
|
|
|
|
|
|
exit 1
|
|
|
|
end
|
|
|
|
|
|
|
|
return if Dir.exist? Gitlab::Emoji.emoji_public_absolute_path
|
|
|
|
|
|
|
|
puts <<~MSG
|
|
|
|
You first need to import the assets for Emoji version: #{Gitlab::Emoji::EMOJI_VERSION}
|
|
|
|
|
|
|
|
Run the following task:
|
|
|
|
|
|
|
|
rake tanuki_emoji:import
|
|
|
|
MSG
|
|
|
|
|
|
|
|
exit 1
|
|
|
|
end
|
|
|
|
|
|
|
|
def resize!(image_path, size)
|
|
|
|
# Resize the image in-place, save it, and free the object
|
|
|
|
image = MiniMagick::Image.open(image_path)
|
|
|
|
image.quality(100)
|
|
|
|
image.resize("#{size}x#{size}")
|
|
|
|
image.write(image_path)
|
|
|
|
end
|
|
|
|
end
|