Module: SvgSprite

Defined in:
lib/svg_sprite.rb

Constant Summary collapse

SVG_ICONS =
Set.new(
  %w[
    address-book
    align-left
    anchor
    angle-down
    angle-right
    angle-up
    angles-down
    angles-left
    angles-right
    angles-up
    arrow-down
    arrow-left
    arrow-right
    arrow-rotate-left
    arrow-rotate-right
    arrow-up
    arrows-rotate
    asterisk
    at
    backward
    backward-fast
    backward-step
    ban
    bars
    bars-staggered
    bed
    bell
    bell-slash
    bold
    book
    book-open-reader
    bookmark
    bookmark-delete
    box-archive
    briefcase
    bullseye
    calendar-days
    caret-down
    caret-left
    caret-right
    caret-up
    certificate
    chart-bar
    chart-pie
    check
    chevron-down
    chevron-left
    chevron-right
    chevron-up
    circle
    circle-check
    circle-chevron-down
    circle-exclamation
    circle-half-stroke
    circle-info
    circle-minus
    circle-plus
    circle-question
    circle-xmark
    clock-rotate-left
    cloud-arrow-up
    code
    comment
    compress
    copy
    crosshairs
    cube
    desktop
    diagram-project
    discourse-amazon
    discourse-bell-exclamation
    discourse-bell-one
    discourse-bell-slash
    discourse-bookmark-clock
    discourse-chevron-collapse
    discourse-chevron-expand
    discourse-compress
    discourse-dnd
    discourse-emojis
    discourse-expand
    discourse-other-tab
    discourse-sidebar
    discourse-sparkles
    discourse-threads
    download
    earth-americas
    ellipsis
    ellipsis-vertical
    envelope
    eye
    fab-android
    fab-apple
    fab-chrome
    fab-discord
    fab-discourse
    fab-facebook
    fab-facebook-square
    fab-github
    fab-instagram
    fab-linkedin-in
    fab-linux
    fab-threads
    fab-threads-square
    fab-twitter
    fab-twitter-square
    fab-x-twitter
    fab-wikipedia-w
    fab-windows
    far-bell
    far-bell-slash
    far-calendar-plus
    far-chart-bar
    far-circle
    far-circle-dot
    far-clipboard
    far-clock
    far-comment
    far-comments
    far-copyright
    far-envelope
    far-eye
    far-eye-slash
    far-face-frown
    far-face-meh
    far-face-smile
    far-file-lines
    far-heart
    far-image
    far-moon
    far-pen-to-square
    far-rectangle-list
    far-square
    far-square-check
    far-star
    far-sun
    far-thumbs-down
    far-thumbs-up
    far-trash-can
    file
    file-lines
    filter
    flag
    flask
    folder
    folder-open
    forward
    forward-fast
    forward-step
    gavel
    gear
    gift
    globe
    grip-lines
    hand-point-right
    handshake-angle
    heart
    hourglass-start
    house
    id-card
    image
    images
    inbox
    italic
    key
    keyboard
    language
    layer-group
    left-right
    link
    link-slash
    list
    list-check
    list-ol
    list-ul
    location-dot
    lock
    magnifying-glass
    magnifying-glass-minus
    magnifying-glass-plus
    microphone-slash
    minus
    mobile-screen-button
    moon
    paintbrush
    palette
    paper-plane
    pause
    pencil
    play
    plug
    plus
    power-off
    puzzle-piece
    question
    quote-left
    quote-right
    reply
    right-from-bracket
    right-left
    right-to-bracket
    robot
    rocket
    rotate
    scroll
    share
    shield-halved
    shuffle
    signal
    sliders
    spinner
    square-check
    square-envelope
    square-full
    square-plus
    star
    table
    table-cells
    table-columns
    tag
    tags
    temperature-three-quarters
    thumbs-down
    thumbs-up
    thumbtack
    tippy-rounded-arrow
    toggle-off
    toggle-on
    trash-can
    triangle-exclamation
    truck-medical
    unlock
    unlock-keyhole
    up-down
    up-right-from-square
    upload
    user
    user-gear
    user-group
    user-pen
    user-plus
    user-secret
    user-shield
    user-xmark
    users
    wand-magic
    wrench
    xmark
  ],
)
FA_4_ICON_MAP =
{ "far fa-" => "far-", "fab fa-" => "fab-", "fas fa-" => "", "fa-" => "" }
CORE_SVG_SPRITES =
Dir.glob("#{Rails.root}/vendor/assets/svg-icons/**/*.svg")
THEME_SPRITE_VAR_NAME =
"icons-sprite"
MAX_THEME_SPRITE_SIZE =
1024.kilobytes
FA5_REMAPS =
{
  "adjust" => "circle-half-stroke",
  "air-freshener" => "spray-can-sparkles",
  "alien-monster" => "alien-8bit",
  "allergies" => "hand-dots",
  "ambulance" => "truck-medical",
  "american-sign-language-interpreting" => "hands-asl-interpreting",
  "analytics" => "chart-mixed",
  "angle-double-down" => "angles-down",
  "angle-double-left" => "angles-left",
  "angle-double-right" => "angles-right",
  "angle-double-up" => "angles-up",
  "angry" => "face-angry",
  "apple-alt" => "apple-whole",
  "apple-crate" => "crate-apple",
  "archive" => "box-archive",
  "arrow-alt-circle-down" => "circle-down",
  "arrow-alt-circle-left" => "circle-left",
  "arrow-alt-circle-right" => "circle-right",
  "arrow-alt-circle-up" => "circle-up",
  "arrow-alt-down" => "down",
  "arrow-alt-from-bottom" => "up-from-line",
  "arrow-alt-from-left" => "right-from-line",
  "arrow-alt-from-right" => "left-from-line",
  "arrow-alt-from-top" => "down-from-line",
  "arrow-alt-left" => "left",
  "arrow-alt-right" => "right",
  "arrow-alt-square-down" => "square-down",
  "arrow-alt-square-left" => "square-left",
  "arrow-alt-square-right" => "square-right",
  "arrow-alt-square-up" => "square-up",
  "arrow-alt-to-bottom" => "down-to-line",
  "arrow-alt-to-left" => "left-to-line",
  "arrow-alt-to-right" => "right-to-line",
  "arrow-alt-to-top" => "up-to-line",
  "arrow-alt-up" => "up",
  "arrow-circle-down" => "circle-arrow-down",
  "arrow-circle-left" => "circle-arrow-left",
  "arrow-circle-right" => "circle-arrow-right",
  "arrow-circle-up" => "circle-arrow-up",
  "arrow-from-bottom" => "arrow-up-from-line",
  "arrow-from-left" => "arrow-right-from-line",
  "arrow-from-right" => "arrow-left-from-line",
  "arrow-from-top" => "arrow-down-from-line",
  "arrow-square-down" => "square-arrow-down",
  "arrow-square-left" => "square-arrow-left",
  "arrow-square-right" => "square-arrow-right",
  "arrow-square-up" => "square-arrow-up",
  "arrow-to-bottom" => "arrow-down-to-line",
  "arrow-to-left" => "arrow-left-to-line",
  "arrow-to-right" => "arrow-right-to-line",
  "arrow-to-top" => "arrow-up-to-line",
  "arrows" => "arrows-up-down-left-right",
  "arrows-alt" => "up-down-left-right",
  "arrows-alt-h" => "left-right",
  "arrows-alt-v" => "up-down",
  "arrows-h" => "arrows-left-right",
  "arrows-v" => "arrows-up-down",
  "assistive-listening-systems" => "ear-listen",
  "atlas" => "book-atlas",
  "atom-alt" => "atom-simple",
  "backspace" => "delete-left",
  "balance-scale" => "scale-balanced",
  "balance-scale-left" => "scale-unbalanced",
  "balance-scale-right" => "scale-unbalanced-flip",
  "band-aid" => "bandage",
  "barcode-alt" => "rectangle-barcode",
  "baseball-ball" => "baseball",
  "basketball-ball" => "basketball",
  "bed-alt" => "bed-front",
  "beer" => "beer-mug-empty",
  "betamax" => "cassette-betamax",
  "bible" => "book-bible",
  "biking" => "person-biking",
  "biking-mountain" => "person-biking-mountain",
  "birthday-cake" => "cake-candles",
  "blind" => "person-walking-with-cane",
  "book-alt" => "book-blank",
  "book-dead" => "book-skull",
  "book-reader" => "book-open-reader",
  "book-spells" => "book-sparkles",
  "border-style" => "border-top-left",
  "border-style-alt" => "border-bottom-right",
  "box-alt" => "box-taped",
  "box-fragile" => "square-fragile",
  "box-full" => "box-open-full",
  "box-up" => "square-this-way-up",
  "box-usd" => "box-dollar",
  "boxes" => "boxes-stacked",
  "boxes-alt" => "boxes-stacked",
  "brackets" => "brackets-square",
  "broadcast-tower" => "tower-broadcast",
  "burn" => "fire-flame-simple",
  "bus-alt" => "bus-simple",
  "calculator-alt" => "calculator-simple",
  "calendar-alt" => "calendar-days",
  "calendar-edit" => "calendar-pen",
  "calendar-times" => "calendar-xmark",
  "camera-alt" => "camera",
  "camera-home" => "camera-security",
  "car-alt" => "car-rear",
  "car-crash" => "car-burst",
  "car-mechanic" => "car-wrench",
  "caravan-alt" => "caravan-simple",
  "caret-circle-down" => "circle-caret-down",
  "caret-circle-left" => "circle-caret-left",
  "caret-circle-right" => "circle-caret-right",
  "caret-circle-up" => "circle-caret-up",
  "caret-square-down" => "square-caret-down",
  "caret-square-left" => "square-caret-left",
  "caret-square-right" => "square-caret-right",
  "caret-square-up" => "square-caret-up",
  "cctv" => "camera-cctv",
  "chalkboard-teacher" => "chalkboard-user",
  "chart-pie-alt" => "chart-pie-simple",
  "check-circle" => "circle-check",
  "check-square" => "square-check",
  "cheeseburger" => "burger-cheese",
  "chess-bishop-alt" => "chess-bishop-piece",
  "chess-clock-alt" => "chess-clock-flip",
  "chess-king-alt" => "chess-king-piece",
  "chess-knight-alt" => "chess-knight-piece",
  "chess-pawn-alt" => "chess-pawn-piece",
  "chess-queen-alt" => "chess-queen-piece",
  "chess-rook-alt" => "chess-rook-piece",
  "chevron-circle-down" => "circle-chevron-down",
  "chevron-circle-left" => "circle-chevron-left",
  "chevron-circle-right" => "circle-chevron-right",
  "chevron-circle-up" => "circle-chevron-up",
  "chevron-double-down" => "chevrons-down",
  "chevron-double-left" => "chevrons-left",
  "chevron-double-right" => "chevrons-right",
  "chevron-double-up" => "chevrons-up",
  "chevron-square-down" => "square-chevron-down",
  "chevron-square-left" => "square-chevron-left",
  "chevron-square-right" => "square-chevron-right",
  "chevron-square-up" => "square-chevron-up",
  "clinic-medical" => "house-chimney-medical",
  "cloud-download" => "cloud-arrow-down",
  "cloud-download-alt" => "cloud-arrow-down",
  "cloud-upload" => "cloud-arrow-up",
  "cloud-upload-alt" => "cloud-arrow-up",
  "cocktail" => "martini-glass-citrus",
  "coffee" => "mug-saucer",
  "coffee-togo" => "cup-togo",
  "cog" => "gear",
  "cogs" => "gears",
  "columns" => "table-columns",
  "comment-alt" => "message",
  "comment-alt-check" => "message-check",
  "comment-alt-dollar" => "message-dollar",
  "comment-alt-dots" => "message-dots",
  "comment-alt-edit" => "message-pen",
  "comment-alt-exclamation" => "message-exclamation",
  "comment-alt-lines" => "message-lines",
  "comment-alt-medical" => "message-medical",
  "comment-alt-minus" => "message-minus",
  "comment-alt-music" => "message-music",
  "comment-alt-plus" => "message-plus",
  "comment-alt-slash" => "message-slash",
  "comment-alt-smile" => "message-smile",
  "comment-alt-times" => "message-xmark",
  "comment-edit" => "comment-pen",
  "comment-times" => "comment-xmark",
  "comments-alt" => "messages",
  "comments-alt-dollar" => "messages-dollar",
  "compress-alt" => "down-left-and-up-right-to-center",
  "compress-arrows-alt" => "minimize",
  "concierge-bell" => "bell-concierge",
  "construction" => "triangle-person-digging",
  "conveyor-belt-alt" => "conveyor-belt-boxes",
  "cowbell-more" => "cowbell-circle-plus",
  "cricket" => "cricket-bat-ball",
  "crop-alt" => "crop-simple",
  "curling" => "curling-stone",
  "cut" => "scissors",
  "deaf" => "ear-deaf",
  "debug" => "ban-bug",
  "desktop-alt" => "desktop",
  "dewpoint" => "droplet-degree",
  "diagnoses" => "person-dots-from-line",
  "digging" => "person-digging",
  "digital-tachograph" => "tachograph-digital",
  "directions" => "diamond-turn-right",
  "dizzy" => "face-dizzy",
  "dolly-flatbed" => "cart-flatbed",
  "dolly-flatbed-alt" => "cart-flatbed-boxes",
  "dolly-flatbed-empty" => "cart-flatbed-empty",
  "donate" => "circle-dollar-to-slot",
  "dot-circle" => "circle-dot",
  "drafting-compass" => "compass-drafting",
  "drone-alt" => "drone-front",
  "dryer-alt" => "dryer-heat",
  "eclipse-alt" => "moon-over-sun",
  "edit" => "pen-to-square",
  "ellipsis-h" => "ellipsis",
  "ellipsis-h-alt" => "ellipsis-stroke",
  "ellipsis-v" => "ellipsis-vertical",
  "ellipsis-v-alt" => "ellipsis-stroke-vertical",
  "envelope-square" => "square-envelope",
  "exchange" => "arrow-right-arrow-left",
  "exchange-alt" => "right-left",
  "exclamation-circle" => "circle-exclamation",
  "exclamation-square" => "square-exclamation",
  "exclamation-triangle" => "triangle-exclamation",
  "expand-alt" => "up-right-and-down-left-from-center",
  "expand-arrows" => "arrows-maximize",
  "expand-arrows-alt" => "maximize",
  "external-link" => "arrow-up-right-from-square",
  "external-link-alt" => "up-right-from-square",
  "external-link-square" => "square-arrow-up-right",
  "external-link-square-alt" => "square-up-right",
  "eyedropper" => "eye-dropper",
  "fast-backward" => "backward-fast",
  "fast-forward" => "forward-fast",
  "feather-alt" => "feather-pointed",
  "female" => "person-dress",
  "field-hockey" => "field-hockey-stick-ball",
  "fighter-jet" => "jet-fighter",
  "file-alt" => "file-lines",
  "file-archive" => "file-zipper",
  "file-chart-line" => "file-chart-column",
  "file-download" => "file-arrow-down",
  "file-edit" => "file-pen",
  "file-medical-alt" => "file-waveform",
  "file-search" => "file-magnifying-glass",
  "file-times" => "file-xmark",
  "file-upload" => "file-arrow-up",
  "film-alt" => "film-simple",
  "fire-alt" => "fire-flame-curved",
  "first-aid" => "kit-medical",
  "fist-raised" => "hand-fist",
  "flag-alt" => "flag-swallowtail",
  "flame" => "fire-flame",
  "flask-poison" => "flask-round-poison",
  "flask-potion" => "flask-round-potion",
  "flushed" => "face-flushed",
  "fog" => "cloud-fog",
  "folder-download" => "folder-arrow-down",
  "folder-times" => "folder-xmark",
  "folder-upload" => "folder-arrow-up",
  "font-awesome-alt" => "square-font-awesome-stroke",
  "font-awesome-flag" => "font-awesome",
  "font-awesome-logo-full" => "font-awesome",
  "football-ball" => "football",
  "fragile" => "wine-glass-crack",
  "frosty-head" => "snowman-head",
  "frown" => "face-frown",
  "frown-open" => "face-frown-open",
  "funnel-dollar" => "filter-circle-dollar",
  "game-board-alt" => "game-board-simple",
  "gamepad-alt" => "gamepad-modern",
  "glass-champagne" => "champagne-glass",
  "glass-cheers" => "champagne-glasses",
  "glass-martini" => "martini-glass-empty",
  "glass-martini-alt" => "martini-glass",
  "glass-whiskey" => "whiskey-glass",
  "glass-whiskey-rocks" => "whiskey-glass-ice",
  "glasses-alt" => "glasses-round",
  "globe-africa" => "earth-africa",
  "globe-americas" => "earth-americas",
  "globe-asia" => "earth-asia",
  "globe-europe" => "earth-europe",
  "golf-ball" => "golf-ball-tee",
  "grimace" => "face-grimace",
  "grin" => "face-grin",
  "grin-alt" => "face-grin-wide",
  "grin-beam" => "face-grin-beam",
  "grin-beam-sweat" => "face-grin-beam-sweat",
  "grin-hearts" => "face-grin-hearts",
  "grin-squint" => "face-grin-squint",
  "grin-squint-tears" => "face-grin-squint-tears",
  "grin-stars" => "face-grin-stars",
  "grin-tears" => "face-grin-tears",
  "grin-tongue" => "face-grin-tongue",
  "grin-tongue-squint" => "face-grin-tongue-squint",
  "grin-tongue-wink" => "face-grin-tongue-wink",
  "grin-wink" => "face-grin-wink",
  "grip-horizontal" => "grip",
  "h-square" => "square-h",
  "hamburger" => "burger",
  "hand-holding-usd" => "hand-holding-dollar",
  "hand-holding-water" => "hand-holding-droplet",
  "hand-paper" => "hand",
  "hand-receiving" => "hands-holding-diamond",
  "hand-rock" => "hand-back-fist",
  "hands-heart" => "hands-holding-heart",
  "hands-helping" => "handshake-angle",
  "hands-usd" => "hands-holding-dollar",
  "hands-wash" => "hands-bubbles",
  "handshake-alt" => "handshake-simple",
  "handshake-alt-slash" => "handshake-simple-slash",
  "hard-hat" => "helmet-safety",
  "hdd" => "hard-drive",
  "head-vr" => "head-side-goggles",
  "headphones-alt" => "headphones-simple",
  "heart-broken" => "heart-crack",
  "heart-circle" => "circle-heart",
  "heart-rate" => "wave-pulse",
  "heart-square" => "square-heart",
  "heartbeat" => "heart-pulse",
  "hiking" => "person-hiking",
  "history" => "clock-rotate-left",
  "home" => "house",
  "home-alt" => "house",
  "home-heart" => "house-heart",
  "home-lg" => "house-chimney",
  "home-lg-alt" => "house",
  "hospital-alt" => "hospital",
  "hospital-symbol" => "circle-h",
  "hot-tub" => "hot-tub-person",
  "hourglass-half" => "hourglass",
  "house-damage" => "house-chimney-crack",
  "house-leave" => "house-person-leave",
  "house-return" => "house-person-return",
  "hryvnia" => "hryvnia-sign",
  "humidity" => "droplet-percent",
  "icons-alt" => "symbols",
  "id-card-alt" => "id-card-clip",
  "industry-alt" => "industry-windows",
  "info-circle" => "circle-info",
  "info-square" => "square-info",
  "innosoft" => "42-group",
  "inventory" => "shelves",
  "journal-whills" => "book-journal-whills",
  "kiss" => "face-kiss",
  "kiss-beam" => "face-kiss-beam",
  "kiss-wink-heart" => "face-kiss-wink-heart",
  "landmark-alt" => "landmark-dome",
  "laptop-house" => "house-laptop",
  "laugh" => "face-laugh",
  "laugh-beam" => "face-laugh-beam",
  "laugh-squint" => "face-laugh-squint",
  "laugh-wink" => "face-laugh-wink",
  "level-down" => "arrow-turn-down",
  "level-down-alt" => "turn-down",
  "level-up" => "arrow-turn-up",
  "level-up-alt" => "turn-up",
  "list-alt" => "rectangle-list",
  "location" => "location-crosshairs",
  "location-circle" => "circle-location-arrow",
  "location-slash" => "location-crosshairs-slash",
  "lock-alt" => "lock-keyhole",
  "lock-open-alt" => "lock-keyhole-open",
  "long-arrow-alt-down" => "down-long",
  "long-arrow-alt-left" => "left-long",
  "long-arrow-alt-right" => "right-long",
  "long-arrow-alt-up" => "up-long",
  "long-arrow-down" => "arrow-down-long",
  "long-arrow-left" => "arrow-left-long",
  "long-arrow-right" => "arrow-right-long",
  "long-arrow-up" => "arrow-up-long",
  "low-vision" => "eye-low-vision",
  "luchador" => "luchador-mask",
  "luggage-cart" => "cart-flatbed-suitcase",
  "magic" => "wand-magic",
  "mail-bulk" => "envelopes-bulk",
  "male" => "person",
  "map-marked" => "map-location",
  "map-marked-alt" => "map-location-dot",
  "map-marker" => "location-pin",
  "map-marker-alt" => "location-dot",
  "map-marker-alt-slash" => "location-dot-slash",
  "map-marker-check" => "location-check",
  "map-marker-edit" => "location-pen",
  "map-marker-exclamation" => "location-exclamation",
  "map-marker-minus" => "location-minus",
  "map-marker-plus" => "location-plus",
  "map-marker-question" => "location-question",
  "map-marker-slash" => "location-pin-slash",
  "map-marker-smile" => "location-smile",
  "map-marker-times" => "location-xmark",
  "map-signs" => "signs-post",
  "mars-stroke-h" => "mars-stroke-right",
  "mars-stroke-v" => "mars-stroke-up",
  "medium-m" => "medium",
  "medkit" => "suitcase-medical",
  "meh" => "face-meh",
  "meh-blank" => "face-meh-blank",
  "meh-rolling-eyes" => "face-rolling-eyes",
  "microphone-alt" => "microphone-lines",
  "microphone-alt-slash" => "microphone-lines-slash",
  "mind-share" => "brain-arrow-curved-right",
  "minus-circle" => "circle-minus",
  "minus-hexagon" => "hexagon-minus",
  "minus-octagon" => "octagon-minus",
  "minus-square" => "square-minus",
  "mobile-alt" => "mobile-screen-button",
  "mobile-android" => "mobile",
  "mobile-android-alt" => "mobile-screen",
  "money-bill-alt" => "money-bill-1",
  "money-bill-wave-alt" => "money-bill-1-wave",
  "money-check-alt" => "money-check-dollar",
  "money-check-edit" => "money-check-pen",
  "money-check-edit-alt" => "money-check-dollar-pen",
  "monitor-heart-rate" => "monitor-waveform",
  "mouse" => "computer-mouse",
  "mouse-alt" => "computer-mouse-scrollwheel",
  "mouse-pointer" => "arrow-pointer",
  "music-alt" => "music-note",
  "music-alt-slash" => "music-note-slash",
  "oil-temp" => "oil-temperature",
  "page-break" => "file-dashed-line",
  "paint-brush" => "paintbrush",
  "paint-brush-alt" => "paintbrush-fine",
  "paint-brush-fine" => "paintbrush-fine",
  "pallet-alt" => "pallet-boxes",
  "paragraph-rtl" => "paragraph-left",
  "parking" => "square-parking",
  "parking-circle" => "circle-parking",
  "parking-circle-slash" => "ban-parking",
  "parking-slash" => "square-parking-slash",
  "pastafarianism" => "spaghetti-monster-flying",
  "pause-circle" => "circle-pause",
  "paw-alt" => "paw-simple",
  "pen-alt" => "pen-clip",
  "pen-square" => "square-pen",
  "pencil-alt" => "pencil",
  "pencil-paintbrush" => "pen-paintbrush",
  "pencil-ruler" => "pen-ruler",
  "pennant" => "flag-pennant",
  "people-arrows" => "people-arrows-left-right",
  "people-carry" => "people-carry-box",
  "percentage" => "percent",
  "person-carry" => "person-carry-box",
  "phone-alt" => "phone-flip",
  "phone-laptop" => "laptop-mobile",
  "phone-square" => "square-phone",
  "phone-square-alt" => "square-phone-flip",
  "photo-video" => "photo-film",
  "plane-alt" => "plane-engines",
  "play-circle" => "circle-play",
  "plus-circle" => "circle-plus",
  "plus-hexagon" => "hexagon-plus",
  "plus-octagon" => "octagon-plus",
  "plus-square" => "square-plus",
  "poll" => "square-poll-vertical",
  "poll-h" => "square-poll-horizontal",
  "portal-enter" => "person-to-portal",
  "portal-exit" => "person-from-portal",
  "portrait" => "image-portrait",
  "pound-sign" => "sterling-sign",
  "pray" => "person-praying",
  "praying-hands" => "hands-praying",
  "prescription-bottle-alt" => "prescription-bottle-medical",
  "presentation" => "presentation-screen",
  "print-search" => "print-magnifying-glass",
  "procedures" => "bed-pulse",
  "project-diagram" => "diagram-project",
  "question-circle" => "circle-question",
  "question-square" => "square-question",
  "quran" => "book-quran",
  "rabbit-fast" => "rabbit-running",
  "radiation-alt" => "circle-radiation",
  "radio-alt" => "radio-tuner",
  "random" => "shuffle",
  "rectangle-landscape" => "rectangle",
  "rectangle-portrait" => "rectangle-vertical",
  "redo" => "arrow-rotate-right",
  "redo-alt" => "rotate-right",
  "remove-format" => "text-slash",
  "repeat-1-alt" => "arrows-repeat-1",
  "repeat-alt" => "arrows-repeat",
  "retweet-alt" => "arrows-retweet",
  "rss-square" => "square-rss",
  "running" => "person-running",
  "sad-cry" => "face-sad-cry",
  "sad-tear" => "face-sad-tear",
  "save" => "floppy-disk",
  "sax-hot" => "saxophone-fire",
  "scalpel-path" => "scalpel-line-dashed",
  "scanner-image" => "scanner",
  "search" => "magnifying-glass",
  "search-dollar" => "magnifying-glass-dollar",
  "search-location" => "magnifying-glass-location",
  "search-minus" => "magnifying-glass-minus",
  "search-plus" => "magnifying-glass-plus",
  "sensor-alert" => "sensor-triangle-exclamation",
  "sensor-smoke" => "sensor-cloud",
  "share-alt" => "share-nodes",
  "share-alt-square" => "square-share-nodes",
  "share-square" => "share-from-square",
  "shield-alt" => "shield-halved",
  "shipping-fast" => "truck-fast",
  "shipping-timed" => "truck-clock",
  "shopping-bag" => "bag-shopping",
  "shopping-basket" => "basket-shopping",
  "shopping-cart" => "cart-shopping",
  "shuttle-van" => "van-shuttle",
  "sign" => "sign-hanging",
  "sign-in" => "arrow-right-to-bracket",
  "sign-in-alt" => "right-to-bracket",
  "sign-language" => "hands",
  "sign-out" => "arrow-right-from-bracket",
  "sign-out-alt" => "right-from-bracket",
  "signal-1" => "signal-weak",
  "signal-2" => "signal-fair",
  "signal-3" => "signal-good",
  "signal-4" => "signal-strong",
  "signal-alt" => "signal-bars",
  "signal-alt-1" => "signal-bars-weak",
  "signal-alt-2" => "signal-bars-fair",
  "signal-alt-3" => "signal-bars-good",
  "signal-alt-slash" => "signal-bars-slash",
  "skating" => "person-skating",
  "ski-jump" => "person-ski-jumping",
  "ski-lift" => "person-ski-lift",
  "skiing" => "person-skiing",
  "skiing-nordic" => "person-skiing-nordic",
  "slack-hash" => "slack",
  "sledding" => "person-sledding",
  "sliders-h" => "sliders",
  "sliders-h-square" => "square-sliders",
  "sliders-v" => "sliders-up",
  "sliders-v-square" => "square-sliders-vertical",
  "smile" => "face-smile",
  "smile-beam" => "face-smile-beam",
  "smile-plus" => "face-smile-plus",
  "smile-wink" => "face-smile-wink",
  "smoking-ban" => "ban-smoking",
  "sms" => "comment-sms",
  "snapchat-ghost" => "snapchat",
  "snowboarding" => "person-snowboarding",
  "snowmobile" => "person-snowmobiling",
  "sort-alpha-down" => "arrow-down-a-z",
  "sort-alpha-down-alt" => "arrow-down-z-a",
  "sort-alpha-up" => "arrow-up-a-z",
  "sort-alpha-up-alt" => "arrow-up-z-a",
  "sort-alt" => "arrow-down-arrow-up",
  "sort-amount-down" => "arrow-down-wide-short",
  "sort-amount-down-alt" => "arrow-down-short-wide",
  "sort-amount-up" => "arrow-up-wide-short",
  "sort-amount-up-alt" => "arrow-up-short-wide",
  "sort-circle" => "circle-sort",
  "sort-circle-down" => "circle-sort-down",
  "sort-circle-up" => "circle-sort-up",
  "sort-numeric-down" => "arrow-down-1-9",
  "sort-numeric-down-alt" => "arrow-down-9-1",
  "sort-numeric-up" => "arrow-up-1-9",
  "sort-numeric-up-alt" => "arrow-up-9-1",
  "sort-shapes-down" => "arrow-down-triangle-square",
  "sort-shapes-down-alt" => "arrow-down-square-triangle",
  "sort-shapes-up" => "arrow-up-triangle-square",
  "sort-shapes-up-alt" => "arrow-up-square-triangle",
  "sort-size-down" => "arrow-down-big-small",
  "sort-size-down-alt" => "arrow-down-small-big",
  "sort-size-up" => "arrow-up-big-small",
  "sort-size-up-alt" => "arrow-up-small-big",
  "soup" => "bowl-hot",
  "space-shuttle" => "shuttle-space",
  "space-station-moon-alt" => "space-station-moon-construction",
  "square-root-alt" => "square-root-variable",
  "star-half-alt" => "star-half-stroke",
  "starfighter-alt" => "starfighter-twin-ion-engine",
  "step-backward" => "backward-step",
  "step-forward" => "forward-step",
  "sticky-note" => "note-sticky",
  "stop-circle" => "circle-stop",
  "store-alt" => "shop",
  "store-alt-slash" => "shop-slash",
  "stream" => "bars-staggered",
  "subway" => "train-subway",
  "surprise" => "face-surprise",
  "swimmer" => "person-swimming",
  "swimming-pool" => "water-ladder",
  "sync" => "arrows-rotate",
  "sync-alt" => "rotate",
  "table-tennis" => "table-tennis-paddle-ball",
  "tablet-alt" => "tablet-screen-button",
  "tablet-android" => "tablet",
  "tablet-android-alt" => "tablet-screen",
  "tachometer" => "gauge-simple",
  "tachometer-alt" => "gauge",
  "tachometer-alt-average" => "gauge-med",
  "tachometer-alt-fast" => "gauge",
  "tachometer-alt-fastest" => "gauge-max",
  "tachometer-alt-slow" => "gauge-low",
  "tachometer-alt-slowest" => "gauge-min",
  "tachometer-average" => "gauge-simple-med",
  "tachometer-fast" => "gauge-simple",
  "tachometer-fastest" => "gauge-simple-max",
  "tachometer-slow" => "gauge-simple-low",
  "tachometer-slowest" => "gauge-simple-min",
  "tanakh" => "book-tanakh",
  "tasks" => "list-check",
  "tasks-alt" => "bars-progress",
  "telegram-plane" => "telegram",
  "temperature-down" => "temperature-arrow-down",
  "temperature-frigid" => "temperature-snow",
  "temperature-hot" => "temperature-sun",
  "temperature-up" => "temperature-arrow-up",
  "tenge" => "tenge-sign",
  "th" => "table-cells",
  "th-large" => "table-cells-large",
  "th-list" => "table-list",
  "theater-masks" => "masks-theater",
  "thermometer-empty" => "temperature-empty",
  "thermometer-full" => "temperature-full",
  "thermometer-half" => "temperature-half",
  "thermometer-quarter" => "temperature-quarter",
  "thermometer-three-quarters" => "temperature-three-quarters",
  "thumb-tack" => "thumbtack",
  "thunderstorm" => "cloud-bolt",
  "thunderstorm-moon" => "cloud-bolt-moon",
  "thunderstorm-sun" => "cloud-bolt-sun",
  "ticket-alt" => "ticket-simple",
  "times" => "xmark",
  "times-circle" => "circle-xmark",
  "times-hexagon" => "hexagon-xmark",
  "times-octagon" => "octagon-xmark",
  "times-square" => "square-xmark",
  "tint" => "droplet",
  "tint-slash" => "droplet-slash",
  "tired" => "face-tired",
  "toilet-paper-alt" => "toilet-paper-blank",
  "tombstone-alt" => "tombstone-blank",
  "tools" => "screwdriver-wrench",
  "torah" => "scroll-torah",
  "tram" => "train-tram",
  "transgender-alt" => "transgender",
  "trash-alt" => "trash-can",
  "trash-restore" => "trash-arrow-up",
  "trash-restore-alt" => "trash-can-arrow-up",
  "trash-undo-alt" => "trash-can-undo",
  "tree-alt" => "tree-deciduous",
  "triangle-music" => "triangle-instrument",
  "trophy-alt" => "trophy-star",
  "truck-couch" => "truck-ramp-couch",
  "truck-loading" => "truck-ramp-box",
  "tshirt" => "shirt",
  "tv-alt" => "tv",
  "undo" => "arrow-rotate-left",
  "undo-alt" => "rotate-left",
  "university" => "building-columns",
  "unlink" => "link-slash",
  "unlock-alt" => "unlock-keyhole",
  "usd-circle" => "circle-dollar",
  "usd-square" => "square-dollar",
  "user-alt" => "user-large",
  "user-alt-slash" => "user-large-slash",
  "user-chart" => "chart-user",
  "user-circle" => "circle-user",
  "user-cog" => "user-gear",
  "user-edit" => "user-pen",
  "user-friends" => "user-group",
  "user-hard-hat" => "user-helmet-safety",
  "user-md" => "user-doctor",
  "user-md-chat" => "user-doctor-message",
  "user-times" => "user-xmark",
  "users-class" => "screen-users",
  "users-cog" => "users-gear",
  "users-crown" => "user-group-crown",
  "utensil-fork" => "fork",
  "utensil-knife" => "knife",
  "utensil-spoon" => "spoon",
  "utensils-alt" => "fork-knife",
  "vhs" => "cassette-vhs",
  "volleyball-ball" => "volleyball",
  "volume-down" => "volume-low",
  "volume-mute" => "volume-xmark",
  "volume-up" => "volume-high",
  "vote-nay" => "xmark-to-slot",
  "vote-yea" => "check-to-slot",
  "walking" => "person-walking",
  "warehouse-alt" => "warehouse-full",
  "washer" => "washing-machine",
  "water-lower" => "water-arrow-down",
  "water-rise" => "water-arrow-up",
  "waveform-path" => "waveform-lines",
  "webcam" => "camera-web",
  "webcam-slash" => "camera-web-slash",
  "weight" => "weight-scale",
  "wifi-1" => "wifi-weak",
  "wifi-2" => "wifi-fair",
  "window-alt" => "window-flip",
  "window-close" => "rectangle-xmark",
  "wine-glass-alt" => "wine-glass-empty",
}

