Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Unicon

One concept, three icon names.

An app knows it wants to draw a house. What a house is called depends on who is drawing it: Bootstrap Icons says house, SF Symbols says house, Material Symbols says home. Unicon holds that translation, so a Rails app can name the concept once and let the web page, the iOS client and the Android client each draw it from the set they already ship.

Unicon.fetch :house
# => { bootstrap: 'house', ios: 'house', android: 'home' }

Unicon[:contact]
# => { bootstrap: 'person-rolodex', ios: 'person.crop.circle', android: 'contacts' }

Unicon[] and Unicon.fetch are the same method; [] is the shorter spelling.

The keys are symbols and the names are frozen strings: a name is on its way into "bi bi-#{icon}" or into JSON either way, and person.crop.circle is a string long before it is a symbol.

Installation

gem 'unicon'

The three keys

Every concept carries exactly three keys, and never fewer:

Key Design system License
:bootstrap Bootstrap Icons MIT
:ios SF Symbols Apple, Apple platforms only
:android Material Symbols Apache 2.0

The keys are named after the client that draws the icon rather than after the system, because that is the question a caller is answering. :ios always holds an SF Symbols name and :android always holds a Material Symbols name — nothing else is meant by them.

Anything unknown draws a circle

Unicon.fetch :nothing_by_this_name
# => { bootstrap: 'circle', ios: 'circle', android: 'circle' }

A caller rendering whatever it is handed never has to check first, and never draws a blank. A concept may be given as a string, so Unicon['contact'] works too.

Three lists, and which one you want

Unicon.icons    # => [:account, :airplane, :alarm, :archive, :award, :badge, ...]    127
Unicon.names    # => [:account, :address, :agent, :airplane, :alarm, :alert, ...]    303
Unicon.actions  # => [:arrow_down, :arrow_left, :arrow_right, :arrow_up, ...]         42
  • Unicon.icons is one name per distinct picture. No two entries draw the same thing, which is what makes it the list to show somebody choosing an icon.
  • Unicon.names is the union of all three groups — the icons, the actions and the model synonyms — and so every name that resolves. Ask for it to find out whether a name draws something; ask for icons when somebody is choosing one.
  • Unicon.actions is the doing words: close, pencil, every chevron. A toolbar needs them and Unicon[:close] answers, but nobody has a Close model, so icons leaves them out on purpose.

All three are frozen, sorted arrays of symbols; only what fetch returns is strings. Unicon::ICONS, Unicon::TABLE and Unicon::ACTIONS are the tables behind them, for a caller who wants the pictures as well as the names.

Model names

A host app looks an icon up by the name of the model it is rendering, and the more names answer, the less any app has to declare. 134 of them borrow the icons of a concept — :user takes the person, :zip takes the pin — and the Aliases column of the table below says which took which. They resolve without swelling the list a picker offers.

Four borrow an action rather than a thing, so they are the four the table cannot show: :export takes the download, :import the upload, :sync the refresh, :subscription the repeat. Each still answers to Unicon[] like any other name.

Every concept

A concept is listed only when all three systems have a sensible icon for it. Where one of the three has none, the concept is left out rather than filled in with something close — an agent is a badge rather than a robot here, because Bootstrap and Material both draw a robot and SF Symbols has none.

The SF Symbols are shown under section 2.11 of the Xcode and Apple SDKs Agreement, which licenses them for developing applications for Apple-branded products, and this repository is part of building one. They may not be redistributed for any other purpose, so anyone reusing this gem outside that context should show the names alone.

The cells hold the icon and not its name, so the table stays readable at 127 rows. The name each system uses is on the icon: hover it, or reach it with a screen reader, and Unicon[:search][:ios] reads back as magnifyingglass.

The 42 action icons are not in the table. They are fetchable — Unicon[:pencil] answers — but they name what an app does rather than what it has, and this table is Unicon.icons drawn out. Unicon.actions names them all.

