From 1de79833452ff84420bee18d1f34912fdfff030f Mon Sep 17 00:00:00 2001 From: Valdemar Lorenzen Date: Thu, 15 Oct 2026 13:59:10 +0200 Subject: [PATCH] feat: add searchable emoji picker --- Makefile | 1 + Package.swift | 2 +- README.md | 10 +- Sources/Conjure/EmojiPickerController.swift | 192 ++ .../Conjure/LauncherWindowController.swift | 108 +- Sources/ConjureKit/Applications.swift | 2 + Sources/ConjureKit/EmojiCatalog.swift | 61 + .../ConjureKit/Resources/LICENSE-gemoji.txt | 28 + Sources/ConjureKit/Resources/emoji.tsv | 1870 +++++++++++++++++ TODO.md | 2 +- Tests/ConjureKitTests/EmojiCatalogTests.swift | 20 + Tests/ConjureKitTests/EmojiPickerTests.swift | 69 + 12 files changed, 2322 insertions(+), 43 deletions(-) create mode 100644 Sources/Conjure/EmojiPickerController.swift create mode 100644 Sources/ConjureKit/EmojiCatalog.swift create mode 100644 Sources/ConjureKit/Resources/LICENSE-gemoji.txt create mode 100644 Sources/ConjureKit/Resources/emoji.tsv create mode 100644 Tests/ConjureKitTests/EmojiCatalogTests.swift create mode 100644 Tests/ConjureKitTests/EmojiPickerTests.swift diff --git a/Makefile b/Makefile index 097509f..2ac4492 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ build: mkdir -p $(APP)/Contents/MacOS $(APP)/Contents/Resources cp .build/release/Conjure $(APP)/Contents/MacOS/Conjure cp Resources/Info.plist $(APP)/Contents/Info.plist + cp -R .build/release/Conjure_ConjureKit.bundle $(APP)/Contents/Resources/ swift Scripts/icon.swift .build/Conjure.iconset iconutil -c icns .build/Conjure.iconset -o $(APP)/Contents/Resources/Conjure.icns codesign --force --sign - $(APP) diff --git a/Package.swift b/Package.swift index 0243f84..138f611 100644 --- a/Package.swift +++ b/Package.swift @@ -6,7 +6,7 @@ let package = Package( platforms: [.macOS(.v14)], products: [.executable(name: "Conjure", targets: ["Conjure"])], targets: [ - .target(name: "ConjureKit"), + .target(name: "ConjureKit", resources: [.process("Resources")]), .executableTarget(name: "Conjure", dependencies: ["ConjureKit"]), .testTarget(name: "ConjureKitTests", dependencies: ["ConjureKit", "Conjure"]), ] diff --git a/README.md b/README.md index dbec387..41c0e5f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Conjure -A native macOS launcher for applications, calculations, unit and currency conversions, and English → Japanese translation. +A native macOS launcher for applications, calculations, unit and currency conversions, emoji, and English → Japanese translation. ## Build and install @@ -75,6 +75,14 @@ Convert length, mass, temperature, volume, duration, speed, area, and data with Currency and crypto conversions require internet access and use [currency-api](https://github.com/fawazahmed0/exchange-api). These are **daily rates, not live market prices**; the snapshot date is shown with the answer. Treat them as estimates, not trading or payment quotes. Fetch failures show an error rather than silently using old rates; change the query to retry. +## Emoji picker + +Search for **Conjure Emoji** and open it. Browse the grid or search by name, keyword, `:shortcode:`, or emoji. Use the category menu to filter results or show **Recently Used**. Your last 30 selections are saved locally and appear first when you reopen the picker. + +Use the arrow keys to navigate; Control-J/Control-K move one emoji forward/back. Return or clicking an emoji copies it and dismisses Conjure, restoring focus to the previous app. Paste with Command-V; no Accessibility permission is needed. Escape or the Back chevron returns to the launcher and restores your search. + +The picker works offline with 1,870 emoji from [gemoji v4.1.0](https://github.com/github/gemoji/tree/v4.1.0). Its [MIT license](Sources/ConjureKit/Resources/LICENSE-gemoji.txt) is included in the application. + ## Translation Search for **Conjure Translate** and open it. Enter English in the search bar, choose a provider, then press Return or click **Translate**. Typing alone never sends text. Copy selected Japanese output with Command-C; the copy hint appears beside the Translate action at the bottom. The Back chevron beside the input or Escape returns to the launcher and restores your search. diff --git a/Sources/Conjure/EmojiPickerController.swift b/Sources/Conjure/EmojiPickerController.swift new file mode 100644 index 0000000..95eff35 --- /dev/null +++ b/Sources/Conjure/EmojiPickerController.swift @@ -0,0 +1,192 @@ +import AppKit +import ConjureKit + +@MainActor +final class EmojiPickerController: NSViewController, NSCollectionViewDataSource { + private let collection = NSCollectionView() + private let category = NSPopUpButton() + private let status = NSTextField(labelWithString: "") + private let empty = NSTextField(labelWithString: "No matching emoji") + private let copyButton = NSButton(title: "Copy Emoji", target: nil, action: nil) + private let defaults: UserDefaults + private let pasteboard: NSPasteboard + private var results: [Emoji] = [] + private var selected = 0 + var input: (() -> String)? + var closed: (() -> Void)? + var copied: (() -> Void)? + + init(defaults: UserDefaults = .standard, pasteboard: NSPasteboard = .general) { + self.defaults = defaults + self.pasteboard = pasteboard + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { fatalError("Conjure creates its emoji picker programmatically") } + + override func loadView() { + view = NSView() + category.addItems(withTitles: ["All Emoji", "Recently Used"] + EmojiCatalog.categories) + category.setAccessibilityLabel("Emoji category") + category.target = self + category.action = #selector(categoryChanged) + let layout = NSCollectionViewFlowLayout() + layout.itemSize = NSSize(width: 64, height: 56) + layout.minimumInteritemSpacing = 6 + layout.minimumLineSpacing = 6 + layout.sectionInset = NSEdgeInsets(top: 12, left: 16, bottom: 12, right: 16) + collection.collectionViewLayout = layout + collection.backgroundColors = [.clear] + collection.dataSource = self + collection.register(EmojiItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier("emoji")) + collection.setAccessibilityLabel("Emoji grid") + let scroll = LauncherScrollView() + scroll.documentView = collection + scroll.hasVerticalScroller = true + scroll.autohidesScrollers = true + scroll.scrollerStyle = .overlay + scroll.drawsBackground = false + scroll.contentView.drawsBackground = false + empty.textColor = SunsetPalette.secondaryText + status.font = .systemFont(ofSize: 12) + status.textColor = SunsetPalette.secondaryText + status.lineBreakMode = .byTruncatingTail + status.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) + copyButton.target = self + copyButton.action = #selector(copySelection) + copyButton.keyEquivalent = "\r" + copyButton.isBordered = false + copyButton.font = .systemFont(ofSize: 12, weight: .medium) + copyButton.contentTintColor = SunsetPalette.text + let footer = NSStackView(views: [status, NSView(), copyButton, ShortcutIndicator("↵")]) + footer.spacing = 8 + for child in [category, scroll, empty, footer] { + child.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(child) + } + NSLayoutConstraint.activate([ + category.topAnchor.constraint(equalTo: view.topAnchor), + category.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16), + scroll.topAnchor.constraint(equalTo: category.bottomAnchor, constant: 4), + scroll.leadingAnchor.constraint(equalTo: view.leadingAnchor), + scroll.trailingAnchor.constraint(equalTo: view.trailingAnchor), + scroll.bottomAnchor.constraint(equalTo: footer.topAnchor, constant: -4), + empty.centerXAnchor.constraint(equalTo: scroll.centerXAnchor), + empty.centerYAnchor.constraint(equalTo: scroll.centerYAnchor), + footer.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16), + footer.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16), + footer.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8), + footer.heightAnchor.constraint(equalToConstant: 36), + ]) + inputChanged() + } + + @objc private func categoryChanged() { inputChanged() } + @objc func goBack() { closed?() } + override func cancelOperation(_ sender: Any?) { goBack() } + + func inputChanged() { + let recent = defaults.stringArray(forKey: "recentEmoji") ?? [] + let matches = EmojiCatalog.search(input?() ?? "", category: category.indexOfSelectedItem > 1 ? category.titleOfSelectedItem : nil) + if category.indexOfSelectedItem == 1 { + results = recent.compactMap { value in matches.first { $0.value == value } } + } else if category.indexOfSelectedItem == 0, (input?() ?? "").isEmpty { + let recentSet = Set(recent) + results = recent.compactMap { value in matches.first { $0.value == value } } + + matches.filter { !recentSet.contains($0.value) } + } else { + results = matches + } + selected = 0 + collection.reloadData() + collection.scroll(NSPoint.zero) + updateSelection() + } + + func moveSelection(by offset: Int) { + guard !results.isEmpty else { return } + let old = selected + selected = min(max(selected + offset, 0), results.count - 1) + (collection.item(at: IndexPath(item: old, section: 0)) as? EmojiItem)?.highlight(false) + updateSelection() + collection.scrollToItems(at: [IndexPath(item: selected, section: 0)], scrollPosition: .nearestVerticalEdge) + } + + func handle(_ selector: Selector) -> Bool { + let columns = max(1, Int((collection.bounds.width - 32 + 6) / 70)) + switch selector { + case #selector(NSResponder.moveLeft(_:)): moveSelection(by: -1) + case #selector(NSResponder.moveRight(_:)): moveSelection(by: 1) + case #selector(NSResponder.moveUp(_:)): moveSelection(by: -columns) + case #selector(NSResponder.moveDown(_:)): moveSelection(by: columns) + case #selector(NSResponder.insertNewline(_:)): copySelection() + case #selector(NSResponder.cancelOperation(_:)): goBack() + default: return false + } + return true + } + + private func updateSelection() { + empty.isHidden = !results.isEmpty + if results.isEmpty { + empty.stringValue = category.indexOfSelectedItem == 1 ? "No recently used emoji match" : "No matching emoji" + } + copyButton.isEnabled = !results.isEmpty + status.stringValue = results.isEmpty ? "0 emoji" : "\(results[selected].name) · \(results.count) emoji" + (collection.item(at: IndexPath(item: selected, section: 0)) as? EmojiItem)?.highlight(true) + } + + @objc func copySelection() { + guard results.indices.contains(selected) else { return } + let value = results[selected].value + pasteboard.clearContents() + guard pasteboard.setString(value, forType: .string) else { + status.stringValue = "Couldn’t copy emoji. Try again." + return + } + var recent = defaults.stringArray(forKey: "recentEmoji") ?? [] + recent.removeAll { $0 == value } + defaults.set(Array(([value] + recent).prefix(30)), forKey: "recentEmoji") + closed?() + copied?() + } + + func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { results.count } + + func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { + let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier("emoji"), for: indexPath) as! EmojiItem + let emoji = results[indexPath.item] + item.button.title = emoji.value + item.button.toolTip = emoji.name + item.button.setAccessibilityLabel(emoji.name) + item.highlight(indexPath.item == selected) + item.clicked = { [weak self] in + self?.selected = indexPath.item + self?.copySelection() + } + return item + } +} + +@MainActor +private final class EmojiItem: NSCollectionViewItem { + let button = NSButton() + var clicked: (() -> Void)? + + override func loadView() { + button.font = .systemFont(ofSize: 32) + button.isBordered = false + button.target = self + button.action = #selector(copyEmoji) + button.wantsLayer = true + button.layer?.cornerRadius = 10 + view = button + } + + func highlight(_ selected: Bool) { + button.layer?.backgroundColor = selected ? SunsetPalette.accent.withAlphaComponent(0.22).cgColor : nil + button.setAccessibilitySelected(selected) + } + + @objc private func copyEmoji() { clicked?() } +} diff --git a/Sources/Conjure/LauncherWindowController.swift b/Sources/Conjure/LauncherWindowController.swift index 18a8500..1191baa 100644 --- a/Sources/Conjure/LauncherWindowController.swift +++ b/Sources/Conjure/LauncherWindowController.swift @@ -5,7 +5,7 @@ import ConjureKit final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSearchFieldDelegate, NSTableViewDataSource, NSTableViewDelegate { private let searchField = NSSearchField() private let searchSymbol = IconView(font: .systemFont(ofSize: 20)) - private let translationBack = NSButton(title: "", target: nil, action: nil) + private let commandBack = NSButton(title: "", target: nil, action: nil) private let tableView = ApplicationTableView() private let statusLabel = NSTextField(labelWithString: "Finding applications…") private let emptyLabel = NSTextField(labelWithString: "Finding applications…") @@ -34,6 +34,8 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe private var launcherViews: [NSView] = [] private var launcherFrameBeforeReview: NSRect? private var translation: TranslationController? + private var emojiPicker: EmojiPickerController? + private var isCommandOpen: Bool { translation != nil || emojiPicker != nil } init(history: LaunchHistory = LaunchHistory(), uninstaller: ApplicationUninstaller = ApplicationUninstaller()) { self.history = history @@ -61,13 +63,14 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe guard let self else { return } if let review = self.uninstallReview { review.moveSelection(offset) } else if self.actions.isShown { self.actions.moveSelection(by: offset) } + else if let picker = self.emojiPicker { picker.moveSelection(by: offset) } else { self.moveSelection(by: offset) } } window.dismiss = { [weak self] in self?.dismiss() } window.canUseNumberShortcuts = { [weak self] in guard let self else { return false } return !self.isLaunching && self.calculation == nil && self.resultCount > 0 - && self.launcherFrameBeforeReview == nil && !self.actions.isShown && self.translation == nil + && self.launcherFrameBeforeReview == nil && !self.actions.isShown && !self.isCommandOpen } window.numberHintsChanged = { [weak self] in self?.updateNumberHints() } window.launchNumber = { [weak self] index in @@ -98,7 +101,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe func present() { (window as? LauncherPanel)?.beginNumberHintSession() - if launcherFrameBeforeReview != nil || translation != nil { + if launcherFrameBeforeReview != nil || isCommandOpen { showWindow(nil) NSApp.activate() window?.makeKeyAndOrderFront(nil) @@ -134,8 +137,8 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe func dismiss(restoringFocus: Bool = true) { guard !restoringFocus || (!isLaunching && window?.attachedSheet == nil) else { return } if let review = uninstallReview { review.goBack(); return } - if let translation { - translation.goBack() + if isCommandOpen { + goBackCommand() if restoringFocus { return } } guard launcherFrameBeforeReview == nil else { return } @@ -230,18 +233,18 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe searchSymbol.image = NSImage(systemSymbolName: "sparkles", accessibilityDescription: nil) searchSymbol.contentTintColor = SunsetPalette.accent - translationBack.image = IconStyle.symbol("chevron.left", for: searchFont) - translationBack.imageScaling = .scaleProportionallyDown - translationBack.isBordered = false - translationBack.contentTintColor = SunsetPalette.secondaryText - translationBack.setAccessibilityLabel("Back to applications") - translationBack.toolTip = "Back to applications (Escape)" - translationBack.isHidden = true + commandBack.image = IconStyle.symbol("chevron.left", for: searchFont) + commandBack.imageScaling = .scaleProportionallyDown + commandBack.isBordered = false + commandBack.contentTintColor = SunsetPalette.secondaryText + commandBack.setAccessibilityLabel("Back to applications") + commandBack.toolTip = "Back to applications (Escape)" + commandBack.isHidden = true NSLayoutConstraint.activate([ - translationBack.widthAnchor.constraint(equalToConstant: IconStyle.applicationSize(for: searchFont)), - translationBack.heightAnchor.constraint(equalToConstant: IconStyle.applicationSize(for: searchFont)), + commandBack.widthAnchor.constraint(equalToConstant: IconStyle.applicationSize(for: searchFont)), + commandBack.heightAnchor.constraint(equalToConstant: IconStyle.applicationSize(for: searchFont)), ]) - let header = NSStackView(views: [searchSymbol, translationBack, searchField]) + let header = NSStackView(views: [searchSymbol, commandBack, searchField]) header.orientation = .horizontal header.alignment = .centerY header.spacing = 12 @@ -431,7 +434,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe } private func updateResults(preservingSelection: Bool = false, allowingCurrencyFetch: Bool = true) { - guard translation == nil else { return } + guard !isCommandOpen else { return } let selectedURL = preservingSelection && results.indices.contains(tableView.selectedRow) ? results[tableView.selectedRow].id : nil let query = searchField.stringValue @@ -497,10 +500,12 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe func controlTextDidChange(_ notification: Notification) { if let translation { translation.inputChanged(); return } + if let emojiPicker { emojiPicker.inputChanged(); return } updateResults() } func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool { + if let emojiPicker { return emojiPicker.handle(commandSelector) } if let translation { if commandSelector == #selector(NSResponder.insertNewline(_:)) { translation.translate(); return true } if commandSelector == #selector(NSResponder.cancelOperation(_:)) { translation.goBack(); return true } @@ -524,7 +529,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe private var resultCount: Int { calculation == nil ? results.count : 1 } private func moveSelection(by offset: Int) { - guard translation == nil else { return } + guard !isCommandOpen else { return } guard resultCount > 0 else { return } let row = min(max(tableView.selectedRow + offset, 0), resultCount - 1) tableView.selectRowIndexes(IndexSet(integer: row), byExtendingSelection: false) @@ -532,7 +537,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe } private func updateOpenButton() { - let canAct = !isLaunching && launcherFrameBeforeReview == nil && translation == nil && tableView.selectedRow >= 0 + let canAct = !isLaunching && launcherFrameBeforeReview == nil && !isCommandOpen && tableView.selectedRow >= 0 openButton.title = calculation == nil ? (results.indices.contains(tableView.selectedRow) && results[tableView.selectedRow].command != nil ? "Open Command" : "Open Application") : "Copy Answer" @@ -584,9 +589,9 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe cell.locationLabel.isHidden = true cell.kindLabel.attributedStringValue = history.isFavorite(entry) ? ApplicationCell.favoriteCommandKind : ApplicationCell.commandKind - cell.imageView?.image = NSImage(systemSymbolName: "character.bubble", accessibilityDescription: nil) + cell.imageView?.image = NSImage(systemSymbolName: entry.command == .emoji ? "face.smiling" : "character.bubble", accessibilityDescription: nil) cell.imageView?.contentTintColor = SunsetPalette.accent - cell.toolTip = "Translate English to Japanese" + cell.toolTip = entry.command == .emoji ? "Search and copy emoji" : "Translate English to Japanese" } else { let application = results[row] cell.textField?.stringValue = application.name @@ -616,7 +621,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe private func configureNumberHint(_ cell: ApplicationCell, row: Int, animated: Bool = false) { let visible = (window as? LauncherPanel)?.numberHintsVisible == true - && calculation == nil && row < 9 && row < resultCount && translation == nil + && calculation == nil && row < 9 && row < resultCount && !isCommandOpen cell.setNumberHint(visible ? String(row + 1) : nil, animated: animated) cell.setAccessibilityHelp(visible ? "Command-\(row + 1) opens this entry" : nil) } @@ -639,7 +644,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe @objc private func showActions() { guard !isLaunching, launcherFrameBeforeReview == nil, window?.attachedSheet == nil, results.indices.contains(tableView.selectedRow) else { return } - guard translation == nil else { return } + guard !isCommandOpen else { return } (window as? LauncherPanel)?.resetNumberHints() let application = results[tableView.selectedRow] actions.open = { [weak self] in self?.openApplication(application) } @@ -727,7 +732,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe } @objc private func openSelection() { - guard !isLaunching, translation == nil, launcherFrameBeforeReview == nil, window?.attachedSheet == nil else { return } + guard !isLaunching, !isCommandOpen, launcherFrameBeforeReview == nil, window?.attachedSheet == nil else { return } if let calculation { guard tableView.selectedRow == 0, let value = calculation.copyValue else { return } let pasteboard = NSPasteboard.general @@ -753,11 +758,9 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe } private func openApplication(_ application: Application) { - guard !isLaunching, translation == nil, launcherFrameBeforeReview == nil, window?.attachedSheet == nil else { return } + guard !isLaunching, !isCommandOpen, launcherFrameBeforeReview == nil, window?.attachedSheet == nil else { return } if let command = application.command { - switch command { - case .translate: showTranslation() - } + showCommand(command) history.recordLaunch(of: application) return } @@ -781,19 +784,42 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe } } - private func showTranslation() { - guard translation == nil, let content = window?.contentView else { return } - let controller = TranslationController() - translation = controller - controller.input = { [weak self] in self?.searchField.stringValue ?? "" } + @objc private func goBackCommand() { + translation?.goBack() + emojiPicker?.goBack() + } + + private func showCommand(_ command: Application.Command) { + guard !isCommandOpen, let content = window?.contentView else { return } + let controller: NSViewController + let placeholder: String + let accessibilityLabel: String + switch command { + case .translate: + let tool = TranslationController() + translation = tool + tool.input = { [weak self] in self?.searchField.stringValue ?? "" } + controller = tool + placeholder = "Enter English text to translate…" + accessibilityLabel = "English text to translate into Japanese" + case .emoji: + let tool = EmojiPickerController() + emojiPicker = tool + tool.input = { [weak self] in self?.searchField.stringValue ?? "" } + tool.copied = { [weak self] in self?.dismiss() } + controller = tool + placeholder = "Search emoji by name or :shortcode:…" + accessibilityLabel = "Search emoji" + } let previousQuery = searchField.stringValue let previousPlaceholder = searchField.placeholderAttributedString - controller.closed = { [weak self, weak controller] in + let close: () -> Void = { [weak self, weak controller] in guard let self, let controller else { return } controller.view.removeFromSuperview() self.translation = nil - self.translationBack.isHidden = true - self.translationBack.target = nil + self.emojiPicker = nil + self.commandBack.isHidden = true + self.commandBack.target = nil self.searchSymbol.isHidden = false for view in self.launcherViews.dropFirst() { view.isHidden = false @@ -807,19 +833,21 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe self.updateResults() self.window?.makeFirstResponder(self.searchField) } + translation?.closed = close + emojiPicker?.closed = close actions.close() (window as? LauncherPanel)?.resetNumberHints() openButton.keyEquivalent = "" searchSymbol.isHidden = true - translationBack.target = controller - translationBack.action = #selector(TranslationController.goBack) - translationBack.isHidden = false + commandBack.target = self + commandBack.action = #selector(goBackCommand) + commandBack.isHidden = false searchField.stringValue = "" searchField.placeholderAttributedString = NSAttributedString( - string: "Enter English text to translate…", + string: placeholder, attributes: previousPlaceholder?.attributes(at: 0, effectiveRange: nil) ?? [:] ) - searchField.setAccessibilityLabel("English text to translate into Japanese") + searchField.setAccessibilityLabel(accessibilityLabel) for view in launcherViews.dropFirst() { view.isHidden = true view.setAccessibilityHidden(true) diff --git a/Sources/ConjureKit/Applications.swift b/Sources/ConjureKit/Applications.swift index 0486a34..efd5203 100644 --- a/Sources/ConjureKit/Applications.swift +++ b/Sources/ConjureKit/Applications.swift @@ -3,6 +3,7 @@ import Foundation public struct Application: Identifiable, Sendable { public enum Command: String, CaseIterable, Sendable { case translate + case emoji } public static let commands = Command.allCases.map { Application(command: $0) } public let command: Command? @@ -20,6 +21,7 @@ public struct Application: Identifiable, Sendable { public init(command: Command) { let name = switch command { case .translate: "Conjure Translate" + case .emoji: "Conjure Emoji" } self.init(canonicalURL: URL(string: "conjure-command://\(command.rawValue)")!, name: name, command: command) } diff --git a/Sources/ConjureKit/EmojiCatalog.swift b/Sources/ConjureKit/EmojiCatalog.swift new file mode 100644 index 0000000..04c5c72 --- /dev/null +++ b/Sources/ConjureKit/EmojiCatalog.swift @@ -0,0 +1,61 @@ +import Foundation + +public struct Emoji: Sendable { + public let value: String + public let name: String + public let category: String +} + +public enum EmojiCatalog { + private struct Entry: Sendable { + let emoji: Emoji + let searchText: String + } + + private static let entries: [Entry] = { + // SwiftPM's generated accessor does not search Contents/Resources in a packaged app. + let packagedBundle = Bundle.main.resourceURL.flatMap { + Bundle(url: $0.appendingPathComponent("Conjure_ConjureKit.bundle", isDirectory: true)) + } + let bundle = packagedBundle ?? Bundle.module + guard let url = bundle.url(forResource: "emoji", withExtension: "tsv"), + let contents = try? String(contentsOf: url, encoding: .utf8) else { + preconditionFailure("The bundled emoji catalog is missing or unreadable") + } + + // Pinned github/gemoji v4.1.0; attribution and license accompany the TSV. + return contents.split(whereSeparator: \.isNewline).map { line in + let fields = line.split(separator: "\t", omittingEmptySubsequences: false) + precondition(fields.count == 5, "Invalid bundled emoji catalog row") + return Entry( + emoji: Emoji(value: String(fields[0]), name: String(fields[1]), category: String(fields[2])), + searchText: normalized([fields[0], fields[1], fields[3], fields[4]].joined(separator: " ")) + ) + } + }() + + public static let all: [Emoji] = entries.map(\.emoji) + + public static let categories: [String] = { + var seen = Set() + return all.compactMap { seen.insert($0.category).inserted ? $0.category : nil } + }() + + /// Matches every query word against names, GitHub aliases, tags, or literal emoji. + /// Category names use the exact values supplied by `categories`; results retain catalog order. + public static func search(_ query: String, category: String? = nil) -> [Emoji] { + let words = normalized(query).split(whereSeparator: \.isWhitespace) + if words.isEmpty && category == nil { return all } + return entries.compactMap { entry in + guard category == nil || entry.emoji.category == category, + words.allSatisfy({ entry.searchText.contains($0) }) else { return nil } + return entry.emoji + } + } + + private static func normalized(_ text: String) -> String { + text.folding(options: [.caseInsensitive, .diacriticInsensitive], locale: Locale(identifier: "en_US_POSIX")) + .replacingOccurrences(of: "_", with: " ") + .replacingOccurrences(of: ":", with: " ") + } +} diff --git a/Sources/ConjureKit/Resources/LICENSE-gemoji.txt b/Sources/ConjureKit/Resources/LICENSE-gemoji.txt new file mode 100644 index 0000000..0fc5983 --- /dev/null +++ b/Sources/ConjureKit/Resources/LICENSE-gemoji.txt @@ -0,0 +1,28 @@ +Emoji catalog derived from github/gemoji v4.1.0. +Source: https://raw.githubusercontent.com/github/gemoji/v4.1.0/db/emoji.json +License: https://raw.githubusercontent.com/github/gemoji/v4.1.0/LICENSE + +TSV columns: emoji, description, category, space-separated aliases, space-separated tags. + +Copyright (c) 2019 GitHub, Inc. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/Sources/ConjureKit/Resources/emoji.tsv b/Sources/ConjureKit/Resources/emoji.tsv new file mode 100644 index 0000000..a472dbf --- /dev/null +++ b/Sources/ConjureKit/Resources/emoji.tsv @@ -0,0 +1,1870 @@ +😀 grinning face Smileys & Emotion grinning smile happy +😃 grinning face with big eyes Smileys & Emotion smiley happy joy haha +😄 grinning face with smiling eyes Smileys & Emotion smile happy joy laugh pleased +😁 beaming face with smiling eyes Smileys & Emotion grin +😆 grinning squinting face Smileys & Emotion laughing satisfied happy haha +😅 grinning face with sweat Smileys & Emotion sweat_smile hot +🤣 rolling on the floor laughing Smileys & Emotion rofl lol laughing +😂 face with tears of joy Smileys & Emotion joy tears +🙂 slightly smiling face Smileys & Emotion slightly_smiling_face +🙃 upside-down face Smileys & Emotion upside_down_face +🫠 melting face Smileys & Emotion melting_face sarcasm dread +😉 winking face Smileys & Emotion wink flirt +😊 smiling face with smiling eyes Smileys & Emotion blush proud +😇 smiling face with halo Smileys & Emotion innocent angel +🥰 smiling face with hearts Smileys & Emotion smiling_face_with_three_hearts love +😍 smiling face with heart-eyes Smileys & Emotion heart_eyes love crush +🤩 star-struck Smileys & Emotion star_struck eyes +😘 face blowing a kiss Smileys & Emotion kissing_heart flirt +😗 kissing face Smileys & Emotion kissing +☺️ smiling face Smileys & Emotion relaxed blush pleased +😚 kissing face with closed eyes Smileys & Emotion kissing_closed_eyes +😙 kissing face with smiling eyes Smileys & Emotion kissing_smiling_eyes +🥲 smiling face with tear Smileys & Emotion smiling_face_with_tear +😋 face savoring food Smileys & Emotion yum tongue lick +😛 face with tongue Smileys & Emotion stuck_out_tongue +😜 winking face with tongue Smileys & Emotion stuck_out_tongue_winking_eye prank silly +🤪 zany face Smileys & Emotion zany_face goofy wacky +😝 squinting face with tongue Smileys & Emotion stuck_out_tongue_closed_eyes prank +🤑 money-mouth face Smileys & Emotion money_mouth_face rich +🤗 smiling face with open hands Smileys & Emotion hugs +🤭 face with hand over mouth Smileys & Emotion hand_over_mouth quiet whoops +🫢 face with open eyes and hand over mouth Smileys & Emotion face_with_open_eyes_and_hand_over_mouth gasp shock +🫣 face with peeking eye Smileys & Emotion face_with_peeking_eye +🤫 shushing face Smileys & Emotion shushing_face silence quiet +🤔 thinking face Smileys & Emotion thinking +🫡 saluting face Smileys & Emotion saluting_face respect +🤐 zipper-mouth face Smileys & Emotion zipper_mouth_face silence hush +🤨 face with raised eyebrow Smileys & Emotion raised_eyebrow suspicious +😐 neutral face Smileys & Emotion neutral_face meh +😑 expressionless face Smileys & Emotion expressionless +😶 face without mouth Smileys & Emotion no_mouth mute silence +🫥 dotted line face Smileys & Emotion dotted_line_face invisible +😶‍🌫️ face in clouds Smileys & Emotion face_in_clouds +😏 smirking face Smileys & Emotion smirk smug +😒 unamused face Smileys & Emotion unamused meh +🙄 face with rolling eyes Smileys & Emotion roll_eyes +😬 grimacing face Smileys & Emotion grimacing +😮‍💨 face exhaling Smileys & Emotion face_exhaling +🤥 lying face Smileys & Emotion lying_face liar +🫨 shaking face Smileys & Emotion shaking_face shock +😌 relieved face Smileys & Emotion relieved whew +😔 pensive face Smileys & Emotion pensive +😪 sleepy face Smileys & Emotion sleepy tired +🤤 drooling face Smileys & Emotion drooling_face +😴 sleeping face Smileys & Emotion sleeping zzz +😷 face with medical mask Smileys & Emotion mask sick ill +🤒 face with thermometer Smileys & Emotion face_with_thermometer sick +🤕 face with head-bandage Smileys & Emotion face_with_head_bandage hurt +🤢 nauseated face Smileys & Emotion nauseated_face sick barf disgusted +🤮 face vomiting Smileys & Emotion vomiting_face barf sick +🤧 sneezing face Smileys & Emotion sneezing_face achoo sick +🥵 hot face Smileys & Emotion hot_face heat sweating +🥶 cold face Smileys & Emotion cold_face freezing ice +🥴 woozy face Smileys & Emotion woozy_face groggy +😵 face with crossed-out eyes Smileys & Emotion dizzy_face +😵‍💫 face with spiral eyes Smileys & Emotion face_with_spiral_eyes +🤯 exploding head Smileys & Emotion exploding_head mind blown +🤠 cowboy hat face Smileys & Emotion cowboy_hat_face +🥳 partying face Smileys & Emotion partying_face celebration birthday +🥸 disguised face Smileys & Emotion disguised_face +😎 smiling face with sunglasses Smileys & Emotion sunglasses cool +🤓 nerd face Smileys & Emotion nerd_face geek glasses +🧐 face with monocle Smileys & Emotion monocle_face +😕 confused face Smileys & Emotion confused +🫤 face with diagonal mouth Smileys & Emotion face_with_diagonal_mouth confused +😟 worried face Smileys & Emotion worried nervous +🙁 slightly frowning face Smileys & Emotion slightly_frowning_face +☹️ frowning face Smileys & Emotion frowning_face +😮 face with open mouth Smileys & Emotion open_mouth surprise impressed wow +😯 hushed face Smileys & Emotion hushed silence speechless +😲 astonished face Smileys & Emotion astonished amazed gasp +😳 flushed face Smileys & Emotion flushed +🥺 pleading face Smileys & Emotion pleading_face puppy eyes +🥹 face holding back tears Smileys & Emotion face_holding_back_tears tears gratitude +😦 frowning face with open mouth Smileys & Emotion frowning +😧 anguished face Smileys & Emotion anguished stunned +😨 fearful face Smileys & Emotion fearful scared shocked oops +😰 anxious face with sweat Smileys & Emotion cold_sweat nervous +😥 sad but relieved face Smileys & Emotion disappointed_relieved phew sweat nervous +😢 crying face Smileys & Emotion cry sad tear +😭 loudly crying face Smileys & Emotion sob sad cry bawling +😱 face screaming in fear Smileys & Emotion scream horror shocked +😖 confounded face Smileys & Emotion confounded +😣 persevering face Smileys & Emotion persevere struggling +😞 disappointed face Smileys & Emotion disappointed sad +😓 downcast face with sweat Smileys & Emotion sweat +😩 weary face Smileys & Emotion weary tired +😫 tired face Smileys & Emotion tired_face upset whine +🥱 yawning face Smileys & Emotion yawning_face +😤 face with steam from nose Smileys & Emotion triumph smug +😡 enraged face Smileys & Emotion rage pout angry +😠 angry face Smileys & Emotion angry mad annoyed +🤬 face with symbols on mouth Smileys & Emotion cursing_face foul +😈 smiling face with horns Smileys & Emotion smiling_imp devil evil horns +👿 angry face with horns Smileys & Emotion imp angry devil evil horns +💀 skull Smileys & Emotion skull dead danger poison +☠️ skull and crossbones Smileys & Emotion skull_and_crossbones danger pirate +💩 pile of poo Smileys & Emotion hankey poop shit crap +🤡 clown face Smileys & Emotion clown_face +👹 ogre Smileys & Emotion japanese_ogre monster +👺 goblin Smileys & Emotion japanese_goblin +👻 ghost Smileys & Emotion ghost halloween +👽 alien Smileys & Emotion alien ufo +👾 alien monster Smileys & Emotion space_invader game retro +🤖 robot Smileys & Emotion robot +😺 grinning cat Smileys & Emotion smiley_cat +😸 grinning cat with smiling eyes Smileys & Emotion smile_cat +😹 cat with tears of joy Smileys & Emotion joy_cat +😻 smiling cat with heart-eyes Smileys & Emotion heart_eyes_cat +😼 cat with wry smile Smileys & Emotion smirk_cat +😽 kissing cat Smileys & Emotion kissing_cat +🙀 weary cat Smileys & Emotion scream_cat horror +😿 crying cat Smileys & Emotion crying_cat_face sad tear +😾 pouting cat Smileys & Emotion pouting_cat +🙈 see-no-evil monkey Smileys & Emotion see_no_evil monkey blind ignore +🙉 hear-no-evil monkey Smileys & Emotion hear_no_evil monkey deaf +🙊 speak-no-evil monkey Smileys & Emotion speak_no_evil monkey mute hush +💌 love letter Smileys & Emotion love_letter email envelope +💘 heart with arrow Smileys & Emotion cupid love heart +💝 heart with ribbon Smileys & Emotion gift_heart chocolates +💖 sparkling heart Smileys & Emotion sparkling_heart +💗 growing heart Smileys & Emotion heartpulse +💓 beating heart Smileys & Emotion heartbeat +💞 revolving hearts Smileys & Emotion revolving_hearts +💕 two hearts Smileys & Emotion two_hearts +💟 heart decoration Smileys & Emotion heart_decoration +❣️ heart exclamation Smileys & Emotion heavy_heart_exclamation +💔 broken heart Smileys & Emotion broken_heart +❤️‍🔥 heart on fire Smileys & Emotion heart_on_fire +❤️‍🩹 mending heart Smileys & Emotion mending_heart +❤️ red heart Smileys & Emotion heart love +🩷 pink heart Smileys & Emotion pink_heart +🧡 orange heart Smileys & Emotion orange_heart +💛 yellow heart Smileys & Emotion yellow_heart +💚 green heart Smileys & Emotion green_heart +💙 blue heart Smileys & Emotion blue_heart +🩵 light blue heart Smileys & Emotion light_blue_heart +💜 purple heart Smileys & Emotion purple_heart +🤎 brown heart Smileys & Emotion brown_heart +🖤 black heart Smileys & Emotion black_heart +🩶 grey heart Smileys & Emotion grey_heart +🤍 white heart Smileys & Emotion white_heart +💋 kiss mark Smileys & Emotion kiss lipstick +💯 hundred points Smileys & Emotion 100 score perfect +💢 anger symbol Smileys & Emotion anger angry +💥 collision Smileys & Emotion boom collision explode +💫 dizzy Smileys & Emotion dizzy star +💦 sweat droplets Smileys & Emotion sweat_drops water workout +💨 dashing away Smileys & Emotion dash wind blow fast +🕳️ hole Smileys & Emotion hole +💬 speech balloon Smileys & Emotion speech_balloon comment +👁️‍🗨️ eye in speech bubble Smileys & Emotion eye_speech_bubble +🗨️ left speech bubble Smileys & Emotion left_speech_bubble +🗯️ right anger bubble Smileys & Emotion right_anger_bubble +💭 thought balloon Smileys & Emotion thought_balloon thinking +💤 ZZZ Smileys & Emotion zzz sleeping +👋 waving hand People & Body wave goodbye +🤚 raised back of hand People & Body raised_back_of_hand +🖐️ hand with fingers splayed People & Body raised_hand_with_fingers_splayed +✋ raised hand People & Body hand raised_hand highfive stop +🖖 vulcan salute People & Body vulcan_salute prosper spock +🫱 rightwards hand People & Body rightwards_hand +🫲 leftwards hand People & Body leftwards_hand +🫳 palm down hand People & Body palm_down_hand +🫴 palm up hand People & Body palm_up_hand +🫷 leftwards pushing hand People & Body leftwards_pushing_hand +🫸 rightwards pushing hand People & Body rightwards_pushing_hand +👌 OK hand People & Body ok_hand +🤌 pinched fingers People & Body pinched_fingers +🤏 pinching hand People & Body pinching_hand +✌️ victory hand People & Body v victory peace +🤞 crossed fingers People & Body crossed_fingers luck hopeful +🫰 hand with index finger and thumb crossed People & Body hand_with_index_finger_and_thumb_crossed +🤟 love-you gesture People & Body love_you_gesture +🤘 sign of the horns People & Body metal +🤙 call me hand People & Body call_me_hand +👈 backhand index pointing left People & Body point_left +👉 backhand index pointing right People & Body point_right +👆 backhand index pointing up People & Body point_up_2 +🖕 middle finger People & Body middle_finger fu +👇 backhand index pointing down People & Body point_down +☝️ index pointing up People & Body point_up +🫵 index pointing at the viewer People & Body index_pointing_at_the_viewer +👍 thumbs up People & Body +1 thumbsup approve ok +👎 thumbs down People & Body -1 thumbsdown disapprove bury +✊ raised fist People & Body fist_raised fist power +👊 oncoming fist People & Body fist_oncoming facepunch punch attack +🤛 left-facing fist People & Body fist_left +🤜 right-facing fist People & Body fist_right +👏 clapping hands People & Body clap praise applause +🙌 raising hands People & Body raised_hands hooray +🫶 heart hands People & Body heart_hands love +👐 open hands People & Body open_hands +🤲 palms up together People & Body palms_up_together +🤝 handshake People & Body handshake deal +🙏 folded hands People & Body pray please hope wish +✍️ writing hand People & Body writing_hand +💅 nail polish People & Body nail_care beauty manicure +🤳 selfie People & Body selfie +💪 flexed biceps People & Body muscle flex bicep strong workout +🦾 mechanical arm People & Body mechanical_arm +🦿 mechanical leg People & Body mechanical_leg +🦵 leg People & Body leg +🦶 foot People & Body foot +👂 ear People & Body ear hear sound listen +🦻 ear with hearing aid People & Body ear_with_hearing_aid +👃 nose People & Body nose smell +🧠 brain People & Body brain +🫀 anatomical heart People & Body anatomical_heart +🫁 lungs People & Body lungs +🦷 tooth People & Body tooth +🦴 bone People & Body bone +👀 eyes People & Body eyes look see watch +👁️ eye People & Body eye +👅 tongue People & Body tongue taste +👄 mouth People & Body lips kiss +🫦 biting lip People & Body biting_lip +👶 baby People & Body baby child newborn +🧒 child People & Body child +👦 boy People & Body boy child +👧 girl People & Body girl child +🧑 person People & Body adult +👱 person: blond hair People & Body blond_haired_person +👨 man People & Body man mustache father dad +🧔 person: beard People & Body bearded_person +🧔‍♂️ man: beard People & Body man_beard +🧔‍♀️ woman: beard People & Body woman_beard +👨‍🦰 man: red hair People & Body red_haired_man +👨‍🦱 man: curly hair People & Body curly_haired_man +👨‍🦳 man: white hair People & Body white_haired_man +👨‍🦲 man: bald People & Body bald_man +👩 woman People & Body woman girls +👩‍🦰 woman: red hair People & Body red_haired_woman +🧑‍🦰 person: red hair People & Body person_red_hair +👩‍🦱 woman: curly hair People & Body curly_haired_woman +🧑‍🦱 person: curly hair People & Body person_curly_hair +👩‍🦳 woman: white hair People & Body white_haired_woman +🧑‍🦳 person: white hair People & Body person_white_hair +👩‍🦲 woman: bald People & Body bald_woman +🧑‍🦲 person: bald People & Body person_bald +👱‍♀️ woman: blond hair People & Body blond_haired_woman blonde_woman +👱‍♂️ man: blond hair People & Body blond_haired_man +🧓 older person People & Body older_adult +👴 old man People & Body older_man +👵 old woman People & Body older_woman +🙍 person frowning People & Body frowning_person +🙍‍♂️ man frowning People & Body frowning_man +🙍‍♀️ woman frowning People & Body frowning_woman +🙎 person pouting People & Body pouting_face +🙎‍♂️ man pouting People & Body pouting_man +🙎‍♀️ woman pouting People & Body pouting_woman +🙅 person gesturing NO People & Body no_good stop halt denied +🙅‍♂️ man gesturing NO People & Body no_good_man ng_man stop halt denied +🙅‍♀️ woman gesturing NO People & Body no_good_woman ng_woman stop halt denied +🙆 person gesturing OK People & Body ok_person +🙆‍♂️ man gesturing OK People & Body ok_man +🙆‍♀️ woman gesturing OK People & Body ok_woman +💁 person tipping hand People & Body tipping_hand_person information_desk_person +💁‍♂️ man tipping hand People & Body tipping_hand_man sassy_man information +💁‍♀️ woman tipping hand People & Body tipping_hand_woman sassy_woman information +🙋 person raising hand People & Body raising_hand +🙋‍♂️ man raising hand People & Body raising_hand_man +🙋‍♀️ woman raising hand People & Body raising_hand_woman +🧏 deaf person People & Body deaf_person +🧏‍♂️ deaf man People & Body deaf_man +🧏‍♀️ deaf woman People & Body deaf_woman +🙇 person bowing People & Body bow respect thanks +🙇‍♂️ man bowing People & Body bowing_man respect thanks +🙇‍♀️ woman bowing People & Body bowing_woman respect thanks +🤦 person facepalming People & Body facepalm +🤦‍♂️ man facepalming People & Body man_facepalming +🤦‍♀️ woman facepalming People & Body woman_facepalming +🤷 person shrugging People & Body shrug +🤷‍♂️ man shrugging People & Body man_shrugging +🤷‍♀️ woman shrugging People & Body woman_shrugging +🧑‍⚕️ health worker People & Body health_worker +👨‍⚕️ man health worker People & Body man_health_worker doctor nurse +👩‍⚕️ woman health worker People & Body woman_health_worker doctor nurse +🧑‍🎓 student People & Body student +👨‍🎓 man student People & Body man_student graduation +👩‍🎓 woman student People & Body woman_student graduation +🧑‍🏫 teacher People & Body teacher +👨‍🏫 man teacher People & Body man_teacher school professor +👩‍🏫 woman teacher People & Body woman_teacher school professor +🧑‍⚖️ judge People & Body judge +👨‍⚖️ man judge People & Body man_judge justice +👩‍⚖️ woman judge People & Body woman_judge justice +🧑‍🌾 farmer People & Body farmer +👨‍🌾 man farmer People & Body man_farmer +👩‍🌾 woman farmer People & Body woman_farmer +🧑‍🍳 cook People & Body cook +👨‍🍳 man cook People & Body man_cook chef +👩‍🍳 woman cook People & Body woman_cook chef +🧑‍🔧 mechanic People & Body mechanic +👨‍🔧 man mechanic People & Body man_mechanic +👩‍🔧 woman mechanic People & Body woman_mechanic +🧑‍🏭 factory worker People & Body factory_worker +👨‍🏭 man factory worker People & Body man_factory_worker +👩‍🏭 woman factory worker People & Body woman_factory_worker +🧑‍💼 office worker People & Body office_worker +👨‍💼 man office worker People & Body man_office_worker business +👩‍💼 woman office worker People & Body woman_office_worker business +🧑‍🔬 scientist People & Body scientist +👨‍🔬 man scientist People & Body man_scientist research +👩‍🔬 woman scientist People & Body woman_scientist research +🧑‍💻 technologist People & Body technologist +👨‍💻 man technologist People & Body man_technologist coder +👩‍💻 woman technologist People & Body woman_technologist coder +🧑‍🎤 singer People & Body singer +👨‍🎤 man singer People & Body man_singer rockstar +👩‍🎤 woman singer People & Body woman_singer rockstar +🧑‍🎨 artist People & Body artist +👨‍🎨 man artist People & Body man_artist painter +👩‍🎨 woman artist People & Body woman_artist painter +🧑‍✈️ pilot People & Body pilot +👨‍✈️ man pilot People & Body man_pilot +👩‍✈️ woman pilot People & Body woman_pilot +🧑‍🚀 astronaut People & Body astronaut +👨‍🚀 man astronaut People & Body man_astronaut space +👩‍🚀 woman astronaut People & Body woman_astronaut space +🧑‍🚒 firefighter People & Body firefighter +👨‍🚒 man firefighter People & Body man_firefighter +👩‍🚒 woman firefighter People & Body woman_firefighter +👮 police officer People & Body police_officer cop law +👮‍♂️ man police officer People & Body policeman law cop +👮‍♀️ woman police officer People & Body policewoman law cop +🕵️ detective People & Body detective sleuth +🕵️‍♂️ man detective People & Body male_detective sleuth +🕵️‍♀️ woman detective People & Body female_detective sleuth +💂 guard People & Body guard +💂‍♂️ man guard People & Body guardsman +💂‍♀️ woman guard People & Body guardswoman +🥷 ninja People & Body ninja +👷 construction worker People & Body construction_worker helmet +👷‍♂️ man construction worker People & Body construction_worker_man helmet +👷‍♀️ woman construction worker People & Body construction_worker_woman helmet +🫅 person with crown People & Body person_with_crown +🤴 prince People & Body prince crown royal +👸 princess People & Body princess crown royal +👳 person wearing turban People & Body person_with_turban +👳‍♂️ man wearing turban People & Body man_with_turban +👳‍♀️ woman wearing turban People & Body woman_with_turban +👲 person with skullcap People & Body man_with_gua_pi_mao +🧕 woman with headscarf People & Body woman_with_headscarf hijab +🤵 person in tuxedo People & Body person_in_tuxedo groom marriage wedding +🤵‍♂️ man in tuxedo People & Body man_in_tuxedo +🤵‍♀️ woman in tuxedo People & Body woman_in_tuxedo +👰 person with veil People & Body person_with_veil marriage wedding +👰‍♂️ man with veil People & Body man_with_veil +👰‍♀️ woman with veil People & Body woman_with_veil bride_with_veil +🤰 pregnant woman People & Body pregnant_woman +🫃 pregnant man People & Body pregnant_man +🫄 pregnant person People & Body pregnant_person +🤱 breast-feeding People & Body breast_feeding nursing +👩‍🍼 woman feeding baby People & Body woman_feeding_baby +👨‍🍼 man feeding baby People & Body man_feeding_baby +🧑‍🍼 person feeding baby People & Body person_feeding_baby +👼 baby angel People & Body angel +🎅 Santa Claus People & Body santa christmas +🤶 Mrs. Claus People & Body mrs_claus santa +🧑‍🎄 mx claus People & Body mx_claus +🦸 superhero People & Body superhero +🦸‍♂️ man superhero People & Body superhero_man +🦸‍♀️ woman superhero People & Body superhero_woman +🦹 supervillain People & Body supervillain +🦹‍♂️ man supervillain People & Body supervillain_man +🦹‍♀️ woman supervillain People & Body supervillain_woman +🧙 mage People & Body mage wizard +🧙‍♂️ man mage People & Body mage_man wizard +🧙‍♀️ woman mage People & Body mage_woman wizard +🧚 fairy People & Body fairy +🧚‍♂️ man fairy People & Body fairy_man +🧚‍♀️ woman fairy People & Body fairy_woman +🧛 vampire People & Body vampire +🧛‍♂️ man vampire People & Body vampire_man +🧛‍♀️ woman vampire People & Body vampire_woman +🧜 merperson People & Body merperson +🧜‍♂️ merman People & Body merman +🧜‍♀️ mermaid People & Body mermaid +🧝 elf People & Body elf +🧝‍♂️ man elf People & Body elf_man +🧝‍♀️ woman elf People & Body elf_woman +🧞 genie People & Body genie +🧞‍♂️ man genie People & Body genie_man +🧞‍♀️ woman genie People & Body genie_woman +🧟 zombie People & Body zombie +🧟‍♂️ man zombie People & Body zombie_man +🧟‍♀️ woman zombie People & Body zombie_woman +🧌 troll People & Body troll +💆 person getting massage People & Body massage spa +💆‍♂️ man getting massage People & Body massage_man spa +💆‍♀️ woman getting massage People & Body massage_woman spa +💇 person getting haircut People & Body haircut beauty +💇‍♂️ man getting haircut People & Body haircut_man +💇‍♀️ woman getting haircut People & Body haircut_woman +🚶 person walking People & Body walking +🚶‍♂️ man walking People & Body walking_man +🚶‍♀️ woman walking People & Body walking_woman +🧍 person standing People & Body standing_person +🧍‍♂️ man standing People & Body standing_man +🧍‍♀️ woman standing People & Body standing_woman +🧎 person kneeling People & Body kneeling_person +🧎‍♂️ man kneeling People & Body kneeling_man +🧎‍♀️ woman kneeling People & Body kneeling_woman +🧑‍🦯 person with white cane People & Body person_with_probing_cane +👨‍🦯 man with white cane People & Body man_with_probing_cane +👩‍🦯 woman with white cane People & Body woman_with_probing_cane +🧑‍🦼 person in motorized wheelchair People & Body person_in_motorized_wheelchair +👨‍🦼 man in motorized wheelchair People & Body man_in_motorized_wheelchair +👩‍🦼 woman in motorized wheelchair People & Body woman_in_motorized_wheelchair +🧑‍🦽 person in manual wheelchair People & Body person_in_manual_wheelchair +👨‍🦽 man in manual wheelchair People & Body man_in_manual_wheelchair +👩‍🦽 woman in manual wheelchair People & Body woman_in_manual_wheelchair +🏃 person running People & Body runner running exercise workout marathon +🏃‍♂️ man running People & Body running_man exercise workout marathon +🏃‍♀️ woman running People & Body running_woman exercise workout marathon +💃 woman dancing People & Body woman_dancing dancer dress +🕺 man dancing People & Body man_dancing dancer +🕴️ person in suit levitating People & Body business_suit_levitating +👯 people with bunny ears People & Body dancers bunny +👯‍♂️ men with bunny ears People & Body dancing_men bunny +👯‍♀️ women with bunny ears People & Body dancing_women bunny +🧖 person in steamy room People & Body sauna_person steamy +🧖‍♂️ man in steamy room People & Body sauna_man steamy +🧖‍♀️ woman in steamy room People & Body sauna_woman steamy +🧗 person climbing People & Body climbing bouldering +🧗‍♂️ man climbing People & Body climbing_man bouldering +🧗‍♀️ woman climbing People & Body climbing_woman bouldering +🤺 person fencing People & Body person_fencing +🏇 horse racing People & Body horse_racing +⛷️ skier People & Body skier +🏂 snowboarder People & Body snowboarder +🏌️ person golfing People & Body golfing +🏌️‍♂️ man golfing People & Body golfing_man +🏌️‍♀️ woman golfing People & Body golfing_woman +🏄 person surfing People & Body surfer +🏄‍♂️ man surfing People & Body surfing_man +🏄‍♀️ woman surfing People & Body surfing_woman +🚣 person rowing boat People & Body rowboat +🚣‍♂️ man rowing boat People & Body rowing_man +🚣‍♀️ woman rowing boat People & Body rowing_woman +🏊 person swimming People & Body swimmer +🏊‍♂️ man swimming People & Body swimming_man +🏊‍♀️ woman swimming People & Body swimming_woman +⛹️ person bouncing ball People & Body bouncing_ball_person basketball +⛹️‍♂️ man bouncing ball People & Body bouncing_ball_man basketball_man +⛹️‍♀️ woman bouncing ball People & Body bouncing_ball_woman basketball_woman +🏋️ person lifting weights People & Body weight_lifting gym workout +🏋️‍♂️ man lifting weights People & Body weight_lifting_man gym workout +🏋️‍♀️ woman lifting weights People & Body weight_lifting_woman gym workout +🚴 person biking People & Body bicyclist +🚴‍♂️ man biking People & Body biking_man +🚴‍♀️ woman biking People & Body biking_woman +🚵 person mountain biking People & Body mountain_bicyclist +🚵‍♂️ man mountain biking People & Body mountain_biking_man +🚵‍♀️ woman mountain biking People & Body mountain_biking_woman +🤸 person cartwheeling People & Body cartwheeling +🤸‍♂️ man cartwheeling People & Body man_cartwheeling +🤸‍♀️ woman cartwheeling People & Body woman_cartwheeling +🤼 people wrestling People & Body wrestling +🤼‍♂️ men wrestling People & Body men_wrestling +🤼‍♀️ women wrestling People & Body women_wrestling +🤽 person playing water polo People & Body water_polo +🤽‍♂️ man playing water polo People & Body man_playing_water_polo +🤽‍♀️ woman playing water polo People & Body woman_playing_water_polo +🤾 person playing handball People & Body handball_person +🤾‍♂️ man playing handball People & Body man_playing_handball +🤾‍♀️ woman playing handball People & Body woman_playing_handball +🤹 person juggling People & Body juggling_person +🤹‍♂️ man juggling People & Body man_juggling +🤹‍♀️ woman juggling People & Body woman_juggling +🧘 person in lotus position People & Body lotus_position meditation +🧘‍♂️ man in lotus position People & Body lotus_position_man meditation +🧘‍♀️ woman in lotus position People & Body lotus_position_woman meditation +🛀 person taking bath People & Body bath shower +🛌 person in bed People & Body sleeping_bed +🧑‍🤝‍🧑 people holding hands People & Body people_holding_hands couple date +👭 women holding hands People & Body two_women_holding_hands couple date +👫 woman and man holding hands People & Body couple date +👬 men holding hands People & Body two_men_holding_hands couple date +💏 kiss People & Body couplekiss +👩‍❤️‍💋‍👨 kiss: woman, man People & Body couplekiss_man_woman +👨‍❤️‍💋‍👨 kiss: man, man People & Body couplekiss_man_man +👩‍❤️‍💋‍👩 kiss: woman, woman People & Body couplekiss_woman_woman +💑 couple with heart People & Body couple_with_heart +👩‍❤️‍👨 couple with heart: woman, man People & Body couple_with_heart_woman_man +👨‍❤️‍👨 couple with heart: man, man People & Body couple_with_heart_man_man +👩‍❤️‍👩 couple with heart: woman, woman People & Body couple_with_heart_woman_woman +👪 family People & Body family home parents child +👨‍👩‍👦 family: man, woman, boy People & Body family_man_woman_boy +👨‍👩‍👧 family: man, woman, girl People & Body family_man_woman_girl +👨‍👩‍👧‍👦 family: man, woman, girl, boy People & Body family_man_woman_girl_boy +👨‍👩‍👦‍👦 family: man, woman, boy, boy People & Body family_man_woman_boy_boy +👨‍👩‍👧‍👧 family: man, woman, girl, girl People & Body family_man_woman_girl_girl +👨‍👨‍👦 family: man, man, boy People & Body family_man_man_boy +👨‍👨‍👧 family: man, man, girl People & Body family_man_man_girl +👨‍👨‍👧‍👦 family: man, man, girl, boy People & Body family_man_man_girl_boy +👨‍👨‍👦‍👦 family: man, man, boy, boy People & Body family_man_man_boy_boy +👨‍👨‍👧‍👧 family: man, man, girl, girl People & Body family_man_man_girl_girl +👩‍👩‍👦 family: woman, woman, boy People & Body family_woman_woman_boy +👩‍👩‍👧 family: woman, woman, girl People & Body family_woman_woman_girl +👩‍👩‍👧‍👦 family: woman, woman, girl, boy People & Body family_woman_woman_girl_boy +👩‍👩‍👦‍👦 family: woman, woman, boy, boy People & Body family_woman_woman_boy_boy +👩‍👩‍👧‍👧 family: woman, woman, girl, girl People & Body family_woman_woman_girl_girl +👨‍👦 family: man, boy People & Body family_man_boy +👨‍👦‍👦 family: man, boy, boy People & Body family_man_boy_boy +👨‍👧 family: man, girl People & Body family_man_girl +👨‍👧‍👦 family: man, girl, boy People & Body family_man_girl_boy +👨‍👧‍👧 family: man, girl, girl People & Body family_man_girl_girl +👩‍👦 family: woman, boy People & Body family_woman_boy +👩‍👦‍👦 family: woman, boy, boy People & Body family_woman_boy_boy +👩‍👧 family: woman, girl People & Body family_woman_girl +👩‍👧‍👦 family: woman, girl, boy People & Body family_woman_girl_boy +👩‍👧‍👧 family: woman, girl, girl People & Body family_woman_girl_girl +🗣️ speaking head People & Body speaking_head +👤 bust in silhouette People & Body bust_in_silhouette user +👥 busts in silhouette People & Body busts_in_silhouette users group team +🫂 people hugging People & Body people_hugging +👣 footprints People & Body footprints feet tracks +🐵 monkey face Animals & Nature monkey_face +🐒 monkey Animals & Nature monkey +🦍 gorilla Animals & Nature gorilla +🦧 orangutan Animals & Nature orangutan +🐶 dog face Animals & Nature dog pet +🐕 dog Animals & Nature dog2 +🦮 guide dog Animals & Nature guide_dog +🐕‍🦺 service dog Animals & Nature service_dog +🐩 poodle Animals & Nature poodle dog +🐺 wolf Animals & Nature wolf +🦊 fox Animals & Nature fox_face +🦝 raccoon Animals & Nature raccoon +🐱 cat face Animals & Nature cat pet +🐈 cat Animals & Nature cat2 +🐈‍⬛ black cat Animals & Nature black_cat +🦁 lion Animals & Nature lion +🐯 tiger face Animals & Nature tiger +🐅 tiger Animals & Nature tiger2 +🐆 leopard Animals & Nature leopard +🐴 horse face Animals & Nature horse +🫎 moose Animals & Nature moose canada +🫏 donkey Animals & Nature donkey mule +🐎 horse Animals & Nature racehorse speed +🦄 unicorn Animals & Nature unicorn +🦓 zebra Animals & Nature zebra +🦌 deer Animals & Nature deer +🦬 bison Animals & Nature bison +🐮 cow face Animals & Nature cow +🐂 ox Animals & Nature ox +🐃 water buffalo Animals & Nature water_buffalo +🐄 cow Animals & Nature cow2 +🐷 pig face Animals & Nature pig +🐖 pig Animals & Nature pig2 +🐗 boar Animals & Nature boar +🐽 pig nose Animals & Nature pig_nose +🐏 ram Animals & Nature ram +🐑 ewe Animals & Nature sheep +🐐 goat Animals & Nature goat +🐪 camel Animals & Nature dromedary_camel desert +🐫 two-hump camel Animals & Nature camel +🦙 llama Animals & Nature llama +🦒 giraffe Animals & Nature giraffe +🐘 elephant Animals & Nature elephant +🦣 mammoth Animals & Nature mammoth +🦏 rhinoceros Animals & Nature rhinoceros +🦛 hippopotamus Animals & Nature hippopotamus +🐭 mouse face Animals & Nature mouse +🐁 mouse Animals & Nature mouse2 +🐀 rat Animals & Nature rat +🐹 hamster Animals & Nature hamster pet +🐰 rabbit face Animals & Nature rabbit bunny +🐇 rabbit Animals & Nature rabbit2 +🐿️ chipmunk Animals & Nature chipmunk +🦫 beaver Animals & Nature beaver +🦔 hedgehog Animals & Nature hedgehog +🦇 bat Animals & Nature bat +🐻 bear Animals & Nature bear +🐻‍❄️ polar bear Animals & Nature polar_bear +🐨 koala Animals & Nature koala +🐼 panda Animals & Nature panda_face +🦥 sloth Animals & Nature sloth +🦦 otter Animals & Nature otter +🦨 skunk Animals & Nature skunk +🦘 kangaroo Animals & Nature kangaroo +🦡 badger Animals & Nature badger +🐾 paw prints Animals & Nature feet paw_prints +🦃 turkey Animals & Nature turkey thanksgiving +🐔 chicken Animals & Nature chicken +🐓 rooster Animals & Nature rooster +🐣 hatching chick Animals & Nature hatching_chick +🐤 baby chick Animals & Nature baby_chick +🐥 front-facing baby chick Animals & Nature hatched_chick +🐦 bird Animals & Nature bird +🐧 penguin Animals & Nature penguin +🕊️ dove Animals & Nature dove peace +🦅 eagle Animals & Nature eagle +🦆 duck Animals & Nature duck +🦢 swan Animals & Nature swan +🦉 owl Animals & Nature owl +🦤 dodo Animals & Nature dodo +🪶 feather Animals & Nature feather +🦩 flamingo Animals & Nature flamingo +🦚 peacock Animals & Nature peacock +🦜 parrot Animals & Nature parrot +🪽 wing Animals & Nature wing fly +🐦‍⬛ black bird Animals & Nature black_bird +🪿 goose Animals & Nature goose honk +🐸 frog Animals & Nature frog +🐊 crocodile Animals & Nature crocodile +🐢 turtle Animals & Nature turtle slow +🦎 lizard Animals & Nature lizard +🐍 snake Animals & Nature snake +🐲 dragon face Animals & Nature dragon_face +🐉 dragon Animals & Nature dragon +🦕 sauropod Animals & Nature sauropod dinosaur +🦖 T-Rex Animals & Nature t-rex dinosaur +🐳 spouting whale Animals & Nature whale sea +🐋 whale Animals & Nature whale2 +🐬 dolphin Animals & Nature dolphin flipper +🦭 seal Animals & Nature seal +🐟 fish Animals & Nature fish +🐠 tropical fish Animals & Nature tropical_fish +🐡 blowfish Animals & Nature blowfish +🦈 shark Animals & Nature shark +🐙 octopus Animals & Nature octopus +🐚 spiral shell Animals & Nature shell sea beach +🪸 coral Animals & Nature coral +🪼 jellyfish Animals & Nature jellyfish +🐌 snail Animals & Nature snail slow +🦋 butterfly Animals & Nature butterfly +🐛 bug Animals & Nature bug +🐜 ant Animals & Nature ant +🐝 honeybee Animals & Nature bee honeybee +🪲 beetle Animals & Nature beetle +🐞 lady beetle Animals & Nature lady_beetle bug +🦗 cricket Animals & Nature cricket +🪳 cockroach Animals & Nature cockroach +🕷️ spider Animals & Nature spider +🕸️ spider web Animals & Nature spider_web +🦂 scorpion Animals & Nature scorpion +🦟 mosquito Animals & Nature mosquito +🪰 fly Animals & Nature fly +🪱 worm Animals & Nature worm +🦠 microbe Animals & Nature microbe germ +💐 bouquet Animals & Nature bouquet flowers +🌸 cherry blossom Animals & Nature cherry_blossom flower spring +💮 white flower Animals & Nature white_flower +🪷 lotus Animals & Nature lotus +🏵️ rosette Animals & Nature rosette +🌹 rose Animals & Nature rose flower +🥀 wilted flower Animals & Nature wilted_flower +🌺 hibiscus Animals & Nature hibiscus +🌻 sunflower Animals & Nature sunflower +🌼 blossom Animals & Nature blossom +🌷 tulip Animals & Nature tulip flower +🪻 hyacinth Animals & Nature hyacinth +🌱 seedling Animals & Nature seedling plant +🪴 potted plant Animals & Nature potted_plant +🌲 evergreen tree Animals & Nature evergreen_tree wood +🌳 deciduous tree Animals & Nature deciduous_tree wood +🌴 palm tree Animals & Nature palm_tree +🌵 cactus Animals & Nature cactus +🌾 sheaf of rice Animals & Nature ear_of_rice +🌿 herb Animals & Nature herb +☘️ shamrock Animals & Nature shamrock +🍀 four leaf clover Animals & Nature four_leaf_clover luck +🍁 maple leaf Animals & Nature maple_leaf canada +🍂 fallen leaf Animals & Nature fallen_leaf autumn +🍃 leaf fluttering in wind Animals & Nature leaves leaf +🪹 empty nest Animals & Nature empty_nest +🪺 nest with eggs Animals & Nature nest_with_eggs +🍄 mushroom Animals & Nature mushroom fungus +🍇 grapes Food & Drink grapes +🍈 melon Food & Drink melon +🍉 watermelon Food & Drink watermelon +🍊 tangerine Food & Drink tangerine orange mandarin +🍋 lemon Food & Drink lemon +🍌 banana Food & Drink banana fruit +🍍 pineapple Food & Drink pineapple +🥭 mango Food & Drink mango +🍎 red apple Food & Drink apple +🍏 green apple Food & Drink green_apple fruit +🍐 pear Food & Drink pear +🍑 peach Food & Drink peach +🍒 cherries Food & Drink cherries fruit +🍓 strawberry Food & Drink strawberry fruit +🫐 blueberries Food & Drink blueberries +🥝 kiwi fruit Food & Drink kiwi_fruit +🍅 tomato Food & Drink tomato +🫒 olive Food & Drink olive +🥥 coconut Food & Drink coconut +🥑 avocado Food & Drink avocado +🍆 eggplant Food & Drink eggplant aubergine +🥔 potato Food & Drink potato +🥕 carrot Food & Drink carrot +🌽 ear of corn Food & Drink corn +🌶️ hot pepper Food & Drink hot_pepper spicy +🫑 bell pepper Food & Drink bell_pepper +🥒 cucumber Food & Drink cucumber +🥬 leafy green Food & Drink leafy_green +🥦 broccoli Food & Drink broccoli +🧄 garlic Food & Drink garlic +🧅 onion Food & Drink onion +🥜 peanuts Food & Drink peanuts +🫘 beans Food & Drink beans +🌰 chestnut Food & Drink chestnut +🫚 ginger root Food & Drink ginger_root +🫛 pea pod Food & Drink pea_pod +🍞 bread Food & Drink bread toast +🥐 croissant Food & Drink croissant +🥖 baguette bread Food & Drink baguette_bread +🫓 flatbread Food & Drink flatbread +🥨 pretzel Food & Drink pretzel +🥯 bagel Food & Drink bagel +🥞 pancakes Food & Drink pancakes +🧇 waffle Food & Drink waffle +🧀 cheese wedge Food & Drink cheese +🍖 meat on bone Food & Drink meat_on_bone +🍗 poultry leg Food & Drink poultry_leg meat chicken +🥩 cut of meat Food & Drink cut_of_meat +🥓 bacon Food & Drink bacon +🍔 hamburger Food & Drink hamburger burger +🍟 french fries Food & Drink fries +🍕 pizza Food & Drink pizza +🌭 hot dog Food & Drink hotdog +🥪 sandwich Food & Drink sandwich +🌮 taco Food & Drink taco +🌯 burrito Food & Drink burrito +🫔 tamale Food & Drink tamale +🥙 stuffed flatbread Food & Drink stuffed_flatbread +🧆 falafel Food & Drink falafel +🥚 egg Food & Drink egg +🍳 cooking Food & Drink fried_egg breakfast +🥘 shallow pan of food Food & Drink shallow_pan_of_food paella curry +🍲 pot of food Food & Drink stew +🫕 fondue Food & Drink fondue +🥣 bowl with spoon Food & Drink bowl_with_spoon +🥗 green salad Food & Drink green_salad +🍿 popcorn Food & Drink popcorn +🧈 butter Food & Drink butter +🧂 salt Food & Drink salt +🥫 canned food Food & Drink canned_food +🍱 bento box Food & Drink bento +🍘 rice cracker Food & Drink rice_cracker +🍙 rice ball Food & Drink rice_ball +🍚 cooked rice Food & Drink rice +🍛 curry rice Food & Drink curry +🍜 steaming bowl Food & Drink ramen noodle +🍝 spaghetti Food & Drink spaghetti pasta +🍠 roasted sweet potato Food & Drink sweet_potato +🍢 oden Food & Drink oden +🍣 sushi Food & Drink sushi +🍤 fried shrimp Food & Drink fried_shrimp tempura +🍥 fish cake with swirl Food & Drink fish_cake +🥮 moon cake Food & Drink moon_cake +🍡 dango Food & Drink dango +🥟 dumpling Food & Drink dumpling +🥠 fortune cookie Food & Drink fortune_cookie +🥡 takeout box Food & Drink takeout_box +🦀 crab Food & Drink crab +🦞 lobster Food & Drink lobster +🦐 shrimp Food & Drink shrimp +🦑 squid Food & Drink squid +🦪 oyster Food & Drink oyster +🍦 soft ice cream Food & Drink icecream +🍧 shaved ice Food & Drink shaved_ice +🍨 ice cream Food & Drink ice_cream +🍩 doughnut Food & Drink doughnut +🍪 cookie Food & Drink cookie +🎂 birthday cake Food & Drink birthday party +🍰 shortcake Food & Drink cake dessert +🧁 cupcake Food & Drink cupcake +🥧 pie Food & Drink pie +🍫 chocolate bar Food & Drink chocolate_bar +🍬 candy Food & Drink candy sweet +🍭 lollipop Food & Drink lollipop +🍮 custard Food & Drink custard +🍯 honey pot Food & Drink honey_pot +🍼 baby bottle Food & Drink baby_bottle milk +🥛 glass of milk Food & Drink milk_glass +☕ hot beverage Food & Drink coffee cafe espresso +🫖 teapot Food & Drink teapot +🍵 teacup without handle Food & Drink tea green breakfast +🍶 sake Food & Drink sake +🍾 bottle with popping cork Food & Drink champagne bottle bubbly celebration +🍷 wine glass Food & Drink wine_glass +🍸 cocktail glass Food & Drink cocktail drink +🍹 tropical drink Food & Drink tropical_drink summer vacation +🍺 beer mug Food & Drink beer drink +🍻 clinking beer mugs Food & Drink beers drinks +🥂 clinking glasses Food & Drink clinking_glasses cheers toast +🥃 tumbler glass Food & Drink tumbler_glass whisky +🫗 pouring liquid Food & Drink pouring_liquid +🥤 cup with straw Food & Drink cup_with_straw +🧋 bubble tea Food & Drink bubble_tea +🧃 beverage box Food & Drink beverage_box +🧉 mate Food & Drink mate +🧊 ice Food & Drink ice_cube +🥢 chopsticks Food & Drink chopsticks +🍽️ fork and knife with plate Food & Drink plate_with_cutlery dining dinner +🍴 fork and knife Food & Drink fork_and_knife cutlery +🥄 spoon Food & Drink spoon +🔪 kitchen knife Food & Drink hocho knife cut chop +🫙 jar Food & Drink jar +🏺 amphora Food & Drink amphora +🌍 globe showing Europe-Africa Travel & Places earth_africa globe world international +🌎 globe showing Americas Travel & Places earth_americas globe world international +🌏 globe showing Asia-Australia Travel & Places earth_asia globe world international +🌐 globe with meridians Travel & Places globe_with_meridians world global international +🗺️ world map Travel & Places world_map travel +🗾 map of Japan Travel & Places japan +🧭 compass Travel & Places compass +🏔️ snow-capped mountain Travel & Places mountain_snow +⛰️ mountain Travel & Places mountain +🌋 volcano Travel & Places volcano +🗻 mount fuji Travel & Places mount_fuji +🏕️ camping Travel & Places camping +🏖️ beach with umbrella Travel & Places beach_umbrella +🏜️ desert Travel & Places desert +🏝️ desert island Travel & Places desert_island +🏞️ national park Travel & Places national_park +🏟️ stadium Travel & Places stadium +🏛️ classical building Travel & Places classical_building +🏗️ building construction Travel & Places building_construction +🧱 brick Travel & Places bricks +🪨 rock Travel & Places rock +🪵 wood Travel & Places wood +🛖 hut Travel & Places hut +🏘️ houses Travel & Places houses +🏚️ derelict house Travel & Places derelict_house +🏠 house Travel & Places house +🏡 house with garden Travel & Places house_with_garden +🏢 office building Travel & Places office +🏣 Japanese post office Travel & Places post_office +🏤 post office Travel & Places european_post_office +🏥 hospital Travel & Places hospital +🏦 bank Travel & Places bank +🏨 hotel Travel & Places hotel +🏩 love hotel Travel & Places love_hotel +🏪 convenience store Travel & Places convenience_store +🏫 school Travel & Places school +🏬 department store Travel & Places department_store +🏭 factory Travel & Places factory +🏯 Japanese castle Travel & Places japanese_castle +🏰 castle Travel & Places european_castle +💒 wedding Travel & Places wedding marriage +🗼 Tokyo tower Travel & Places tokyo_tower +🗽 Statue of Liberty Travel & Places statue_of_liberty +⛪ church Travel & Places church +🕌 mosque Travel & Places mosque +🛕 hindu temple Travel & Places hindu_temple +🕍 synagogue Travel & Places synagogue +⛩️ shinto shrine Travel & Places shinto_shrine +🕋 kaaba Travel & Places kaaba +⛲ fountain Travel & Places fountain +⛺ tent Travel & Places tent camping +🌁 foggy Travel & Places foggy karl +🌃 night with stars Travel & Places night_with_stars +🏙️ cityscape Travel & Places cityscape skyline +🌄 sunrise over mountains Travel & Places sunrise_over_mountains +🌅 sunrise Travel & Places sunrise +🌆 cityscape at dusk Travel & Places city_sunset +🌇 sunset Travel & Places city_sunrise +🌉 bridge at night Travel & Places bridge_at_night +♨️ hot springs Travel & Places hotsprings +🎠 carousel horse Travel & Places carousel_horse +🛝 playground slide Travel & Places playground_slide +🎡 ferris wheel Travel & Places ferris_wheel +🎢 roller coaster Travel & Places roller_coaster +💈 barber pole Travel & Places barber +🎪 circus tent Travel & Places circus_tent +🚂 locomotive Travel & Places steam_locomotive train +🚃 railway car Travel & Places railway_car +🚄 high-speed train Travel & Places bullettrain_side train +🚅 bullet train Travel & Places bullettrain_front train +🚆 train Travel & Places train2 +🚇 metro Travel & Places metro +🚈 light rail Travel & Places light_rail +🚉 station Travel & Places station +🚊 tram Travel & Places tram +🚝 monorail Travel & Places monorail +🚞 mountain railway Travel & Places mountain_railway +🚋 tram car Travel & Places train +🚌 bus Travel & Places bus +🚍 oncoming bus Travel & Places oncoming_bus +🚎 trolleybus Travel & Places trolleybus +🚐 minibus Travel & Places minibus +🚑 ambulance Travel & Places ambulance +🚒 fire engine Travel & Places fire_engine +🚓 police car Travel & Places police_car +🚔 oncoming police car Travel & Places oncoming_police_car +🚕 taxi Travel & Places taxi +🚖 oncoming taxi Travel & Places oncoming_taxi +🚗 automobile Travel & Places car red_car +🚘 oncoming automobile Travel & Places oncoming_automobile +🚙 sport utility vehicle Travel & Places blue_car +🛻 pickup truck Travel & Places pickup_truck +🚚 delivery truck Travel & Places truck +🚛 articulated lorry Travel & Places articulated_lorry +🚜 tractor Travel & Places tractor +🏎️ racing car Travel & Places racing_car +🏍️ motorcycle Travel & Places motorcycle +🛵 motor scooter Travel & Places motor_scooter +🦽 manual wheelchair Travel & Places manual_wheelchair +🦼 motorized wheelchair Travel & Places motorized_wheelchair +🛺 auto rickshaw Travel & Places auto_rickshaw +🚲 bicycle Travel & Places bike bicycle +🛴 kick scooter Travel & Places kick_scooter +🛹 skateboard Travel & Places skateboard +🛼 roller skate Travel & Places roller_skate +🚏 bus stop Travel & Places busstop +🛣️ motorway Travel & Places motorway +🛤️ railway track Travel & Places railway_track +🛢️ oil drum Travel & Places oil_drum +⛽ fuel pump Travel & Places fuelpump +🛞 wheel Travel & Places wheel +🚨 police car light Travel & Places rotating_light 911 emergency +🚥 horizontal traffic light Travel & Places traffic_light +🚦 vertical traffic light Travel & Places vertical_traffic_light semaphore +🛑 stop sign Travel & Places stop_sign +🚧 construction Travel & Places construction wip +⚓ anchor Travel & Places anchor ship +🛟 ring buoy Travel & Places ring_buoy life preserver +⛵ sailboat Travel & Places boat sailboat +🛶 canoe Travel & Places canoe +🚤 speedboat Travel & Places speedboat ship +🛳️ passenger ship Travel & Places passenger_ship cruise +⛴️ ferry Travel & Places ferry +🛥️ motor boat Travel & Places motor_boat +🚢 ship Travel & Places ship +✈️ airplane Travel & Places airplane flight +🛩️ small airplane Travel & Places small_airplane flight +🛫 airplane departure Travel & Places flight_departure +🛬 airplane arrival Travel & Places flight_arrival +🪂 parachute Travel & Places parachute +💺 seat Travel & Places seat +🚁 helicopter Travel & Places helicopter +🚟 suspension railway Travel & Places suspension_railway +🚠 mountain cableway Travel & Places mountain_cableway +🚡 aerial tramway Travel & Places aerial_tramway +🛰️ satellite Travel & Places artificial_satellite orbit space +🚀 rocket Travel & Places rocket ship launch +🛸 flying saucer Travel & Places flying_saucer ufo +🛎️ bellhop bell Travel & Places bellhop_bell +🧳 luggage Travel & Places luggage +⌛ hourglass done Travel & Places hourglass time +⏳ hourglass not done Travel & Places hourglass_flowing_sand time +⌚ watch Travel & Places watch time +⏰ alarm clock Travel & Places alarm_clock morning +⏱️ stopwatch Travel & Places stopwatch +⏲️ timer clock Travel & Places timer_clock +🕰️ mantelpiece clock Travel & Places mantelpiece_clock +🕛 twelve o’clock Travel & Places clock12 +🕧 twelve-thirty Travel & Places clock1230 +🕐 one o’clock Travel & Places clock1 +🕜 one-thirty Travel & Places clock130 +🕑 two o’clock Travel & Places clock2 +🕝 two-thirty Travel & Places clock230 +🕒 three o’clock Travel & Places clock3 +🕞 three-thirty Travel & Places clock330 +🕓 four o’clock Travel & Places clock4 +🕟 four-thirty Travel & Places clock430 +🕔 five o’clock Travel & Places clock5 +🕠 five-thirty Travel & Places clock530 +🕕 six o’clock Travel & Places clock6 +🕡 six-thirty Travel & Places clock630 +🕖 seven o’clock Travel & Places clock7 +🕢 seven-thirty Travel & Places clock730 +🕗 eight o’clock Travel & Places clock8 +🕣 eight-thirty Travel & Places clock830 +🕘 nine o’clock Travel & Places clock9 +🕤 nine-thirty Travel & Places clock930 +🕙 ten o’clock Travel & Places clock10 +🕥 ten-thirty Travel & Places clock1030 +🕚 eleven o’clock Travel & Places clock11 +🕦 eleven-thirty Travel & Places clock1130 +🌑 new moon Travel & Places new_moon +🌒 waxing crescent moon Travel & Places waxing_crescent_moon +🌓 first quarter moon Travel & Places first_quarter_moon +🌔 waxing gibbous moon Travel & Places moon waxing_gibbous_moon +🌕 full moon Travel & Places full_moon +🌖 waning gibbous moon Travel & Places waning_gibbous_moon +🌗 last quarter moon Travel & Places last_quarter_moon +🌘 waning crescent moon Travel & Places waning_crescent_moon +🌙 crescent moon Travel & Places crescent_moon night +🌚 new moon face Travel & Places new_moon_with_face +🌛 first quarter moon face Travel & Places first_quarter_moon_with_face +🌜 last quarter moon face Travel & Places last_quarter_moon_with_face +🌡️ thermometer Travel & Places thermometer +☀️ sun Travel & Places sunny weather +🌝 full moon face Travel & Places full_moon_with_face +🌞 sun with face Travel & Places sun_with_face summer +🪐 ringed planet Travel & Places ringed_planet +⭐ star Travel & Places star +🌟 glowing star Travel & Places star2 +🌠 shooting star Travel & Places stars +🌌 milky way Travel & Places milky_way +☁️ cloud Travel & Places cloud +⛅ sun behind cloud Travel & Places partly_sunny weather cloud +⛈️ cloud with lightning and rain Travel & Places cloud_with_lightning_and_rain +🌤️ sun behind small cloud Travel & Places sun_behind_small_cloud +🌥️ sun behind large cloud Travel & Places sun_behind_large_cloud +🌦️ sun behind rain cloud Travel & Places sun_behind_rain_cloud +🌧️ cloud with rain Travel & Places cloud_with_rain +🌨️ cloud with snow Travel & Places cloud_with_snow +🌩️ cloud with lightning Travel & Places cloud_with_lightning +🌪️ tornado Travel & Places tornado +🌫️ fog Travel & Places fog +🌬️ wind face Travel & Places wind_face +🌀 cyclone Travel & Places cyclone swirl +🌈 rainbow Travel & Places rainbow +🌂 closed umbrella Travel & Places closed_umbrella weather rain +☂️ umbrella Travel & Places open_umbrella +☔ umbrella with rain drops Travel & Places umbrella rain weather +⛱️ umbrella on ground Travel & Places parasol_on_ground beach_umbrella +⚡ high voltage Travel & Places zap lightning thunder +❄️ snowflake Travel & Places snowflake winter cold weather +☃️ snowman Travel & Places snowman_with_snow winter christmas +⛄ snowman without snow Travel & Places snowman winter +☄️ comet Travel & Places comet +🔥 fire Travel & Places fire burn +💧 droplet Travel & Places droplet water +🌊 water wave Travel & Places ocean sea +🎃 jack-o-lantern Activities jack_o_lantern halloween +🎄 Christmas tree Activities christmas_tree +🎆 fireworks Activities fireworks festival celebration +🎇 sparkler Activities sparkler +🧨 firecracker Activities firecracker +✨ sparkles Activities sparkles shiny +🎈 balloon Activities balloon party birthday +🎉 party popper Activities tada hooray party +🎊 confetti ball Activities confetti_ball +🎋 tanabata tree Activities tanabata_tree +🎍 pine decoration Activities bamboo +🎎 Japanese dolls Activities dolls +🎏 carp streamer Activities flags +🎐 wind chime Activities wind_chime +🎑 moon viewing ceremony Activities rice_scene +🧧 red envelope Activities red_envelope +🎀 ribbon Activities ribbon +🎁 wrapped gift Activities gift present birthday christmas +🎗️ reminder ribbon Activities reminder_ribbon +🎟️ admission tickets Activities tickets +🎫 ticket Activities ticket +🎖️ military medal Activities medal_military +🏆 trophy Activities trophy award contest winner +🏅 sports medal Activities medal_sports gold winner +🥇 1st place medal Activities 1st_place_medal gold +🥈 2nd place medal Activities 2nd_place_medal silver +🥉 3rd place medal Activities 3rd_place_medal bronze +⚽ soccer ball Activities soccer sports +⚾ baseball Activities baseball sports +🥎 softball Activities softball +🏀 basketball Activities basketball sports +🏐 volleyball Activities volleyball +🏈 american football Activities football sports +🏉 rugby football Activities rugby_football +🎾 tennis Activities tennis sports +🥏 flying disc Activities flying_disc +🎳 bowling Activities bowling +🏏 cricket game Activities cricket_game +🏑 field hockey Activities field_hockey +🏒 ice hockey Activities ice_hockey +🥍 lacrosse Activities lacrosse +🏓 ping pong Activities ping_pong +🏸 badminton Activities badminton +🥊 boxing glove Activities boxing_glove +🥋 martial arts uniform Activities martial_arts_uniform +🥅 goal net Activities goal_net +⛳ flag in hole Activities golf +⛸️ ice skate Activities ice_skate skating +🎣 fishing pole Activities fishing_pole_and_fish +🤿 diving mask Activities diving_mask +🎽 running shirt Activities running_shirt_with_sash marathon +🎿 skis Activities ski +🛷 sled Activities sled +🥌 curling stone Activities curling_stone +🎯 bullseye Activities dart target +🪀 yo-yo Activities yo_yo +🪁 kite Activities kite +🔫 water pistol Activities gun shoot weapon +🎱 pool 8 ball Activities 8ball pool billiards +🔮 crystal ball Activities crystal_ball fortune +🪄 magic wand Activities magic_wand +🎮 video game Activities video_game play controller console +🕹️ joystick Activities joystick +🎰 slot machine Activities slot_machine +🎲 game die Activities game_die dice gambling +🧩 puzzle piece Activities jigsaw +🧸 teddy bear Activities teddy_bear +🪅 piñata Activities pinata +🪩 mirror ball Activities mirror_ball disco party +🪆 nesting dolls Activities nesting_dolls +♠️ spade suit Activities spades +♥️ heart suit Activities hearts +♦️ diamond suit Activities diamonds +♣️ club suit Activities clubs +♟️ chess pawn Activities chess_pawn +🃏 joker Activities black_joker +🀄 mahjong red dragon Activities mahjong +🎴 flower playing cards Activities flower_playing_cards +🎭 performing arts Activities performing_arts theater drama +🖼️ framed picture Activities framed_picture +🎨 artist palette Activities art design paint +🧵 thread Activities thread +🪡 sewing needle Activities sewing_needle +🧶 yarn Activities yarn +🪢 knot Activities knot +👓 glasses Objects eyeglasses glasses +🕶️ sunglasses Objects dark_sunglasses +🥽 goggles Objects goggles +🥼 lab coat Objects lab_coat +🦺 safety vest Objects safety_vest +👔 necktie Objects necktie shirt formal +👕 t-shirt Objects shirt tshirt +👖 jeans Objects jeans pants +🧣 scarf Objects scarf +🧤 gloves Objects gloves +🧥 coat Objects coat +🧦 socks Objects socks +👗 dress Objects dress +👘 kimono Objects kimono +🥻 sari Objects sari +🩱 one-piece swimsuit Objects one_piece_swimsuit +🩲 briefs Objects swim_brief +🩳 shorts Objects shorts +👙 bikini Objects bikini beach +👚 woman’s clothes Objects womans_clothes +🪭 folding hand fan Objects folding_hand_fan sensu +👛 purse Objects purse +👜 handbag Objects handbag bag +👝 clutch bag Objects pouch bag +🛍️ shopping bags Objects shopping bags +🎒 backpack Objects school_satchel +🩴 thong sandal Objects thong_sandal +👞 man’s shoe Objects mans_shoe shoe +👟 running shoe Objects athletic_shoe sneaker sport running +🥾 hiking boot Objects hiking_boot +🥿 flat shoe Objects flat_shoe +👠 high-heeled shoe Objects high_heel shoe +👡 woman’s sandal Objects sandal shoe +🩰 ballet shoes Objects ballet_shoes +👢 woman’s boot Objects boot +🪮 hair pick Objects hair_pick +👑 crown Objects crown king queen royal +👒 woman’s hat Objects womans_hat +🎩 top hat Objects tophat hat classy +🎓 graduation cap Objects mortar_board education college university graduation +🧢 billed cap Objects billed_cap +🪖 military helmet Objects military_helmet +⛑️ rescue worker’s helmet Objects rescue_worker_helmet +📿 prayer beads Objects prayer_beads +💄 lipstick Objects lipstick makeup +💍 ring Objects ring wedding marriage engaged +💎 gem stone Objects gem diamond +🔇 muted speaker Objects mute sound volume +🔈 speaker low volume Objects speaker +🔉 speaker medium volume Objects sound volume +🔊 speaker high volume Objects loud_sound volume +📢 loudspeaker Objects loudspeaker announcement +📣 megaphone Objects mega +📯 postal horn Objects postal_horn +🔔 bell Objects bell sound notification +🔕 bell with slash Objects no_bell volume off +🎼 musical score Objects musical_score +🎵 musical note Objects musical_note +🎶 musical notes Objects notes music +🎙️ studio microphone Objects studio_microphone podcast +🎚️ level slider Objects level_slider +🎛️ control knobs Objects control_knobs +🎤 microphone Objects microphone sing +🎧 headphone Objects headphones music earphones +📻 radio Objects radio podcast +🎷 saxophone Objects saxophone +🪗 accordion Objects accordion +🎸 guitar Objects guitar rock +🎹 musical keyboard Objects musical_keyboard piano +🎺 trumpet Objects trumpet +🎻 violin Objects violin +🪕 banjo Objects banjo +🥁 drum Objects drum +🪘 long drum Objects long_drum +🪇 maracas Objects maracas shaker +🪈 flute Objects flute recorder +📱 mobile phone Objects iphone smartphone mobile +📲 mobile phone with arrow Objects calling call incoming +☎️ telephone Objects phone telephone +📞 telephone receiver Objects telephone_receiver phone call +📟 pager Objects pager +📠 fax machine Objects fax +🔋 battery Objects battery power +🪫 low battery Objects low_battery +🔌 electric plug Objects electric_plug +💻 laptop Objects computer desktop screen +🖥️ desktop computer Objects desktop_computer +🖨️ printer Objects printer +⌨️ keyboard Objects keyboard +🖱️ computer mouse Objects computer_mouse +🖲️ trackball Objects trackball +💽 computer disk Objects minidisc +💾 floppy disk Objects floppy_disk save +💿 optical disk Objects cd +📀 dvd Objects dvd +🧮 abacus Objects abacus +🎥 movie camera Objects movie_camera film video +🎞️ film frames Objects film_strip +📽️ film projector Objects film_projector +🎬 clapper board Objects clapper film +📺 television Objects tv +📷 camera Objects camera photo +📸 camera with flash Objects camera_flash photo +📹 video camera Objects video_camera +📼 videocassette Objects vhs +🔍 magnifying glass tilted left Objects mag search zoom +🔎 magnifying glass tilted right Objects mag_right +🕯️ candle Objects candle +💡 light bulb Objects bulb idea light +🔦 flashlight Objects flashlight +🏮 red paper lantern Objects izakaya_lantern lantern +🪔 diya lamp Objects diya_lamp +📔 notebook with decorative cover Objects notebook_with_decorative_cover +📕 closed book Objects closed_book +📖 open book Objects book open_book +📗 green book Objects green_book +📘 blue book Objects blue_book +📙 orange book Objects orange_book +📚 books Objects books library +📓 notebook Objects notebook +📒 ledger Objects ledger +📃 page with curl Objects page_with_curl +📜 scroll Objects scroll document +📄 page facing up Objects page_facing_up document +📰 newspaper Objects newspaper press +🗞️ rolled-up newspaper Objects newspaper_roll press +📑 bookmark tabs Objects bookmark_tabs +🔖 bookmark Objects bookmark +🏷️ label Objects label tag +💰 money bag Objects moneybag dollar cream +🪙 coin Objects coin +💴 yen banknote Objects yen +💵 dollar banknote Objects dollar money +💶 euro banknote Objects euro +💷 pound banknote Objects pound +💸 money with wings Objects money_with_wings dollar +💳 credit card Objects credit_card subscription +🧾 receipt Objects receipt +💹 chart increasing with yen Objects chart +✉️ envelope Objects envelope letter email +📧 e-mail Objects email e-mail +📨 incoming envelope Objects incoming_envelope +📩 envelope with arrow Objects envelope_with_arrow +📤 outbox tray Objects outbox_tray +📥 inbox tray Objects inbox_tray +📦 package Objects package shipping +📫 closed mailbox with raised flag Objects mailbox +📪 closed mailbox with lowered flag Objects mailbox_closed +📬 open mailbox with raised flag Objects mailbox_with_mail +📭 open mailbox with lowered flag Objects mailbox_with_no_mail +📮 postbox Objects postbox +🗳️ ballot box with ballot Objects ballot_box +✏️ pencil Objects pencil2 +✒️ black nib Objects black_nib +🖋️ fountain pen Objects fountain_pen +🖊️ pen Objects pen +🖌️ paintbrush Objects paintbrush +🖍️ crayon Objects crayon +📝 memo Objects memo pencil document note +💼 briefcase Objects briefcase business +📁 file folder Objects file_folder directory +📂 open file folder Objects open_file_folder +🗂️ card index dividers Objects card_index_dividers +📅 calendar Objects date calendar schedule +📆 tear-off calendar Objects calendar schedule +🗒️ spiral notepad Objects spiral_notepad +🗓️ spiral calendar Objects spiral_calendar +📇 card index Objects card_index +📈 chart increasing Objects chart_with_upwards_trend graph metrics +📉 chart decreasing Objects chart_with_downwards_trend graph metrics +📊 bar chart Objects bar_chart stats metrics +📋 clipboard Objects clipboard +📌 pushpin Objects pushpin location +📍 round pushpin Objects round_pushpin location +📎 paperclip Objects paperclip +🖇️ linked paperclips Objects paperclips +📏 straight ruler Objects straight_ruler +📐 triangular ruler Objects triangular_ruler +✂️ scissors Objects scissors cut +🗃️ card file box Objects card_file_box +🗄️ file cabinet Objects file_cabinet +🗑️ wastebasket Objects wastebasket trash +🔒 locked Objects lock security private +🔓 unlocked Objects unlock security +🔏 locked with pen Objects lock_with_ink_pen +🔐 locked with key Objects closed_lock_with_key security +🔑 key Objects key lock password +🗝️ old key Objects old_key +🔨 hammer Objects hammer tool +🪓 axe Objects axe +⛏️ pick Objects pick +⚒️ hammer and pick Objects hammer_and_pick +🛠️ hammer and wrench Objects hammer_and_wrench +🗡️ dagger Objects dagger +⚔️ crossed swords Objects crossed_swords +💣 bomb Objects bomb boom +🪃 boomerang Objects boomerang +🏹 bow and arrow Objects bow_and_arrow archery +🛡️ shield Objects shield +🪚 carpentry saw Objects carpentry_saw +🔧 wrench Objects wrench tool +🪛 screwdriver Objects screwdriver +🔩 nut and bolt Objects nut_and_bolt +⚙️ gear Objects gear +🗜️ clamp Objects clamp +⚖️ balance scale Objects balance_scale +🦯 white cane Objects probing_cane +🔗 link Objects link +⛓️ chains Objects chains +🪝 hook Objects hook +🧰 toolbox Objects toolbox +🧲 magnet Objects magnet +🪜 ladder Objects ladder +⚗️ alembic Objects alembic +🧪 test tube Objects test_tube +🧫 petri dish Objects petri_dish +🧬 dna Objects dna +🔬 microscope Objects microscope science laboratory investigate +🔭 telescope Objects telescope +📡 satellite antenna Objects satellite signal +💉 syringe Objects syringe health hospital needle +🩸 drop of blood Objects drop_of_blood +💊 pill Objects pill health medicine +🩹 adhesive bandage Objects adhesive_bandage +🩼 crutch Objects crutch +🩺 stethoscope Objects stethoscope +🩻 x-ray Objects x_ray +🚪 door Objects door +🛗 elevator Objects elevator +🪞 mirror Objects mirror +🪟 window Objects window +🛏️ bed Objects bed +🛋️ couch and lamp Objects couch_and_lamp +🪑 chair Objects chair +🚽 toilet Objects toilet wc +🪠 plunger Objects plunger +🚿 shower Objects shower bath +🛁 bathtub Objects bathtub +🪤 mouse trap Objects mouse_trap +🪒 razor Objects razor +🧴 lotion bottle Objects lotion_bottle +🧷 safety pin Objects safety_pin +🧹 broom Objects broom +🧺 basket Objects basket +🧻 roll of paper Objects roll_of_paper toilet +🪣 bucket Objects bucket +🧼 soap Objects soap +🫧 bubbles Objects bubbles +🪥 toothbrush Objects toothbrush +🧽 sponge Objects sponge +🧯 fire extinguisher Objects fire_extinguisher +🛒 shopping cart Objects shopping_cart +🚬 cigarette Objects smoking cigarette +⚰️ coffin Objects coffin funeral +🪦 headstone Objects headstone +⚱️ funeral urn Objects funeral_urn +🧿 nazar amulet Objects nazar_amulet +🪬 hamsa Objects hamsa +🗿 moai Objects moyai stone +🪧 placard Objects placard +🪪 identification card Objects identification_card +🏧 ATM sign Symbols atm +🚮 litter in bin sign Symbols put_litter_in_its_place +🚰 potable water Symbols potable_water +♿ wheelchair symbol Symbols wheelchair accessibility +🚹 men’s room Symbols mens +🚺 women’s room Symbols womens +🚻 restroom Symbols restroom toilet +🚼 baby symbol Symbols baby_symbol +🚾 water closet Symbols wc toilet restroom +🛂 passport control Symbols passport_control +🛃 customs Symbols customs +🛄 baggage claim Symbols baggage_claim airport +🛅 left luggage Symbols left_luggage +⚠️ warning Symbols warning wip +🚸 children crossing Symbols children_crossing +⛔ no entry Symbols no_entry limit +🚫 prohibited Symbols no_entry_sign block forbidden +🚳 no bicycles Symbols no_bicycles +🚭 no smoking Symbols no_smoking +🚯 no littering Symbols do_not_litter +🚱 non-potable water Symbols non-potable_water +🚷 no pedestrians Symbols no_pedestrians +📵 no mobile phones Symbols no_mobile_phones +🔞 no one under eighteen Symbols underage +☢️ radioactive Symbols radioactive +☣️ biohazard Symbols biohazard +⬆️ up arrow Symbols arrow_up +↗️ up-right arrow Symbols arrow_upper_right +➡️ right arrow Symbols arrow_right +↘️ down-right arrow Symbols arrow_lower_right +⬇️ down arrow Symbols arrow_down +↙️ down-left arrow Symbols arrow_lower_left +⬅️ left arrow Symbols arrow_left +↖️ up-left arrow Symbols arrow_upper_left +↕️ up-down arrow Symbols arrow_up_down +↔️ left-right arrow Symbols left_right_arrow +↩️ right arrow curving left Symbols leftwards_arrow_with_hook return +↪️ left arrow curving right Symbols arrow_right_hook +⤴️ right arrow curving up Symbols arrow_heading_up +⤵️ right arrow curving down Symbols arrow_heading_down +🔃 clockwise vertical arrows Symbols arrows_clockwise +🔄 counterclockwise arrows button Symbols arrows_counterclockwise sync +🔙 BACK arrow Symbols back +🔚 END arrow Symbols end +🔛 ON! arrow Symbols on +🔜 SOON arrow Symbols soon +🔝 TOP arrow Symbols top +🛐 place of worship Symbols place_of_worship +⚛️ atom symbol Symbols atom_symbol +🕉️ om Symbols om +✡️ star of David Symbols star_of_david +☸️ wheel of dharma Symbols wheel_of_dharma +☯️ yin yang Symbols yin_yang +✝️ latin cross Symbols latin_cross +☦️ orthodox cross Symbols orthodox_cross +☪️ star and crescent Symbols star_and_crescent +☮️ peace symbol Symbols peace_symbol +🕎 menorah Symbols menorah +🔯 dotted six-pointed star Symbols six_pointed_star +🪯 khanda Symbols khanda +♈ Aries Symbols aries +♉ Taurus Symbols taurus +♊ Gemini Symbols gemini +♋ Cancer Symbols cancer +♌ Leo Symbols leo +♍ Virgo Symbols virgo +♎ Libra Symbols libra +♏ Scorpio Symbols scorpius +♐ Sagittarius Symbols sagittarius +♑ Capricorn Symbols capricorn +♒ Aquarius Symbols aquarius +♓ Pisces Symbols pisces +⛎ Ophiuchus Symbols ophiuchus +🔀 shuffle tracks button Symbols twisted_rightwards_arrows shuffle +🔁 repeat button Symbols repeat loop +🔂 repeat single button Symbols repeat_one +▶️ play button Symbols arrow_forward +⏩ fast-forward button Symbols fast_forward +⏭️ next track button Symbols next_track_button +⏯️ play or pause button Symbols play_or_pause_button +◀️ reverse button Symbols arrow_backward +⏪ fast reverse button Symbols rewind +⏮️ last track button Symbols previous_track_button +🔼 upwards button Symbols arrow_up_small +⏫ fast up button Symbols arrow_double_up +🔽 downwards button Symbols arrow_down_small +⏬ fast down button Symbols arrow_double_down +⏸️ pause button Symbols pause_button +⏹️ stop button Symbols stop_button +⏺️ record button Symbols record_button +⏏️ eject button Symbols eject_button +🎦 cinema Symbols cinema film movie +🔅 dim button Symbols low_brightness +🔆 bright button Symbols high_brightness +📶 antenna bars Symbols signal_strength wifi +🛜 wireless Symbols wireless wifi +📳 vibration mode Symbols vibration_mode +📴 mobile phone off Symbols mobile_phone_off mute off +♀️ female sign Symbols female_sign +♂️ male sign Symbols male_sign +⚧️ transgender symbol Symbols transgender_symbol +✖️ multiply Symbols heavy_multiplication_x +➕ plus Symbols heavy_plus_sign +➖ minus Symbols heavy_minus_sign +➗ divide Symbols heavy_division_sign +🟰 heavy equals sign Symbols heavy_equals_sign +♾️ infinity Symbols infinity +‼️ double exclamation mark Symbols bangbang +⁉️ exclamation question mark Symbols interrobang +❓ red question mark Symbols question confused +❔ white question mark Symbols grey_question +❕ white exclamation mark Symbols grey_exclamation +❗ red exclamation mark Symbols exclamation heavy_exclamation_mark bang +〰️ wavy dash Symbols wavy_dash +💱 currency exchange Symbols currency_exchange +💲 heavy dollar sign Symbols heavy_dollar_sign +⚕️ medical symbol Symbols medical_symbol +♻️ recycling symbol Symbols recycle environment green +⚜️ fleur-de-lis Symbols fleur_de_lis +🔱 trident emblem Symbols trident +📛 name badge Symbols name_badge +🔰 Japanese symbol for beginner Symbols beginner +⭕ hollow red circle Symbols o +✅ check mark button Symbols white_check_mark +☑️ check box with check Symbols ballot_box_with_check +✔️ check mark Symbols heavy_check_mark +❌ cross mark Symbols x +❎ cross mark button Symbols negative_squared_cross_mark +➰ curly loop Symbols curly_loop +➿ double curly loop Symbols loop +〽️ part alternation mark Symbols part_alternation_mark +✳️ eight-spoked asterisk Symbols eight_spoked_asterisk +✴️ eight-pointed star Symbols eight_pointed_black_star +❇️ sparkle Symbols sparkle +©️ copyright Symbols copyright +®️ registered Symbols registered +™️ trade mark Symbols tm trademark +#️⃣ keycap: # Symbols hash number +*️⃣ keycap: * Symbols asterisk +0️⃣ keycap: 0 Symbols zero +1️⃣ keycap: 1 Symbols one +2️⃣ keycap: 2 Symbols two +3️⃣ keycap: 3 Symbols three +4️⃣ keycap: 4 Symbols four +5️⃣ keycap: 5 Symbols five +6️⃣ keycap: 6 Symbols six +7️⃣ keycap: 7 Symbols seven +8️⃣ keycap: 8 Symbols eight +9️⃣ keycap: 9 Symbols nine +🔟 keycap: 10 Symbols keycap_ten +🔠 input latin uppercase Symbols capital_abcd letters +🔡 input latin lowercase Symbols abcd +🔢 input numbers Symbols 1234 numbers +🔣 input symbols Symbols symbols +🔤 input latin letters Symbols abc alphabet +🅰️ A button (blood type) Symbols a +🆎 AB button (blood type) Symbols ab +🅱️ B button (blood type) Symbols b +🆑 CL button Symbols cl +🆒 COOL button Symbols cool +🆓 FREE button Symbols free +ℹ️ information Symbols information_source +🆔 ID button Symbols id +Ⓜ️ circled M Symbols m +🆕 NEW button Symbols new fresh +🆖 NG button Symbols ng +🅾️ O button (blood type) Symbols o2 +🆗 OK button Symbols ok yes +🅿️ P button Symbols parking +🆘 SOS button Symbols sos help emergency +🆙 UP! button Symbols up +🆚 VS button Symbols vs +🈁 Japanese “here” button Symbols koko +🈂️ Japanese “service charge” button Symbols sa +🈷️ Japanese “monthly amount” button Symbols u6708 +🈶 Japanese “not free of charge” button Symbols u6709 +🈯 Japanese “reserved” button Symbols u6307 +🉐 Japanese “bargain” button Symbols ideograph_advantage +🈹 Japanese “discount” button Symbols u5272 +🈚 Japanese “free of charge” button Symbols u7121 +🈲 Japanese “prohibited” button Symbols u7981 +🉑 Japanese “acceptable” button Symbols accept +🈸 Japanese “application” button Symbols u7533 +🈴 Japanese “passing grade” button Symbols u5408 +🈳 Japanese “vacancy” button Symbols u7a7a +㊗️ Japanese “congratulations” button Symbols congratulations +㊙️ Japanese “secret” button Symbols secret +🈺 Japanese “open for business” button Symbols u55b6 +🈵 Japanese “no vacancy” button Symbols u6e80 +🔴 red circle Symbols red_circle +🟠 orange circle Symbols orange_circle +🟡 yellow circle Symbols yellow_circle +🟢 green circle Symbols green_circle +🔵 blue circle Symbols large_blue_circle +🟣 purple circle Symbols purple_circle +🟤 brown circle Symbols brown_circle +⚫ black circle Symbols black_circle +⚪ white circle Symbols white_circle +🟥 red square Symbols red_square +🟧 orange square Symbols orange_square +🟨 yellow square Symbols yellow_square +🟩 green square Symbols green_square +🟦 blue square Symbols blue_square +🟪 purple square Symbols purple_square +🟫 brown square Symbols brown_square +⬛ black large square Symbols black_large_square +⬜ white large square Symbols white_large_square +◼️ black medium square Symbols black_medium_square +◻️ white medium square Symbols white_medium_square +◾ black medium-small square Symbols black_medium_small_square +◽ white medium-small square Symbols white_medium_small_square +▪️ black small square Symbols black_small_square +▫️ white small square Symbols white_small_square +🔶 large orange diamond Symbols large_orange_diamond +🔷 large blue diamond Symbols large_blue_diamond +🔸 small orange diamond Symbols small_orange_diamond +🔹 small blue diamond Symbols small_blue_diamond +🔺 red triangle pointed up Symbols small_red_triangle +🔻 red triangle pointed down Symbols small_red_triangle_down +💠 diamond with a dot Symbols diamond_shape_with_a_dot_inside +🔘 radio button Symbols radio_button +🔳 white square button Symbols white_square_button +🔲 black square button Symbols black_square_button +🏁 chequered flag Flags checkered_flag milestone finish +🚩 triangular flag Flags triangular_flag_on_post +🎌 crossed flags Flags crossed_flags +🏴 black flag Flags black_flag +🏳️ white flag Flags white_flag +🏳️‍🌈 rainbow flag Flags rainbow_flag pride +🏳️‍⚧️ transgender flag Flags transgender_flag +🏴‍☠️ pirate flag Flags pirate_flag +🇦🇨 flag: Ascension Island Flags ascension_island +🇦🇩 flag: Andorra Flags andorra +🇦🇪 flag: United Arab Emirates Flags united_arab_emirates +🇦🇫 flag: Afghanistan Flags afghanistan +🇦🇬 flag: Antigua & Barbuda Flags antigua_barbuda +🇦🇮 flag: Anguilla Flags anguilla +🇦🇱 flag: Albania Flags albania +🇦🇲 flag: Armenia Flags armenia +🇦🇴 flag: Angola Flags angola +🇦🇶 flag: Antarctica Flags antarctica +🇦🇷 flag: Argentina Flags argentina +🇦🇸 flag: American Samoa Flags american_samoa +🇦🇹 flag: Austria Flags austria +🇦🇺 flag: Australia Flags australia +🇦🇼 flag: Aruba Flags aruba +🇦🇽 flag: Åland Islands Flags aland_islands +🇦🇿 flag: Azerbaijan Flags azerbaijan +🇧🇦 flag: Bosnia & Herzegovina Flags bosnia_herzegovina +🇧🇧 flag: Barbados Flags barbados +🇧🇩 flag: Bangladesh Flags bangladesh +🇧🇪 flag: Belgium Flags belgium +🇧🇫 flag: Burkina Faso Flags burkina_faso +🇧🇬 flag: Bulgaria Flags bulgaria +🇧🇭 flag: Bahrain Flags bahrain +🇧🇮 flag: Burundi Flags burundi +🇧🇯 flag: Benin Flags benin +🇧🇱 flag: St. Barthélemy Flags st_barthelemy +🇧🇲 flag: Bermuda Flags bermuda +🇧🇳 flag: Brunei Flags brunei +🇧🇴 flag: Bolivia Flags bolivia +🇧🇶 flag: Caribbean Netherlands Flags caribbean_netherlands +🇧🇷 flag: Brazil Flags brazil +🇧🇸 flag: Bahamas Flags bahamas +🇧🇹 flag: Bhutan Flags bhutan +🇧🇻 flag: Bouvet Island Flags bouvet_island +🇧🇼 flag: Botswana Flags botswana +🇧🇾 flag: Belarus Flags belarus +🇧🇿 flag: Belize Flags belize +🇨🇦 flag: Canada Flags canada +🇨🇨 flag: Cocos (Keeling) Islands Flags cocos_islands keeling +🇨🇩 flag: Congo - Kinshasa Flags congo_kinshasa +🇨🇫 flag: Central African Republic Flags central_african_republic +🇨🇬 flag: Congo - Brazzaville Flags congo_brazzaville +🇨🇭 flag: Switzerland Flags switzerland +🇨🇮 flag: Côte d’Ivoire Flags cote_divoire ivory +🇨🇰 flag: Cook Islands Flags cook_islands +🇨🇱 flag: Chile Flags chile +🇨🇲 flag: Cameroon Flags cameroon +🇨🇳 flag: China Flags cn china +🇨🇴 flag: Colombia Flags colombia +🇨🇵 flag: Clipperton Island Flags clipperton_island +🇨🇷 flag: Costa Rica Flags costa_rica +🇨🇺 flag: Cuba Flags cuba +🇨🇻 flag: Cape Verde Flags cape_verde +🇨🇼 flag: Curaçao Flags curacao +🇨🇽 flag: Christmas Island Flags christmas_island +🇨🇾 flag: Cyprus Flags cyprus +🇨🇿 flag: Czechia Flags czech_republic +🇩🇪 flag: Germany Flags de flag germany +🇩🇬 flag: Diego Garcia Flags diego_garcia +🇩🇯 flag: Djibouti Flags djibouti +🇩🇰 flag: Denmark Flags denmark +🇩🇲 flag: Dominica Flags dominica +🇩🇴 flag: Dominican Republic Flags dominican_republic +🇩🇿 flag: Algeria Flags algeria +🇪🇦 flag: Ceuta & Melilla Flags ceuta_melilla +🇪🇨 flag: Ecuador Flags ecuador +🇪🇪 flag: Estonia Flags estonia +🇪🇬 flag: Egypt Flags egypt +🇪🇭 flag: Western Sahara Flags western_sahara +🇪🇷 flag: Eritrea Flags eritrea +🇪🇸 flag: Spain Flags es spain +🇪🇹 flag: Ethiopia Flags ethiopia +🇪🇺 flag: European Union Flags eu european_union +🇫🇮 flag: Finland Flags finland +🇫🇯 flag: Fiji Flags fiji +🇫🇰 flag: Falkland Islands Flags falkland_islands +🇫🇲 flag: Micronesia Flags micronesia +🇫🇴 flag: Faroe Islands Flags faroe_islands +🇫🇷 flag: France Flags fr france french +🇬🇦 flag: Gabon Flags gabon +🇬🇧 flag: United Kingdom Flags gb uk flag british +🇬🇩 flag: Grenada Flags grenada +🇬🇪 flag: Georgia Flags georgia +🇬🇫 flag: French Guiana Flags french_guiana +🇬🇬 flag: Guernsey Flags guernsey +🇬🇭 flag: Ghana Flags ghana +🇬🇮 flag: Gibraltar Flags gibraltar +🇬🇱 flag: Greenland Flags greenland +🇬🇲 flag: Gambia Flags gambia +🇬🇳 flag: Guinea Flags guinea +🇬🇵 flag: Guadeloupe Flags guadeloupe +🇬🇶 flag: Equatorial Guinea Flags equatorial_guinea +🇬🇷 flag: Greece Flags greece +🇬🇸 flag: South Georgia & South Sandwich Islands Flags south_georgia_south_sandwich_islands +🇬🇹 flag: Guatemala Flags guatemala +🇬🇺 flag: Guam Flags guam +🇬🇼 flag: Guinea-Bissau Flags guinea_bissau +🇬🇾 flag: Guyana Flags guyana +🇭🇰 flag: Hong Kong SAR China Flags hong_kong +🇭🇲 flag: Heard & McDonald Islands Flags heard_mcdonald_islands +🇭🇳 flag: Honduras Flags honduras +🇭🇷 flag: Croatia Flags croatia +🇭🇹 flag: Haiti Flags haiti +🇭🇺 flag: Hungary Flags hungary +🇮🇨 flag: Canary Islands Flags canary_islands +🇮🇩 flag: Indonesia Flags indonesia +🇮🇪 flag: Ireland Flags ireland +🇮🇱 flag: Israel Flags israel +🇮🇲 flag: Isle of Man Flags isle_of_man +🇮🇳 flag: India Flags india +🇮🇴 flag: British Indian Ocean Territory Flags british_indian_ocean_territory +🇮🇶 flag: Iraq Flags iraq +🇮🇷 flag: Iran Flags iran +🇮🇸 flag: Iceland Flags iceland +🇮🇹 flag: Italy Flags it italy +🇯🇪 flag: Jersey Flags jersey +🇯🇲 flag: Jamaica Flags jamaica +🇯🇴 flag: Jordan Flags jordan +🇯🇵 flag: Japan Flags jp japan +🇰🇪 flag: Kenya Flags kenya +🇰🇬 flag: Kyrgyzstan Flags kyrgyzstan +🇰🇭 flag: Cambodia Flags cambodia +🇰🇮 flag: Kiribati Flags kiribati +🇰🇲 flag: Comoros Flags comoros +🇰🇳 flag: St. Kitts & Nevis Flags st_kitts_nevis +🇰🇵 flag: North Korea Flags north_korea +🇰🇷 flag: South Korea Flags kr korea +🇰🇼 flag: Kuwait Flags kuwait +🇰🇾 flag: Cayman Islands Flags cayman_islands +🇰🇿 flag: Kazakhstan Flags kazakhstan +🇱🇦 flag: Laos Flags laos +🇱🇧 flag: Lebanon Flags lebanon +🇱🇨 flag: St. Lucia Flags st_lucia +🇱🇮 flag: Liechtenstein Flags liechtenstein +🇱🇰 flag: Sri Lanka Flags sri_lanka +🇱🇷 flag: Liberia Flags liberia +🇱🇸 flag: Lesotho Flags lesotho +🇱🇹 flag: Lithuania Flags lithuania +🇱🇺 flag: Luxembourg Flags luxembourg +🇱🇻 flag: Latvia Flags latvia +🇱🇾 flag: Libya Flags libya +🇲🇦 flag: Morocco Flags morocco +🇲🇨 flag: Monaco Flags monaco +🇲🇩 flag: Moldova Flags moldova +🇲🇪 flag: Montenegro Flags montenegro +🇲🇫 flag: St. Martin Flags st_martin +🇲🇬 flag: Madagascar Flags madagascar +🇲🇭 flag: Marshall Islands Flags marshall_islands +🇲🇰 flag: North Macedonia Flags macedonia +🇲🇱 flag: Mali Flags mali +🇲🇲 flag: Myanmar (Burma) Flags myanmar burma +🇲🇳 flag: Mongolia Flags mongolia +🇲🇴 flag: Macao SAR China Flags macau +🇲🇵 flag: Northern Mariana Islands Flags northern_mariana_islands +🇲🇶 flag: Martinique Flags martinique +🇲🇷 flag: Mauritania Flags mauritania +🇲🇸 flag: Montserrat Flags montserrat +🇲🇹 flag: Malta Flags malta +🇲🇺 flag: Mauritius Flags mauritius +🇲🇻 flag: Maldives Flags maldives +🇲🇼 flag: Malawi Flags malawi +🇲🇽 flag: Mexico Flags mexico +🇲🇾 flag: Malaysia Flags malaysia +🇲🇿 flag: Mozambique Flags mozambique +🇳🇦 flag: Namibia Flags namibia +🇳🇨 flag: New Caledonia Flags new_caledonia +🇳🇪 flag: Niger Flags niger +🇳🇫 flag: Norfolk Island Flags norfolk_island +🇳🇬 flag: Nigeria Flags nigeria +🇳🇮 flag: Nicaragua Flags nicaragua +🇳🇱 flag: Netherlands Flags netherlands +🇳🇴 flag: Norway Flags norway +🇳🇵 flag: Nepal Flags nepal +🇳🇷 flag: Nauru Flags nauru +🇳🇺 flag: Niue Flags niue +🇳🇿 flag: New Zealand Flags new_zealand +🇴🇲 flag: Oman Flags oman +🇵🇦 flag: Panama Flags panama +🇵🇪 flag: Peru Flags peru +🇵🇫 flag: French Polynesia Flags french_polynesia +🇵🇬 flag: Papua New Guinea Flags papua_new_guinea +🇵🇭 flag: Philippines Flags philippines +🇵🇰 flag: Pakistan Flags pakistan +🇵🇱 flag: Poland Flags poland +🇵🇲 flag: St. Pierre & Miquelon Flags st_pierre_miquelon +🇵🇳 flag: Pitcairn Islands Flags pitcairn_islands +🇵🇷 flag: Puerto Rico Flags puerto_rico +🇵🇸 flag: Palestinian Territories Flags palestinian_territories +🇵🇹 flag: Portugal Flags portugal +🇵🇼 flag: Palau Flags palau +🇵🇾 flag: Paraguay Flags paraguay +🇶🇦 flag: Qatar Flags qatar +🇷🇪 flag: Réunion Flags reunion +🇷🇴 flag: Romania Flags romania +🇷🇸 flag: Serbia Flags serbia +🇷🇺 flag: Russia Flags ru russia +🇷🇼 flag: Rwanda Flags rwanda +🇸🇦 flag: Saudi Arabia Flags saudi_arabia +🇸🇧 flag: Solomon Islands Flags solomon_islands +🇸🇨 flag: Seychelles Flags seychelles +🇸🇩 flag: Sudan Flags sudan +🇸🇪 flag: Sweden Flags sweden +🇸🇬 flag: Singapore Flags singapore +🇸🇭 flag: St. Helena Flags st_helena +🇸🇮 flag: Slovenia Flags slovenia +🇸🇯 flag: Svalbard & Jan Mayen Flags svalbard_jan_mayen +🇸🇰 flag: Slovakia Flags slovakia +🇸🇱 flag: Sierra Leone Flags sierra_leone +🇸🇲 flag: San Marino Flags san_marino +🇸🇳 flag: Senegal Flags senegal +🇸🇴 flag: Somalia Flags somalia +🇸🇷 flag: Suriname Flags suriname +🇸🇸 flag: South Sudan Flags south_sudan +🇸🇹 flag: São Tomé & Príncipe Flags sao_tome_principe +🇸🇻 flag: El Salvador Flags el_salvador +🇸🇽 flag: Sint Maarten Flags sint_maarten +🇸🇾 flag: Syria Flags syria +🇸🇿 flag: Eswatini Flags swaziland +🇹🇦 flag: Tristan da Cunha Flags tristan_da_cunha +🇹🇨 flag: Turks & Caicos Islands Flags turks_caicos_islands +🇹🇩 flag: Chad Flags chad +🇹🇫 flag: French Southern Territories Flags french_southern_territories +🇹🇬 flag: Togo Flags togo +🇹🇭 flag: Thailand Flags thailand +🇹🇯 flag: Tajikistan Flags tajikistan +🇹🇰 flag: Tokelau Flags tokelau +🇹🇱 flag: Timor-Leste Flags timor_leste +🇹🇲 flag: Turkmenistan Flags turkmenistan +🇹🇳 flag: Tunisia Flags tunisia +🇹🇴 flag: Tonga Flags tonga +🇹🇷 flag: Turkey Flags tr turkey +🇹🇹 flag: Trinidad & Tobago Flags trinidad_tobago +🇹🇻 flag: Tuvalu Flags tuvalu +🇹🇼 flag: Taiwan Flags taiwan +🇹🇿 flag: Tanzania Flags tanzania +🇺🇦 flag: Ukraine Flags ukraine +🇺🇬 flag: Uganda Flags uganda +🇺🇲 flag: U.S. Outlying Islands Flags us_outlying_islands +🇺🇳 flag: United Nations Flags united_nations +🇺🇸 flag: United States Flags us flag united america +🇺🇾 flag: Uruguay Flags uruguay +🇺🇿 flag: Uzbekistan Flags uzbekistan +🇻🇦 flag: Vatican City Flags vatican_city +🇻🇨 flag: St. Vincent & Grenadines Flags st_vincent_grenadines +🇻🇪 flag: Venezuela Flags venezuela +🇻🇬 flag: British Virgin Islands Flags british_virgin_islands +🇻🇮 flag: U.S. Virgin Islands Flags us_virgin_islands +🇻🇳 flag: Vietnam Flags vietnam +🇻🇺 flag: Vanuatu Flags vanuatu +🇼🇫 flag: Wallis & Futuna Flags wallis_futuna +🇼🇸 flag: Samoa Flags samoa +🇽🇰 flag: Kosovo Flags kosovo +🇾🇪 flag: Yemen Flags yemen +🇾🇹 flag: Mayotte Flags mayotte +🇿🇦 flag: South Africa Flags south_africa +🇿🇲 flag: Zambia Flags zambia +🇿🇼 flag: Zimbabwe Flags zimbabwe +🏴󠁧󠁢󠁥󠁮󠁧󠁿 flag: England Flags england +🏴󠁧󠁢󠁳󠁣󠁴󠁿 flag: Scotland Flags scotland +🏴󠁧󠁢󠁷󠁬󠁳󠁿 flag: Wales Flags wales diff --git a/TODO.md b/TODO.md index 72f124d..14ba937 100644 --- a/TODO.md +++ b/TODO.md @@ -1,3 +1,3 @@ -- [ ] add an emoji picker inspired raycast's emoji picker +- [x] add an emoji picker inspired raycast's emoji picker - [ ] add a notes app inspired by raycast notes - [ ] improve on the conjure translation command \ No newline at end of file diff --git a/Tests/ConjureKitTests/EmojiCatalogTests.swift b/Tests/ConjureKitTests/EmojiCatalogTests.swift new file mode 100644 index 0000000..500b2fb --- /dev/null +++ b/Tests/ConjureKitTests/EmojiCatalogTests.swift @@ -0,0 +1,20 @@ +import ConjureKit +import Testing + +@Test func emojiCatalogSupportsOfflineSearchAndOrderedCategories() { + #expect(EmojiCatalog.search(" \n ").map(\.value) == EmojiCatalog.all.map(\.value)) + #expect(EmojiCatalog.search("", category: "Flags").map(\.value) + == EmojiCatalog.all.filter { $0.category == "Flags" }.map(\.value)) + + // Names, shortcodes, aliases, tags, and literals share the same search path. + #expect(EmojiCatalog.search("woman tech").map(\.value) == ["👩‍💻"]) + #expect(EmojiCatalog.search(":WOMAN_TECHNOLOGIST:").map(\.value) == ["👩‍💻"]) + #expect(EmojiCatalog.search("coder woman", category: "People & Body").map(\.value) == ["👩‍💻"]) + #expect(EmojiCatalog.search("coder woman", category: "Objects").isEmpty) + #expect(EmojiCatalog.search(":+1:").map(\.value) == ["👍"]) + #expect(EmojiCatalog.search("CÁFÉ", category: "Food & Drink").contains { $0.value == "☕" }) + #expect(EmojiCatalog.search("👩‍💻").map(\.value) == ["👩‍💻"]) + #expect(EmojiCatalog.search("🇩🇰", category: "Flags").map(\.value) == ["🇩🇰"]) + #expect(EmojiCatalog.search("no-such-emoji").isEmpty) + #expect(EmojiCatalog.search("", category: "no-such-category").isEmpty) +} diff --git a/Tests/ConjureKitTests/EmojiPickerTests.swift b/Tests/ConjureKitTests/EmojiPickerTests.swift new file mode 100644 index 0000000..6ad5a5f --- /dev/null +++ b/Tests/ConjureKitTests/EmojiPickerTests.swift @@ -0,0 +1,69 @@ +import AppKit +import ConjureKit +import Testing +@testable import Conjure + +@Test @MainActor func emojiPickerNavigatesCopiesAndRemembersRecentSelections() throws { + _ = NSApplication.shared + let suite = "ConjureEmoji.\(UUID().uuidString)" + let defaults = UserDefaults(suiteName: suite)! + let pasteboard = NSPasteboard.withUniqueName() + defer { + defaults.removePersistentDomain(forName: suite) + pasteboard.releaseGlobally() + } + var query = "face" + var closed = false + let picker = EmojiPickerController(defaults: defaults, pasteboard: pasteboard) + picker.input = { query } + picker.closed = { closed = true } + _ = picker.view + let matches = EmojiCatalog.search(query) + #expect(picker.handle(#selector(NSResponder.moveRight(_:)))) + #expect(picker.handle(#selector(NSResponder.insertNewline(_:)))) + #expect(pasteboard.string(forType: .string) == matches[1].value) + #expect(closed) + #expect(defaults.stringArray(forKey: "recentEmoji") == [matches[1].value]) + + closed = false + query = "no-such-emoji" + picker.inputChanged() + picker.copySelection() + #expect(!closed) + #expect(pasteboard.string(forType: .string) == matches[1].value) + query = "👩‍💻" + picker.inputChanged() + picker.copySelection() + #expect(pasteboard.string(forType: .string) == "👩‍💻") + + let reopened = EmojiPickerController(defaults: defaults, pasteboard: pasteboard) + _ = reopened.view + reopened.copySelection() + #expect(pasteboard.string(forType: .string) == "👩‍💻") + #expect(defaults.stringArray(forKey: "recentEmoji") == ["👩‍💻", matches[1].value]) +} + +@Test @MainActor func emojiCommandRestoresLauncherSearchOnEscape() throws { + _ = NSApplication.shared + let suite = "ConjureEmojiCommand.\(UUID().uuidString)" + let defaults = UserDefaults(suiteName: suite)! + defer { defaults.removePersistentDomain(forName: suite) } + let history = LaunchHistory(defaults: defaults, now: { Date(timeIntervalSinceReferenceDate: 12_000) }) + let launcher = LauncherWindowController(history: history) + let content = try #require(launcher.window?.contentView) + func descendants(_ view: NSView) -> [NSView] { [view] + view.subviews.flatMap(descendants) } + let search = try #require(descendants(content).compactMap { $0 as? NSSearchField }.first) + search.stringValue = "emoji" + launcher.controlTextDidChange(Notification(name: NSControl.textDidChangeNotification, object: search)) + _ = launcher.control(search, textView: NSTextView(), doCommandBy: #selector(NSResponder.insertNewline(_:))) + let grid = try #require(descendants(content).compactMap { $0 as? NSCollectionView }.first) + search.stringValue = ":woman_technologist:" + launcher.controlTextDidChange(Notification(name: NSControl.textDidChangeNotification, object: search)) + #expect(grid.numberOfItems(inSection: 0) == 1) + #expect((grid.dataSource?.collectionView(grid, itemForRepresentedObjectAt: IndexPath(item: 0, section: 0)).view as? NSButton)?.title == "👩‍💻") + _ = launcher.control(search, textView: NSTextView(), doCommandBy: #selector(NSResponder.cancelOperation(_:))) + #expect(!descendants(content).contains { $0 === grid }) + #expect(search.stringValue == "emoji") + let table = try #require(descendants(content).compactMap { $0 as? NSTableView }.first) + #expect(table.numberOfRows == 1) +}