Class Method Summary collapse

Class Method Details

.all_icons(theme_id = nil) ⇒ Object



367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
# File 'lib/svg_sprite.rb', line 367

def self.all_icons(theme_id = nil)
  get_set_cache("icons_#{Theme.transform_ids(theme_id).join(",")}") do
    Set
      .new()
      .merge(settings_icons)
      .merge(plugin_icons)
      .merge(badge_icons)
      .merge(group_icons)
      .merge(theme_icons(theme_id))
      .merge(custom_icons(theme_id))
      .delete_if { |i| i.blank? || i.include?("/") }
      .map! { |i| process(i.dup) }
      .merge(SVG_ICONS)
      .sort
  end
end

.badge_iconsObject



483
484
485
# File 'lib/svg_sprite.rb', line 483

def self.badge_icons
  get_set_cache("badge_icons") { Badge.pluck(:icon).uniq }
end

.bundle(theme_id = nil) ⇒ Object



404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
# File 'lib/svg_sprite.rb', line 404

def self.bundle(theme_id = nil)
  icons = all_icons(theme_id)

  svg_subset =
    "" \
      "<!--
Discourse SVG subset of Font Awesome Free by @fontawesome - https://fontawesome.com
License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
-->
<svg xmlns='http://www.w3.org/2000/svg' style='display: none;'>
" \
      "".dup

  svg_subset << core_svgs.slice(*icons).values.join
  svg_subset << custom_svgs(theme_id).values.join

  svg_subset << "</svg>"
