diff --git a/Package.resolved b/Package.resolved index 2a997d26..f448cfc0 100644 --- a/Package.resolved +++ b/Package.resolved @@ -14,9 +14,27 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-docc-plugin", "state" : { - "revision" : "3303b164430d9a7055ba484c8ead67a52f7b74f6", + "revision" : "26ac5758409154cc448d7ab82389c520fa8a8247", + "version" : "1.3.0" + } + }, + { + "identity" : "swift-docc-symbolkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-docc-symbolkit", + "state" : { + "revision" : "b45d1f2ed151d057b54504d653e0da5552844e34", "version" : "1.0.0" } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-syntax.git", + "state" : { + "revision" : "67c5007099d9ffdd292f421f81f4efe5ee42963e", + "version" : "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-07-10-a" + } } ], "version" : 2 diff --git a/Package.swift b/Package.swift index 96347b62..edb47c73 100644 --- a/Package.swift +++ b/Package.swift @@ -1,7 +1,8 @@ -// swift-tools-version: 5.7 +// swift-tools-version: 5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription +import CompilerPluginSupport let package = Package( name: "SlideKit", @@ -12,9 +13,29 @@ let package = Package( dependencies: [ .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"), .package(url: "https://github.com/JohnSundell/Splash", from: "0.1.0"), + .package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0"), ], targets: [ - .target(name: "SlideKit", dependencies: ["Splash"]), - .testTarget(name: "SlideKitTests", dependencies: ["SlideKit"]), + .target( + name: "SlideKit", + dependencies: [ + "SlideKitMacros", + "Splash" + ] + ), + .macro( + name: "SlideKitMacros", + dependencies: [ + .product(name: "SwiftSyntaxMacros", package: "swift-syntax"), + .product(name: "SwiftCompilerPlugin", package: "swift-syntax") + ] + ), + .testTarget( + name: "SlideKitTests", + dependencies: [ + "SlideKit", + .product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax") + ] + ) ] ) diff --git a/README.md b/README.md index a181b383..c01d4b21 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,11 @@ You can easily make presentation slides and customize the design perfectly becau ![Slides](https://user-images.githubusercontent.com/12427733/190956930-ea9ce4d0-0a19-4bb3-b43b-28dd2d73374a.png) +## Requirements +- Xcode 15+ +- Swift 5.9 -## Document +## Documents First, see the [Tutorial for SlideKit](https://mtj0928.github.io/SlideKit/tutorials/meet-slidekit). You can learn how to use SlideKit and make presentation slides through making the sample presentation slides. @@ -22,14 +25,15 @@ If you want to know more details, refer the [DocC Style Document](https://mtj092 - [x] Show the current slide index at bottom right on slide. - [x] Support two windows, presentation window and presenter window. - [x] Show scripts on only presenter window (only macOS) -- [x] Provide `PhasedState`, so you can divide a one slide step by step. +- [x] Provide `@Phase`, so you can divide a one slide step by step. - [x] Export PDF file (only macOS 13+) ## Simple Example You can create a presentation by SwiftUI like this. ```swift -struct IntroductionSlide: Slide { +@Slide +struct IntroductionSlide: View { var body: some View { HeaderSlide("SlideKit") { Item("SlideKit helps you make presentation slides by SwiftUI") @@ -47,4 +51,5 @@ And then, this is the result of the code. ## Presentations made with SlideKit If you make presentations slide with SlideKit, add it to the following litst!! -- [After iOSDC](https://github.com/mtj0928/AfteriOSDC): A presentation which shares the hard points to make presentations slides by SwiftUI. (Japanese) +- [After iOSDC](https://github.com/mtj0928/AfteriOSDC): A presentation, which shares the hard points to make presentations slides by SwiftUI. (Japanese) +- [iOSDC23](https://github.com/mtj0928/iOSDC23) A presentation, which shows a dependency injection strategy on SwiftUI. (Japanese) diff --git a/SlideKit.xcworkspace/xcshareddata/swiftpm/Package.resolved b/SlideKit.xcworkspace/xcshareddata/swiftpm/Package.resolved index 2a997d26..10691b77 100644 --- a/SlideKit.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/SlideKit.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -14,9 +14,27 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-docc-plugin", "state" : { - "revision" : "3303b164430d9a7055ba484c8ead67a52f7b74f6", + "revision" : "26ac5758409154cc448d7ab82389c520fa8a8247", + "version" : "1.3.0" + } + }, + { + "identity" : "swift-docc-symbolkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-docc-symbolkit", + "state" : { + "revision" : "b45d1f2ed151d057b54504d653e0da5552844e34", "version" : "1.0.0" } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-syntax.git", + "state" : { + "revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036", + "version" : "509.0.2" + } } ], "version" : 2 diff --git a/SlideKitDemo-iOS/SlideKitDemo-iOS/Slides/BasicSlide.swift b/SlideKitDemo-iOS/SlideKitDemo-iOS/Slides/BasicSlide.swift index 7ed4e117..3e09997d 100644 --- a/SlideKitDemo-iOS/SlideKitDemo-iOS/Slides/BasicSlide.swift +++ b/SlideKitDemo-iOS/SlideKitDemo-iOS/Slides/BasicSlide.swift @@ -8,7 +8,8 @@ import SlideKit import SwiftUI -struct BasicSlide: Slide { +@Slide +struct BasicSlide: View { var body: some View { HeaderSlide("Title") { Item("Hoge") { @@ -28,7 +29,8 @@ struct BasicSlide: Slide { } } -struct SampleSlide: Slide { +@Slide +struct SampleSlide: View { var body: some View { HeaderSlide("Sample Slide") { Item("This is a sample slide.") { diff --git a/SlideKitDemo-iOS/SlideKitDemo-iOS/Slides/TitleSlide.swift b/SlideKitDemo-iOS/SlideKitDemo-iOS/Slides/TitleSlide.swift index 81cb6893..539db3e0 100644 --- a/SlideKitDemo-iOS/SlideKitDemo-iOS/Slides/TitleSlide.swift +++ b/SlideKitDemo-iOS/SlideKitDemo-iOS/Slides/TitleSlide.swift @@ -8,20 +8,20 @@ import SlideKit import SwiftUI -struct TitleSlide: Slide { +@Slide +struct TitleSlide: View { enum SlidePhasedState: Int, PhasedState { case initial, double } - @Phase var phasedStateStore - let title: String + @Phase var phase: SlidePhasedState var body: some View { VStack { Text(title) - if phasedStateStore.when(.double) { + if phase == .double { Text(title) } } @@ -35,5 +35,6 @@ struct TitleSlide_Previews: PreviewProvider { TitleSlide(title: "Hoge") TitleSlide(title: "Piyo") } + .preferredColorScheme(.dark) } } diff --git a/SlideKitDemo-macOS/SlideKitDemo-macOS.xcodeproj/project.pbxproj b/SlideKitDemo-macOS/SlideKitDemo-macOS.xcodeproj/project.pbxproj index 6f1cabed..d8cbe160 100644 --- a/SlideKitDemo-macOS/SlideKitDemo-macOS.xcodeproj/project.pbxproj +++ b/SlideKitDemo-macOS/SlideKitDemo-macOS.xcodeproj/project.pbxproj @@ -311,7 +311,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 12.4; + MACOSX_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = "net.matsuji.SlideKitDemo-macOS"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -340,7 +340,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 12.4; + MACOSX_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = "net.matsuji.SlideKitDemo-macOS"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/SlideKitDemo-macOS/SlideKitDemo-macOS/SlideKitDemo_macOSApp.swift b/SlideKitDemo-macOS/SlideKitDemo-macOS/SlideKitDemo_macOSApp.swift index 46336bb6..9091aece 100644 --- a/SlideKitDemo-macOS/SlideKitDemo-macOS/SlideKitDemo_macOSApp.swift +++ b/SlideKitDemo-macOS/SlideKitDemo-macOS/SlideKitDemo_macOSApp.swift @@ -11,6 +11,8 @@ import SlideKit @main struct SlideKitDemo_macOSApp: App { + @Environment(\.openWindow) var openWindow + /// Edit slide configurations in SlideConfiguration.swift private static let configuration = SlideConfiguration() @@ -29,10 +31,12 @@ struct SlideKitDemo_macOSApp: App { presentationContentView } } - .setupAsPresentationWindow(Self.configuration.slideIndexController, appName: "slide") + .setupAsPresentationWindow(Self.configuration.slideIndexController) { + openWindow(id: "presenter") + } .addPDFExportCommands(for: presentationContentView, with: Self.configuration.slideIndexController, size: Self.configuration.size) - WindowGroup { + WindowGroup(id: "presenter") { macOSPresenterView( slideSize: Self.configuration.size, slideIndexController: Self.configuration.slideIndexController diff --git a/SlideKitDemo-macOS/SlideKitDemo-macOS/Slides/BasicSlide.swift b/SlideKitDemo-macOS/SlideKitDemo-macOS/Slides/BasicSlide.swift index 891f004e..2f60f564 100644 --- a/SlideKitDemo-macOS/SlideKitDemo-macOS/Slides/BasicSlide.swift +++ b/SlideKitDemo-macOS/SlideKitDemo-macOS/Slides/BasicSlide.swift @@ -8,13 +8,14 @@ import SlideKit import SwiftUI -struct BasicSlide: Slide { +@Slide +struct BasicSlide: View { - enum SlidePhasedState: Int, PhasedState { + enum SlidePhase: Int, PhasedState { case initial, next } - @Phase var phasedStateStore + @Phase var phase: SlidePhase var body: some View { HeaderSlide("How to use the slide") { @@ -22,7 +23,7 @@ struct BasicSlide: Slide { Item("You can go to the next state") Item("You can also use \"return\" or \"→\"") } - if phasedStateStore.when(.next) { + if phase == .next { Item("Please tap the left half of this window") { Item("You can back the previous slide") Item("You can also use \"←\"") @@ -32,7 +33,7 @@ struct BasicSlide: Slide { } var script: String { - switch phasedStateStore.current { + switch phase { case .initial: return """ Let me show how to use the slide. @@ -50,6 +51,7 @@ struct BasicSlide_Previews: PreviewProvider { static var previews: some View { SlidePreview { BasicSlide() + .phase(.next) } } } diff --git a/SlideKitDemo-macOS/SlideKitDemo-macOS/Slides/CustomHeaderStyleSlide.swift b/SlideKitDemo-macOS/SlideKitDemo-macOS/Slides/CustomHeaderStyleSlide.swift index 9e931ffc..b30b4616 100644 --- a/SlideKitDemo-macOS/SlideKitDemo-macOS/Slides/CustomHeaderStyleSlide.swift +++ b/SlideKitDemo-macOS/SlideKitDemo-macOS/Slides/CustomHeaderStyleSlide.swift @@ -8,7 +8,8 @@ import SlideKit import SwiftUI -struct CustomHeaderStyleSlide: Slide { +@Slide +struct CustomHeaderStyleSlide: View { var body: some View { HeaderSlide("Custom Style Slide") { Item("Header Slide Style") { diff --git a/Sources/SlideKit/EnvironmentValues/EnvironmentValues+ObservableObjectContainer.swift b/Sources/SlideKit/EnvironmentValues/EnvironmentValues+ObservableObjectContainer.swift index 1d648ce9..2bf764e5 100644 --- a/Sources/SlideKit/EnvironmentValues/EnvironmentValues+ObservableObjectContainer.swift +++ b/Sources/SlideKit/EnvironmentValues/EnvironmentValues+ObservableObjectContainer.swift @@ -7,14 +7,14 @@ import SwiftUI -private enum Key: EnvironmentKey { - static let defaultValue = ObservableObjectContainer() +public enum ObservableObjectContainerKey: EnvironmentKey { + public static let defaultValue = ObservableObjectContainer() } extension EnvironmentValues { public var observableObjectContainer: ObservableObjectContainer { - get { self[Key.self] } - set { self[Key.self] = newValue } + get { self[ObservableObjectContainerKey.self] } + set { self[ObservableObjectContainerKey.self] = newValue } } } diff --git a/Sources/SlideKit/PhaseWrapper.swift b/Sources/SlideKit/PhaseWrapper.swift index 0e709dee..14bf9939 100644 --- a/Sources/SlideKit/PhaseWrapper.swift +++ b/Sources/SlideKit/PhaseWrapper.swift @@ -11,8 +11,8 @@ import SwiftUI @propertyWrapper public struct PhaseWrapper: DynamicProperty { - @Environment(\.observableObjectContainer) - private var observableObjectContainer + @Environment(\.slideIndexController) + private var slideIndexController @ObservedObject private var internalPhasedStore = InternalObservableObject>() @@ -20,13 +20,25 @@ public struct PhaseWrapper: DynamicProperty { public init() { } - public var wrappedValue: PhasedStateStore { - if internalPhasedStore.observedObject == nil { - internalPhasedStore.observedObject = observableObjectContainer.resolve { - PhasedStateStore() + public var wrappedValue: State { + get { + projectedValue.current + } + set { + projectedValue.current = newValue + } + } + + public var projectedValue: PhasedStateStore { + get { + if internalPhasedStore.observedObject == nil { + internalPhasedStore.observedObject = slideIndexController?.phaseStateStore() } + return internalPhasedStore.observedObject! + } + nonmutating set { + internalPhasedStore.observedObject = newValue } - return internalPhasedStore.observedObject! } } diff --git a/Sources/SlideKit/PhasedStateStore.swift b/Sources/SlideKit/PhasedStateStore.swift index a3be5c25..ddca6f66 100644 --- a/Sources/SlideKit/PhasedStateStore.swift +++ b/Sources/SlideKit/PhasedStateStore.swift @@ -16,7 +16,7 @@ protocol PhasedStateStoreProtocol { public class PhasedStateStore: ObservableObject, PhasedStateStoreProtocol { - @Published public private(set) var current: State + @Published public var current: State public init(_ state: State = .initial) { self.current = state diff --git a/Sources/SlideKit/Slide.swift b/Sources/SlideKit/Slide.swift index f1df9981..751c08b2 100644 --- a/Sources/SlideKit/Slide.swift +++ b/Sources/SlideKit/Slide.swift @@ -40,18 +40,6 @@ public protocol Slide: View { /// The default type is ``SimplePhasedState``. associatedtype SlidePhasedState: PhasedState - typealias Phase = PhaseWrapper - - /// A store which controls current `SlidePhasedState`. - /// - /// You can get current `SlidePhasedState` and forward / back it. - /// > Note: The property must be defined with `Phase` like the bellow. - /// - /// ```swift - /// @Phase var phasedStateStore: PhasedStateStore - /// ``` - var phasedStateStore: PhasedStateStore { get } - /// A script for the current slide. The script will be shown on presenter view (macOS only). /// The default value is an empty String. var script: String { get } @@ -59,16 +47,14 @@ public protocol Slide: View { /// A boolean value indicating whether the slide index at the right bottom is hidden or not. /// The default value is `false` var shouldHideIndex: Bool { get } + + /// Inject PhasedStateStore. + /// This function should be called by SlideKit, please do not call the function. + func phasesStateSore(_ phasedStateStore: PhasedStateStore) } extension Slide { public var script: String { "" } public var shouldHideIndex: Bool { false } -} - -extension Slide where SlidePhasedState == SimplePhasedState { - - public var phasedStateStore: PhasedStateStore { - PhasedStateStore() - } + public func phasesStateSore(_ phasedStateStore: PhasedStateStore) {} } diff --git a/Sources/SlideKit/SlideComponents/Code/SlideCodeFormat.swift b/Sources/SlideKit/SlideComponents/Code/SlideCodeFormat.swift index ab78a6ef..bde6b47c 100644 --- a/Sources/SlideKit/SlideComponents/Code/SlideCodeFormat.swift +++ b/Sources/SlideKit/SlideComponents/Code/SlideCodeFormat.swift @@ -64,7 +64,7 @@ extension SlideCodeFormat { } extension Splash.Color { - convenience init(red: CGFloat, green: CGFloat, blue: CGFloat) { + public convenience init(red: CGFloat, green: CGFloat, blue: CGFloat) { self.init(red: red, green: green, blue: blue, alpha: 1) } } diff --git a/Sources/SlideKit/SlideComponents/HeaderSlide/HeaderSlide.swift b/Sources/SlideKit/SlideComponents/HeaderSlide/HeaderSlide.swift index c724baa3..70cab975 100644 --- a/Sources/SlideKit/SlideComponents/HeaderSlide/HeaderSlide.swift +++ b/Sources/SlideKit/SlideComponents/HeaderSlide/HeaderSlide.swift @@ -26,7 +26,8 @@ import SwiftUI /// ## Topics /// ### Customize Style /// - ``HeaderSlideStyle`` -public struct HeaderSlide: Slide { +@Slide +public struct HeaderSlide: View { @Environment(\.headerSlideStyle) private var style diff --git a/Sources/SlideKit/SlideComponents/ViewSlide.swift b/Sources/SlideKit/SlideComponents/ViewSlide.swift index e7786a19..097220f3 100644 --- a/Sources/SlideKit/SlideComponents/ViewSlide.swift +++ b/Sources/SlideKit/SlideComponents/ViewSlide.swift @@ -7,7 +7,8 @@ import SwiftUI -public struct ViewSlide: Slide { +@Slide +public struct ViewSlide: View{ let content: () -> Content public let script: String diff --git a/Sources/SlideKit/SlideIndexController.swift b/Sources/SlideKit/SlideIndexController.swift index 92946f68..3bf22a5b 100644 --- a/Sources/SlideKit/SlideIndexController.swift +++ b/Sources/SlideKit/SlideIndexController.swift @@ -17,12 +17,19 @@ public class SlideIndexController: ObservableObject { public let slides: [any Slide] + private let objectContainer: ObservableObjectContainer + public var currentSlide: any Slide { slides[currentIndex] } - public init(index: Int = 0, @SlideBuilder slideBuilder: () -> [any Slide]) { + public init( + index: Int = 0, + container: ObservableObjectContainer = ObservableObjectContainerKey.defaultValue, + @SlideBuilder slideBuilder: () -> [any Slide] + ) { self.slides = slideBuilder() + self.objectContainer = container guard index < slides.count else { fatalError("index must be less than the number of slides.") @@ -33,7 +40,7 @@ public class SlideIndexController: ObservableObject { @discardableResult public func forward() -> Bool { - defer { currentScript = currentSlide.script } + defer { currentScript = currentSlide.script(on: objectContainer) } let phasedStateStore = getPhasedStateStore(at: currentIndex) if phasedStateStore.forward() { return true @@ -50,7 +57,7 @@ public class SlideIndexController: ObservableObject { @discardableResult public func back() -> Bool { - defer { currentScript = currentSlide.script } + defer { currentScript = currentSlide.script(on: objectContainer) } let phasedStateStore = getPhasedStateStore(at: currentIndex) if phasedStateStore.back() { return true @@ -69,23 +76,41 @@ public class SlideIndexController: ObservableObject { currentIndex = 0 let phasedStateStore = getPhasedStateStore(at: currentIndex) phasedStateStore.backToFirst() - currentScript = currentSlide.script + currentScript = currentSlide.script(on: objectContainer) } private func getPhasedStateStore(at index: Int) -> any PhasedStateStoreProtocol { let slide = slides[index] - return slide.typeErasedPhasedStateStore + return slide.typeErasedPhasedStateStore(on: objectContainer) } public func move(to index: Int) { currentIndex = index let newPhasedStateStore = getPhasedStateStore(at: currentIndex) newPhasedStateStore.backToFirst() + currentScript = currentSlide.script(on: objectContainer) + } + + public func phaseStateStore() -> PhasedStateStore { + objectContainer.resolve { + PhasedStateStore() + } } } extension Slide { - fileprivate var typeErasedPhasedStateStore: any PhasedStateStoreProtocol { - phasedStateStore + fileprivate func typeErasedPhasedStateStore(on container: ObservableObjectContainer) -> any PhasedStateStoreProtocol { + container.resolve { + PhasedStateStore() + } + } + + fileprivate func script(on container: ObservableObjectContainer) -> String { + let object = self + let store = container.resolve { + PhasedStateStore() + } + object.phasesStateSore(store) + return object.script } } diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-03-IntroductionSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-03-IntroductionSlide.swift index 142fa72b..f7323ccc 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-03-IntroductionSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-03-IntroductionSlide.swift @@ -1,7 +1,8 @@ import SwiftUI import SlideKit -struct IntroductionSlide: Slide { +@Slide +struct IntroductionSlide: View { var body: some View { Text("Hello, World!") } diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-04-IntroductionSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-04-IntroductionSlide.swift index 2fb23269..554c8f55 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-04-IntroductionSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-04-IntroductionSlide.swift @@ -1,7 +1,8 @@ import SwiftUI import SlideKit -struct IntroductionSlide: Slide { +@Slide +struct IntroductionSlide: View { var body: some View { Text("Hello, World!") } diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-05-IntroductionSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-05-IntroductionSlide.swift index 4e679483..c87f3fae 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-05-IntroductionSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-05-IntroductionSlide.swift @@ -1,7 +1,8 @@ import SwiftUI import SlideKit -struct IntroductionSlide: Slide { +@Slide +struct IntroductionSlide: View { var body: some View { HeaderSlide("SlideKit") { } diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-06-IntroductionSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-06-IntroductionSlide.swift index bb245856..e3ffdb14 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-06-IntroductionSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-06-IntroductionSlide.swift @@ -1,7 +1,8 @@ import SwiftUI import SlideKit -struct IntroductionSlide: Slide { +@Slide +struct IntroductionSlide: View { var body: some View { HeaderSlide("SlideKit") { Item("SlideKit helps you make presentation slides by SwiftUI.") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-07-IntroductionSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-07-IntroductionSlide.swift index 2ceedb07..d05c59ba 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-07-IntroductionSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/01-creating-simple-slide/code-files/01-01-02-07-IntroductionSlide.swift @@ -1,7 +1,8 @@ import SwiftUI import SlideKit -struct IntroductionSlide: Slide { +@Slide +struct IntroductionSlide: View { var body: some View { HeaderSlide("SlideKit") { Item("SlideKit helps you make presentation slides by SwiftUI.") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/02-dividing-slide-step-by-step/code-files/01-02-01-01-PhasedSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/02-dividing-slide-step-by-step/code-files/01-02-01-01-PhasedSlide.swift index 4ed3da91..b344a2d5 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/02-dividing-slide-step-by-step/code-files/01-02-01-01-PhasedSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/02-dividing-slide-step-by-step/code-files/01-02-01-01-PhasedSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct PhasedSlide: Slide { +@Slide +struct PhasedSlide: View { var body: some View { HeaderSlide("Phased Slide") { Item("Slide can be divided to multiple steps by defining PhasedState.", accessory: nil) { diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/02-dividing-slide-step-by-step/code-files/01-02-01-02-PhasedSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/02-dividing-slide-step-by-step/code-files/01-02-01-02-PhasedSlide.swift index 1f69b8e7..7d9643aa 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/02-dividing-slide-step-by-step/code-files/01-02-01-02-PhasedSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/02-dividing-slide-step-by-step/code-files/01-02-01-02-PhasedSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct PhasedSlide: Slide { +@Slide +struct PhasedSlide: View { enum Substep: Int, PhasedState { case initial, second, third diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/02-dividing-slide-step-by-step/code-files/01-02-01-03-PhasedSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/02-dividing-slide-step-by-step/code-files/01-02-01-03-PhasedSlide.swift index f2b16559..969b0896 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/02-dividing-slide-step-by-step/code-files/01-02-01-03-PhasedSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/02-dividing-slide-step-by-step/code-files/01-02-01-03-PhasedSlide.swift @@ -1,14 +1,14 @@ import SlideKit import SwiftUI -struct PhasedSlide: Slide { +@Slide +struct PhasedSlide: View { - enum Substep: Int, PhasedState { + enum SlidePhase: Int, PhasedState { case initial, second, third } - @Phase - var phasedStateStore: PhasedStateStore + @Phase var phase: SlidePhase var body: some View { HeaderSlide("Phased Slide") { diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/02-dividing-slide-step-by-step/code-files/01-02-01-04-PhasedSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/02-dividing-slide-step-by-step/code-files/01-02-01-04-PhasedSlide.swift index 2051d9b4..e1955852 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/02-dividing-slide-step-by-step/code-files/01-02-01-04-PhasedSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/02-dividing-slide-step-by-step/code-files/01-02-01-04-PhasedSlide.swift @@ -1,14 +1,14 @@ import SlideKit import SwiftUI -struct PhasedSlide: Slide { +@Slide +struct PhasedSlide: View { - enum Substep: Int, PhasedState { + enum SlidePhase: Int, PhasedState { case initial, second, third } - @Phase - var phasedStateStore: PhasedStateStore + @Phase var phase: SlidePhase var body: some View { HeaderSlide("Phased Slide") { diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-01-TitleSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-01-TitleSlide.swift index 322c789e..b06aef10 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-01-TitleSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-01-TitleSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct TitleSlide: Slide { +@Slide +struct TitleSlide: View { var body: some View { Text("Hello, World!") } diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-02-TitleSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-02-TitleSlide.swift index 2f7f02c8..a5e06a59 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-02-TitleSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-02-TitleSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct TitleSlide: Slide { +@Slide +struct TitleSlide: View { var body: some View { VStack(alignment: .leading, spacing: 32) { Text("SlideKit Presentations") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-03-TitleSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-03-TitleSlide.swift index 56109e75..46590412 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-03-TitleSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-03-TitleSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct TitleSlide: Slide { +@Slide +struct TitleSlide: View { var body: some View { VStack(alignment: .leading, spacing: 32) { Text("SlideKit Presentations") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-04-TitleSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-04-TitleSlide.swift index d263aadb..d0854f98 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-04-TitleSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-04-TitleSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct TitleSlide: Slide { +@Slide +struct TitleSlide: View { var body: some View { VStack(alignment: .leading, spacing: 32) { Text("SlideKit Presentations") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-05-TitleSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-05-TitleSlide.swift index 0d6dacab..e6270bb0 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-05-TitleSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-05-TitleSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct TitleSlide: Slide { +@Slide +struct TitleSlide: View { var body: some View { VStack(alignment: .leading, spacing: 32) { Text("SlideKit Presentations") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-06-TitleSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-06-TitleSlide.swift index 3b9b28fa..d0bfbb68 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-06-TitleSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-01-06-TitleSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct TitleSlide: Slide { +@Slide +struct TitleSlide: View { var body: some View { VStack(alignment: .leading, spacing: 32) { Text("SlideKit Presentations") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-02-01-CodeSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-02-01-CodeSlide.swift index d96f3138..2d575d60 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-02-01-CodeSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-02-01-CodeSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct CodeSlide: Slide { +@Slide +struct CodeSlide: View { var body: some View { HeaderSlide("Code Slide") { diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-02-02-CodeSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-02-02-CodeSlide.swift index 42c58b0e..6afa19f8 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-02-02-CodeSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 1/03-using-slide-components/code-files/01-03-02-02-CodeSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct CodeSlide: Slide { +@Slide +struct CodeSlide: View { var body: some View { HeaderSlide("Code Slide") { diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-01-01-CustomizedSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-01-01-CustomizedSlide.swift index d6d68fff..e73b5bd7 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-01-01-CustomizedSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-01-01-CustomizedSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct CustomizedSlide: Slide { +@Slide +struct CustomizedSlide: View { var body: some View { HeaderSlide("Customize Slide Theme") { Item("HeaderSlide supports HeaderSlideStyle.") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-01-02-CustomizedSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-01-02-CustomizedSlide.swift index c08f8869..423346d2 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-01-02-CustomizedSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-01-02-CustomizedSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct CustomizedSlide: Slide { +@Slide +struct CustomizedSlide: View { var body: some View { HeaderSlide("Customize Slide Theme") { Item("HeaderSlide supports HeaderSlideStyle.") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-01-03-CustomizedSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-01-03-CustomizedSlide.swift index b9e50f8f..5a6218a1 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-01-03-CustomizedSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-01-03-CustomizedSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct CustomizedSlide: Slide { +@Slide +struct CustomizedSlide: View { var body: some View { HeaderSlide("Customize Slide Theme") { Item("HeaderSlide supports HeaderSlideStyle.") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-01-04-CustomizedSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-01-04-CustomizedSlide.swift index 7f3bad0c..aed2c9d8 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-01-04-CustomizedSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-01-04-CustomizedSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct CustomizedSlide: Slide { +@Slide +struct CustomizedSlide: View { var body: some View { HeaderSlide("Customize Slide Theme") { Item("HeaderSlide supports HeaderSlideStyle.") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-01-CustomizedSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-01-CustomizedSlide.swift index 146291dc..086eb281 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-01-CustomizedSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-01-CustomizedSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct CustomizedSlide: Slide { +@Slide +struct CustomizedSlide: View { var body: some View { HeaderSlide("Customize Slide Theme") { Item("HeaderSlide supports HeaderSlideStyle.") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-02-CustomizedSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-02-CustomizedSlide.swift index 9f4eee84..43739530 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-02-CustomizedSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-02-CustomizedSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct CustomizedSlide: Slide { +@Slide +struct CustomizedSlide: View { var body: some View { HeaderSlide("Customize Slide Theme") { Item("HeaderSlide supports HeaderSlideStyle.") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-03-CustomizedSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-03-CustomizedSlide.swift index d2981d37..6e6c319a 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-03-CustomizedSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-03-CustomizedSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct CustomizedSlide: Slide { +@Slide +struct CustomizedSlide: View { var body: some View { HeaderSlide("Customize Slide Theme") { Item("HeaderSlide supports HeaderSlideStyle.") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-04-CustomizedSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-04-CustomizedSlide.swift index 3649fff7..91b309b9 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-04-CustomizedSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-04-CustomizedSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct CustomizedSlide: Slide { +@Slide +struct CustomizedSlide: View { var body: some View { HeaderSlide("Customize Slide Theme") { Item("HeaderSlide supports HeaderSlideStyle.") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-05-CustomizedSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-05-CustomizedSlide.swift index e07b53a8..a12eb705 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-05-CustomizedSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-05-CustomizedSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct CustomizedSlide: Slide { +@Slide +struct CustomizedSlide: View { var body: some View { HeaderSlide("Customize Slide Theme") { Item("HeaderSlide supports HeaderSlideStyle.") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-06-CustomizedSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-06-CustomizedSlide.swift index e53f426f..812261eb 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-06-CustomizedSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-02-06-CustomizedSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct CustomizedSlide: Slide { +@Slide +struct CustomizedSlide: View { var body: some View { HeaderSlide("Customize Slide Theme") { Item("HeaderSlide supports HeaderSlideStyle.") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-03-02-CustomizedSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-03-02-CustomizedSlide.swift index ef9badd9..c0609577 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-03-02-CustomizedSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-03-02-CustomizedSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct CustomizedSlide: Slide { +@Slide +struct CustomizedSlide: View { var body: some View { HeaderSlide("Customize Slide Theme") { Item("HeaderSlide supports HeaderSlideStyle.") diff --git a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-03-03-CustomizedSlide.swift b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-03-03-CustomizedSlide.swift index fe4e058c..6f3f1ff0 100644 --- a/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-03-03-CustomizedSlide.swift +++ b/Sources/SlideKit/SlideKit.docc/Resources/Chapter 2/01-designing-slide-theme/code-files/02-01-03-03-CustomizedSlide.swift @@ -1,7 +1,8 @@ import SlideKit import SwiftUI -struct CustomizedSlide: Slide { +@Slide +struct CustomizedSlide: View { var body: some View { HeaderSlide("Customize Slide Theme") { Item("HeaderSlide supports HeaderSlideStyle.") diff --git a/Sources/SlideKit/SlideKit.docc/SlideKit.md b/Sources/SlideKit/SlideKit.docc/SlideKit.md index a1699c15..ea6dcb82 100644 --- a/Sources/SlideKit/SlideKit.docc/SlideKit.md +++ b/Sources/SlideKit/SlideKit.docc/SlideKit.md @@ -12,7 +12,8 @@ You can create your presentation slides using a ``Slide`` protocol. You can make presentation slides like this. ```swift -struct IntroductionSlide: Slide { +@Slide +struct IntroductionSlide: View { var body: some View { HeaderSlide("SlideKit") { Item("SlideKit helps you make presentation slides by SwiftUI") diff --git a/Sources/SlideKit/SlideKit.docc/Tutorials/Chapter 1/Creating Simple Slide.tutorial b/Sources/SlideKit/SlideKit.docc/Tutorials/Chapter 1/Creating Simple Slide.tutorial index d330448a..1cba946f 100644 --- a/Sources/SlideKit/SlideKit.docc/Tutorials/Chapter 1/Creating Simple Slide.tutorial +++ b/Sources/SlideKit/SlideKit.docc/Tutorials/Chapter 1/Creating Simple Slide.tutorial @@ -50,7 +50,7 @@ } @Step { - Change the conforming protocol to `Slide` from `View`. + Attach `@Slide` macro to the view. @Code(name: "IntroductionSlide.swift", file: "01-01-02-03-IntroductionSlide.swift") } diff --git a/Sources/SlideKit/SlideKit.docc/Tutorials/Chapter 1/Dividing Slide Step by Step.tutorial b/Sources/SlideKit/SlideKit.docc/Tutorials/Chapter 1/Dividing Slide Step by Step.tutorial index 681cff79..ceb7b8e3 100644 --- a/Sources/SlideKit/SlideKit.docc/Tutorials/Chapter 1/Dividing Slide Step by Step.tutorial +++ b/Sources/SlideKit/SlideKit.docc/Tutorials/Chapter 1/Dividing Slide Step by Step.tutorial @@ -25,14 +25,14 @@ } @Step { - Add a new property `phasedStateStore`. + Add a new property `phase`. The property has current phased state and the state is managed by SlideKit. @Code(name: "PhasedSlide.swift", file: "01-02-01-03-PhasedSlide.swift") } @Step { - Update the layout based on the current phased state. + Update the layout based on the current `phase`. @Code(name: "PhasedSlide.swift", file: "01-02-01-04-PhasedSlide.swift") } diff --git a/Sources/SlideKit/SlideKitMacro.swift b/Sources/SlideKit/SlideKitMacro.swift new file mode 100644 index 00000000..34c0b482 --- /dev/null +++ b/Sources/SlideKit/SlideKitMacro.swift @@ -0,0 +1,3 @@ +@attached(extension, conformances: Slide) +@attached(member, names: named(_phase), named(_resolvePhaseStateStore), named(SlidePhasedState), named(phase), named(container), named(phasesStateSore), named(Phase)) +public macro Slide() = #externalMacro(module: "SlideKitMacros", type: "SlideMacro") diff --git a/Sources/SlideKit/Views/Previews/SlideIndexController+Previews.swift b/Sources/SlideKit/Views/Previews/SlideIndexController+Previews.swift index 1779b24d..d5a232e9 100644 --- a/Sources/SlideKit/Views/Previews/SlideIndexController+Previews.swift +++ b/Sources/SlideKit/Views/Previews/SlideIndexController+Previews.swift @@ -8,24 +8,24 @@ import SwiftUI extension SlideIndexController { + static let previews = SlideIndexController(index: 0) { + SampleSlide(text: "Hoge") + SampleSlide(text: "Piyo") + } +} - struct SampleSlide: Slide { - let text: String - - var body: some View { - Text(text) - .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(.white) - .allowsHitTesting(false) - } +@Slide +private struct SampleSlide: View { + let text: String - var script: String { - "This is a script for \(text)." - } + var body: some View { + Text(text) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(.white) + .allowsHitTesting(false) } - static let previews = SlideIndexController(index: 0) { - SampleSlide(text: "Hoge") - SampleSlide(text: "Piyo") + var script: String { + "This is a script for \(text)." } } diff --git a/Sources/SlideKit/Views/macOS/Scene+macOS.swift b/Sources/SlideKit/Views/macOS/Scene+macOS.swift index 5fae9923..65845604 100644 --- a/Sources/SlideKit/Views/macOS/Scene+macOS.swift +++ b/Sources/SlideKit/Views/macOS/Scene+macOS.swift @@ -9,6 +9,7 @@ import SwiftUI extension Scene { + @available(*, deprecated, message: "Use the other setupAsPresentationWindow.") public func setupAsPresentationWindow( _ slideIndexController: SlideIndexController, appName: String @@ -28,6 +29,27 @@ extension Scene { } } + public func setupAsPresentationWindow( + _ slideIndexController: SlideIndexController, + openWindow: @escaping () -> Void + ) -> some Scene { + windowStyle(.hiddenTitleBar) + .commands { + CommandGroup(after: .undoRedo) { + forwardButton(.rightArrow, slideIndexController: slideIndexController) + forwardButton(.return, slideIndexController: slideIndexController) + backButton(.leftArrow, slideIndexController: slideIndexController) + } + + CommandGroup(after: .windowList) { + Button("Open Presenter Window") { + openWindow() + } + .keyboardShortcut("p", modifiers: .command) + } + } + } + private func forwardButton(_ key: KeyEquivalent, slideIndexController: SlideIndexController) -> some View { Button("forward") { slideIndexController.forward() } .keyboardShortcut(key, modifiers: []) diff --git a/Sources/SlideKitMacros/SlideKitMacros.swift b/Sources/SlideKitMacros/SlideKitMacros.swift new file mode 100644 index 00000000..19e7c3dc --- /dev/null +++ b/Sources/SlideKitMacros/SlideKitMacros.swift @@ -0,0 +1,9 @@ +import SwiftCompilerPlugin +import SwiftSyntaxMacros + +@main +struct SlideKitMacrosPlugin: CompilerPlugin { + let providingMacros: [Macro.Type] = [ + SlideMacro.self + ] +} diff --git a/Sources/SlideKitMacros/SlideMacro.swift b/Sources/SlideKitMacros/SlideMacro.swift new file mode 100644 index 00000000..84f6f15c --- /dev/null +++ b/Sources/SlideKitMacros/SlideMacro.swift @@ -0,0 +1,108 @@ +import SwiftCompilerPlugin +import SwiftSyntax +import SwiftSyntaxBuilder +import SwiftSyntaxMacros + +public struct SlideMacro: ExtensionMacro, MemberMacro { + + public static func expansion( + of node: AttributeSyntax, + attachedTo declaration: some DeclGroupSyntax, + providingExtensionsOf type: some TypeSyntaxProtocol, + conformingTo protocols: [TypeSyntax], + in context: some MacroExpansionContext + ) throws -> [ExtensionDeclSyntax] { + try [ + ExtensionDeclSyntax( + """ + extension \(type): Slide {} + """ + ) + ] + } + + public static func expansion( + of node: AttributeSyntax, + providingMembersOf declaration: some DeclGroupSyntax, + in context: some MacroExpansionContext + ) throws -> [DeclSyntax] { + let variables = declaration.memberBlock.members.map(\.decl).compactMap { $0.as(VariableDeclSyntax.self) } + let phasedVariables: [(name: String, type: String)] = variables.compactMap { variable -> (name: String, type: String)? in + guard hasPhase(variable), + let name = extractVariableName(variable), + let type = extractTypeName(variable) + else { return nil } + return (name: name, type: type) + } + if phasedVariables.isEmpty { + return [ + "public typealias SlidePhasedState = SimplePhasedState" + ] + } + else if phasedVariables.count == 1 { + let type = phasedVariables[0].type + let name = phasedVariables[0].name + return [ + type != "SlidePhasedState" ? "public typealias SlidePhasedState = \(raw: type)" : nil, + "public typealias Phase = PhaseWrapper", + """ + @Environment(\\.observableObjectContainer) private var container + """, + """ + func phase(_ phase: \(raw: type)) -> Self { + let store: PhasedStateStore<\(raw: type)> = container.resolve { + PhasedStateStore(phase) + } + store.current = phase + return self + } + """, + """ + func phasesStateSore(_ phasedStateStore: PhasedStateStore) { + $\(raw: name) = phasedStateStore + } + """ + ].compactMap { $0 } + } + else { + context.addDiagnostics(from: SlideError("There are two or more @Phase"), node: declaration) + return [] + } + } + + private static func hasPhase(_ variable: VariableDeclSyntax) -> Bool { + variable.attributes + .compactMap({ $0.as(AttributeSyntax.self) }) + .map(\.attributeName) + .compactMap({ $0.as(IdentifierTypeSyntax.self) }) + .map(\.name.text) + .contains(where: { name in + name == "Phase" + }) + } + + private static func extractTypeName(_ variable: VariableDeclSyntax) -> String? { + variable.bindings + .first? + .typeAnnotation? + .type.as(IdentifierTypeSyntax.self)? + .name + .text + } + + private static func extractVariableName(_ variable: VariableDeclSyntax) -> String? { + variable.bindings + .first? + .pattern.as(IdentifierPatternSyntax.self)? + .identifier + .text + } +} + +struct SlideError: CustomStringConvertible, Error { + let description: String + + init(_ description: String) { + self.description = description + } +} diff --git a/Tests/SlideKitTests/SlideKitTests.swift b/Tests/SlideKitTests/SlideKitTests.swift deleted file mode 100644 index c0f1da0f..00000000 --- a/Tests/SlideKitTests/SlideKitTests.swift +++ /dev/null @@ -1,7 +0,0 @@ -import XCTest -@testable import SlideKit - -final class SlideKitTests: XCTestCase { - func testExample() throws { - } -} diff --git a/Tests/SlideKitTests/SlidePageMacroTests.swift b/Tests/SlideKitTests/SlidePageMacroTests.swift new file mode 100644 index 00000000..9f947446 --- /dev/null +++ b/Tests/SlideKitTests/SlidePageMacroTests.swift @@ -0,0 +1,71 @@ +import XCTest +import SwiftSyntaxMacros +import SwiftSyntaxMacrosTestSupport +@testable import SlideKit +import SlideKitMacros + +let testMacros: [String: Macro.Type] = [ + "Slide": SlideMacro.self +] + +final class SlideMacroTests: XCTestCase { + func testSlideWithPhase() { + assertMacroExpansion( + """ + @Slide + struct FooSlide: View { + @Phase var state: State + } + """, + expandedSource: + """ + struct FooSlide: View { + @Phase var state: State + + public typealias SlidePhasedState = State + + public typealias Phase = PhaseWrapper + + @Environment(\\.observableObjectContainer) private var container + + func phase(_ phase: State) -> Self { + let store: PhasedStateStore = container.resolve { + PhasedStateStore(phase) + } + store.current = phase + return self + } + + func phasesStateSore(_ phasedStateStore: PhasedStateStore) { + $state = phasedStateStore + } + } + + extension FooSlide: Slide { + } + """, + macros: testMacros + ) + } + + func testSlideWithoutPhase() { + assertMacroExpansion( + """ + @Slide + struct FooSlide: View { + } + """, + expandedSource: + """ + struct FooSlide: View { + + public typealias SlidePhasedState = SimplePhasedState + } + + extension FooSlide: Slide { + } + """, + macros: testMacros + ) + } +}