mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Move Compound Inspector into the project.
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// Copyright 2023, 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import Compound
|
||||
import SwiftUI
|
||||
|
||||
struct ButtonsScreen: View {
|
||||
var body: some View {
|
||||
ScreenContent(navigationTitle: "Buttons") {
|
||||
CompoundButtonStyle_Previews.states
|
||||
SendButton_Previews.states
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ButtonsScreen_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
ButtonsScreen()
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 700))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// Copyright 2023, 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Compound
|
||||
import HyperionCore
|
||||
|
||||
struct ListScreen: View {
|
||||
var body: some View {
|
||||
ListRow_Previews.previews
|
||||
.navigationTitle("Lists")
|
||||
}
|
||||
}
|
||||
|
||||
struct ListScreen_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
ListScreen()
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 700))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// Copyright 2023, 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import DesignKit
|
||||
|
||||
struct TextFieldsScreen: View {
|
||||
var body: some View {
|
||||
ScreenContent(navigationTitle: "Text Fields") {
|
||||
BorderedInputFieldStyle_Previews.states
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TextFieldsScreen_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
TextFieldsScreen()
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 700))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// Copyright 2023, 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Compound
|
||||
import HyperionCore
|
||||
|
||||
@main
|
||||
struct CompoundInspectorApp: App {
|
||||
@State private var colorScheme: ColorScheme = .light
|
||||
@State private var dynamicTypeSize: DynamicTypeSize = .large
|
||||
|
||||
private var isDark: Bool { colorScheme == .dark }
|
||||
private var preferredColorScheme: ColorScheme? { ProcessInfo.processInfo.isMacCatalystApp ? colorScheme : nil }
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
NavigationSplitView {
|
||||
SidebarList()
|
||||
.navigationTitle("Components")
|
||||
.navigationDestination(for: Screen.self) { screen in
|
||||
screen
|
||||
#if targetEnvironment(macCatalyst)
|
||||
.dynamicTypeSize(dynamicTypeSize)
|
||||
#endif
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar { screenToolbar }
|
||||
}
|
||||
} detail: {
|
||||
EmptyView()
|
||||
}
|
||||
.accentColor(.compound.textActionPrimary)
|
||||
.preferredColorScheme(preferredColorScheme)
|
||||
.introspect(.window, on: .supportedVersions) { window in
|
||||
// Apply the tint colour to alerts and confirmation dialogs
|
||||
window.tintColor = .compound.textActionPrimary
|
||||
}
|
||||
}
|
||||
.commands {
|
||||
CommandMenu("Options") {
|
||||
Button("Hyperion", action: HyperionManager.sharedInstance().togglePluginDrawer)
|
||||
.keyboardShortcut("i", modifiers: [.command, .option])
|
||||
|
||||
Divider()
|
||||
|
||||
Button("Toggle Appearance", action: toggleDarkMode)
|
||||
.keyboardShortcut("a", modifiers: [.command, .shift])
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
textSizePicker
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var textSizePicker: some View {
|
||||
Picker("Text Size", selection: $dynamicTypeSize) {
|
||||
ForEach(DynamicTypeSize.allCases, id: \.self) { size in
|
||||
Text(String(describing: size)).tag(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
var screenToolbar: some View {
|
||||
#if targetEnvironment(macCatalyst)
|
||||
Menu {
|
||||
textSizePicker
|
||||
.pickerStyle(.inline)
|
||||
} label: {
|
||||
Image(systemName: "textformat.size")
|
||||
}
|
||||
#endif
|
||||
|
||||
Button(action: HyperionManager.sharedInstance().togglePluginDrawer) {
|
||||
Image(systemName: "ruler")
|
||||
}
|
||||
}
|
||||
|
||||
func toggleDarkMode() {
|
||||
colorScheme = isDark ? .light : .dark
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// Copyright 2023, 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
/// A screen of components/tokens that can be navigated to.
|
||||
enum Screen: Hashable, View {
|
||||
/// Colour tokens
|
||||
case colors
|
||||
/// Gradients assembled from colour tokens
|
||||
case gradients
|
||||
/// Font tokens
|
||||
case fonts
|
||||
/// Icon tokens
|
||||
case icons
|
||||
/// Size tokens
|
||||
case sizes
|
||||
|
||||
/// List styles and components
|
||||
case list
|
||||
/// Label styles
|
||||
case labels
|
||||
/// Button styles
|
||||
case buttons
|
||||
/// Text field styles.
|
||||
case textFields
|
||||
|
||||
/// The system's confirmation dialog component
|
||||
case actionSheet
|
||||
/// The system's alert component
|
||||
case alert
|
||||
/// The system's context menu component
|
||||
case contextMenu
|
||||
/// The system's navigation bar component
|
||||
case navigationBar
|
||||
/// The system's share sheet component
|
||||
case shareSheet
|
||||
|
||||
var body: some View {
|
||||
switch self {
|
||||
case .colors: ColorsScreen()
|
||||
case .gradients: GradientsScreen()
|
||||
case .fonts: FontsScreen()
|
||||
case .icons: IconsScreen()
|
||||
|
||||
case .list: ListScreen()
|
||||
case .sizes: EmptyView()
|
||||
case .labels: EmptyView()
|
||||
case .buttons: ButtonsScreen()
|
||||
case .textFields: EmptyView()
|
||||
|
||||
case .actionSheet: ActionSheetScreen()
|
||||
case .alert: AlertScreen()
|
||||
case .contextMenu: ContextMenuScreen()
|
||||
case .navigationBar: NavigationBarScreen()
|
||||
case .shareSheet: ShareSheetScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// Copyright 2023, 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
/// A helper to provider a default layout for the content of a screen.
|
||||
struct ScreenContent<Content: View>: View {
|
||||
let navigationTitle: String
|
||||
@ViewBuilder var content: () -> Content
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
LazyVStack(spacing: 16) {
|
||||
content()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.navigationTitle(navigationTitle)
|
||||
}
|
||||
}
|
||||
|
||||
struct ComponentsContainer_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
ScreenContent(navigationTitle: "Buttons") {
|
||||
Button("Confirm") { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// Copyright 2023, 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct SidebarList: View {
|
||||
var body: some View {
|
||||
List {
|
||||
tokensSection
|
||||
componentsSection
|
||||
systemComponentsSection
|
||||
}
|
||||
.navigationTitle("Components")
|
||||
.listStyle(.sidebar)
|
||||
.tint(.compound.iconAccentTertiary)
|
||||
}
|
||||
|
||||
var tokensSection: some View {
|
||||
Section("Tokens") {
|
||||
NavigationLink(value: Screen.colors) {
|
||||
Label("Colours", systemImage: "paintpalette")
|
||||
}
|
||||
NavigationLink(value: Screen.gradients) {
|
||||
Label("Gradients", systemImage: "lightspectrum.horizontal")
|
||||
}
|
||||
NavigationLink(value: Screen.fonts) {
|
||||
Label("Typography", systemImage: "character")
|
||||
}
|
||||
NavigationLink(value: Screen.icons) {
|
||||
Label("Icons", systemImage: "pencil.and.outline")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var componentsSection: some View {
|
||||
Section("Components") {
|
||||
NavigationLink(value: Screen.buttons) {
|
||||
Label("Buttons", systemImage: "rectangle.and.hand.point.up.left")
|
||||
}
|
||||
NavigationLink(value: Screen.list) {
|
||||
Label("List", systemImage: "list.bullet.clipboard")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var systemComponentsSection: some View {
|
||||
Section("System Components") {
|
||||
NavigationLink(value: Screen.actionSheet) {
|
||||
Label("Action Sheets", systemImage: "window.shade.closed")
|
||||
}
|
||||
|
||||
NavigationLink(value: Screen.alert) {
|
||||
Label("Alerts", systemImage: "exclamationmark.triangle")
|
||||
}
|
||||
|
||||
NavigationLink(value: Screen.contextMenu) {
|
||||
Label("Context Menus", systemImage: "contextualmenu.and.cursorarrow")
|
||||
}
|
||||
|
||||
NavigationLink(value: Screen.navigationBar) {
|
||||
Label("Navigation Bar", systemImage: "window.shade.open")
|
||||
}
|
||||
|
||||
NavigationLink(value: Screen.shareSheet) {
|
||||
Label("Share Sheet", systemImage: "square.and.arrow.up")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
SidebarList()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// Copyright 2023, 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Compound
|
||||
|
||||
struct ActionSheetScreen: View {
|
||||
@State private var isPresentingConfirmationDialog = true
|
||||
|
||||
var body: some View {
|
||||
ScreenContent(navigationTitle: "Action Sheets") {
|
||||
Text("This component will be rendered differently when running on macOS.")
|
||||
.font(.footnote)
|
||||
.foregroundColor(.secondary)
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .bottomBar) {
|
||||
Button("Show Sheet") {
|
||||
isPresentingConfirmationDialog = true
|
||||
}
|
||||
.confirmationDialog("A Short Title is Best",
|
||||
isPresented: $isPresentingConfirmationDialog) {
|
||||
Button("Default") { }
|
||||
Button("Default") { }
|
||||
Button("Default") { }
|
||||
Button("Disabled") { }
|
||||
.disabled(true) // This hides the button on iOS 16 😐
|
||||
Button("Destructive", role: .destructive) { }
|
||||
} message: {
|
||||
Text("A message should be a short, complete sentence.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ActionSheetScreen_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
ActionSheetScreen()
|
||||
}
|
||||
.introspect(.window, on: .supportedVersions) { window in
|
||||
// Fix the tint colour like the App strut does.
|
||||
window.tintColor = .compound.textActionPrimary
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 750))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// Copyright 2023, 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Compound
|
||||
|
||||
struct AlertScreen: View {
|
||||
@State private var isPresentingActionAlert = false
|
||||
@State private var isPresentingActionAndCancelAlert = false
|
||||
@State private var isPresentingDestructiveAlert = false
|
||||
@State private var isPresentingTextFieldAlert = false
|
||||
@State private var textFieldValue = ""
|
||||
|
||||
private let title = "A Short Title is Best"
|
||||
private let message = "A message should be a short, complete sentence."
|
||||
|
||||
var body: some View {
|
||||
ScreenContent(navigationTitle: "Alerts") {
|
||||
Text("This component will be rendered differently when running on macOS.")
|
||||
.font(.footnote)
|
||||
.foregroundColor(.secondary)
|
||||
.multilineTextAlignment(.center)
|
||||
|
||||
Button("Action") { isPresentingActionAlert = true }
|
||||
.padding(.top)
|
||||
.alert(title, isPresented: $isPresentingActionAlert) {
|
||||
Button("Action") { }
|
||||
} message: {
|
||||
Text(message)
|
||||
}
|
||||
|
||||
Button("Action and Cancel") { isPresentingActionAndCancelAlert = true }
|
||||
.padding(.top)
|
||||
.alert(title, isPresented: $isPresentingActionAndCancelAlert) {
|
||||
Button("Action") { }
|
||||
Button("Cancel", role: .cancel) { }
|
||||
} message: {
|
||||
Text(message)
|
||||
}
|
||||
|
||||
Button("Destructive") { isPresentingDestructiveAlert = true }
|
||||
.padding(.top)
|
||||
.alert(title, isPresented: $isPresentingDestructiveAlert) {
|
||||
Button("Action") { }
|
||||
Button("Destructive", role: .destructive) { }
|
||||
Button("Cancel", role: .cancel) { }
|
||||
} message: {
|
||||
Text(message)
|
||||
}
|
||||
|
||||
Button("TextField") { isPresentingTextFieldAlert = true }
|
||||
.padding(.top)
|
||||
.alert(title, isPresented: $isPresentingTextFieldAlert) {
|
||||
TextField("Input", text: $textFieldValue, prompt: Text("Placeholder"))
|
||||
Button("Action") { }
|
||||
Button("Cancel", role: .cancel) { }
|
||||
} message: {
|
||||
Text(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AlertScreen_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
AlertScreen()
|
||||
}
|
||||
.introspect(.window, on: .supportedVersions) { window in
|
||||
// Fix the tint colour like the App strut does.
|
||||
window.tintColor = .compound.textActionPrimary
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 750))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// Copyright 2023, 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Compound
|
||||
|
||||
struct ContextMenuScreen: View {
|
||||
var body: some View {
|
||||
ScreenContent(navigationTitle: "Context Menus") {
|
||||
Text("This component will be rendered differently when running on macOS.")
|
||||
.font(.footnote)
|
||||
.foregroundColor(.secondary)
|
||||
.multilineTextAlignment(.center)
|
||||
|
||||
Text("Actions")
|
||||
.padding()
|
||||
.contentShape(.contextMenuPreview, RoundedRectangle(cornerRadius: 12))
|
||||
.contextMenu {
|
||||
Section {
|
||||
Button { } label: {
|
||||
Label("Action", systemImage: "square.dashed")
|
||||
}
|
||||
Button { } label: {
|
||||
Label("Action", systemImage: "square.dashed")
|
||||
}
|
||||
Button { } label: {
|
||||
Label("Disabled", systemImage: "square.dashed")
|
||||
}
|
||||
.disabled(true)
|
||||
Button(role: .destructive) { } label: {
|
||||
Label("Destructive", systemImage: "square.dashed")
|
||||
}
|
||||
}
|
||||
Section {
|
||||
Button { } label: {
|
||||
Label("Action", systemImage: "square.dashed")
|
||||
}
|
||||
Button { } label: {
|
||||
Label("Action", systemImage: "square.dashed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text("Toggles")
|
||||
.padding()
|
||||
.contentShape(.contextMenuPreview, RoundedRectangle(cornerRadius: 12))
|
||||
.contextMenu {
|
||||
Section {
|
||||
Toggle(isOn: .constant(true)) {
|
||||
Label("Toggle", systemImage: "square.dashed")
|
||||
}
|
||||
Toggle(isOn: .constant(false)) {
|
||||
Label("Toggle", systemImage: "square.dashed")
|
||||
}
|
||||
Toggle(isOn: .constant(false)) {
|
||||
Label("Disabled", systemImage: "square.dashed")
|
||||
}
|
||||
.disabled(true)
|
||||
}
|
||||
Section {
|
||||
Toggle(isOn: .constant(true)) {
|
||||
Label("Toggle", systemImage: "square.dashed")
|
||||
}
|
||||
Toggle(isOn: .constant(true)) {
|
||||
Label("Toggle", systemImage: "square.dashed")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ContextMenuScreen_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
ContextMenuScreen()
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 750))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
//
|
||||
// Copyright 2023, 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Compound
|
||||
|
||||
struct NavigationBarScreen: View {
|
||||
enum TitleMode {
|
||||
case large
|
||||
case inline
|
||||
case hidden
|
||||
}
|
||||
|
||||
enum BackButtonMode {
|
||||
case navigation
|
||||
case cancellationAction
|
||||
case hidden
|
||||
}
|
||||
|
||||
@State private var titleMode = TitleMode.inline
|
||||
@State private var backButtonMode = BackButtonMode.navigation
|
||||
@State private var hasConfirmationAction = true
|
||||
@State private var hasPrimaryAction = false
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section {
|
||||
ListRow(kind: .custom {
|
||||
Text("This component may be rendered differently when running on macOS.")
|
||||
.font(.compound.bodySM)
|
||||
.foregroundColor(.compound.textSecondary)
|
||||
.multilineTextAlignment(.center)
|
||||
.frame(maxWidth: .infinity)
|
||||
.listRowBackground(Color.clear)
|
||||
})
|
||||
}
|
||||
|
||||
Section {
|
||||
ListRow(label: .plain(title: "Title"),
|
||||
kind: .picker(selection: $titleMode, items: [
|
||||
(title: "Large", tag: .large),
|
||||
(title: "Inline", tag: .inline),
|
||||
(title: "Hidden", tag: .hidden)
|
||||
]))
|
||||
ListRow(label: .plain(title: "Back Button"),
|
||||
kind: .picker(selection: $backButtonMode, items: [
|
||||
(title: "Navigation", tag: .navigation),
|
||||
(title: "Cancelation Action", tag: .cancellationAction),
|
||||
(title: "Hidden", tag: .hidden)
|
||||
]))
|
||||
|
||||
ListRow(label: .plain(title: "Confirmation Action"),
|
||||
kind: .toggle($hasConfirmationAction))
|
||||
ListRow(label: .plain(title: "Primary Action"),
|
||||
kind: .toggle($hasPrimaryAction))
|
||||
} header: {
|
||||
Text("Configuration")
|
||||
.compoundListSectionHeader()
|
||||
}
|
||||
|
||||
Section {
|
||||
ListRow(kind: .custom {
|
||||
VStack {
|
||||
Text("Empty section to make the form scrollable")
|
||||
.font(.compound.bodySM)
|
||||
.foregroundColor(.compound.textSecondary)
|
||||
Spacer(minLength: 500)
|
||||
}
|
||||
.padding(ListRowPadding.insets)
|
||||
})
|
||||
}
|
||||
}
|
||||
.compoundList()
|
||||
.navigationTitle(titleMode == .hidden ? "" : "Navigation Bar")
|
||||
.navigationBarTitleDisplayMode(titleMode == .large ? .large : .inline)
|
||||
.navigationBarBackButtonHidden(backButtonMode != .navigation)
|
||||
.toolbar {
|
||||
if hasConfirmationAction {
|
||||
ToolbarItem(placement: .confirmationAction) {
|
||||
Button("Confirm") { }
|
||||
}
|
||||
}
|
||||
|
||||
if hasPrimaryAction {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Button("Primary") { }
|
||||
}
|
||||
}
|
||||
|
||||
if backButtonMode == .cancellationAction {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button("Cancel") { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct NavigationBarScreen_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
NavigationBarScreen()
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 750))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Copyright 2023, 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Compound
|
||||
|
||||
struct ShareSheetScreen: View {
|
||||
var body: some View {
|
||||
ScreenContent(navigationTitle: "Share Sheets") {
|
||||
Text("This component will be rendered differently when running on macOS.")
|
||||
.font(.footnote)
|
||||
.foregroundColor(.secondary)
|
||||
.multilineTextAlignment(.center)
|
||||
|
||||
ShareLink(item: URL(string: "https://element.io")!, subject: Text("The subject"), message: Text("The message"))
|
||||
.padding(.top)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ShareSheetScreen_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
ShareSheetScreen()
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 750))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// Copyright 2023, 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import Compound
|
||||
import SwiftUI
|
||||
|
||||
protocol AllValues {
|
||||
associatedtype ValueType
|
||||
var allValues: [(name: String, value: ValueType)] { get }
|
||||
}
|
||||
|
||||
extension AllValues {
|
||||
var allValues: [(name: String, value: ValueType)] {
|
||||
var values: [(name: String, value: ValueType)] = []
|
||||
let mirror = Mirror(reflecting: self)
|
||||
|
||||
for property in mirror.children {
|
||||
if let label = property.label, let value = property.value as? ValueType {
|
||||
values.append((label, value))
|
||||
}
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
}
|
||||
|
||||
extension CompoundColors: AllValues { typealias ValueType = Color }
|
||||
extension CompoundColorTokens: AllValues { typealias ValueType = Color }
|
||||
extension CompoundGradients: AllValues { typealias ValueType = Gradient }
|
||||
extension CompoundFonts: AllValues { typealias ValueType = Font }
|
||||
extension CompoundIcons: AllValues { typealias ValueType = Image }
|
||||
|
||||
extension CompoundColors {
|
||||
var allColors: [(name: String, value: Color)] {
|
||||
CompoundColorTokens().allValues + allValues
|
||||
}
|
||||
}
|
||||
|
||||
extension CompoundIcons {
|
||||
var allKeyPaths: [(name: String, value: KeyPath<CompoundIcons, Image>)] {
|
||||
var icons: [(name: String, value: KeyPath<CompoundIcons, Image>)] = []
|
||||
let mirror = Mirror(reflecting: self)
|
||||
|
||||
for property in mirror.children {
|
||||
if let label = property.label {
|
||||
let keyPath = \CompoundIcons.[checkedMirrorDescendant: label] as PartialKeyPath
|
||||
|
||||
if let imageKeyPath = keyPath as? KeyPath<CompoundIcons, Image> {
|
||||
icons.append((label, imageKeyPath))
|
||||
} else {
|
||||
print("Nope")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return icons
|
||||
}
|
||||
|
||||
private subscript(checkedMirrorDescendant key: String) -> Any {
|
||||
return Mirror(reflecting: self).descendant(key)!
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
//
|
||||
// Copyright 2023, 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Compound
|
||||
|
||||
struct ColorsScreen: View {
|
||||
var body: some View {
|
||||
ScreenContent(navigationTitle: "Colors") {
|
||||
ForEach(Color.compound.allColors, id: \.name) { color in
|
||||
ColorItem(color: color.value, name: color.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ColorItem: View {
|
||||
let color: Color
|
||||
let name: String
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
swatch
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text(name)
|
||||
.font(.compound.bodyLG)
|
||||
.foregroundColor(.compound.textPrimary)
|
||||
Text(color.hexValue())
|
||||
.font(.compound.bodySM.monospaced())
|
||||
.foregroundColor(.compound.textSecondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var swatch: some View {
|
||||
swatchShape
|
||||
.foregroundColor(color)
|
||||
.frame(height: 40)
|
||||
.aspectRatio(1, contentMode: .fit)
|
||||
.overlay {
|
||||
swatchShape
|
||||
.strokeBorder(Color.compound.iconPrimary, lineWidth: 1.5)
|
||||
.opacity(0.2)
|
||||
}
|
||||
}
|
||||
|
||||
var swatchShape: some InsettableShape {
|
||||
RoundedRectangle(cornerRadius: 12, style: .continuous)
|
||||
}
|
||||
}
|
||||
|
||||
private extension Color {
|
||||
func hexValue() -> String {
|
||||
let uiColor = UIColor(self)
|
||||
|
||||
var red: CGFloat = 0
|
||||
var green: CGFloat = 0
|
||||
var blue: CGFloat = 0
|
||||
var alpha: CGFloat = 0
|
||||
|
||||
uiColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
|
||||
|
||||
return "#\(red.asHex)\(green.asHex)\(blue.asHex)"
|
||||
}
|
||||
}
|
||||
|
||||
private extension CGFloat {
|
||||
var asHex: String {
|
||||
String(format:"%02X", Int((self * 255).rounded()))
|
||||
}
|
||||
}
|
||||
|
||||
struct ColorsScreen_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
ColorsScreen()
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 700))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// Copyright 2023, 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Compound
|
||||
|
||||
struct FontsScreen: View {
|
||||
var body: some View {
|
||||
ScreenContent(navigationTitle: "Fonts") {
|
||||
ForEach(Font.compound.allValues, id: \.name) { font in
|
||||
FontItem(font: font.value, name: font.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FontItem: View {
|
||||
let font: Font
|
||||
let name: String
|
||||
|
||||
var body: some View {
|
||||
Text(name)
|
||||
.font(font)
|
||||
.foregroundColor(.compound.textPrimary)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
}
|
||||
|
||||
struct FontsScreen_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
FontsScreen()
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 750))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// Copyright 2025 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Compound
|
||||
|
||||
struct GradientsScreen: View {
|
||||
var body: some View {
|
||||
ScreenContent(navigationTitle: "Colors") {
|
||||
ForEach(Gradient.compound.allValues, id: \.name) { gradient in
|
||||
GradientItem(gradient: gradient.value, name: gradient.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct GradientItem: View {
|
||||
let gradient: Gradient
|
||||
let name: String
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
swatch
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text(name)
|
||||
.font(.compound.bodyLG)
|
||||
.foregroundColor(.compound.textPrimary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var swatch: some View {
|
||||
swatchShape
|
||||
.foregroundStyle(gradient)
|
||||
.frame(height: 40)
|
||||
.aspectRatio(1, contentMode: .fit)
|
||||
.overlay {
|
||||
swatchShape
|
||||
.strokeBorder(Color.compound.iconPrimary, lineWidth: 1.5)
|
||||
.opacity(0.2)
|
||||
}
|
||||
}
|
||||
|
||||
var swatchShape: some InsettableShape {
|
||||
RoundedRectangle(cornerRadius: 12, style: .continuous)
|
||||
}
|
||||
}
|
||||
|
||||
struct GradientsScreen_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
ColorsScreen()
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 700))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// Copyright 2023, 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Compound
|
||||
|
||||
struct IconsScreen: View {
|
||||
let icons = Image.compound.allValues.sorted(by: { $0.name < $1.name })
|
||||
|
||||
var body: some View {
|
||||
ScreenContent(navigationTitle: "Icons") {
|
||||
ForEach(icons, id: \.name) { icon in
|
||||
IconItem(icon: icon.value, name: icon.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct IconItem: View {
|
||||
let icon: Image
|
||||
let name: String
|
||||
|
||||
var body: some View {
|
||||
Label {
|
||||
Text(name)
|
||||
.foregroundColor(.compound.textPrimary)
|
||||
} icon: {
|
||||
CompoundIcon(customImage: icon)
|
||||
.foregroundColor(.compound.iconSecondary)
|
||||
}
|
||||
.font(.compound.bodyLG)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
}
|
||||
|
||||
struct IconsScreen_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
IconsScreen()
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 750))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user