end

.cacheObject



537
538
539
# File 'lib/svg_sprite.rb', line 537

def self.cache
  @cache ||= DistributedCache.new("svg_sprite")
end

.clear_plugin_svg_sprite_cache!Object

Just used in tests



296
297
298
# File 'lib/svg_sprite.rb', line 296

def self.clear_plugin_svg_sprite_cache!
  @plugin_svgs = nil
end

.core_svgsObject



288
289
290
291
292
293
# File 'lib/svg_sprite.rb', line 288

def self.core_svgs
  @core_svgs ||=
    CORE_SVG_SPRITES.reduce({}) do |symbols, path|
      symbols.merge!(symbols_for(File.basename(path, ".svg"), File.read(path), strict: true))
    end
end

.custom_icons(theme_id) ⇒ Object



514
515
516
517
# File 'lib/svg_sprite.rb', line 514

def self.custom_icons(theme_id)
  # Automatically register icons in sprites added via themes or plugins
  custom_svgs(theme_id).keys
end

.custom_svgs(theme_id) ⇒ Object



363
364
365
# File 'lib/svg_sprite.rb', line 363

def self.custom_svgs(theme_id)
  plugin_svgs.merge(theme_svgs(theme_id))
end

.expire_cacheObject



394
395
396
# File 'lib/svg_sprite.rb', line 394