Icon Aliases Bootstrap iOS Android
:account :avatar :profile person-circle person.crop.circle account_circle
:airplane airplane airplane flight
:alarm :deadline alarm alarm alarm
:archive archive archivebox archive
:award :specialty award rosette workspace_premium
:badge :agent :employee :role person-vcard person.text.rectangle badge
:bag bag bag shopping_bag
:bank bank building.columns account_balance
:bar_chart :vertical bar-chart chart.bar bar_chart
:barcode upc barcode barcode
:battery battery battery.100 battery_full
:bell :notification :reminder bell bell notifications
:bicycle bicycle bicycle directions_bike
:bolt lightning bolt bolt
:book book book book
:bookmark bookmark bookmark bookmark
:box :inventory :item :package :product box shippingbox inventory_2
:briefcase :provider briefcase briefcase work
:brush brush paintbrush brush
:building :brand :business :city :company :office :organization building building apartment
:bus bus-front bus directions_bus
:calendar :event :plan :schedule calendar calendar calendar_month
:calendar_check :appointment :booking calendar-check calendar.badge.checkmark event_available
:camera camera camera photo_camera
:car :ride :vehicle car-front car directions_car
:cart :order :purchase cart cart shopping_cart
:cash :cost cash banknote payments
:chat :comment :conversation :message chat message chat
:check_circle check-circle checkmark.circle check_circle
:circle circle circle circle
:clipboard :assessment :survey clipboard list.clipboard content_paste
:clock :history :session :shift clock clock schedule
:close_circle x-circle xmark.circle cancel
:cloud :backup cloud cloud cloud
:compass compass location.north.circle explore
:contact person-rolodex person.crop.circle contacts
:credit_card :charge :payment :transaction credit-card creditcard credit_card
:display :screen display display monitor
:document :file :form :page :summary file-earmark doc description
:droplet droplet drop water_drop
:envelope :email envelope envelope mail
:eye :view eye eye visibility
:filter funnel line.3.horizontal.decrease filter_alt
:fingerprint fingerprint touchid fingerprint
:fire fire flame local_fire_department
:flag :milestone flag flag flag
:folder :project folder folder folder
:gear :configuration :setting gear gearshape settings
:gift :coupon :offer gift gift redeem
:globe :country :site globe globe public
:grid grid square.grid.2x2 grid_view
:hammer :job hammer hammer hardware
:headphones headphones headphones headphones
:heart heart heart favorite
:hospital hospital cross.case local_hospital
:hourglass hourglass hourglass hourglass_empty
:house :home house house home
:image :banner :photo :picture image photo image
:inbox inbox tray inbox
:infinity infinity infinity all_inclusive
:info info-circle info.circle info
:invoice :bill file-earmark-text doc.text receipt_long
:key :credential :permission :token key key key
:keyboard keyboard keyboard keyboard
:laptop laptop laptopcomputer computer
:lightbulb lightbulb lightbulb lightbulb
:link link link link
:list :log list-ul list.bullet list
:lock :password lock lock lock
:map :area :county :market :region :state :territory :trip map map map
:megaphone :announcement :campaign megaphone megaphone campaign
:microphone :recording mic mic mic
:mobile phone smartphone mobile
:moon moon moon dark_mode
:music :track music-note music.note music_note
:note :memo sticky note.text sticky_note_2
:palette palette paintpalette palette
:paperclip :attachment paperclip paperclip attach_file
:people :group :staff :team people person.2 group
:percent :discount percent percent percent
:person :client :customer :lead :member :user person person person
:phone :call telephone phone call
:pie_chart pie-chart chart.pie pie_chart
:pin :address :destination :location :zip geo-alt mappin location_on
:playlist :episode collection-play play.square.stack video_library
:puzzle :integration :platform :plugin puzzle puzzlepiece extension
:qr_code qr-code qrcode qr_code
:question :answer question-circle questionmark.circle help
:rain cloud-rain cloud.rain rainy
:receipt receipt receipt receipt
:reply reply arrowshape.turn.up.left reply
:ruler rulers ruler straighten
:search search magnifyingglass search
:server hdd-rack server.rack dns
:shield shield shield shield
:shop :franchise :vendor shop storefront storefront
:signature :contract pen signature draw
:signpost :route :source signpost-split signpost.right signpost
:sliders :optimization :preference sliders slider.horizontal.3 tune
:smiley :feedback emoji-smile face.smiling sentiment_satisfied
:snow snow snowflake weather_snowy
:speedometer :dashboard :evaluation speedometer gauge speed
:square square square square
:star :rating :review star star star
:stopwatch stopwatch stopwatch timer
:sun sun sun.max light_mode
:table table tablecells table_chart
:tag :category :label :price tag tag sell
:task :todo check2-square checklist task_alt
:terminal :api :prompt terminal terminal terminal
:thumbs_down hand-thumbs-down hand.thumbsdown thumb_down
:thumbs_up hand-thumbs-up hand.thumbsup thumb_up
:ticket ticket ticket confirmation_number
:toolbox tools wrench.and.screwdriver handyman
:train train-front train.side.front.car train
:tree tree tree park
:trending_up graph-up chart.line.uptrend.xyaxis trending_up
:trophy :goal trophy trophy trophy
:truck :delivery :fleet :shipment :supplier truck truck.box local_shipping
:video :movie camera-video video videocam
:volume volume-up speaker.wave.2 volume_up
:wallet wallet wallet.pass wallet
:warning :alert :issue exclamation-triangle exclamationmark.triangle warning
:waveform :audio :echo soundwave waveform graphic_eq
:wifi wifi wifi wifi
:window :app window macwindow web_asset
:wrench wrench wrench build

