Collection.icon can be a literal emoji or a string key into Outline's own icon library (~50 custom outline-icons keys + ~90 FontAwesome keys, per shared/utils/IconLibrary.tsx in outline/outline — a different mapping than the outline-icons package itself, which is keyed by PascalCase component name, not the string stored on the collection). Only emoji was handled before, so most non-emoji collections fell back to a generic folder glyph. Covers the high-confidence subset with an unambiguous SF Symbol match; unmapped keys keep falling back to the folder rather than risk an invalid symbol name rendering blank.
97 lines
3.5 KiB
Swift
97 lines
3.5 KiB
Swift
import Foundation
|
|
|
|
/// Best-effort SF Symbol equivalents for Outline's non-emoji collection icons.
|
|
///
|
|
/// `Collection.icon` is either a literal emoji or a string key into Outline's
|
|
/// own icon set — a mix of custom `outline-icons` components (camelCase keys)
|
|
/// and FontAwesome icons (kebab-case keys, e.g. `faCake` → `"cake"`). The
|
|
/// canonical key list lives in `outline/outline`'s `shared/utils/IconLibrary.tsx`,
|
|
/// not in the `outline-icons` package itself (that's just the raw component
|
|
/// library, keyed by PascalCase component name — a different naming scheme).
|
|
///
|
|
/// SF Symbols has no exact match for everything in that set, so this only
|
|
/// covers keys with a confident, unambiguous equivalent. Anything else falls
|
|
/// back to the generic folder glyph — better than a blank/invalid symbol name
|
|
/// from a wrong guess.
|
|
enum OutlineIconMapping {
|
|
static func sfSymbolName(for outlineIconKey: String) -> String? {
|
|
mapping[outlineIconKey]
|
|
}
|
|
|
|
private static let mapping: [String: String] = [
|
|
// Outline's own custom icon set (camelCase keys).
|
|
"academicCap": "graduationcap.fill",
|
|
"bicycle": "bicycle",
|
|
"beaker": "testtube.2",
|
|
"buildingBlocks": "cube.fill",
|
|
"bookmark": "bookmark.fill",
|
|
"browser": "globe",
|
|
"collection": "square.grid.2x2.fill",
|
|
"coins": "dollarsign.circle.fill",
|
|
"camera": "camera.fill",
|
|
"carrot": "leaf.fill",
|
|
"clock": "clock.fill",
|
|
"cloud": "cloud.fill",
|
|
"code": "chevron.left.forwardslash.chevron.right",
|
|
"database": "cylinder.fill",
|
|
"done": "checkmark.circle.fill",
|
|
"email": "envelope.fill",
|
|
"eye": "eye.fill",
|
|
"feedback": "bubble.left.and.bubble.right.fill",
|
|
"flame": "flame.fill",
|
|
"graph": "chart.line.uptrend.xyaxis",
|
|
"globe": "globe",
|
|
"hashtag": "number",
|
|
"info": "info.circle.fill",
|
|
"image": "photo.fill",
|
|
"internet": "network",
|
|
"leaf": "leaf.fill",
|
|
"library": "books.vertical.fill",
|
|
"lightbulb": "lightbulb.fill",
|
|
"lightning": "bolt.fill",
|
|
"letter": "envelope.fill",
|
|
"math": "function",
|
|
"moon": "moon.fill",
|
|
"notepad": "note.text",
|
|
"padlock": "lock.fill",
|
|
"palette": "paintpalette.fill",
|
|
"pencil": "pencil",
|
|
"plane": "airplane",
|
|
"promote": "megaphone.fill",
|
|
"ramen": "fork.knife",
|
|
"question": "questionmark.circle.fill",
|
|
"server": "server.rack",
|
|
"sun": "sun.max.fill",
|
|
"shapes": "square.on.circle",
|
|
"sport": "sportscourt.fill",
|
|
"smiley": "face.smiling.fill",
|
|
"target": "target",
|
|
"team": "person.3.fill",
|
|
"terminal": "terminal.fill",
|
|
"thumbsup": "hand.thumbsup.fill",
|
|
"truck": "shippingbox.fill",
|
|
"tools": "wrench.and.screwdriver.fill",
|
|
"vehicle": "car.fill",
|
|
"warning": "exclamationmark.triangle.fill",
|
|
|
|
// FontAwesome icons (kebab-case keys) — high-confidence subset only.
|
|
"book": "book.fill",
|
|
"cake": "birthday.cake.fill",
|
|
"cat": "cat.fill",
|
|
"dog": "dog.fill",
|
|
"cube": "cube.fill",
|
|
"heart": "heart.fill",
|
|
"gift": "gift.fill",
|
|
"hammer": "hammer.fill",
|
|
"laptop": "laptopcomputer",
|
|
"map": "map.fill",
|
|
"newspaper": "newspaper.fill",
|
|
"paw": "pawprint.fill",
|
|
"shield": "shield.fill",
|
|
"tree": "tree.fill",
|
|
"trophy": "trophy.fill",
|
|
"umbrella": "umbrella.fill",
|
|
"fish": "fish.fill"
|
|
]
|
|
}
|