def self.expire_cache
  cache&.clear
end

.get_set_cache(key, &block) ⇒ Object



533
534
535
# File 'lib/svg_sprite.rb', line 533

def self.get_set_cache(key, &block)
  cache.defer_get_set(key, &block)
end

.group_iconsObject



487
488
489
# File 'lib/svg_sprite.rb', line 487

def self.group_icons
  get_set_cache("group_icons") { Group.pluck(:flair_icon).uniq }
end

.icon_picker_search(keyword, only_available = false) ⇒ Object



429
430
431
432
433
434
# File 'lib/svg_sprite.rb', line 429

def self.icon_picker_search(keyword, only_available = false)
  symbols = svgs_for(SiteSetting.default_theme_id)
  symbols.slice!(*all_icons(SiteSetting.default_theme_id)) if only_available
  symbols.reject! { |icon_id, _sym| !icon_id.include?(keyword) } if keyword.present?
  symbols.sort_by(&:first).map { |id, symbol| { id:, symbol: } }
end

.path(theme_id = nil) ⇒ Object



390
391
392
# File 'lib/svg_sprite.rb', line 390

def self.path(theme_id = nil)
  "/svg-sprite/#{Discourse.current_hostname}/svg-#{theme_id}-#{version(theme_id)}.js"
end

.plugin_iconsObject



479
480
481
# File 'lib/svg_sprite.rb', line 479

def self.plugin_icons
  DiscoursePluginRegistry.svg_icons
end

.plugin_svgsObject



300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/svg_sprite.rb', line 300

def self.plugin_svgs
  @plugin_svgs ||=
    begin
      plugin_paths = []
      Discourse
        .plugins
        .map { |plugin| File.dirname(plugin.path) }
        .each { |path| plugin_paths << "#{path}/svg-icons/*.svg" }

      custom_sprite_paths = Dir.glob(plugin_paths)

      custom_sprite_paths.reduce({}) do |symbols, path|
        symbols.merge!(symbols_for(File.basename(path, ".svg"), File.read(path), strict: true))
      end
    end
end

.preloadObject



265
266
267
268
269
# File 'lib/svg_sprite.rb', line 265

def self.preload
  settings_icons
  group_icons
  badge_icons
end

.prepare_symbol(symbol, svg_filename = nil) ⇒ Object



453
454
455
456
457
458
459
460
461
462
463
464
# File 'lib/svg_sprite.rb', line 453

def self.prepare_symbol(symbol, svg_filename = nil)
  icon_id = symbol.attr("id")

  case svg_filename
  when "regular"
    icon_id = icon_id.prepend("far-")
  when "brands"
    icon_id = icon_id.prepend("fab-")
  end

  icon_id
end

.process(icon_name) ⇒ Object



519
520
521
522
523
524
525
526
527
528
529
530
531
# File 'lib/svg_sprite.rb', line 519

def self.process(icon_name)
  new_name = icon_name.strip

  FA_4_ICON_MAP.each { |k, v| new_name = new_name.sub(k, v) }
  new_name = remap_from_fa5(new_name)

  if icon_name != new_name
    Discourse.deprecate("The icon `#{icon_name}` is deprecated. Use `#{new_name}` instead.")
    return new_name
  end

  icon_name
end

.raw_svg(name) ⇒ Object

For use in no_ember .html.erb layouts



437
438
439
440
441
442
443
444
445
446
447
# File 'lib/svg_sprite.rb', line 437

def self.raw_svg(name)
  get_set_cache("raw_svg_#{name}") do
    symbol = search(name)
    break "" unless symbol
    symbol = Nokogiri.XML(symbol).children.first
    symbol.name = "svg"
    <<~HTML
      <svg class="fa d-icon svg-icon svg-node" aria-hidden="true">#{symbol}</svg>
    HTML
  end.html_safe
end

.remap_from_fa5(icon_name) ⇒ Object



541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
# File 'lib/svg_sprite.rb', line 541

def self.remap_from_fa5(icon_name)
  lookup_name = icon_name
  prefix = nil

  if lookup_name.start_with?("far-")
    prefix = "far"
    lookup_name = lookup_name[4..-1]
  elsif lookup_name.start_with?("fab-")
    prefix = "fab"
    lookup_name = lookup_name[4..-1]
  end

  if FA5_REMAPS.key?(lookup_name)
    new_name = FA5_REMAPS[lookup_name]
    new_name = "#{prefix}-#{new_name}" if prefix

    return new_name
  end

  icon_name
end

.search(searched_icon) ⇒ Object



423
424
425
426
427
# File 'lib/svg_sprite.rb', line 423

def self.search(searched_icon)
  searched_icon = process(searched_icon.dup)

  svgs_for(SiteSetting.default_theme_id)[searched_icon] || false
end

.settings_iconsObject



466
467
468
469
470
471
472
473
474
475
476
477
# File 'lib/svg_sprite.rb', line 466

def self.settings_icons
  get_set_cache("settings_icons") do
    # includes svg_icon_subset and any settings containing _icon (incl. plugin settings)
    site_setting_icons = []

    SiteSetting.settings_hash.select do |key, value|
      site_setting_icons |= value.split("|") if key.to_s.include?("_icon") && String === value
    end

    site_setting_icons
  end
end

.svgs_for(theme_id) ⇒ Object



398
399
400
401
402
# File 'lib/svg_sprite.rb', line 398

def self.svgs_for(theme_id)
  svgs = core_svgs
  svgs = svgs.merge(custom_svgs(theme_id)) if theme_id.present?
  svgs
end

.symbols_for(svg_filename, sprite, strict:) ⇒ Object



271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/svg_sprite.rb', line 271

def self.symbols_for(svg_filename, sprite, strict:)
  if strict
    Nokogiri.XML(sprite) { |config| config.options = Nokogiri::XML::ParseOptions::NOBLANKS }
  else
    Nokogiri.XML(sprite)
  end.css("symbol")
    .filter_map do |sym|
      icon_id = prepare_symbol(sym, svg_filename)
      if icon_id.present?
        sym.attributes["id"].value = icon_id
        sym.css("title").each(&:remove)
        [icon_id, sym.to_xml]
      end
    end
    .to_h
end

.theme_icons(theme_id) ⇒ Object



491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
# File 'lib/svg_sprite.rb', line 491

def self.theme_icons(theme_id)
  return [] if theme_id.blank?

  theme_icon_settings = []
  theme_ids = Theme.transform_ids(theme_id)

  # Need to load full records for default values
  Theme
    .where(id: theme_ids)
    .each do |theme|
      _settings =
        theme.cached_settings.each do |key, value|
          if key.to_s.include?("_icon") && String === value
            theme_icon_settings |= value.split("|")
          end
        end
    end

  theme_icon_settings |= ThemeModifierHelper.new(theme_ids: theme_ids).svg_icons

  theme_icon_settings
end

.theme_sprite_variable_nameObject



449
450
451
# File 'lib/svg_sprite.rb', line 449

def self.theme_sprite_variable_name
  THEME_SPRITE_VAR_NAME
end

.theme_svgs(theme_id) ⇒ Object



317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/svg_sprite.rb', line 317

def self.theme_svgs(theme_id)
  if theme_id.present?
    cache
      .defer_get_set_bulk(
        Theme.transform_ids(theme_id),
        lambda { |theme_id| "theme_svg_sprites_#{theme_id}" },
      ) do |theme_ids|
        theme_field_uploads =
          ThemeField.where(
            type_id: ThemeField.types[:theme_upload_var],
            name: THEME_SPRITE_VAR_NAME,
            theme_id: theme_ids,
          ).pluck(:upload_id)

        theme_sprites =
          ThemeSvgSprite.where(theme_id: theme_ids).pluck(:theme_id, :upload_id, :sprite)
        missing_sprites = (theme_field_uploads - theme_sprites.map(&:second))

        if missing_sprites.present?
          Rails.logger.warn(
            "Missing ThemeSvgSprites for theme #{theme_id}, uploads #{missing_sprites.join(", ")}",
          )
        end

        theme_sprites
          .map do |(theme_id, upload_id, sprite)|
            begin
              [theme_id, symbols_for("theme_#{theme_id}_#{upload_id}.svg", sprite, strict: false)]
            rescue => e
              Rails.logger.warn(
                "Bad XML in custom sprite in theme with ID=#{theme_id}. Error info: #{e.inspect}",
              )
            end
          end
          .compact
          .to_h
          .values_at(*theme_ids)
      end
      .values
      .compact
      .reduce({}) { |a, b| a.merge!(b) }
  else
    {}
  end
end

.version(theme_id = nil) ⇒ Object



384
385
386
387
388
# File 'lib/svg_sprite.rb', line 384

def self.version(theme_id = nil)
  get_set_cache("version_#{Theme.transform_ids(theme_id).join(",")}") do
    Digest::SHA1.hexdigest(bundle(theme_id))
  end
end