/DeckUI

Swift DSL for writing slide decks in Xcode

Primary LanguageSwiftMIT LicenseMIT

✨ DeckUI

DeckUI is a Swift DSL (domain specific language) for writing slide decks in Xcode. It allows for quick creation of slides and content in a language and environment you are familiar with.

But why?

Well, I made this because:

  • I was bored on an airplane
  • Wanted to use this as a demo for future conference talk on Swift DSLs
  • Need something more customizable than markdown for writing slide decks and more codey than Keynote

πŸ‘‰ Watch Introducing DeckUI - Write slide decks in Swift on my YouTube channel for more explaination and full demo

✨ Features

  • Create slide decks in pure Swift code
  • Decks are presented in SwiftUI with Presenter
  • Build decks without knowing any SwiftUI
    • With Deck, Slide, Title, Words, Bullets, Media, Columns
  • Use RawView to drop any SwiftUI view
    • Fully interactable and great for demos
  • Display code with Code
    • Use up and down arrows to highlight lines of code as your talking about them
  • Support videos on Media

🐌 Future Features

  • Support iOS and maybe tvOS
  • Fix bug with Media remote image loading and slide transitions
  • Animations within a slide
  • More customization on Words
  • Nesting of Bullets
  • Syntax highlighting for Code
  • Documentation
  • More examples

Simple Demo

import SwiftUI
import DeckUI

struct ContentView: View {
    var body: some View {
        Presenter(deck: self.deck)
    }
}

extension ContentView {
    var deck: Deck {
        Deck(title: "SomeConf 2023") {
            Slide(alignment: .center) {
                Title("Welcome to DeckUI")
            }

            Slide {
                Title("Quick Demo")
                Columns {
                    Column {
                        Bullets {
                            Words("Bullets")
                            Words("Words")
                            Words("Images")
                            Words("Columns")
                        }
                    }
                    
                    Column {
                        Media(.remoteImage(URL(string: "https://www.fillmurray.com/g/200/300")!))
                    }
                }
            }
        }
    }
}
Screen.Recording.2022-09-08.at.12.40.41.AM.mov

πŸ’» Installing

Swift Package Manager

  • File > Swift Packages > Add Package Dependency
  • Add https://github.com/joshdholtz/DeckUI.git
  • Select "Up to Next Major" with "1.0.0"

πŸš€ Getting Started

There are no official "Getting Started" docs yet πŸ˜… But look at...

πŸ“– Documentation

100% not documented yet but I'll get there πŸ€·β€β™‚οΈ

🏎 Performance

Probably bad and never production ready 😈 Please only use DeckUI for a single presentation and never at any scale.

πŸ‘¨β€πŸ’» Contributing

Yes please! I'm happy to discuss issues and review/merge pull requests πŸ™‚ I will do my best to get to the but I am a dad, work at RevenueCat, and the lead maintainer of fastlane so I might not respond right away.

πŸ“š Examples

Slide

Slide can be used without any parameters but can be given a custom alignment, padding, and theme.

Slide {
    // Content
}
Slide(alignment: .center, padding: 80, theme: .white) {
    // Content
}

Title

Title can be used by itself or with an optional subtitle. It was real similar to Words but larger.

Slide(alignment: .center) {
    Title("Introducing...")
}
Slide {
    Title("Introduction", subtitle: "What is it?")
    // Content
}

Words

Words are similar to what a textbox would be in Keynote, PowerPoint, or Google Slides. There will eventually be more style configurations for words.

Slide(alignment: .center) {
    Title("Center alignment")
    Words("Slides can be center aligned")
    Words("And more words")
}

Bullets

Bullets turns Words into a list. It takes an optional style parameter where you can choose between .bullets and .dash. Bullets cannot be nested yet but soonℒ️.

Slide {
    Title("Introduction", subtitle: "What is it?")
    Bullets {
        Words("A custom Swift DSL to make slide decks")
        Words("Distributed as a Swift Package")
        Words("Develop your slide deck in Xcode with Swift")
    }
}
Slide {
    Title("Introduction", subtitle: "What is it?")
    Bullets(style: .dash) {
        Words("A custom Swift DSL to make slide decks")
        Words("Distributed as a Swift Package")
        Words("Develop your slide deck in Xcode with Swift")
    }
}

Media

Media provides a few ways to display images from various source types. This will eventually support videos.

Slide {
    Media(.assetImage("some-asset-name"))
    Media(.bundleImage("some-file-name.jpg"))
    Media(.remoteImage(URL(string: "http://placekitten.com/g/200/300"))!)
}

Columns

Columns allow you to use one to infinte Columns. Put other slide content in Column.

Slide {
    Title("Columns")
    Columns {
        Column {
            // Content
        }
        
        Column {
            // Content
        }
    }
}
Slide {
    Title("Columns")
    Columns {
        Column {
            // Content
        }
        
        Column {
            // Content
        }

        Column {
            // Content
        }

        Column {
            // Content
        }
    }
}

Code

Code is a super specifi version Words. It will:

  • Display text as monospace
  • Scroll vertical if bigger than screen
  • Highlight lines of code when up and down arrows are pressed
Slide {
    Code("""
    struct ContentView: View {
        var body: some View {
            Text("Hello slides")
        }
    }
    """)
}
Slide {
    Code("""
    struct ContentView: View {
        var body: some View {
            Text("Hello slides")
        }
    }
    """, , enableHighlight: false)
}

RawView

Drop any SwiftUI view inside of RawView. Could be built-in SwiftUI views like Text or Button but can also be any custom SwiftUI view.

Slide {
    RawView {
        CounterView()
    }
}

struct CounterView: View {
    @State var count = 0
    
    var body: some View {
        Button {
            self.count += 1
        } label: {
            Text("Press me - \(self.count)")
                .font(.system(size: 60))
                .padding(.horizontal, 40)
                .padding(.vertical, 20)
                .foregroundColor(.white)
                .overlay(
                    RoundedRectangle(cornerRadius: 25)
                    .stroke(Color.white, lineWidth: 2)
                )
        }.buttonStyle(.plain)
    }
}

Themes

A Theme can be set in Presenter or individually on Slide. There are three default themes (.dark, .black, .white) but feel free to use your own.

struct ContentView: View {
    var body: some View {
        Presenter(deck: self.deck, showCamera: true)
    }
}

extension Theme {
    public static let venonat: Theme = Theme(
        background: Color(hex: "#624a7b"),
        title: Foreground(
            color: Color(hex: "#ff5a5a"),
            font: Font.system(size: 80,
                              weight: .bold,
                              design: .default)
        ),
        subtitle: Foreground(
            color: Color(hex: "#a48bbd"),
            font: Font.system(size: 50,
                              weight: .light,
                              design: .default).italic()
        ),
        body: Foreground(
            color: Color(hex: "#FFFFFF"),
            font: Font.system(size: 50,
                              weight: .regular,
                              design: .default)
        ),
        code: Foreground(
            color: Color(hex: "#FFFFFF"),
            font: Font.system(size: 26,
                              weight: .regular,
                              design: .monospaced)
        ),
        codeHighlighted: (Color(hex: "#312952"), Foreground(
            color: Color(hex: "#FFFFFF"),
            font: Font.system(size: 26,
                              weight: .heavy,
                              design: .monospaced)
        ))
    )
}