Home

Awesome

Enlighten πŸ’‘

<p align="center"> <a href="http://cocoadocs.org/docsets/Enlighten" style="text-decoration:none"> <img alt="Platform" src ="https://img.shields.io/cocoapods/p/Enlighten.svg?style=flat"/> </a> <a href="http://cocoadocs.org/docsets/Enlighten/" style="text-decoration:none"> <img alt="Pod Version" src ="https://img.shields.io/cocoapods/v/Enlighten.svg?style=flat"/> </a> <a href="https://github.com/Carthage/Carthage" style="text-decoration:none"> <img alt="Carthage compatible" src ="https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat"/> </a> <a href="https://developer.apple.com/swift" style="text-decoration:none"> <img alt="Swift Version" src ="https://img.shields.io/badge/language-swift%204.2-brightgreen.svg"/> </a> <a href="https://github.com/chriszielinski/Enlighten/blob/master/LICENSE" style="text-decoration:none"> <img alt="GitHub license" src ="https://img.shields.io/badge/license-MIT-blue.svg"/> </a> <br> <img src ="https://raw.githubusercontent.com/chriszielinski/Enlighten/master/readme-assets/gifs/enlighten.gif"/> <br> <br> <b>An integrated spotlight-based onboarding and help library for macOS, written in Swift.</b> <br> </p>

Looking for...

Features

Installation

Enlighten is available for installation using CocoaPods or Carthage.

Using Carthage

github "chriszielinski/Enlighten"

Using CocoaPods

pod "Enlighten"

Requirements

Terminology

Components

The demo project provides a comprehensive, documentented example of how to integrate and configure the various components of the Enlighten library.

Enlighten Spotlight Controller

There are two spotlight controllers available to use:


Key-less Spotlight Controller Quick Start

The code below will create a four-stage EnlightenSpotlightController comprised of two irises. It illustrates the various ways of creating/adding irises and stages.

πŸ“£ Note: The irises will be presented in the order they are added to the spotlight controller. In this example, the firstIris (and its stages) will be presented first, with the secondIris following.

// Create the controller.
let spotlightController = EnlightenSpotlightController()

// Create an iris with a single stage.
let firstIris = EnlightenIris(view: aView, markdownString: "This is a `NSView`.")
// Add another stage to the iris.
firstIris.addAdditionalStage(using: "This is the iris' second stage.")
// Create a third stage.
let thirdStage = EnlightenIrisStage(markdownString: "This is the **third** stage!")
// Add the third stage to the iris.
firstIris.addAdditional(stage: thirdStage)
// Add the iris to the spotlight controller.
spotlightController.addSpotlight(iris: firstIris)

// This is a convenience method for creating and adding an iris to the controller.
let secondIris = spotlightController.addSpotlight(view: anotherView, markdownString: "This is another `NSView`.")

Keyed Spotlight Controller Quick Start

The methods used above are also available for the EnlightenKeyedSpotlightController with only a few requiring an additional argumentβ€”the key. But first, we must define a key enumeration whose case declaration order will correspond directly to the owning iris' presentation order.

🎑 Try: Switch the order of the SpotlightKey cases to change the presentation order.

// The keys that define the presentation order of the keyed spotlight controller's irises. The keys can also be used for identification purposes.
enum SpotlightKey: String, EnlightenSpotlightControllerKeys {
    // The controller will begin with the iris that corresponds to this key.
    case firstView
    // And finish with the iris that corresponds to this key.
    case secondView
}

/// Create a keyed spotlight controller using the `SpotlightKey` enum to specify the presentation order.
let keyedSpotlightController = EnlightenKeyedSpotlightController(keys: SpotlightKey.self)

// Create a keyed iris with a single stage.
let firstIris = EnlightenKeyedIris(presentationOrderKey: SpotlightKey.firstView,
                                   view: aView,
                                   markdownString: "This is a `NSView`.")
// Add another stage to the keyed iris.
firstIris.addAdditionalStage(using: "This is the iris' second stage.")
// Create a third stage.
let thirdStage = EnlightenIrisStage(markdownString: "This is the **third** stage!")
// Add the third stage to the keyed iris.
firstIris.addAdditional(stage: thirdStage)
// Add the keyed iris to the keyed spotlight controller.
keyedSpotlightController.addSpotlight(iris: firstIris)

// This is a convenience method for creating and adding a keyed iris to the keyed controller.
let secondIris = keyedSpotlightController.addSpotlight(presentationOrderKey: .secondView,
                                                       view: anotherView,
                                                       markdownString: "This is another `NSView`.")

Presentation

Presenting and dismissing a spotlight controller is simple.

πŸ“£ Note: The controller dismisses itself upon navigating through all the stages.

aSpotlightController.present()
aSpotlightController.dismiss()

Followspot Shape

Configure the followspot shape (the larger, moving spotlight).

spotlightController.followspotShape = .circle

The followspot shape can be set to the following values:

Uses Profile Spot

When using a circle or ellipse followspot, the profile spot is optional. You can specify your preference by setting the controller's usesProfileSpot property. It has a default value of true.

A .circle followspot with no profile spot looks like so:

<div style="text-align:center;"> <img src="https://raw.githubusercontent.com/chriszielinski/Enlighten/master/readme-assets/gifs/no-profile-spot-circle.gif" alt="Circle Followspot with no Profile Spot" width="500"> </div>

Delegate

You can set the spotlight controller's delegate to an EnlightenSpotlightControllerDelegate-conforming class to receive events.

spotlightController.delegate = self

The set of optional methods that Enlighten spotlight controller delegates can implement:

/// Invoked before the controller shows a stage.
func spotlightControllerWillShow(stage: Int, in iris: EnlightenIris, navigating: EnlightenSpotlightController.NavigationDirection) {}

/// Invoked when the controller has finished dismissing.
func spotlightControllerDidDismiss() {}

/// Invoked when a Markdown string fails to load, this method optionally returns a replacement.
///
/// If the delegate does not implement this method or returns nil, the spotlight stage is skipped.
///
/// - Note: This delegate method should not be necessary if appropriate testing procedures are employed to ensure
///         that all Markdown strings load successfully (i.e. `EnlightenSpotlightController.validateMarkdownStrings()`
///         testing method).
func spotlightControllerFailedToLoad(markdownString: String, for iris: EnlightenIris, with error: Error) -> String? {}

Enlighten Help Button

A help button that displays a popover with app-specific help documentation rendered from a CommonMark Markdown string.

There are two ways to create an EnlightenHelpButton: Interface Builder, or programmatically. The demo uses a multi-page EnlightenHelpButton created in the Interface Builder.

<div style="text-align:center;"> <img src="https://raw.githubusercontent.com/chriszielinski/Enlighten/master/readme-assets/gifs/enlighten-help-button.gif" alt="Enlighten Help Button" width="500"> </div> <br> <br>

Programmatically, it would look something like this.

πŸ“£ Note: If you enjoy making financial transactions on a public wifi network over an HTTP connection, go ahead and use that try!. You're gonna have to use some really funky Markdown to throw an error.

// The Markdown string to render.
let helpButtonMarkdownString = "**Need help?** – Something that's helpful."
// Create the help button.
let enlightenHelpButton = try! EnlightenHelpButton(markdownString: helpButtonMarkdownString)
// And that's it... you still need to add it to the view hierarchy, of course.

// Optionally, you can have the popover be detachable, which allows the popover to be dragged into its own _floating_ window.
enlightenHelpButton.canDetach = true

Delegate

You can set the help button's delegate to an EnlightenPopoverDelegate-conforming class to receive events.

enlightenHelpButton.enlightenPopoverDelegate = self

The set of optional methods that Enlighten popover delegates can implement:

/// Invoked when an Enlighten URL scheme was clicked in the popover.
func enlightenPopover(didClickEnlighten url: URL) {}

/// Invoked when a Markdown string fails to load, this method optionally returns a replacement.
func enlightenPopoverFailedToLoad(downError: Error) -> String? {}

Tooltips

It may be useful to craft your spotlight controller stages' Markdown content in such a way that they can also be used as plaintext tooltips.

πŸ”₯ Kill two birds with one stone.

<div style="text-align:center;"> <img src="https://raw.githubusercontent.com/chriszielinski/Enlighten/master/readme-assets/pngs/tooltip.png" alt="Enlighten Tooltip" width="500"> </div> <br> <br>

You can set a NSView's tooltip from a Markdown string as so:

πŸ“£ Note: If you enjoy eating raw cookie dough and refueling your car with the engine on, go ahead and use that try!. You're gonna have to use some really funky Markdown to throw an error.

let helpButtonToolTip = """
    # Need help?

    **This is a Markdown string**, stripped of any _styling_.
    """
try? aView.enlightenTooltip(markdownString: helpButtonToolTip)

And from the Markdown file named 'tooltip.md' located in the main bundle:

try? aView.enlightenTooltip(markdownFilename: "tooltip", in: Bundle.main)

Documentation

There's a basket of other configurable properties available to make your onboarding experience/help documentation perfect. You can explore the docs here.

// ToDo:

Community

Contributors

Frameworks & Libraries

Enlighten depends on the wonderful contributions of the Swift community, namely:

License

Enlighten is available under the MIT license, see the LICENSE file for more information.