A dashed circle is a symbol newer than the macOS that drew this table, which knows the SF Symbols 5 set. Hover it for the name, which resolves in an app built against a newer SDK.

Where the names come from

Every name in the table is checked, by rake validate, against the list its own design system publishes. The lists are vendored under data/, so the check needs no network and runs as part of the default rake task.

  • data/bootstrap-icons.txt — 2,078 names, from font/bootstrap-icons.json at tag v1.13.1 of twbs/icons.
  • data/material-symbols.txt — 3,896 names, from Google's metadata endpoint, keeping only what Material Symbols Outlined actually ships. The endpoint also lists legacy Material Icons, such as laptop and smartphone, which no longer resolve as symbols.
  • data/sf-symbols.txt — 8,295 names, from Metadata/name_availability.plist inside SF Symbols.app, filtered to names whose iOS availability is 18.3 or earlier. The plist gives each release an iOS version, and that version is the constraint, so the filter reads it rather than the release year. A name added in iOS 18.4 or later is left out and cannot enter the table.

The artwork in the table

All three columns show artwork vendored under vendor/, so the table renders whether or not a CDN answers, and each directory carries the license its artwork came with.

Bootstrap Icons and Material Symbols are downloaded from their published sources, and differ from upstream in two attributes: a gray fill, so a row reads on a light and a dark theme alike, and a 20px box, so the columns line up. Apple publishes no files to fetch, so tools/sf_symbols.swift asks macOS to draw each symbol and writes a PNG in the same gray and the same box.

That rendering is done by the machine running rake readme, and a machine only knows the symbols its own system shipped with. Anything newer gets assets/undrawn.svg — a dashed circle of our own drawing, not Apple's — with the symbol's name still on it to hover. One row is in that state today: :receipt, whose SF symbol arrived in iOS 18.2, drawn on a Mac running macOS 14.3. rake validate has already proved every name real, which is why a symbol this Mac cannot draw is reported rather than fatal.

License

MIT. See LICENSE.txt.

About

One concept, the icon for it in Bootstrap Icons, SF Symbols and Material

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages