diff --git a/AUTHORS.txt b/.github/AUTHORS.txt similarity index 100% rename from AUTHORS.txt rename to .github/AUTHORS.txt diff --git a/CODEOWNERS b/.github/CODEOWNERS similarity index 100% rename from CODEOWNERS rename to .github/CODEOWNERS diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md diff --git a/CONTRIBUTORS.txt b/.github/CONTRIBUTORS.txt similarity index 100% rename from CONTRIBUTORS.txt rename to .github/CONTRIBUTORS.txt diff --git a/DEVELOP.md b/.github/DEVELOP.md similarity index 78% rename from DEVELOP.md rename to .github/DEVELOP.md index 8a20e018..d08b9bf4 100644 --- a/DEVELOP.md +++ b/.github/DEVELOP.md @@ -25,6 +25,12 @@ brew install peripheryapp/periphery/periphery # For jq (https://jqlang.github.io/jq/) brew install jq + +# For gitleaks (https://github.com/gitleaks/gitleaks) +brew install gitleaks + +# For licenseplist (https://github.com/mono0926/LicensePlist) +brew install licenseplist ``` ## Build OrangeDesignSystemDemo @@ -133,3 +139,35 @@ gitleaks detect -v -l debug --source . ``` Note that we face some issues about the use of _Gitleaks GitHub Action_ and _Gitleaks_ as CLI command, for fur further details see [#131](https://github.com/gitleaks/gitleaks-action/issues/131), [#132](https://github.com/gitleaks/gitleaks-action/issues/132) and [#1331](https://github.com/gitleaks/gitleaks/issues/1331). + +## Update dependencies + +Sometimes dependencies should be updated, with for example warnings of [Renovate bot](https://github.com/apps/renovate). +Here is the list of files to update to keep the project clean: +- CHANGELOG (to note for releases the update of the version) +- THIRD-PARTY (because we list all third-party components) +- Of course, update and save in tyout VSC the new states of the Podfile, Package.swift or Gemfile (and do not forget locks) +- doctor.sh (to notify to newcomers the version they should have when using this doctor script) +- And update the resources embeded in the demo app bundle settings: + +```shell +license-plist --add-version-numbers +``` + +Maybe yo will need to update your pods repo before if you updated a Pod: + +```shell +bundle exec pod install --repo-update +``` + +## Third-party components declaration + +It is a good practice to have in the app, e.g. in the app settings, the list of third-party components in use, at least for the app. +The [LicensePlist](https://github.com/mono0926/LicensePlist) project helps to get dependencies +and produce files to place inside the _Settings.bundle_ file: + +To use it: + +```shell +license-plist --add-version-numbers +``` diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b3aca36..3d18894b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,37 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.2.0](https://github.com/Orange-OpenSource/ods-ios/compare/1.1.0...1.2.0) - 2024-08-23 + +### Added + +- [Doc] Add Documentation versionning ([#223](https://github.com/Orange-OpenSource/ods-ios/issues/223)) +- [DemoApp] Add privacy manifest ([#798](https://github.com/Orange-OpenSource/ods-ios/issues/798)) + +### Changed + +- [DemoApp] Update accessibility statement file ([#839](https://github.com/Orange-OpenSource/ods-ios/issues/839)) +- [SDK] Update More Apps to use ListItems with subtile on two lines ([#651](https://github.com/Orange-OpenSource/ods-ios/issues/651)) +- [Doc] Wrong name of MoreApprs module in documentation ([#815](https://github.com/Orange-OpenSource/ods-ios/issues/815)) +- [Doc] Update components and modules documentation to add a description of the API ([#759](https://github.com/Orange-OpenSource/ods-ios/issues/759)) +- [DemoApp/SDK] Rename "Recirculation" module to "MoreApps", and use "EmptyState" assets from Theme bundle ([#801](https://github.com/Orange-OpenSource/ods-ios/issues/801)) +- [Tooling] Update dependency SwiftFormat/CLI to v0.53.5 +- [DemoApp] The main color names, visible on the screen are not vocalized ([#720](https://github.com/Orange-OpenSource/ods-ios/issues/720)) +- [Doc] Improve release documentation +- [Tooling] Define ZIP archive for nightly and production builds (for artifacts storage in CI/CD pipelines) + +### Fixed + +- [DemoApp] A11y - Buttons component : group labels and buttons and state ([#835](https://github.com/Orange-OpenSource/ods-ios/issues/835)) +- [DemoApp] A11y - Slider has no visible text ([#832](https://github.com/Orange-OpenSource/ods-ios/issues/832)) +- [DemoApp] A11y - Irrelevant Colour palette page title: page title is "Palette" ([#730](https://github.com/Orange-OpenSource/ods-ios/issues/730)) +- [DemoApp] A11y - Bars-navigation component accessibility issues ([#830](https://github.com/Orange-OpenSource/ods-ios/issues/830)) +- [DemoApp] A11y - Target size is too small for info and chevron components, difficult to tap without mistake. ([#732](https://github.com/Orange-OpenSource/ods-ios/issues/732)) +- [DemoApp] A11y - Buttons component : group labels and buttons ([#760](https://github.com/Orange-OpenSource/ods-ios/issues/760)) +- [DemoApp] A11y - Title is the same for both variants "Progress bar demo", title must be unique. ([#724](https://github.com/Orange-OpenSource/ods-ios/issues/724)) +- [DemoApp] A11y - Buttons component : group labels and buttons ([#760](https://github.com/Orange-OpenSource/ods-ios/issues/760)) +- [DemoApp/SDK] A11y - Module - About : Title header ([#827](https://github.com/Orange-OpenSource/ods-ios/issues/727)) + ## [1.1.0](https://github.com/Orange-OpenSource/ods-ios/compare/1.0.0...1.1.0) - 2024-03-08 ### Changed diff --git a/InnovationCupTheme/Sources/InnovationCupTheme/InnovationCupTheme.swift b/InnovationCupTheme/Sources/InnovationCupTheme/InnovationCupTheme.swift index ff4250e2..11ab8c68 100644 --- a/InnovationCupTheme/Sources/InnovationCupTheme/InnovationCupTheme.swift +++ b/InnovationCupTheme/Sources/InnovationCupTheme/InnovationCupTheme.swift @@ -82,12 +82,6 @@ public struct InnovationCupThemeFactory { // Fonts: use the default ones // theme.font = { style in } - // Images for empty states - theme.emptyStateImages = ODSThemeEmptyStateImages(error: Image(decorative: "il_emptyStateError (Innovation Cup)", bundle: .innovationCupTheme), - firstUse: Image(decorative: "il_emptyStateFirstUse (Innovation Cup)", bundle: .innovationCupTheme), - noData: Image(decorative: "il_emptyStateNoData (Innovation Cup)", bundle: .innovationCupTheme), - userCleared: Image(decorative: "il_emptyStateUserCleared (Innovation Cup)", bundle: .innovationCupTheme)) - theme.bundle = Bundle.innovationCupTheme self.theme = theme diff --git a/InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateError (Innovation Cup).imageset/Contents.json b/InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateError.imageset/Contents.json similarity index 100% rename from InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateError (Innovation Cup).imageset/Contents.json rename to InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateError.imageset/Contents.json diff --git a/InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateError (Innovation Cup).imageset/Error.svg b/InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateError.imageset/Error.svg similarity index 100% rename from InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateError (Innovation Cup).imageset/Error.svg rename to InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateError.imageset/Error.svg diff --git a/InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateFirstUse (Innovation Cup).imageset/Contents.json b/InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateFirstUse.imageset/Contents.json similarity index 100% rename from InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateFirstUse (Innovation Cup).imageset/Contents.json rename to InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateFirstUse.imageset/Contents.json diff --git a/InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateFirstUse (Innovation Cup).imageset/FirstUser.svg b/InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateFirstUse.imageset/FirstUser.svg similarity index 100% rename from InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateFirstUse (Innovation Cup).imageset/FirstUser.svg rename to InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateFirstUse.imageset/FirstUser.svg diff --git a/InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateNoData (Innovation Cup).imageset/Contents.json b/InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateNoData.imageset/Contents.json similarity index 100% rename from InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateNoData (Innovation Cup).imageset/Contents.json rename to InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateNoData.imageset/Contents.json diff --git a/InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateNoData (Innovation Cup).imageset/NoData.svg b/InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateNoData.imageset/NoData.svg similarity index 100% rename from InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateNoData (Innovation Cup).imageset/NoData.svg rename to InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateNoData.imageset/NoData.svg diff --git a/InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateUserCleared (Innovation Cup).imageset/Contents.json b/InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateUserCleared.imageset/Contents.json similarity index 100% rename from InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateUserCleared (Innovation Cup).imageset/Contents.json rename to InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateUserCleared.imageset/Contents.json diff --git a/InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateUserCleared (Innovation Cup).imageset/UserClear.svg b/InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateUserCleared.imageset/UserClear.svg similarity index 100% rename from InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateUserCleared (Innovation Cup).imageset/UserClear.svg rename to InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateUserCleared.imageset/UserClear.svg diff --git a/NOTICE.txt b/NOTICE.txt index 34bd6924..2e25fd97 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -36,19 +36,16 @@ Any use or displaying shall constitute an infringement under intellectual proper ## Orange Theme -./OrangeTheme/Sources/OrangeTheme/Resources/Assets.xcassets/EmptyState/il_emptyState.imageset/il_emptyState.svg -./OrangeTheme/Sources/OrangeTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateNoData.imageset/il_emptyStateNoData.svg -./OrangeTheme/Sources/OrangeTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateFirstUse.imageset/il_emptyStateFirstUse.svg ./OrangeTheme/Sources/OrangeTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateError.imageset/il_emptyStateError.svg ./OrangeTheme/Sources/OrangeTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateUserCleared.imageset/il_yoga_man.svg +./OrangeTheme/Sources/OrangeTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateNoData.imageset/il_emptyStateNoData.svg +./OrangeTheme/Sources/OrangeTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateFirstUse.imageset/il_emptyStateFirstUse.svg ## Innovation Cup Theme - -./InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateError (Innovation Cup).imageset/Error.svg -./InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateUserCleared (Innovation Cup).imageset/UserClear.svg -./InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateNoData (Innovation Cup).imageset/NoData.svg -./InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateFirstUse (Innovation Cup).imageset/FirstUser.svg -./InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyState (Innovation Cup).imageset/il_emptyState_generic.svg +./InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateError.imageset/Error.svg +./InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateUserCleared.imageset/UserClear.svg +./InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateNoData.imageset/NoData.svg +./InnovationCupTheme/Sources/InnovationCupTheme/Resources/Assets.xcassets/EmptyState/il_emptyStateFirstUse.imageset/FirstUser.svg # Demo app @@ -103,18 +100,20 @@ Any use or displaying shall constitute an infringement under intellectual proper ./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/appTabBar/component-atom_32.imageset/component-atom_32.svg ./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/appTabBar/Module-molecule_32.imageset/Module-molecule_32.svg -./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_recirculation (Innovation Cup).imageset/il_recirculation_generic.svg -./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_lists (Innovation Cup).imageset/il_lists_generic.svg ./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_about (Innovation Cup).imageset/il_about_generic.svg -./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_cardList (Innovation Cup).imageset/il_card_list_generic.svg +./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_cardList (Innovation Cup).imageset/il_cardList_generic.svg +./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_emptyState.imageset/il_emptyState.svg +./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_lists (Innovation Cup).imageset/il_lists_generic.svg +./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_moreApps (Innovation Cup).imageset/il_moreApps_generic.svg -./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_recirculation.imageset/il_recirculation.svg -./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_lists.imageset/il_lists.svg ./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/ic_folderFavourite.imageset/ic_folderFavourite.svg ./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/ic_tools.imageset/ic_tools.svg ./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/ic_subtitles.imageset/ic_subtitles.svg -./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/il_about.imageset/il_about.svg -./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_cardList.imageset/il_card_list.svg +./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_about.imageset/il_about.svg +./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_cardList.imageset/il_cardList.svg +./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_emptyState.imageset/il_emptyState.svg +./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_lists.imageset/il_lists.svg +./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_moreApps.imageset/il_moreApps.svg ./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/AppIconDev.appiconset/iPhone-App-60@2x.png ./OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/AppIconDev.appiconset/iPhone-App-60@3x.png @@ -177,6 +176,10 @@ Any use or displaying shall constitute an infringement under intellectual proper # Documentation +./docs/1.2.0/accessibilityStatement/favicon.ico +./docs/1.2.0/accessibilityStatement/orange-logo.svg +./docs/accessibilityStatement/orange-logo.svg +./docs/accessibilityStatement/favicon.ico ./docs/components/images/buttons_layout_small_with_icon.png ./docs/components/images/list_items_selection_circle_light.png ./docs/components/images/buttons_functional_negative.png diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Cards/ODSCardSmall.swift b/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Cards/ODSCardSmall.swift index fa13c7dd..f62097b0 100644 --- a/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Cards/ODSCardSmall.swift +++ b/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Cards/ODSCardSmall.swift @@ -39,8 +39,8 @@ public struct ODSCardSmall: View { /// - title: Title displayed into the card. /// - imageSource: Image from source [ODSImage.Source] displayed into the card. /// - subtitle: Optional subtitle displayed into the card,d efault set to `nil` - /// - titleAccessibleLineLimit: The line limit to apply to the title is size category is accessibility category, default set to `nil` - /// - subtitleAccessibleLineLimit: The line limit to apply to the subtitle is size category is accessibility category, default set to `nil` + /// - titleAccessibleLineLimit: The line limit to apply to the title if size category is accessibility category, default set to `nil` + /// - subtitleAccessibleLineLimit: The line limit to apply to the subtitle if size category is accessibility category, default set to `nil` public init(title: Text, imageSource: ODSImage.Source, subtitle: Text? = nil, titleAccessibleLineLimit: Int? = nil, subtitleAccessibleLineLimit: Int? = nil) { self.title = title self.subtitle = subtitle diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Chips/Pickers/ODSFilterChipPicker.swift b/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Chips/Pickers/ODSFilterChipPicker.swift index 465d746d..547ccd09 100644 --- a/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Chips/Pickers/ODSFilterChipPicker.swift +++ b/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Chips/Pickers/ODSFilterChipPicker.swift @@ -53,6 +53,7 @@ public struct ODSFilterChipPicker: View where Value: Hashable { VStack(alignment: .leading, spacing: ODSSpacing.s) { title? .odsFont(.headlineS) + .accessibilityAddTraits(.isHeader) .frame(maxWidth: .infinity, alignment: .leading) .padding(.horizontal, ODSSpacing.m) diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Lists/Internal/TrailingView.swift b/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Lists/Internal/TrailingView.swift index 92b55c0a..38ce5262 100644 --- a/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Lists/Internal/TrailingView.swift +++ b/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Lists/Internal/TrailingView.swift @@ -42,6 +42,7 @@ struct TrailingView: View { ODSIconButton(image: Image(systemName: "info.circle"), action: action) .foregroundColor(theme.componentColors.accent) + .frame(width: height, height: height) .buttonStyle(PlainButtonStyle()) } diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Lists/ODSListItem.swift b/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Lists/ODSListItem.swift index 8d162956..17d4a2c3 100644 --- a/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Lists/ODSListItem.swift +++ b/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Lists/ODSListItem.swift @@ -167,7 +167,7 @@ public struct ODSListItem: View { /// - title: The primary text of the list item /// - subtitle: The secondary text of the list item (optional) /// - subtitleNumberOfLines: If `subtitle` is provided, it is possible to limit the text - /// to 1 line or 2 lines. If set to nil, no restriction is applied (be carefull: this is not design compliant). + /// to 1 line or 2 lines. If set to nil, no restriction is applied (be careful: this is not design compliant). /// - leading: The leading icon of the list item (optional) /// public init( @@ -205,7 +205,7 @@ public struct ODSListItem: View { /// - title: The primary text of the list item /// - subtitle: The secondary text of the list item (optional) /// - subtitleNumberOfLines: If `subtitle` is provided, it is possible to limit the text - /// to 1 line or 2 lines. If set to nil, no restriction is applied (be carefull: this is not design compliant). + /// to 1 line or 2 lines. If set to nil, no restriction is applied (be careful: this is not design compliant). /// - leading: The leading icon of the list item (optional) /// - trailingText The text on trailing /// - trailingIButtonAction: The action the i button on trailing @@ -227,7 +227,7 @@ public struct ODSListItem: View { /// - title: The primary text of the list item /// - subtitle: The secondary text of the list item (optional) /// - subtitleNumberOfLines: If `subtitle` is provided, it is possible to limit the text - /// to 1 line or 2 lines. If set to nil, no restriction is applied (be carefull: this is not design compliant). + /// to 1 line or 2 lines. If set to nil, no restriction is applied (be careful: this is not design compliant). /// - leading: The leading icon of the list item (optional) /// - trailingText The text on trailing /// - trailingToggleIsOn: The binding to a property that determines whether the toggle is on or off. @@ -249,7 +249,7 @@ public struct ODSListItem: View { /// - title: The primary text of the list item /// - subtitle: The secondary text of the list item (optional) /// - subtitleNumberOfLines: If `subtitle` is provided, it is possible to limit the text - /// to 1 line or 2 lines. If set to nil, no restriction is applied (be carefull: this is not design compliant). + /// to 1 line or 2 lines. If set to nil, no restriction is applied (be carefull: this is not design compliant). /// - leading: The leading icon of the list item (optional) /// - trailingText The text on trailing /// - trailingCheckmarkIsSelected: The flag to indicate if checkmark is visbile or not. @@ -270,7 +270,7 @@ public struct ODSListItem: View { /// - title: The primary text of the list item /// - subtitle: The secondary text of the list item (optional) /// - subtitleNumberOfLines: If `subtitle` is provided, it is possible to limit the text - /// to 1 line or 2 lines. If set to nil, no restriction is applied (be carefull: this is not design compliant). + /// to 1 line or 2 lines. If set to nil, no restriction is applied (be careful: this is not design compliant). /// - leading: The leading icon of the list item (optional) /// - trailing: The trailing element /// diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/About/Configuration/Items/Recirculation/ODSRecirculationItem.swift b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/About/Configuration/Items/MoreApps/ODSMoreAppsItem.swift similarity index 86% rename from OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/About/Configuration/Items/Recirculation/ODSRecirculationItem.swift rename to OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/About/Configuration/Items/MoreApps/ODSMoreAppsItem.swift index 6b000092..a679eff0 100644 --- a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/About/Configuration/Items/Recirculation/ODSRecirculationItem.swift +++ b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/About/Configuration/Items/MoreApps/ODSMoreAppsItem.swift @@ -13,10 +13,10 @@ import SwiftUI -/// Configuration to add in list the item that opens the apps recirculation view. +/// Configuration to add in list the item that opens the __ODSMoreAppsView__. /// /// By default, this item is placed between legal information item and rate the app item. That can be changed with new priority set in the configuration. -public struct ODSRecirculationItemConfig: ODSAboutListItemConfig { +public struct ODSMoreAppsItemConfig: ODSAboutListItemConfig { // ======================= // MARK: Stored Properties @@ -39,15 +39,15 @@ public struct ODSRecirculationItemConfig: ODSAboutListItemConfig { /// - cacheAppsIcons: True (default) to use app cache to save locally the apps stores icons, false otherwise /// - enableHaptics: True (default) to enable vibrations with the module, false to disable /// - priority: Priority to adjust the position of the item in the list. - public init(dataSource: ODSRecirculationDataSource, + public init(dataSource: ODSMoreAppsDataSource, flattenApps: Bool = false, cacheAppsIcons: Bool = true, enableHaptics: Bool = true, priority: ODSAboutListItemPriority = .moreApps) { - title = "modules.about.recirculation.title".🌐 + title = "modules.about.moreApps.title".🌐 icon = Image("ic_mobile_apps", bundle: Bundle.ods) - let destination = ODSRecirculationView( + let destination = ODSMoreAppsView( dataSource: dataSource, flattenApps: flattenApps, cacheAppsIcons: cacheAppsIcons, diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Data/AppsPlusDTO.swift b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Data/AppsPlusDTO.swift similarity index 100% rename from OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Data/AppsPlusDTO.swift rename to OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Data/AppsPlusDTO.swift diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Data/AppsPlusRepository.swift b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Data/AppsPlusRepository.swift similarity index 87% rename from OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Data/AppsPlusRepository.swift rename to OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Data/AppsPlusRepository.swift index 5bda2e8c..1e3e43db 100644 --- a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Data/AppsPlusRepository.swift +++ b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Data/AppsPlusRepository.swift @@ -18,7 +18,7 @@ import Foundation // ============================ /// Requests the Apps Plus backend to get list of availables apps, usging also HTTP cache and local file cache -struct AppsPlusRepository: RecirculationRepositoryProtocol { +struct AppsPlusRepository: MoreAppsRepositoryProtocol { // ======================= // MARK: Stored properties @@ -51,7 +51,7 @@ struct AppsPlusRepository: RecirculationRepositoryProtocol { /// The data got from the service is also saved in cache (local file) so as to be available if the device is offline or if some error occured. /// - Returns: The list of object containing all apps and sections of apps. /// - Throws: `Error.badConfigurationPrerequisites` if not possible to build the URL for the _Apps Plus_ backend. - func availableAppsList() async throws -> RecirculationAppsList { + func availableAppsList() async throws -> MoreAppsAppsList { var request = URLRequest(url: feedURL) if let lastResourceEtag = Self.lastResourceEtag { @@ -75,7 +75,7 @@ struct AppsPlusRepository: RecirculationRepositoryProtocol { ODSLogger.debug("But AppsPlus data in cache available, use them") return cachedList } - throw RecirculationServiceErrors.sessionError + throw MoreAppsServiceErrors.sessionError } if let httpResponse = httpResponse { @@ -96,17 +96,17 @@ struct AppsPlusRepository: RecirculationRepositoryProtocol { // Only one object sent by AppsPlus backend let appsPlusAppsList: AppsPlusListDTO = try JSONDecoder().decode(AppsPlusDTO.self, from: appsPlusRawData).items[0] ODSLogger.debug("Got data from AppsPlus service with \(appsPlusAppsList.apps.count) apps and \(appsPlusAppsList.sections.count) sections") - let mapper = AppsPlusRecirculationMapper() - let recirculationApps = mapper.appsDetails(from: appsPlusAppsList) - let recirculationSections = mapper.appsSections(from: appsPlusAppsList) - return RecirculationAppsList(sections: recirculationSections, apps: recirculationApps) + let mapper = AppsPlusToMoreAppsMapper() + let apps = mapper.appsDetails(from: appsPlusAppsList) + let sections = mapper.appsSections(from: appsPlusAppsList) + return MoreAppsAppsList(sections: sections, apps: apps) } catch { ODSLogger.error("Failed to decode AppsPlus service data: '\(error.localizedDescription)'") if let cachedList = cachedList(for: request) { ODSLogger.debug("But AppsPlus data in cache available, use them") return cachedList } - throw RecirculationServiceErrors.jsonDecodingFailure + throw MoreAppsServiceErrors.jsonDecodingFailure } } @@ -133,7 +133,7 @@ struct AppsPlusRepository: RecirculationRepositoryProtocol { /// Returns from the cache directory the content previously picked from AppsPlus backend, or nil if error occured /// - Returns RecirculationAppsList? - private func cachedList(for request: URLRequest) -> RecirculationAppsList? { + private func cachedList(for request: URLRequest) -> MoreAppsAppsList? { guard let cachedResponse = cache.cachedResponse(for: request) else { ODSLogger.debug("No cache is available for this request") return nil @@ -142,10 +142,10 @@ struct AppsPlusRepository: RecirculationRepositoryProtocol { do { let appsPlusAppsList: AppsPlusListDTO = try JSONDecoder().decode(AppsPlusDTO.self, from: cachedResponse.data).items[0] ODSLogger.debug("Got data from AppsPlus service with \(appsPlusAppsList.apps.count) apps and \(appsPlusAppsList.sections.count) sections") - let mapper = AppsPlusRecirculationMapper() - let recirculationApps = mapper.appsDetails(from: appsPlusAppsList) - let recirculationSections = mapper.appsSections(from: appsPlusAppsList) - return RecirculationAppsList(sections: recirculationSections, apps: recirculationApps) + let mapper = AppsPlusToMoreAppsMapper() + let apps = mapper.appsDetails(from: appsPlusAppsList) + let sections = mapper.appsSections(from: appsPlusAppsList) + return MoreAppsAppsList(sections: sections, apps: apps) } catch { ODSLogger.error("(ノಠ益ಠ)ノ彡┻━┻ Failed to decode AppsPlus JSON data in cache: '\(error.localizedDescription)'") return nil diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Data/AppsPlusRecirculationMapper.swift b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Data/AppsPlusToMoreAppsMapper.swift similarity index 61% rename from OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Data/AppsPlusRecirculationMapper.swift rename to OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Data/AppsPlusToMoreAppsMapper.swift index 7c869dfa..2ff66799 100644 --- a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Data/AppsPlusRecirculationMapper.swift +++ b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Data/AppsPlusToMoreAppsMapper.swift @@ -14,23 +14,22 @@ import Foundation /// Helps to convert _data transfert objects_ picked from _AppsPlus_ backend to _business objects_ for the ODS modules. -struct AppsPlusRecirculationMapper { +struct AppsPlusToMoreAppsMapper { - func appsSections(from appsList: AppsPlusListDTO) -> [RecirculationAppsListSection] { + func appsSections(from appsList: AppsPlusListDTO) -> [MoreAppsAppsListSection] { appsList.sections.map { appsSection(from: $0) } } - func appsDetails(from appsList: AppsPlusListDTO) -> [RecirculationAppDetails] { + func appsDetails(from appsList: AppsPlusListDTO) -> [MoreAppsAppDetails] { appsList.apps.map { appDetails(from: $0) } } - func appsSection(from section: AppsPlusSectionDTO) -> RecirculationAppsListSection { - RecirculationAppsListSection(description: section.description, - apps: section.apps.map { appDetails(from: $0) }) + func appsSection(from section: AppsPlusSectionDTO) -> MoreAppsAppsListSection { + MoreAppsAppsListSection(description: section.description, apps: section.apps.map { appDetails(from: $0) }) } - func appDetails(from details: AppsPlusAppDetailsDTO) -> RecirculationAppDetails { - RecirculationAppDetails(title: details.title, + func appDetails(from details: AppsPlusAppDetailsDTO) -> MoreAppsAppDetails { + MoreAppsAppDetails(title: details.title, iconURL: URL(string: details.iconURL), description: details.description.isEmpty ? nil : details.description, storeURL: URL(string: details.storeLink)) diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Data/LocalAppsPlusRepository.swift b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Data/LocalAppsPlusRepository.swift similarity index 72% rename from OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Data/LocalAppsPlusRepository.swift rename to OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Data/LocalAppsPlusRepository.swift index 130ae6cf..0ca9484c 100644 --- a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Data/LocalAppsPlusRepository.swift +++ b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Data/LocalAppsPlusRepository.swift @@ -14,7 +14,7 @@ import Foundation /// Parses local JSON data from file, supposing to be Apps Plus data -struct LocalAppsPlusRepository: RecirculationRepositoryProtocol { +struct LocalAppsPlusRepository: MoreAppsRepositoryProtocol { // ======================= // MARK: Stored properties @@ -36,17 +36,17 @@ struct LocalAppsPlusRepository: RecirculationRepositoryProtocol { // MARK: MoreAppsRepositoryProtocol - Impl // ======================================= - func availableAppsList() async throws -> RecirculationAppsList { + func availableAppsList() async throws -> MoreAppsAppsList { do { let rawData = try Data(contentsOf: feedURL) let appsPlusAppsList: AppsPlusListDTO = try JSONDecoder().decode(AppsPlusDTO.self, from: rawData).items[0] - let mapper = AppsPlusRecirculationMapper() - let recirculationApps = mapper.appsDetails(from: appsPlusAppsList) - let recirculationSections = mapper.appsSections(from: appsPlusAppsList) - return RecirculationAppsList(sections: recirculationSections, apps: recirculationApps) + let mapper = AppsPlusToMoreAppsMapper() + let apps = mapper.appsDetails(from: appsPlusAppsList) + let sections = mapper.appsSections(from: appsPlusAppsList) + return MoreAppsAppsList(sections: sections, apps: apps) } catch { ODSLogger.error("(ノಠ益ಠ)ノ彡┻━┻ Failed to decode local AppsPlus file: '\(error.localizedDescription)'") - throw RecirculationServiceErrors.jsonDecodingFailure + throw MoreAppsServiceErrors.jsonDecodingFailure } } } diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Data/RecirculationRepositoryProtocol.swift b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Data/MoreAppsRepositoryProtocol.swift similarity index 85% rename from OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Data/RecirculationRepositoryProtocol.swift rename to OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Data/MoreAppsRepositoryProtocol.swift index 828bb4f0..4209283f 100644 --- a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Data/RecirculationRepositoryProtocol.swift +++ b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Data/MoreAppsRepositoryProtocol.swift @@ -14,8 +14,8 @@ import Foundation /// Abstraction layer if in the future another data feed will be used to get other available apps. -protocol RecirculationRepositoryProtocol { +protocol MoreAppsRepositoryProtocol { /// Supposed to be async method to return the apps lists or to throw some error - func availableAppsList() async throws -> RecirculationAppsList + func availableAppsList() async throws -> MoreAppsAppsList } diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Domain/RecirculationService.swift b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Domain/MoreAppsService.swift similarity index 63% rename from OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Domain/RecirculationService.swift rename to OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Domain/MoreAppsService.swift index 0218976f..96edc664 100644 --- a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Domain/RecirculationService.swift +++ b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Domain/MoreAppsService.swift @@ -13,12 +13,12 @@ import Foundation -// ==================================== -// MARK: - Recirculation Service Errors -// ==================================== +// =============================== +// MARK: - MoreApps Service Errors +// =============================== /// Errors which can occur in repository or service layers and should be managed upside -enum RecirculationServiceErrors: Error { +enum MoreAppsServiceErrors: Error { /// Prerequisites are not fullfilled to request the feeder service case badConfigurationPrerequisites /// Some issue occured with session or network requests, and no cache can be used @@ -27,21 +27,21 @@ enum RecirculationServiceErrors: Error { case jsonDecodingFailure } -// ============================= -// MARK: - Recirculation Service -// ============================= +// ======================== +// MARK: - MoreApps Service +// ======================== /// Helps to test or use some data feeds to get available apps details -struct RecirculationService: RecirculationServiceProtocol { - private let repository: RecirculationRepositoryProtocol +struct MoreAppsService: MoreAppsServiceProtocol { + private let repository: MoreAppsRepositoryProtocol - init(repository: RecirculationRepositoryProtocol) { + init(repository: MoreAppsRepositoryProtocol) { self.repository = repository } - /// Creates the URL to use to get data feed, then through the `RecirculationRepositoryProtocol` request data - /// - Returns `RecirculationAppsList`: The parsed business objects - func availableAppsList() async throws -> RecirculationAppsList { + /// Creates the URL to use to get data feed, then through the `MoreAppsRepositoryProtocol` request data + /// - Returns `MoreAppsAppsList`: The parsed business objects + func availableAppsList() async throws -> MoreAppsAppsList { try await repository.availableAppsList() } } diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Domain/RecirculationServiceBO.swift b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Domain/MoreAppsServiceBO.swift similarity index 63% rename from OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Domain/RecirculationServiceBO.swift rename to OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Domain/MoreAppsServiceBO.swift index bb17f92c..b89d8f77 100644 --- a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Domain/RecirculationServiceBO.swift +++ b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Domain/MoreAppsServiceBO.swift @@ -13,52 +13,52 @@ import Foundation -// =============================== -// MARK: - Recirculation Apps List -// =============================== +// ========================== +// MARK: - MoreApps Apps List +// ========================== -/// Business object to gather both sections and apps ready to use for the _Recirculation module_ -struct RecirculationAppsList { +/// Business object to gather both sections and apps ready to use for the _MoreApps module_ +struct MoreAppsAppsList { /// All available sections of apps - let sections: [RecirculationAppsListSection] + let sections: [MoreAppsAppsListSection] /// All available apps without associated sections - let apps: [RecirculationAppDetails] + let apps: [MoreAppsAppDetails] } -extension RecirculationAppsList { +extension MoreAppsAppsList { /// Returns a fresh new object without any sections anymore but with all apps of all sections add in the_apps_. /// Order of apps is based on order of previous sections. - /// - Returns MoreAppsList: Flattened version without changing `self` - func flattened() -> RecirculationAppsList { + /// - Returns MoreAppsAppsList: Flattened version without changing `self` + func flattened() -> MoreAppsAppsList { var flattenedApps = apps sections.forEach { flattenedApps.append(contentsOf: $0.apps) } - return RecirculationAppsList(sections: [], apps: flattenedApps) + return MoreAppsAppsList(sections: [], apps: flattenedApps) } } // ================================== -// MARK: - Recirculation Apps Section +// MARK: - MoreApps Apps List Section // ================================== -/// Business object to gather a group of apps behind a description ready to use for the _Recirculation module_ -struct RecirculationAppsListSection { +/// Business object to gather a group of apps behind a description ready to use for the _MoreApps module_ +struct MoreAppsAppsListSection { /// Some description for a section, e.g. "customer" or "business" let description: String /// All the apps for this section - let apps: [RecirculationAppDetails] + let apps: [MoreAppsAppDetails] } -extension RecirculationAppsListSection: Hashable {} +extension MoreAppsAppsListSection: Hashable {} -// ================================= -// MARK: - Recirculation App Details -// ================================= +// ============================= +// MARK: - MoreApps Apps Details +// ============================= -/// Business object modelizing details of an app ready to use for the _Recirculation module_ -struct RecirculationAppDetails { +/// Business object modelizing details of an app ready to use for the _MoreApps module_ +struct MoreAppsAppDetails { /// Commercial title of the app let title: String /// URL to use to load the icon of the app @@ -69,4 +69,4 @@ struct RecirculationAppDetails { let storeURL: URL? } -extension RecirculationAppDetails: Hashable {} +extension MoreAppsAppDetails: Hashable {} diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Domain/RecirculationServiceProtocol.swift b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Domain/MoreAppsServiceProtocol.swift similarity index 72% rename from OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Domain/RecirculationServiceProtocol.swift rename to OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Domain/MoreAppsServiceProtocol.swift index 1945d1bb..4799c613 100644 --- a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/Domain/RecirculationServiceProtocol.swift +++ b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/Domain/MoreAppsServiceProtocol.swift @@ -13,11 +13,11 @@ import Foundation -protocol RecirculationServiceProtocol { +protocol MoreAppsServiceProtocol { /// - Parameter repository: The object to use to get the raw data from a feeder - init(repository: RecirculationRepositoryProtocol) + init(repository: MoreAppsRepositoryProtocol) - /// Supposed to be async method to return the apps lists or to throw some error, using the given `RecirculationRepositoryProtocol` - func availableAppsList() async throws -> RecirculationAppsList + /// Supposed to be async method to return the apps lists or to throw some error, using the given `MoreAppsRepositoryProtocol` + func availableAppsList() async throws -> MoreAppsAppsList } diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/ODSRecirculationModel.swift b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/ODSMoreAppsModel.swift similarity index 73% rename from OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/ODSRecirculationModel.swift rename to OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/ODSMoreAppsModel.swift index f429d775..61ec0ddc 100644 --- a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/ODSRecirculationModel.swift +++ b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/ODSMoreAppsModel.swift @@ -15,34 +15,34 @@ import Combine import Foundation import SwiftUI -// ================================ -// MARK: - Recirculation View Model -// ================================ +// =========================== +// MARK: - MoreApps View Model +// =========================== @MainActor -final class ODSRecirculationModel: ObservableObject { +final class ODSMoreAppsModel: ObservableObject { // ======================= // MARK: Stored Properties // ======================= - private let service: RecirculationService + private let service: MoreAppsService private let flattenApps: Bool private let cacheAppsIcons: Bool - @Published var loadingState: LoadingState + @Published var loadingState: LoadingState // ================= // MARK: Initializer // ================= - init(dataSource: ODSRecirculationDataSource, flattenApps: Bool, cacheAppsIcons: Bool) { + init(dataSource: ODSMoreAppsDataSource, flattenApps: Bool, cacheAppsIcons: Bool) { switch dataSource { case let .remote(feedURL): ODSLogger.info("AppsPlus backend will be requested to get apps to display") - service = RecirculationService(repository: AppsPlusRepository(feedURL: feedURL)) + service = MoreAppsService(repository: AppsPlusRepository(feedURL: feedURL)) case let .local(filePath): ODSLogger.info("Local data based on AppsPlus dump will be used to display apps") - service = RecirculationService(repository: LocalAppsPlusRepository(feedURL: filePath)) + service = MoreAppsService(repository: LocalAppsPlusRepository(feedURL: filePath)) } self.flattenApps = flattenApps self.cacheAppsIcons = cacheAppsIcons @@ -66,8 +66,8 @@ final class ODSRecirculationModel: ObservableObject { let appsList = try await service.availableAppsList() loadingState = .loaded(flattenApps ? appsList.flattened() : appsList) } catch { - if let appsRecirculationError = error as? ODSRecirculationModel.Error { - loadingState = .error(appsRecirculationError) + if let moreAppsError = error as? ODSMoreAppsModel.Error { + loadingState = .error(moreAppsError) } else { loadingState = .error(.unknownError) } diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/ODSRecirculationView.swift b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/ODSMoreAppsView.swift similarity index 84% rename from OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/ODSRecirculationView.swift rename to OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/ODSMoreAppsView.swift index ed576cc8..3bc6e833 100644 --- a/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/Recirculation/ODSRecirculationView.swift +++ b/OrangeDesignSystem/Sources/OrangeDesignSystem/Modules/MoreApps/ODSMoreAppsView.swift @@ -18,7 +18,7 @@ import SwiftUI // ============== /// The source of data the module must use to get all available apps -public enum ODSRecirculationDataSource { +public enum ODSMoreAppsDataSource { /// Fetch some backend available at `url` with sufficient `URL` for data retrievement case remote(url: URL) @@ -27,14 +27,14 @@ public enum ODSRecirculationDataSource { } /// The view displaying the available apps in a list -public struct ODSRecirculationView: View { +public struct ODSMoreAppsView: View { // ======================= // MARK: Stored properties // ======================= private let enableHaptics: Bool - @StateObject private var viewModel: ODSRecirculationModel + @StateObject private var viewModel: ODSMoreAppsModel @AccessibilityFocusState private var requestFocus: Focusable? @Environment(\.openURL) private var openURL @Environment(\.theme) private var theme @@ -43,12 +43,12 @@ public struct ODSRecirculationView: View { // MARK: Initializers // ================== - public init(dataSource: ODSRecirculationDataSource, + public init(dataSource: ODSMoreAppsDataSource, flattenApps: Bool, cacheAppsIcons: Bool, enableHaptics: Bool) { self.enableHaptics = enableHaptics - _viewModel = StateObject(wrappedValue: ODSRecirculationModel(dataSource: dataSource, flattenApps: flattenApps, cacheAppsIcons: cacheAppsIcons)) + _viewModel = StateObject(wrappedValue: ODSMoreAppsModel(dataSource: dataSource, flattenApps: flattenApps, cacheAppsIcons: cacheAppsIcons)) } // ========== @@ -90,22 +90,22 @@ public struct ODSRecirculationView: View { private func loadingView() -> some View { ODSEmptyStateView( - title: Text(°°"modules.recirculation.loading.title"), - text: Text(°°"modules.recirculation.loading.text"), - image: theme.emptyStateImages.userCleared + title: Text(°°"modules.moreApps.loading.title"), + text: Text(°°"modules.moreApps.loading.text"), + image: Image("il_emptyStateUserCleared", bundle: theme.bundle) ) } private func errorView() -> some View { ODSEmptyStateView( - title: Text(°°"modules.recirculation.error.title"), - text: Text(°°"modules.recirculation.error.text"), - image: theme.emptyStateImages.error + title: Text(°°"modules.moreApps.error.title"), + text: Text(°°"modules.moreApps.error.text"), + image: Image("il_emptyStateError", bundle: theme.bundle) ) } @ViewBuilder - private func loadedView(_ appsList: RecirculationAppsList) -> some View { + private func loadedView(_ appsList: MoreAppsAppsList) -> some View { List { if appsList.sections.isEmpty { ForEach(appsList.apps, id: \.self) { app in @@ -117,7 +117,7 @@ public struct ODSRecirculationView: View { listItem(for: app).odsListItemStyle() } } header: { - Text("modules.recirculation.uncategorized_apps".🌐) + Text("modules.moreApps.uncategorized_apps".🌐) .accessibilityFocused($requestFocus, equals: .uncategorizedAppsSection) } @@ -141,7 +141,7 @@ public struct ODSRecirculationView: View { } @ViewBuilder - private func listItem(for section: RecirculationAppsListSection) -> some View { + private func listItem(for section: MoreAppsAppsListSection) -> some View { Section { ForEach(section.apps, id: \.self) { app in listItem(for: app).odsListItemStyle() @@ -152,11 +152,11 @@ public struct ODSRecirculationView: View { } @ViewBuilder - private func listItem(for app: RecirculationAppDetails) -> some View { + private func listItem(for app: MoreAppsAppDetails) -> some View { let item = ODSListItem(title: Text(app.title), subtitle: app.description != nil ? Text(app.description!) : nil, + subtitleNumberOfLines: .two, leading: leadingAppIcon(from: app)) - .lineLimit(3) // 3 lines asked .accessibilityChildren { Text(app.title) if let description = app.description { @@ -193,7 +193,7 @@ public struct ODSRecirculationView: View { } } - private func leadingAppIcon(from appDetails: RecirculationAppDetails) -> ODSListItem.Leading? { + private func leadingAppIcon(from appDetails: MoreAppsAppDetails) -> ODSListItem.Leading? { guard let appIconUrl = appDetails.iconURL else { return nil } @@ -206,7 +206,7 @@ public struct ODSRecirculationView: View { Button { openURL(storeURL) } label: { - Text("modules.recirculation.go_to_appstore".🌐) + Text("modules.moreApps.go_to_appstore".🌐) } } } diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Resources/Base.lproj/Localizable.strings b/OrangeDesignSystem/Sources/OrangeDesignSystem/Resources/Base.lproj/Localizable.strings index cfcbdb1d..f66484b8 100644 --- a/OrangeDesignSystem/Sources/OrangeDesignSystem/Resources/Base.lproj/Localizable.strings +++ b/OrangeDesignSystem/Sources/OrangeDesignSystem/Resources/Base.lproj/Localizable.strings @@ -28,18 +28,18 @@ "modules.about.copyright" = "Orange property. All rights reserved"; "modules.about.app_news.no_news" = "No App news found in file"; "modules.about.error.generic_message" = "Something goes wrong"; -"modules.about.recirculation.title" = "Recirculation"; +"modules.about.moreApps.title" = "More Apps"; -// ============================ -// MARK: - Recirculation module -// ============================ +// ======================= +// MARK: - MoreApps module +// ======================= -"modules.recirculation.uncategorized_apps" = "Uncategorized apps"; -"modules.recirculation.go_to_appstore" = "Open in App Store"; -"modules.recirculation.loading.title" = "Loading"; -"modules.recirculation.loading.text" = "Waiting for fresh data\U2026"; -"modules.recirculation.error.title" = "Error"; -"modules.recirculation.error.text" = "Something wrong happened, sorry!"; +"modules.moreApps.uncategorized_apps" = "Uncategorized apps"; +"modules.moreApps.go_to_appstore" = "Open in App Store"; +"modules.moreApps.loading.title" = "Loading"; +"modules.moreApps.loading.text" = "Waiting for fresh data\U2026"; +"modules.moreApps.error.title" = "Error"; +"modules.moreApps.error.text" = "Something wrong happened, sorry!"; // ============ // MARK: - A11Y diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Theme/ODSTheme.swift b/OrangeDesignSystem/Sources/OrangeDesignSystem/Theme/ODSTheme.swift index bb255f46..1a99df53 100644 --- a/OrangeDesignSystem/Sources/OrangeDesignSystem/Theme/ODSTheme.swift +++ b/OrangeDesignSystem/Sources/OrangeDesignSystem/Theme/ODSTheme.swift @@ -19,25 +19,6 @@ import SwiftUI public typealias ODSColorPalette = [ODSColorDecription] -// ==================================== -// MARK: - ODS Theme Empty State Images -// ==================================== - -/// Wraps the images the __ ODS Empty State__ module must use -public struct ODSThemeEmptyStateImages { - let error: Image - let firstUse: Image - let noData: Image - let userCleared: Image - - public init(error: Image, firstUse: Image, noData: Image, userCleared: Image) { - self.error = error - self.firstUse = firstUse - self.noData = noData - self.userCleared = userCleared - } -} - // ================= // MARK: - ODS Theme // ================= @@ -54,7 +35,6 @@ public struct ODSTheme: Identifiable, Hashable { public var colorPalette: ODSColorPalette public var componentColors: ODSComponentColors public var font: (_ style: ODSFontStyle) -> Font - public var emptyStateImages: ODSThemeEmptyStateImages public var bundle: Bundle // ================== @@ -97,11 +77,6 @@ public struct ODSTheme: Identifiable, Hashable { } } - emptyStateImages = ODSThemeEmptyStateImages(error: Image("il_emptyStateUserCleared", bundle: Bundle.ods), - firstUse: Image("il_emptyStateUserCleared", bundle: Bundle.ods), - noData: Image("il_emptyStateUserCleared", bundle: Bundle.ods), - userCleared: Image("il_emptyStateUserCleared", bundle: Bundle.ods)) - bundle = Bundle.ods } diff --git a/OrangeDesignSystemDemo/.xcode-version b/OrangeDesignSystemDemo/.xcode-version deleted file mode 100644 index dafb659a..00000000 --- a/OrangeDesignSystemDemo/.xcode-version +++ /dev/null @@ -1 +0,0 @@ -15.2 diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo.xcodeproj/project.pbxproj b/OrangeDesignSystemDemo/OrangeDesignSystemDemo.xcodeproj/project.pbxproj index 4e1f45ff..785a3659 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo.xcodeproj/project.pbxproj +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo.xcodeproj/project.pbxproj @@ -21,9 +21,9 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ - 071F1CF02B7BC69D00833A33 /* RecirculationModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 071F1CEF2B7BC69D00833A33 /* RecirculationModule.swift */; }; - 071F1CF22B7BC6AE00833A33 /* RecirculationModuleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 071F1CF12B7BC6AE00833A33 /* RecirculationModuleModel.swift */; }; - 071F1CF42B7BC6BC00833A33 /* RecirculationModuleDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 071F1CF32B7BC6BC00833A33 /* RecirculationModuleDemo.swift */; }; + 071F1CF02B7BC69D00833A33 /* MoreAppsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 071F1CEF2B7BC69D00833A33 /* MoreAppsModule.swift */; }; + 071F1CF22B7BC6AE00833A33 /* MoreAppsModuleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 071F1CF12B7BC6AE00833A33 /* MoreAppsModuleModel.swift */; }; + 071F1CF42B7BC6BC00833A33 /* MoreAppsModuleDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 071F1CF32B7BC6BC00833A33 /* MoreAppsModuleDemo.swift */; }; 071F1CF82B7E46C100833A33 /* AccessibilityStatement.xml in Resources */ = {isa = PBXBuildFile; fileRef = 071F1CF72B7E46C100833A33 /* AccessibilityStatement.xml */; }; 072D9EF82B0CA96A00763EAE /* ChoiceChipsVariant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 072D9EF72B0CA96A00763EAE /* ChoiceChipsVariant.swift */; }; 074741EB2B74CE0B00D74F00 /* EmptyStateModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 074741EA2B74CE0B00D74F00 /* EmptyStateModule.swift */; }; @@ -132,6 +132,7 @@ 513DC6952B1F4627001F86A6 /* MockURLAndResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513DC6942B1F4627001F86A6 /* MockURLAndResponse.swift */; }; 513DC6992B1F511B001F86A6 /* AppsPlusCache.json in Resources */ = {isa = PBXBuildFile; fileRef = 513DC6982B1F511B001F86A6 /* AppsPlusCache.json */; }; 5166D4372B18991C0021600D /* MoreAppsServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5166D4362B18991C0021600D /* MoreAppsServiceTests.swift */; }; + 516DA7862BB6BC1C00A864DA /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 516DA7852BB6BC1C00A864DA /* PrivacyInfo.xcprivacy */; }; 518C3BDC2B5699B00003B76E /* MoreAppsBOTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518C3BDB2B5699B00003B76E /* MoreAppsBOTests.swift */; }; 51A08F332B1637E900C14C86 /* ArrayExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A08F322B1637E900C14C86 /* ArrayExtensionTests.swift */; }; 51A08F352B163A3A00C14C86 /* ODSAboutListItemPriorityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A08F342B163A3A00C14C86 /* ODSAboutListItemPriorityTests.swift */; }; @@ -170,9 +171,11 @@ /* Begin PBXFileReference section */ 021ED547747F959E94B4EA22 /* Pods-OrangeDesignSystemDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OrangeDesignSystemDemo.release.xcconfig"; path = "Target Support Files/Pods-OrangeDesignSystemDemo/Pods-OrangeDesignSystemDemo.release.xcconfig"; sourceTree = ""; }; 070E3C012B6152F3008A8856 /* .xcode-version */ = {isa = PBXFileReference; lastKnownFileType = text; path = ".xcode-version"; sourceTree = ""; }; - 071F1CEF2B7BC69D00833A33 /* RecirculationModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecirculationModule.swift; sourceTree = ""; }; - 071F1CF12B7BC6AE00833A33 /* RecirculationModuleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecirculationModuleModel.swift; sourceTree = ""; }; - 071F1CF32B7BC6BC00833A33 /* RecirculationModuleDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecirculationModuleDemo.swift; sourceTree = ""; }; + 071B009F2C78820100C31A3E /* DEVELOP.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = DEVELOP.md; path = ../.github/DEVELOP.md; sourceTree = ""; }; + 071B00A02C78820100C31A3E /* CONTRIBUTING.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = CONTRIBUTING.md; path = ../.github/CONTRIBUTING.md; sourceTree = ""; }; + 071F1CEF2B7BC69D00833A33 /* MoreAppsModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoreAppsModule.swift; sourceTree = ""; }; + 071F1CF12B7BC6AE00833A33 /* MoreAppsModuleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoreAppsModuleModel.swift; sourceTree = ""; }; + 071F1CF32B7BC6BC00833A33 /* MoreAppsModuleDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoreAppsModuleDemo.swift; sourceTree = ""; }; 071F1CF72B7E46C100833A33 /* AccessibilityStatement.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = AccessibilityStatement.xml; path = OrangeDesignSystemDemo/Resources/AccessibilityStatement.xml; sourceTree = ""; }; 07210C402A8FAC6500507988 /* THIRD-PARTY.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = "THIRD-PARTY.md"; path = "../THIRD-PARTY.md"; sourceTree = ""; }; 07210C412A8FAC6500507988 /* NOTICE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = NOTICE.txt; path = ../NOTICE.txt; sourceTree = ""; }; @@ -269,7 +272,6 @@ 079DDC0B2AE6A18D0073A542 /* Recipe+id.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Recipe+id.swift"; sourceTree = ""; }; 07AA3D4D28AE8B160001B75E /* Pods_OrangeDesignSystemDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Pods_OrangeDesignSystemDemo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 07B030592AB0B454001764E7 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - 07B0305A2AB0B4A9001764E7 /* CONTRIBUTING.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = CONTRIBUTING.md; path = ../CONTRIBUTING.md; sourceTree = ""; }; 07B1A09B2B1E191F00ABF0A1 /* InputChipsVariant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputChipsVariant.swift; sourceTree = ""; }; 07B543E62B289B2000A2B6ED /* ListItemSelectionVariantModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListItemSelectionVariantModel.swift; sourceTree = ""; }; 07B94DE82AD9239700AAD1A5 /* ListItemStandardVariantOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListItemStandardVariantOptions.swift; sourceTree = ""; }; @@ -294,6 +296,7 @@ 51664B4E2AEADEFC00E92F83 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = Base; path = Base.lproj/PrivacyNotice.html; sourceTree = ""; }; 5166D4362B18991C0021600D /* MoreAppsServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoreAppsServiceTests.swift; sourceTree = ""; }; 5166FE852AE9669A0038A4AE /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = OrangeDesignSystemDemo/Resources/en.lproj/Localizable.strings; sourceTree = ""; }; + 516DA7852BB6BC1C00A864DA /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 518C3BDB2B5699B00003B76E /* MoreAppsBOTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoreAppsBOTests.swift; sourceTree = ""; }; 51A08F322B1637E900C14C86 /* ArrayExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayExtensionTests.swift; sourceTree = ""; }; 51A08F342B163A3A00C14C86 /* ODSAboutListItemPriorityTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ODSAboutListItemPriorityTests.swift; sourceTree = ""; }; @@ -350,14 +353,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 071F1CEE2B7BC63700833A33 /* Recirculation */ = { + 071F1CEE2B7BC63700833A33 /* MoreApps */ = { isa = PBXGroup; children = ( - 071F1CEF2B7BC69D00833A33 /* RecirculationModule.swift */, - 071F1CF12B7BC6AE00833A33 /* RecirculationModuleModel.swift */, - 071F1CF32B7BC6BC00833A33 /* RecirculationModuleDemo.swift */, + 071F1CEF2B7BC69D00833A33 /* MoreAppsModule.swift */, + 071F1CF12B7BC6AE00833A33 /* MoreAppsModuleModel.swift */, + 071F1CF32B7BC6BC00833A33 /* MoreAppsModuleDemo.swift */, ); - path = Recirculation; + path = MoreApps; sourceTree = ""; }; 07210C342A8FA6BC00507988 /* 🛠 */ = { @@ -367,11 +370,12 @@ 07210C472A8FAD0000507988 /* Fastlane */, F913B86227679A13001CB0AA /* Scripts */, 07210C462A8FACAA00507988 /* LICENSE */, + 071B00A02C78820100C31A3E /* CONTRIBUTING.md */, + 071B009F2C78820100C31A3E /* DEVELOP.md */, 07210C412A8FAC6500507988 /* NOTICE.txt */, 07210C422A8FAC6500507988 /* README.md */, 07210C402A8FAC6500507988 /* THIRD-PARTY.md */, FDDAB0F62809AB2100ACE5F4 /* CHANGELOG.md */, - 07B0305A2AB0B4A9001764E7 /* CONTRIBUTING.md */, ); name = "🛠"; sourceTree = ""; @@ -713,7 +717,7 @@ 077C38402A9DDC79003D6B51 /* Modules */ = { isa = PBXGroup; children = ( - 071F1CEE2B7BC63700833A33 /* Recirculation */, + 071F1CEE2B7BC63700833A33 /* MoreApps */, 074741E92B74CDEA00D74F00 /* EmptyState */, 07E4C85A2AE7BBE900FB4DAC /* Lists */, 0753267E2AD00137003D8832 /* CardListAndCollection */, @@ -955,6 +959,7 @@ EB0AA527275652AE0012E192 = { isa = PBXGroup; children = ( + 516DA7852BB6BC1C00A864DA /* PrivacyInfo.xcprivacy */, 51E547A82B98DEDB00CAEF31 /* Settings.bundle */, 07210C342A8FA6BC00507988 /* 🛠 */, F99FF06D2767ADF0006236A0 /* OrangeDesignSystemDemo */, @@ -1104,6 +1109,7 @@ 51F90B1B2ADED756007AAA45 /* Localizable.strings in Resources */, 5107F55E2AE11BDD00D4D01F /* AppNews.json in Resources */, 5107F5622AE1209A00D4D01F /* PrivacyNotice.html in Resources */, + 516DA7862BB6BC1C00A864DA /* PrivacyInfo.xcprivacy in Resources */, 071F1CF82B7E46C100833A33 /* AccessibilityStatement.xml in Resources */, 51E547A92B98DEDB00CAEF31 /* Settings.bundle in Resources */, 077C37D32A9DD643003D6B51 /* Recipes.json in Resources */, @@ -1303,7 +1309,7 @@ 077C387D2A9DDC79003D6B51 /* ColorUsage.swift in Sources */, 077C38822A9DDC79003D6B51 /* SpacingsPage.swift in Sources */, 077C384A2A9DDC79003D6B51 /* CustomizableVariant.swift in Sources */, - 071F1CF42B7BC6BC00833A33 /* RecirculationModuleDemo.swift in Sources */, + 071F1CF42B7BC6BC00833A33 /* MoreAppsModuleDemo.swift in Sources */, 077C389B2A9DEEDC003D6B51 /* RecipesBook.swift in Sources */, 079DDC0C2AE6A18D0073A542 /* Recipe+id.swift in Sources */, 077C38802A9DDC79003D6B51 /* TypographyPage.swift in Sources */, @@ -1337,7 +1343,7 @@ 07B94E0B2AD98D7900AAD1A5 /* ListItemStandardVariant.swift in Sources */, 077C37E62A9DDC1A003D6B51 /* MainTabView.swift in Sources */, 077C385D2A9DDC79003D6B51 /* ActivityIndicatorVariant.swift in Sources */, - 071F1CF02B7BC69D00833A33 /* RecirculationModule.swift in Sources */, + 071F1CF02B7BC69D00833A33 /* MoreAppsModule.swift in Sources */, 077C38612A9DDC79003D6B51 /* CardExampleData.swift in Sources */, 077C384D2A9DDC79003D6B51 /* ComponentsList.swift in Sources */, 077C38512A9DDC79003D6B51 /* CapitalizedTextInputsVariant.swift in Sources */, @@ -1349,7 +1355,7 @@ 077C389C2A9DEEDC003D6B51 /* RecipesLoader.swift in Sources */, 077C38742A9DDC79003D6B51 /* SliderComponent.swift in Sources */, 07C3C7FC2AE7E4E000833957 /* ListModuleDataModel.swift in Sources */, - 071F1CF22B7BC6AE00833A33 /* RecirculationModuleModel.swift in Sources */, + 071F1CF22B7BC6AE00833A33 /* MoreAppsModuleModel.swift in Sources */, 077C389A2A9DEEDC003D6B51 /* RecipeBookModel.swift in Sources */, F99FF0732767AE2A006236A0 /* OrangeDesignSystemApp.swift in Sources */, 077C38502A9DDC79003D6B51 /* EmphasisAndFunctionnalVariant.swift in Sources */, @@ -1573,7 +1579,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1709748064; + CURRENT_PROJECT_VERSION = 1709893073; DEVELOPMENT_ASSET_PATHS = "\"OrangeDesignSystemDemo/Resources/Preview Content\""; DEVELOPMENT_TEAM = MG2LSJNJB6; ENABLE_PREVIEWS = YES; @@ -1590,7 +1596,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.0; + MARKETING_VERSION = 1.2.0; PRODUCT_BUNDLE_IDENTIFIER = "soft.cocoa.ods-ios-demo.dev"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1610,7 +1616,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1709748064; + CURRENT_PROJECT_VERSION = 1709893073; DEVELOPMENT_ASSET_PATHS = "\"OrangeDesignSystemDemo/Resources/Preview Content\""; DEVELOPMENT_TEAM = MG2LSJNJB6; ENABLE_PREVIEWS = YES; @@ -1627,7 +1633,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.0; + MARKETING_VERSION = 1.2.0; PRODUCT_BUNDLE_IDENTIFIER = "soft.cocoa.ods-ios-demo.dev"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "ods-demo-app-appstore-qualif"; diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/AccessibilityStatement.xml b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/AccessibilityStatement.xml index 1135a4cd..5b68d4a4 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/AccessibilityStatement.xml +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/AccessibilityStatement.xml @@ -15,7 +15,7 @@ This declaration was done in this language: --> en - - The Orange Group Accessibility Skill Centre - -The Orange Group Accessibility Skill Centre

+ The Orange Group Accessibility Skills Center + +The Orange Group Accessibility Skills Center

]]>
@@ -50,12 +50,12 @@ Content: usefull for additional information like a postal address for example. T - Orange Group - -We welcome your feedback on the accessibility of this site. Please let us know if you encounter accessibility problems by sending an email to accessibility.group@orange.com.

+ Équipe Projet + +We welcome your feedback on the accessibility of this site. Please let us know if you encounter accessibility problems by sending an email to XXX@orange.com.

]]>
@@ -64,7 +64,7 @@ Content: full contact informations. This is CDATA-protected, please add properly AUDIT DATE Format: YYYY-MM-DD --> -2024-03-01 +2024-02-29 [Name of the organization] undertakes to make its websites internet, intranet, extranet and its mobile applications accessible in accordance with article 47 of Law No. 2005-102 of February 11, 2005.

@@ -88,17 +88,17 @@ Plan: Paragraph for the digital accessibility plan. This is CDATA-protected, ple REFERENTIAL USED --> - WCAG - 2.2 - AA - https://www.w3.org/Translations/WCAG20-fr/ + WCAG + 2.2 + AA + https://www.w3.org/Translations/WCAG20-fr/ - SwiftUI + SwiftUI - - Accessibility Inspector - - - - Voice Over - - - - Switch Control - - - - Keyboard navigation - - - - Colour Contrat Analyzer - - + + Accessibility Inspector + + + + Voice Over + + + + Switch Control + + + + Keyboard navigation + + + + Colour Contrat Analyzer + + @@ -145,94 +145,94 @@ This is the list of URLs that were tested This is CDATA-protected, please add properly formatted HTML. --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -261,232 +261,232 @@ and blocking points they found (if 0, the document will have to say “with no b RESULTS DETAILS --> - - 32 - 7 - 8 - 17 - 47 - + + 32 + 11 + 4 + 17 + 73 + - - 24 - 11 - 4 - 9 - 73 - + + 24 + 13 + 2 + 9 + 87 + - - 56 - 18 - 12 - 26 - 60 - + + 56 + 24 + 6 + 26 + 80 + - - - 13 - 13 - 1 - 0 - 18 - 11 - 96 + + + 13 + 13 + 0 + 0 + 19 + 11 + 100 - - 13 - 13 - 1 - 0 - 18 - 11 - 96 + + 13 + 13 + 0 + 0 + 19 + 11 + 100 - - 13 - 13 - 1 - 0 - 18 - 11 - 96 + + 13 + 13 + 0 + 0 + 19 + 11 + 100 - - 12 - 14 - 2 - 0 - 18 - 10 - 93 + + 11 + 14 + 2 + 0 + 19 + 10 + 93 - - 11 - 12 - 3 - 0 - 18 - 12 - 88 + + 13 + 12 + 0 + 0 + 19 + 12 + 100 - - 10 - 13 - 2 - 0 - 20 - 11 - 92 + + 10 + 13 + 1 + 0 + 21 + 11 + 96 - - 13 - 13 - 1 - 0 - 18 - 11 - 96 + + 13 + 13 + 0 + 0 + 19 + 11 + 100 - - 12 - 13 - 2 - 0 - 18 - 11 - 93 + + 13 + 13 + 0 + 0 + 19 + 11 + 100 - - 12 - 13 - 2 - 0 - 18 - 11 - 93 + + 13 + 13 + 0 + 0 + 19 + 11 + 100 - - 12 - 14 - 2 - 0 - 18 - 10 - 93 + + 12 + 14 + 1 + 0 + 19 + 10 + 96 - - 13 - 13 - 1 - 0 - 18 - 11 - 96 + + 13 + 13 + 0 + 0 + 19 + 11 + 100 - - 12 - 13 - 2 - 0 - 18 - 11 - 93 + + 13 + 13 + 0 + 0 + 19 + 11 + 100 - - 14 - 14 - 0 - 0 - 18 - 10 - 100 + + 14 + 14 + 0 + 0 + 18 + 10 + 100 - - 13 - 14 - 1 - 0 - 18 - 10 - 96 + + 13 + 14 + 0 + 0 + 19 + 10 + 100 - - 12 - 12 - 2 - 1 - 18 - 11 - 89 + + 13 + 13 + 0 + 0 + 19 + 11 + 100 - - 12 - 14 - 2 - 0 - 18 - 10 - 93 + + 13 + 14 + 0 + 0 + 19 + 10 + 100 - - 11 - 11 - 2 - 2 - 19 - 11 - 85 + + 11 + 11 + 1 + 2 + 20 + 11 + 88 - - 12 - 12 - 2 - 1 - 18 - 11 - 89 + + 12 + 13 + 1 + 0 + 19 + 11 + 96 - - 13 - 13 - 1 - 0 - 18 - 11 - 96 + + 13 + 13 + 0 + 0 + 19 + 11 + 100 - - 14 - 13 - 1 - 0 - 17 - 11 - 96 + + 14 + 13 + 0 + 0 + 18 + 11 + 100 - - 13 - 12 - 1 - 1 - 18 - 11 - 93 + + 13 + 13 + 0 + 0 + 19 + 11 + 100 - - 12 - 13 - 1 - 0 - 19 - 11 - 96 + + 12 + 13 + 0 + 0 + 20 + 11 + 100 @@ -494,70 +494,54 @@ Pages results details Non conformity details -->
- - 1.1.1, Non-text Content, Niveau A - - - - 1.3.1, Info and Relationships, Niveau A - - - - 1.4.1, Use of Color, Niveau A - - - - 1.4.4, Resize text, Niveau AA - - - - 1.4.10, Reflow, Niveau AA - - - - 2.1.1, Keyboard, Niveau A - - - - 2.4.2, Page Titled, Niveau A - - - - 2.4.6, Headings and Labels, Niveau AA - - - - 2.5.1, Pointer Gestures, Niveau A - - - - 2.5.3, Label in Name, Niveau A - - - - 2.5.8, Target size, Niveau AA - - - - 3.2.2, On Input, Niveau A - - + + 1.1.1, Non-text Content, Niveau A + + + + 1.4.4, Resize text, Niveau AA + + + + 1.4.10, Reflow, Niveau AA + + + + 2.1.1, Keyboard, Niveau A + + + + 2.5.1, Pointer Gestures, Niveau A + + + + 3.2.2, On Input, Niveau A + +
+ + + + + - + \ No newline at end of file diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/Contents.json b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/About/Contents.json similarity index 100% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/Contents.json rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/About/Contents.json diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/ic_folderFavourite.imageset/Contents.json b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/About/ic_folderFavourite.imageset/Contents.json similarity index 100% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/ic_folderFavourite.imageset/Contents.json rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/About/ic_folderFavourite.imageset/Contents.json diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/ic_folderFavourite.imageset/ic_folderFavourite.svg b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/About/ic_folderFavourite.imageset/ic_folderFavourite.svg similarity index 100% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/ic_folderFavourite.imageset/ic_folderFavourite.svg rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/About/ic_folderFavourite.imageset/ic_folderFavourite.svg diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/ic_subtitles.imageset/Contents.json b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/About/ic_subtitles.imageset/Contents.json similarity index 100% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/ic_subtitles.imageset/Contents.json rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/About/ic_subtitles.imageset/Contents.json diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/ic_subtitles.imageset/ic_subtitles.svg b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/About/ic_subtitles.imageset/ic_subtitles.svg similarity index 100% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/ic_subtitles.imageset/ic_subtitles.svg rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/About/ic_subtitles.imageset/ic_subtitles.svg diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/ic_tools.imageset/Contents.json b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/About/ic_tools.imageset/Contents.json similarity index 100% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/ic_tools.imageset/Contents.json rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/About/ic_tools.imageset/Contents.json diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/ic_tools.imageset/ic_tools.svg b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/About/ic_tools.imageset/ic_tools.svg similarity index 100% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/ic_tools.imageset/ic_tools.svg rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/About/ic_tools.imageset/ic_tools.svg diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_cardList (Innovation Cup).imageset/Contents.json b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_cardList (Innovation Cup).imageset/Contents.json index bc913fa7..1a1fe128 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_cardList (Innovation Cup).imageset/Contents.json +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_cardList (Innovation Cup).imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "il_card_list_generic.svg", + "filename" : "il_cardList_generic.svg", "idiom" : "universal" } ], diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_cardList (Innovation Cup).imageset/il_card_list_generic.svg b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_cardList (Innovation Cup).imageset/il_cardList_generic.svg similarity index 100% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_cardList (Innovation Cup).imageset/il_card_list_generic.svg rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_cardList (Innovation Cup).imageset/il_cardList_generic.svg diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_lists (Innovation Cup).imageset/Contents.json b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_lists (Innovation Cup).imageset/Contents.json index 426e885a..10ddf447 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_lists (Innovation Cup).imageset/Contents.json +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_lists (Innovation Cup).imageset/Contents.json @@ -2,16 +2,7 @@ "images" : [ { "filename" : "il_lists_generic.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" + "idiom" : "universal" } ], "info" : { diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_recirculation (Innovation Cup).imageset/Contents.json b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_moreApps (Innovation Cup).imageset/Contents.json similarity index 70% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_recirculation (Innovation Cup).imageset/Contents.json rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_moreApps (Innovation Cup).imageset/Contents.json index 67f9b8da..4e484adb 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_recirculation (Innovation Cup).imageset/Contents.json +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_moreApps (Innovation Cup).imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "il_recirculation_generic.svg", + "filename" : "il_moreApps_generic.svg", "idiom" : "universal" } ], diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_recirculation (Innovation Cup).imageset/il_recirculation_generic.svg b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_moreApps (Innovation Cup).imageset/il_moreApps_generic.svg similarity index 100% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_recirculation (Innovation Cup).imageset/il_recirculation_generic.svg rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Innovation Cup/il_moreApps (Innovation Cup).imageset/il_moreApps_generic.svg diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/il_about.imageset/Contents.json b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_about.imageset/Contents.json similarity index 100% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/il_about.imageset/Contents.json rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_about.imageset/Contents.json diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/il_about.imageset/il_about.svg b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_about.imageset/il_about.svg similarity index 100% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/About/il_about.imageset/il_about.svg rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_about.imageset/il_about.svg diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_cardList.imageset/Contents.json b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_cardList.imageset/Contents.json index 5425b6b1..dc56d78f 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_cardList.imageset/Contents.json +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_cardList.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "il_card_list.svg", + "filename" : "il_cardList.svg", "idiom" : "universal" } ], diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_cardList.imageset/il_card_list.svg b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_cardList.imageset/il_cardList.svg similarity index 100% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_cardList.imageset/il_card_list.svg rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_cardList.imageset/il_cardList.svg diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_recirculation.imageset/Contents.json b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_moreApps.imageset/Contents.json similarity index 74% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_recirculation.imageset/Contents.json rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_moreApps.imageset/Contents.json index aae58147..14e422ff 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_recirculation.imageset/Contents.json +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_moreApps.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "il_recirculation.svg", + "filename" : "il_moreApps.svg", "idiom" : "universal" } ], diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_recirculation.imageset/il_recirculation.svg b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_moreApps.imageset/il_moreApps.svg similarity index 100% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_recirculation.imageset/il_recirculation.svg rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Assets.xcassets/Modules/Orange/il_moreApps.imageset/il_moreApps.svg diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Base.lproj/AppNews.json b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Base.lproj/AppNews.json index 29dfbaaf..e05be9ff 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Base.lproj/AppNews.json +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Base.lproj/AppNews.json @@ -1,4 +1,9 @@ [ + { + "version": "1.2.0", + "date": "2024-08-23", + "news": "Rename the Recirculation module to MoreApps\n- Various accessibility fixes\n-Update the accessibility statement\n-Add documentation versionning" + }, { "version": "1.1.0", "date": "2024-03-08", diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Base.lproj/Localizable.strings b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Base.lproj/Localizable.strings index 506e75b2..13c61d00 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Base.lproj/Localizable.strings +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/Base.lproj/Localizable.strings @@ -92,14 +92,14 @@ "screens.guidelines.colors.title" = "Colour"; "screens.guidelines.colors.description" = "It is important to use the iOS system background colours as they are dynamic. They automatically change between the slightly darker base and slightly lighter elevated colours, in order to enhance perception of depth and layering."; -"screens.guidelines.colors.palette.title" = "Palette"; +"screens.guidelines.colors.palette.title" = "Colour palette"; "screens.guidelines.colors.color_palette.title" = "Colour palette"; "screens.guidelines.colors.color_palette.on_light" = "Light mode"; "screens.guidelines.colors.color_palette.on_dark" = "Dark mode"; "screens.guidelines.colors.description.more" = "Some colours are defined with different tints that automatically switches. For the greys, you can use the Apple System Greys. For black and white texts, use the Apple Dynamic System Colors. For more information, see [Apple Color Guidelines](https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/color/)."; "a11y.tap_twice_to_get_more" = "Tap twice to get more information"; -"a11y.color_details" = "asset name: %@, RGB value is %@ . Hex value is %@"; +"a11y.color_details" = "token name: %@, color name is %@ . Hex value is %@"; // ======================================= // MARK: - Screens - Guidelines - Spacings @@ -264,7 +264,7 @@ "screens.components.progress_indicators.title" = "Progress indicators"; "screens.components.progress_indicators.description" = "Progress bar and activity indicator are used when a process is taking place to illustrate progress and to reassure users that something is happening, and if possible, how long it will take."; "screens.components.progress_indicators.progress_bar.title" = "Progress bar demo"; -"screens.components.progress_indicators.activity_bar.title" = "Progress bar demo"; +"screens.components.progress_indicators.activity_bar.title" = "Activity indicator demo"; "screens.components.progress_indicators.downloading" = "Downloading\U2026"; "screens.components.progress_indicators.x_percent" = "%@ %%"; "screens.components.progress_indicators.toggle.label" = "Label"; @@ -390,17 +390,17 @@ "screens.modules.empty_state.usage_no_data.buttonLabel" = "Search"; "screens.modules.empty_state.usage.alert" = "%@ clicked"; -// ========================================= -// MARK: - Screens - Modules - Recirculation -// ========================================= +// ==================================== +// MARK: - Screens - Modules - MoreApps +// ==================================== -"screens.modules.recirculation.title" = "Recirculation"; -"screens.modules.recirculation.title.setup" = "Recirculation: Setup"; -"screens.modules.recirculation.description" = "Recirculation (AppsPlus was a OMD Essential component) making Orange Apps discovery easier than ever."; -"screens.modules.recirculation.option.flatten_apps_sections" = "Uncategorize apps"; -"screens.modules.recirculation.option.use_embeded_data_source" = "Use local data"; -"screens.modules.recirculation.option.cache_more_apps_icons" = "Cache apps images"; -"screens.modules.recirculation.option.enable_haptics" = "Enable vibrations"; +"screens.modules.moreApps.title" = "MoreApps"; +"screens.modules.moreApps.title.setup" = "MoreApps: Setup"; +"screens.modules.moreApps.description" = "MoreApps makes Orange Apps discovery easier than ever (based on AppsPlus which cas an OMD Essential component)"; +"screens.modules.moreApps.option.flatten_apps_sections" = "Uncategorize apps"; +"screens.modules.moreApps.option.use_embeded_data_source" = "Use local data"; +"screens.modules.moreApps.option.cache_more_apps_icons" = "Cache apps images"; +"screens.modules.moreApps.option.enable_haptics" = "Enable vibrations"; // ======================================= // MARK: - Screens - Components - Template diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/en.lproj/Localizable.strings b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/en.lproj/Localizable.strings index c117b452..5456f108 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/en.lproj/Localizable.strings +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Resources/en.lproj/Localizable.strings @@ -92,14 +92,14 @@ "screens.guidelines.colors.title" = "Colour"; "screens.guidelines.colors.description" = "It is important to use the iOS system background colours as they are dynamic. They automatically change between the slightly darker base and slightly lighter elevated colours, in order to enhance perception of depth and layering."; -"screens.guidelines.colors.palette.title" = "Palette"; +"screens.guidelines.colors.palette.title" = "Colour palette"; "screens.guidelines.colors.color_palette.title" = "Colour palette"; "screens.guidelines.colors.color_palette.on_light" = "Light mode"; "screens.guidelines.colors.color_palette.on_dark" = "Dark mode"; "screens.guidelines.colors.description.more" = "Some colours are defined with different tints that automatically switches. For the greys, you can use the Apple System Greys. For black and white texts, use the Apple Dynamic System Colors. For more information, see [Apple Color Guidelines](https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/color/)."; "a11y.tap_twice_to_get_more" = "Tap twice to get more information"; -"a11y.color_details" = "asset name: %@, RGB value is %@ . Hex value is %@"; +"a11y.color_details" = "token name: %@, color name is %@ . Hex value is %@"; // ======================================= // MARK: - Screens - Guidelines - Spacings @@ -140,8 +140,8 @@ "screens.components.bars.navigation.description" = "A navigation bar appears at the top of an app screen, below the status bar, and enables navigation through a series of hierarchical screens."; "screens.components.bars.navigation.button.edit" = "Edit action"; "screens.components.bars.navigation.button.share" = "Share action"; -"screens.components.bars.navigation.standard_title.text" = "Title"; -"screens.components.bars.navigation.large_title.text" = "Large Title"; +"screens.components.bars.navigation.standard_title.text" = "Title example"; +"screens.components.bars.navigation.large_title.text" = "Large Title example"; "screens.components.bars.navigation.standard_title.hint" = "Standard"; "screens.components.bars.navigation.large_title.hint" = "Large"; "screens.components.bars.navigation.size.hint" = "Size"; @@ -266,7 +266,7 @@ "screens.components.progress_indicators.title" = "Progress indicators"; "screens.components.progress_indicators.description" = "Progress bar and activity indicator are used when a process is taking place to illustrate progress and to reassure users that something is happening, and if possible, how long it will take."; "screens.components.progress_indicators.progress_bar.title" = "Progress bar demo"; -"screens.components.progress_indicators.activity_bar.title" = "Progress bar demo"; +"screens.components.progress_indicators.activity_bar.title" = "Activity indicator demo"; "screens.components.progress_indicators.downloading" = "Downloading\U2026"; "screens.components.progress_indicators.x_percent" = "%@ %%"; "screens.components.progress_indicators.toggle.label" = "Label"; @@ -395,17 +395,17 @@ "screens.modules.empty_state.usage_no_data.buttonLabel" = "Search"; "screens.modules.empty_state.usage.alert" = "%@ clicked"; -// ============================================= -// MARK: - Screens - Modules - Recirculation -// ============================================= - -"screens.modules.recirculation.title" = "Recirculation"; -"screens.modules.recirculation.title.setup" = "Recirculation: Setup"; -"screens.modules.recirculation.description" = "Recirculation (AppsPlus was a OMD Essential component) making Orange Apps discovery easier than ever."; -"screens.modules.recirculation.option.flatten_apps_sections" = "Uncategorize apps"; -"screens.modules.recirculation.option.use_embeded_data_source" = "Use local data"; -"screens.modules.recirculation.option.cache_more_apps_icons" = "Cache apps images"; -"screens.modules.recirculation.option.enable_haptics" = "Enable vibrations"; +// ==================================== +// MARK: - Screens - Modules - MoreApps +// ==================================== + +"screens.modules.moreApps.title" = "MoreApps"; +"screens.modules.moreApps.title.setup" = "MoreApps: Setup"; +"screens.modules.moreApps.description" = "MoreApps makes Orange Apps discovery easier than ever (based on AppsPlus which cas an OMD Essential component)"; +"screens.modules.moreApps.option.flatten_apps_sections" = "Uncategorize apps"; +"screens.modules.moreApps.option.use_embeded_data_source" = "Use local data"; +"screens.modules.moreApps.option.cache_more_apps_icons" = "Cache apps images"; +"screens.modules.moreApps.option.enable_haptics" = "Enable vibrations"; // ======================================= // MARK: - Screens - Components - Template diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/About/AboutSceen.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/About/AboutSceen.swift index 5aeaf246..e28a113e 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/About/AboutSceen.swift +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/About/AboutSceen.swift @@ -108,10 +108,10 @@ struct AboutScreen: View { AboutChangelogItemConfig(priority: 200), ] - if let feedURL = Self.recirculationRemoteFeedURL { - customItems.append(ODSRecirculationItemConfig(dataSource: .remote(url: feedURL), priority: 199)) + if let feedURL = Self.moreAppsRemoteFeedURL { + customItems.append(ODSMoreAppsItemConfig(dataSource: .remote(url: feedURL), priority: 199)) } else { - Log.warning("Missing configuration for this recirculation module, did you use a working URL?") + Log.warning("Missing configuration for this MoreApps module, did you use a working URL?") } } @@ -141,7 +141,7 @@ struct AboutScreen: View { AboutHtmlAndMarkdownView(title: °°"screens.about.terms_of_service", htmlFileName: "CGU") } - private static var recirculationRemoteFeedURL: URL? { + private static var moreAppsRemoteFeedURL: URL? { guard let appsPlusURL = Bundle.main.infoDictionary?["APPS_PLUS_URL"] as? String, !appsPlusURL.isEmpty else { Log.warning("No Apps Plus URL found in app settings") return nil diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Components/Pages/Buttons/EmphasisAndFunctionnalVariant.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Components/Pages/Buttons/EmphasisAndFunctionnalVariant.swift index ab7cd345..c73386a7 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Components/Pages/Buttons/EmphasisAndFunctionnalVariant.swift +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Components/Pages/Buttons/EmphasisAndFunctionnalVariant.swift @@ -43,7 +43,6 @@ struct EmphasisVariant: View { .odsFont(.headlineS) Spacer() } - .accessibilityAddTraits(.isHeader) ODSButton(text: Text(model.text), image: model.icon, @@ -52,6 +51,9 @@ struct EmphasisVariant: View { .disabled(!model.showEnabled) } } + .accessibilityElement(children: .combine) + .accessibilityHint(model.text) + .accessibilityValue(model.text) } } @@ -83,7 +85,6 @@ struct FunctionalVariant: View { Text(description(for: style)).odsFont(.headlineS) Spacer() } - .accessibilityAddTraits(.isHeader) ODSFunctionalButton(text: Text(model.text), image: model.icon, @@ -92,6 +93,9 @@ struct FunctionalVariant: View { .disabled(!model.showEnabled) } } + .accessibilityElement(children: .combine) + .accessibilityHint(model.text) + .accessibilityValue(model.text) } // ==================== diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Components/Pages/Buttons/IconVariant.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Components/Pages/Buttons/IconVariant.swift index cab92231..8bf1c9ed 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Components/Pages/Buttons/IconVariant.swift +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Components/Pages/Buttons/IconVariant.swift @@ -45,29 +45,47 @@ struct IconVariant: View { .odsFont(.bodyLRegular) .frame(maxWidth: .infinity, alignment: .leading) - VariantsTitle().frame(maxWidth: .infinity, alignment: .leading) + VariantsTitle() + .frame(maxWidth: .infinity, alignment: .leading) VStack(alignment: .center, spacing: ODSSpacing.l) { - VStack(alignment: .center, spacing: ODSSpacing.s) { - Text("screens.components.buttons.icon_add").odsFont(.headlineS).frame(maxWidth: .infinity, alignment: .leading) - - ODSIconButton(image: Image("Add")) {} - .disabled(!model.showEnabled) + VStack(alignment: .leading, spacing: ODSSpacing.s) { + Text("screens.components.buttons.icon_add") + .odsFont(.headlineS) + .frame(maxWidth: .infinity, alignment: .leading) + + HStack { + Spacer() + ODSIconButton(image: Image("Add")) {} + .disabled(!model.showEnabled) + Spacer() + } } - - VStack(alignment: .center, spacing: ODSSpacing.s) { - Text("screens.components.buttons.icon_info").odsFont(.headlineS).frame(maxWidth: .infinity, alignment: .leading) - - ODSIconButton(image: Image(systemName: "info.circle")) {} - .disabled(!model.showEnabled) + .accessibilityElement(children: .combine) + + VStack(alignment: .leading, spacing: ODSSpacing.s) { + Text("screens.components.buttons.icon_info") + .odsFont(.headlineS) + .frame(maxWidth: .infinity, alignment: .leading) + + HStack { + Spacer() + ODSIconButton(image: Image(systemName: "info.circle")) {} + .disabled(!model.showEnabled) + Spacer() + } } + .accessibilityElement(children: .combine) } + .accessibilityHint(model.text) } .padding(.top, ODSSpacing.m) .padding(.horizontal, ODSSpacing.m) } .padding(.bottom, 55) } + + } // ========================== @@ -80,6 +98,7 @@ final class IconVariantModel: ObservableObject { // MARK: Stored properties // ======================= + @Published var showLongText: Bool @Published var showEnabled: Bool // ================= @@ -87,8 +106,17 @@ final class IconVariantModel: ObservableObject { // ================= init() { + showLongText = false showEnabled = true } + + // ===================== + // MARK: Computed values + // ===================== + + var text: LocalizedStringKey { + showLongText ? "screens.components.buttons.variant.long" : (showEnabled ? "shared.enabled" : "shared.disabled") + } } // ============================ diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Components/Pages/Sliders/SlidersVariant.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Components/Pages/Sliders/SlidersVariant.swift index 8fcdf64d..6cc0721b 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Components/Pages/Sliders/SlidersVariant.swift +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Components/Pages/Sliders/SlidersVariant.swift @@ -43,10 +43,14 @@ struct SliderVariant: View { ScrollView { VStack { if model.showValue { - Text(String(format: "%.2f", value)) - .odsFont(.bodyLRegular) - .frame(maxWidth: .infinity, alignment: .leading) - .accessibilityHidden(true) + HStack { + Text("screens.components.sliders.sample.volume") + .odsFont(.bodyLRegular) + Text(String(format: "%.2f", value)) + .odsFont(.bodyLRegular) + } + .frame(maxWidth: .infinity, alignment: .leading) + .accessibilityHidden(true) } if model.stepped { diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Guidelines/Pages/Colors/Views/ColorIllustration.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Guidelines/Pages/Colors/Views/ColorIllustration.swift index 9a4eaa5f..089da123 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Guidelines/Pages/Colors/Views/ColorIllustration.swift +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Guidelines/Pages/Colors/Views/ColorIllustration.swift @@ -39,11 +39,10 @@ struct ColorIllustration: View { .border(bordered ? Color.secondary : Color.clear) .aspectRatio(1.0, contentMode: .fit) + Text(colorDescription.assetName).odsFont(.headlineS) + ColorName(colorDescription: colorDescription) - Text(colorDescription.assetName) - .font(.system(.caption, design: .monospaced)) - Text(colorDescription.uiColor.hexa(colorScheme: screenState.colorScheme)) .odsFont(.labelMRegular) } @@ -64,7 +63,10 @@ struct ColorIllustration: View { private var accessibilityLabel: String { let rgba = colorDescription.uiColor.rgba(colorScheme: screenState.colorScheme) - return "a11y.color_details" <- [colorDescription.assetName, rgba.accessibilityLabel, rgba.hexa] + return "a11y.color_details" <- [colorDescription.assetName, + colorDescription.name(for: screenState.colorScheme) ?? + colorDescription.assetName, + rgba.hexa] } } @@ -83,7 +85,8 @@ struct ColorName: View { var body: some View { if let colorName = colorName { - Text(colorName).odsFont(.headlineS) + Text(colorName) + .font(.system(.caption, design: .monospaced)) } } diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/About/AboutModule.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/About/AboutModule.swift index 85d9a7b9..049078ae 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/About/AboutModule.swift +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/About/AboutModule.swift @@ -63,6 +63,7 @@ struct AboutSetup: View { .odsFont(.headlineS) .padding(.top, ODSSpacing.m) .padding(.bottom, ODSSpacing.s) + .accessibilityAddTraits(.isHeader) Text("screens.modules.about.mandatory") diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/ModulesList.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/ModulesList.swift index d38098c2..b0fbc9a8 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/ModulesList.swift +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/ModulesList.swift @@ -71,13 +71,13 @@ struct ModulesList: View { } NavigationLink { - RecirculationModule() - .odsNavigationTitle("screens.modules.recirculation.title.setup".🌐) + MoreAppsModule() + .odsNavigationTitle("screens.modules.moreApps.title.setup".🌐) .navigationbarMenuForThemeSelection() } label: { ODSCardVerticalImageFirst( - title: Text("screens.modules.recirculation.title"), - imageSource: .image(imageFrom(resourceName: "il_recirculation"))) + title: Text("screens.modules.moreApps.title"), + imageSource: .image(imageFrom(resourceName: "il_moreApps"))) } NavigationLink { diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/Recirculation/RecirculationModule.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/MoreApps/MoreAppsModule.swift similarity index 67% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/Recirculation/RecirculationModule.swift rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/MoreApps/MoreAppsModule.swift index be1b0027..7f0ebdbd 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/Recirculation/RecirculationModule.swift +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/MoreApps/MoreAppsModule.swift @@ -14,29 +14,29 @@ import SwiftUI import OrangeDesignSystem -// ============================ -// MARK: - Recirculation Module -// ============================ +// ======================= +// MARK: - MoreApps Module +// ======================= -struct RecirculationModule: View { +struct MoreAppsModule: View { var body: some View { - RecirculationModuleSetup(model: RecirculationModuleModel()) + MoreAppsModuleSetup(model: MoreAppsModuleModel()) } } -// =========================== -// MARK: - Recirculation Setup -// =========================== +// ====================== +// MARK: - MoreApps Setup +// ====================== -struct RecirculationModuleSetup: View { +struct MoreAppsModuleSetup: View { // ======================= // MARK: Stored Properties // ======================= @State private var showDemo: Bool = false - @ObservedObject var model: RecirculationModuleModel + @ObservedObject var model: MoreAppsModuleModel // ========== // MARK: Body @@ -44,37 +44,37 @@ struct RecirculationModuleSetup: View { var body: some View { ScrollView { - ThemeProvider().imageFromResources(name: "il_recirculation") + ThemeProvider().imageFromResources(name: "il_moreApps") .resizable() .aspectRatio(contentMode: .fit) .accessibilityHidden(true) VStack(alignment: .leading, spacing: ODSSpacing.m) { - Text("screens.modules.recirculation.description") + Text("screens.modules.moreApps.description") Text("shared.modules.customize") .odsFont(.headlineS) Toggle(isOn: $model.useLocalDataSource) { - Text("screens.modules.recirculation.option.use_embeded_data_source") + Text("screens.modules.moreApps.option.use_embeded_data_source") } .odsFont(.headlineS) .disabled(!model.hasRemoteDateSource) // If no backend URL, force to use mocks Toggle(isOn: $model.flattenAppsCategories) { - Text("screens.modules.recirculation.option.flatten_apps_sections") + Text("screens.modules.moreApps.option.flatten_apps_sections") }.odsFont(.headlineS) Toggle(isOn: $model.cacheAppsIcons) { - Text("screens.modules.recirculation.option.cache_more_apps_icons") + Text("screens.modules.moreApps.option.cache_more_apps_icons") }.odsFont(.headlineS) Toggle(isOn: $model.enableHaptics) { - Text("screens.modules.recirculation.option.enable_haptics") + Text("screens.modules.moreApps.option.enable_haptics") }.odsFont(.headlineS) NavigationLink(isActive: $showDemo) { - RecirculationModuleDemo(model: model) + MoreAppsModuleDemo(model: model) } label: { ODSButton(text: Text("shared.modules.button.view_demo"), emphasis: .high, fullWidth: true) { showDemo.toggle() diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/Recirculation/RecirculationModuleDemo.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/MoreApps/MoreAppsModuleDemo.swift similarity index 76% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/Recirculation/RecirculationModuleDemo.swift rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/MoreApps/MoreAppsModuleDemo.swift index a94253ad..a2f06143 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/Recirculation/RecirculationModuleDemo.swift +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/MoreApps/MoreAppsModuleDemo.swift @@ -14,13 +14,13 @@ import SwiftUI import OrangeDesignSystem -struct RecirculationModuleDemo: View { +struct MoreAppsModuleDemo: View { // ======================= // MARK: Stored Properties // ======================= - let model: RecirculationModuleModel + let model: MoreAppsModuleModel // ========== // MARK: Body @@ -28,23 +28,23 @@ struct RecirculationModuleDemo: View { var body: some View { NavigationView { - ODSRecirculationView( + ODSMoreAppsView( dataSource: model.dataSource, flattenApps: model.flattenAppsCategories, cacheAppsIcons: model.cacheAppsIcons, enableHaptics: model.enableHaptics) } .navigationBarTitleDisplayMode(.inline) - .navigationTitle("screens.modules.recirculation.title") + .navigationTitle("screens.modules.moreApps.title") } } #if DEBUG -struct AppsRecirculationModuleDemo_Previews: PreviewProvider { +struct AppsMoreAppsModuleDemo_Previews: PreviewProvider { static var previews: some View { - RecirculationModuleSetup(model: RecirculationModuleModel()) + MoreAppsModuleSetup(model: MoreAppsModuleModel()) } } #endif diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/Recirculation/RecirculationModuleModel.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/MoreApps/MoreAppsModuleModel.swift similarity index 87% rename from OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/Recirculation/RecirculationModuleModel.swift rename to OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/MoreApps/MoreAppsModuleModel.swift index eb08efe9..08d460b7 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/Recirculation/RecirculationModuleModel.swift +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/MoreApps/MoreAppsModuleModel.swift @@ -14,7 +14,7 @@ import SwiftUI import OrangeDesignSystem -final class RecirculationModuleModel: ObservableObject { +final class MoreAppsModuleModel: ObservableObject { // ========================= // MARK: - Stored properties @@ -24,8 +24,8 @@ final class RecirculationModuleModel: ObservableObject { @Published var flattenAppsCategories: Bool @Published var cacheAppsIcons: Bool @Published var enableHaptics: Bool - private let localDataSource: ODSRecirculationDataSource? - private let remoteDataSource: ODSRecirculationDataSource? + private let localDataSource: ODSMoreAppsDataSource? + private let remoteDataSource: ODSMoreAppsDataSource? // =================== // MARK: - Initializer @@ -65,9 +65,9 @@ final class RecirculationModuleModel: ObservableObject { remoteDataSource != nil } - var dataSource: ODSRecirculationDataSource { + var dataSource: ODSMoreAppsDataSource { if useLocalDataSource { - Log.info("Source of data for Recirculation module is local file") + Log.info("Source of data for MoreApps module is local file") guard let localDataSource = localDataSource else { fatalError("Failed to URL of local data file") @@ -75,7 +75,7 @@ final class RecirculationModuleModel: ObservableObject { return localDataSource } else { - Log.info("Source of data for Recirculation module is Apps Plus backend") + Log.info("Source of data for MoreApps module is Apps Plus backend") guard let remoteDataSource = remoteDataSource else { // Should not happen, previous controls made before diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Utils/UI/Themes/ThemeSelectionView.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Utils/UI/Themes/ThemeSelectionView.swift index 1b48fada..fccab626 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Utils/UI/Themes/ThemeSelectionView.swift +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Utils/UI/Themes/ThemeSelectionView.swift @@ -64,11 +64,11 @@ final class ThemeProvider: ObservableObject { /// - inThemeBundle: If `false` no bundle will be used, otherwise will use the theme bundle. /// - Returns: The decorative image func imageFromResources(name: String, inThemeBundle: Bool = false) -> Image { - let imageName = currentTheme.name == InnovationCupThemeFactory.themeName ? "\(name) (Innovation Cup)" : name - if inThemeBundle { // Supposing the themes have the same types of images but some of them are suffixed - return Image(decorative: imageName, bundle: currentTheme.bundle) + if inThemeBundle { + return Image(decorative: name, bundle: currentTheme.bundle) } else { - return Image(decorative: imageName) + let imageName = currentTheme.name == InnovationCupThemeFactory.themeName ? "\(name) (Innovation Cup)" : name + return Image(decorative: imageName, bundle: Bundle.main) } } } diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/LocalAppsPlusRepositoryTest.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/LocalAppsPlusRepositoryTest.swift index 4128d7dd..55d105fa 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/LocalAppsPlusRepositoryTest.swift +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/LocalAppsPlusRepositoryTest.swift @@ -21,10 +21,10 @@ final class LocalAppsPlusRepositoryTests: XCTestCase { func testReadOfLocalData() async { // Given let localDataURL = XCTestCase.stubURL(for: "AppsPlusMock", ofType: "json", inBundleOf: LocalAppsPlusRepositoryTests.self) - let localAppsPlusRepository: RecirculationRepositoryProtocol = LocalAppsPlusRepository(feedURL: localDataURL) + let localAppsPlusRepository: MoreAppsRepositoryProtocol = LocalAppsPlusRepository(feedURL: localDataURL) // When - let appsList: RecirculationAppsList + let appsList: MoreAppsAppsList do { appsList = try await localAppsPlusRepository.availableAppsList() } catch { diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/MoreAppsAppsPlusMapperTests.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/MoreAppsAppsPlusMapperTests.swift index f8703934..fd75af02 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/MoreAppsAppsPlusMapperTests.swift +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/MoreAppsAppsPlusMapperTests.swift @@ -33,7 +33,7 @@ final class MoreAppsAppsPlusMapperTests: XCTestCase { } // When - let moreAppsAppDetails = AppsPlusRecirculationMapper().appDetails(from: appsPlusAppDetailsDTOMock) + let moreAppsAppDetails = AppsPlusToMoreAppsMapper().appDetails(from: appsPlusAppDetailsDTOMock) // Then compare(businessObject: moreAppsAppDetails, dataTransferObject: appsPlusAppDetailsDTOMock) @@ -53,7 +53,7 @@ final class MoreAppsAppsPlusMapperTests: XCTestCase { } // When - let moreAppsSection = AppsPlusRecirculationMapper().appsSection(from: appsPlusSectionDTOMock) + let moreAppsSection = AppsPlusToMoreAppsMapper().appsSection(from: appsPlusSectionDTOMock) // Then XCTAssertTrue(moreAppsSection.description == appsPlusSectionDTOMock.description) @@ -77,15 +77,15 @@ final class MoreAppsAppsPlusMapperTests: XCTestCase { fatalError("Failed to process the JSON mock data!") } - let mapper = AppsPlusRecirculationMapper() + let mapper = AppsPlusToMoreAppsMapper() let moreAppsAppDetails = mapper.appsDetails(from: appsPlusItemsMock) - let lonelyApps: [RecirculationAppDetails] = appsPlusItemsMock.apps.map { appDTO in + let lonelyApps: [MoreAppsAppDetails] = appsPlusItemsMock.apps.map { appDTO in mapper.appDetails(from: appDTO) } let moreAppsSections = mapper.appsSections(from: appsPlusItemsMock) - let sections: [RecirculationAppsListSection] = appsPlusItemsMock.sections.map { sectionDTO in + let sections: [MoreAppsAppsListSection] = appsPlusItemsMock.sections.map { sectionDTO in mapper.appsSection(from: sectionDTO) } @@ -105,21 +105,21 @@ final class MoreAppsAppsPlusMapperTests: XCTestCase { // MARK: - Helper // ============== - private func compare(businessObject: RecirculationAppDetails, dataTransferObject: AppsPlusAppDetailsDTO) { + private func compare(businessObject: MoreAppsAppDetails, dataTransferObject: AppsPlusAppDetailsDTO) { XCTAssertTrue(businessObject.title == dataTransferObject.title) XCTAssertTrue(businessObject.iconURL == URL(string: dataTransferObject.iconURL)) XCTAssertTrue(businessObject.description == dataTransferObject.description) XCTAssertTrue(businessObject.storeURL == URL(string: dataTransferObject.storeLink)) } - private func compareBoth(_ lhs: RecirculationAppDetails, _ rhs: RecirculationAppDetails) { + private func compareBoth(_ lhs: MoreAppsAppDetails, _ rhs: MoreAppsAppDetails) { XCTAssertTrue(lhs.title == rhs.title) XCTAssertTrue(lhs.iconURL == rhs.iconURL) XCTAssertTrue(lhs.description == rhs.description) XCTAssertTrue(lhs.storeURL == rhs.storeURL) } - private func compareBoth(_ lhs: [RecirculationAppsListSection], _ rhs: [RecirculationAppsListSection]) { + private func compareBoth(_ lhs: [MoreAppsAppsListSection], _ rhs: [MoreAppsAppsListSection]) { XCTAssertTrue(lhs.count == rhs.count) for (lhsItem, rhsItem) in zip(lhs, rhs) { XCTAssertTrue(lhsItem.description == rhsItem.description) diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/MoreAppsBOTests.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/MoreAppsBOTests.swift index 79c45d73..6fd406d6 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/MoreAppsBOTests.swift +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/MoreAppsBOTests.swift @@ -45,7 +45,7 @@ final class MoreAppsBOTests: XCTestCase { // MARK: - Helper // ============== - private func availableAppsList() -> RecirculationAppsList { + private func availableAppsList() -> MoreAppsAppsList { let mockJsonPath = XCTestCase.stubPath(for: "AppsPlusMock", ofType: "json", inBundleOf: MoreAppsServiceTests.self) guard let jsonRawData = try? String(contentsOfFile: mockJsonPath).data(using: .utf8) else { fatalError("Failed to convert the mock JSON for tests!") @@ -54,11 +54,11 @@ final class MoreAppsBOTests: XCTestCase { fatalError("Failed to process the JSON mock data!") } - let mapper = AppsPlusRecirculationMapper() + let mapper = AppsPlusToMoreAppsMapper() let moreAppsAppDetails = mapper.appsDetails(from: appsPlusDTOMock.items[0]) let moreAppsSections = mapper.appsSections(from: appsPlusDTOMock.items[0]) - return RecirculationAppsList(sections: moreAppsSections, apps: moreAppsAppDetails) + return MoreAppsAppsList(sections: moreAppsSections, apps: moreAppsAppDetails) } } // swiftlint:enable line_length diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/MoreAppsBOTests.swift.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/MoreAppsBOTests.swift.swift deleted file mode 100644 index 8a660f7b..00000000 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/MoreAppsBOTests.swift.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// Software Name: Orange Design System -// SPDX-FileCopyrightText: Copyright (c) Orange SA -// SPDX-License-Identifier: MIT -// -// This software is distributed under the MIT license, -// the text of which is available at https://opensource.org/license/MIT/ -// or see the "LICENSE" file for more details. -// -// Authors: See CONTRIBUTORS.txt -// Software description: A SwiftUI components library with code examples for Orange Design System -// - -import Foundation -@testable import OrangeDesignSystem -import XCTest - -// swiftlint:disable line_length -final class MoreAppsBOTests: XCTestCase { - - func testFlattened() { - // Given - let moreAppsList = availableAppsList() - XCTAssertTrue(moreAppsList.apps.count == 3) - XCTAssertTrue(moreAppsList.sections.count == 2) - - // When - let flattened = moreAppsList.flattened() - - // Then - // Apps must have been moved - XCTAssertTrue(flattened.apps.count == 6) - // Sections must have been deleted - XCTAssertTrue(flattened.sections.isEmpty) - // Order must be natural (iteration on each section to add each item in the end of the apps array) - XCTAssertTrue(flattened.apps[0] == moreAppsList.apps[0]) - XCTAssertTrue(flattened.apps[1] == moreAppsList.apps[1]) - XCTAssertTrue(flattened.apps[2] == moreAppsList.apps[2]) - XCTAssertTrue(flattened.apps[3] == moreAppsList.sections[0].apps[0]) - XCTAssertTrue(flattened.apps[4] == moreAppsList.sections[0].apps[1]) - XCTAssertTrue(flattened.apps[5] == moreAppsList.sections[1].apps[0]) - } - - // ============== - // MARK: - Helper - // ============== - - private func availableAppsList() -> MoreAppsList { - let mockJsonPath = XCTestCase.stubPath(for: "AppsPlusMock", ofType: "json", inBundleOf: MoreAppsServiceTests.self) - guard let jsonRawData = try? String(contentsOfFile: mockJsonPath).data(using: .utf8) else { - fatalError("Failed to convert the mock JSON for tests!") - } - guard let appsPlusDTOMock = try? JSONDecoder().decode(AppsPlusDTO.self, from: jsonRawData) else { - fatalError("Failed to process the JSON mock data!") - } - - let mapper = AppsPlusMoreAppsMapper() - let moreAppsAppDetails = mapper.appsDetails(from: appsPlusDTOMock.items[0]) - let moreAppsSections = mapper.appsSections(from: appsPlusDTOMock.items[0]) - - return MoreAppsList(sections: moreAppsSections, apps: moreAppsAppDetails) - } -} -// swiftlint:enable line_length diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/MoreAppsServiceTests.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/MoreAppsServiceTests.swift index 477943b1..b1de2a7c 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/MoreAppsServiceTests.swift +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/MoreApps/MoreAppsServiceTests.swift @@ -22,10 +22,10 @@ final class MoreAppsServiceTests: XCTestCase { /// Assertions on the apps objects read from some mock JSON to test both mapper and service layers func testMoreAppsServiceApps() async { // Given - let moreAppsService = RecirculationService(repository: MockMoreAppsRepository(feedURL: URL(string: "https://opensource.orange.com/")!)) + let moreAppsService = MoreAppsService(repository: MockMoreAppsRepository(feedURL: URL(string: "https://opensource.orange.com/")!)) // When - var apps = [RecirculationAppDetails]() + var apps = [MoreAppsAppDetails]() do { let moreAppsList = try await moreAppsService.availableAppsList() apps = moreAppsList.apps @@ -58,11 +58,11 @@ final class MoreAppsServiceTests: XCTestCase { /// Assertions on the sections objects read from some mock JSON to test both mapper and service layers func testMoreAppsServiceSections() async { // Given - let moreAppsService = RecirculationService(repository: MockMoreAppsRepository(feedURL: URL(string: "https://opensource.orange.com/")!)) + let moreAppsService = MoreAppsService(repository: MockMoreAppsRepository(feedURL: URL(string: "https://opensource.orange.com/")!)) // When - var sections = [RecirculationAppsListSection]() + var sections = [MoreAppsAppsListSection]() do { let moreAppsList = try await moreAppsService.availableAppsList() sections = moreAppsList.sections @@ -104,7 +104,7 @@ final class MoreAppsServiceTests: XCTestCase { // MARK: - Helpers // =============== - private struct MockMoreAppsRepository: RecirculationRepositoryProtocol { + private struct MockMoreAppsRepository: MoreAppsRepositoryProtocol { private let feedURL: URL private let urlSessionConfiguration: URLSessionConfiguration @@ -116,7 +116,7 @@ final class MoreAppsServiceTests: XCTestCase { self.urlSessionConfiguration = urlSessionConfiguration } - func availableAppsList() -> RecirculationAppsList { + func availableAppsList() -> MoreAppsAppsList { let mockJsonPath = XCTestCase.stubPath(for: "AppsPlusMock", ofType: "json", inBundleOf: MoreAppsServiceTests.self) guard let jsonRawData = try? String(contentsOfFile: mockJsonPath).data(using: .utf8) else { fatalError("Failed to convert the mock JSON for tests!") @@ -125,11 +125,11 @@ final class MoreAppsServiceTests: XCTestCase { fatalError("Failed to process the JSON mock data!") } - let mapper = AppsPlusRecirculationMapper() + let mapper = AppsPlusToMoreAppsMapper() let moreAppsAppDetails = mapper.appsDetails(from: appsPlusDTOMock.items[0]) let moreAppsSections = mapper.appsSections(from: appsPlusDTOMock.items[0]) - return RecirculationAppsList(sections: moreAppsSections, apps: moreAppsAppDetails) + return MoreAppsAppsList(sections: moreAppsSections, apps: moreAppsAppDetails) } } } diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/ODSAboutListItemPriorityTests.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/ODSAboutListItemPriorityTests.swift index 9ce64d91..8a409fbb 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/ODSAboutListItemPriorityTests.swift +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemoTests/Modules/About/ODSAboutListItemPriorityTests.swift @@ -41,7 +41,7 @@ final class ODSAboutListItemPriorityTests: XCTestCase { let accessiblityStatementItem = AboutAccessibilityStatementItemConfig(statementConfig: ODSAboutAccessibilityStatement(conformityStatus: "Accessibility: partially conform", fileName: "AccessibilityStatement", reportDetail: URL(string: "https://orange-opensource.github.io/ods-ios/accessibilityStatement/orange-design-system.html")!)) let appNewsItem = ODSAboutAppNewsItemConfig(path: "") let legalInformationItem = ODSAboutLegalInformationItemConfig(legalInformation: fakeView) - let moreAppsItem = ODSRecirculationItemConfig(dataSource: .remote(url: URL(string: "https://opensource.orange.com/")!)) + let moreAppsItem = ODSMoreAppsItemConfig(dataSource: .remote(url: URL(string: "https://opensource.orange.com/")!)) let rateTheAppItem = ODSAboutRateTheAppItemConfig(storeUrl: URL(string: "https://www.apple.com/app-store/")!) let aboutDesignGuidelinesItem = AboutDesignGuidelinesItemConfig(priority: 202) let aboutChangelogItem = AboutChangelogItemConfig(priority: 200) @@ -59,7 +59,7 @@ final class ODSAboutListItemPriorityTests: XCTestCase { XCTAssertTrue(sortedAboutItemsConfig[4] is AboutAccessibilityStatementItemConfig) // 100 (default) XCTAssertTrue(sortedAboutItemsConfig[5] is ODSAboutAppNewsItemConfig) // 60 (default) XCTAssertTrue(sortedAboutItemsConfig[6] is ODSAboutLegalInformationItemConfig) // 50 (default) - XCTAssertTrue(sortedAboutItemsConfig[7] is ODSRecirculationItemConfig) // 40 (default) + XCTAssertTrue(sortedAboutItemsConfig[7] is ODSMoreAppsItemConfig) // 40 (default) XCTAssertTrue(sortedAboutItemsConfig[8] is ODSAboutRateTheAppItemConfig) // 30 (default) } diff --git a/OrangeDesignSystemDemo/Podfile b/OrangeDesignSystemDemo/Podfile index 696d04fb..a3f84013 100644 --- a/OrangeDesignSystemDemo/Podfile +++ b/OrangeDesignSystemDemo/Podfile @@ -21,7 +21,7 @@ target 'OrangeDesignSystemDemo' do inherit! :search_paths pod 'SwiftLint', '0.54.0' - pod 'SwiftFormat/CLI', '0.53.3' + pod 'SwiftFormat/CLI', '0.53.5' end end diff --git a/OrangeDesignSystemDemo/Podfile.lock b/OrangeDesignSystemDemo/Podfile.lock index 760cbd32..52defd66 100644 --- a/OrangeDesignSystemDemo/Podfile.lock +++ b/OrangeDesignSystemDemo/Podfile.lock @@ -2,12 +2,12 @@ PODS: - Down (0.9.5) - Parma (0.3.0): - Down (~> 0.9.3) - - SwiftFormat/CLI (0.53.3) + - SwiftFormat/CLI (0.53.5) - SwiftLint (0.54.0) DEPENDENCIES: - Parma (= 0.3.0) - - SwiftFormat/CLI (= 0.53.3) + - SwiftFormat/CLI (= 0.53.5) - SwiftLint (= 0.54.0) SPEC REPOS: @@ -20,9 +20,9 @@ SPEC REPOS: SPEC CHECKSUMS: Down: 7321a72d0747ed0061dce948bcff518fcb6df2bd Parma: 679bca1c20ac336fffcdf9ff1ba0db9388a86a13 - SwiftFormat: e0a7810b95dec32d11f682b3b119a7d44cc5e0f0 + SwiftFormat: 57d49d9a63f4249c625b1e623fb9fde0c30cae9d SwiftLint: c1de071d9d08c8aba837545f6254315bc900e211 -PODFILE CHECKSUM: 67ccc8dde6e27678052686a4cae13ebc751f3721 +PODFILE CHECKSUM: 363fa16af968a90b8aa67b0a71e43cdeac1c6ecf COCOAPODS: 1.15.2 diff --git a/OrangeDesignSystemDemo/PrivacyInfo.xcprivacy b/OrangeDesignSystemDemo/PrivacyInfo.xcprivacy new file mode 100644 index 00000000..4a31ee18 --- /dev/null +++ b/OrangeDesignSystemDemo/PrivacyInfo.xcprivacy @@ -0,0 +1,21 @@ + + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + NSPrivacyTrackingDomains + + NSPrivacyTracking + + + diff --git a/OrangeDesignSystemDemo/Settings.bundle/com.mono0926.LicensePlist.plist b/OrangeDesignSystemDemo/Settings.bundle/com.mono0926.LicensePlist.plist index ccf58724..6ba70dbe 100644 --- a/OrangeDesignSystemDemo/Settings.bundle/com.mono0926.LicensePlist.plist +++ b/OrangeDesignSystemDemo/Settings.bundle/com.mono0926.LicensePlist.plist @@ -54,7 +54,7 @@ File com.mono0926.LicensePlist/SwiftFormat Title - SwiftFormat (0.53.3) + SwiftFormat (0.53.5) Type PSChildPaneSpecifier diff --git a/OrangeDesignSystemDemo/fastlane/Fastfile b/OrangeDesignSystemDemo/fastlane/Fastfile index 347e2e5d..8623f063 100644 --- a/OrangeDesignSystemDemo/fastlane/Fastfile +++ b/OrangeDesignSystemDemo/fastlane/Fastfile @@ -14,7 +14,7 @@ # App features configuration # -------------------------- -# URL for recirculation module to get feed from backend +# URL for MoreApps module to get feed from APPS_PLUS backend APPS_PLUS_SERVICE_URL = ENV["ODS_APPS_PLUS_SERVICE_URL"] # Apple configuration @@ -59,7 +59,7 @@ default_platform(:ios) platform :ios do before_all do |lane, options| - xcversion(version: "~> 15.1") + xcversion(version: "~> 15.2") end # ------------------------------------------------------------ @@ -77,7 +77,7 @@ platform :ios do end # ------------------------------------------------------------ - # ADD APPS PLUS CREDENTIALS (Recirculation module) + # ADD APPS PLUS CREDENTIALS (MoreApps module) # ------------------------------------------------------------ desc "ADD APPS PLUS CREDENTIALS" lane :add_credentials_appsplus do @@ -87,7 +87,7 @@ platform :ios do puts "Warning: APPS_PLUS_SERVICE_URL is not defined, are you aware of that?" publish_mattermost_notification("⚙️ ⚠️ @channel Warning: APPS_PLUS_SERVICE_URL is not defined, are you aware of that?") else - puts "URL for recirculation module is '#{APPS_PLUS_SERVICE_URL}'" # Ensure your variable is "masked" in your CI/CD chain + puts "URL for MoreApps module is '#{APPS_PLUS_SERVICE_URL}'" # Ensure your variable is "masked" in your CI/CD chain end plistPath="#{Dir.pwd}/../OrangeDesignSystemDemo/Resources/Info.plist" @@ -204,7 +204,9 @@ platform :ios do commitHash=params[:commitHash] puts "👉 Build and upload (commit hash = #{commitHash})" - # If already build, prevents to build again for nothing + # If already built, prevents to build again for nothing + # Warning: tag is done before build and not remove, so if build failed, tag will remain and needs to be remove manualy. + # It prevents to have loops of failing builds. if tag_ci_build(commitHash) # Ensure this build-then-uploaded app has a new and unique build number matching also to code version update_build_number @@ -218,7 +220,7 @@ platform :ios do puts "Upload to TestFlight requested" # If already uploaded, prevents to upload again if tag_testflight_upload(commitHash) - upload + upload else puts "Nothing new to build today, a TestFlight tag for commit '#{commitHash}' already exists" publish_mattermost_notification("⚙️ 🤔 Nothing new to build today, a TestFlight tag for commit '#{commitHash}' already exists") @@ -259,12 +261,17 @@ platform :ios do gym(workspace: "#{ODS_WORKSPACE}", scheme: ODS_SCHEME, - configuration: 'Release', - output_directory: 'build/', - export_method: 'app-store', - archive_path: 'build/odsApp.xcarchive', + configuration: "Release", + output_directory: "build/", + export_method: "app-store", + archive_path: "build/odsApp.xcarchive", xcargs: "-allowProvisioningUpdates") + # Build a ZIP archive to put as artificat to the GitLab CI runner + # Needed for upload later as .xcarchive for App Store through corporate portal + zip(path: "build/odsApp.xcarchive", + output_path: "build/odsApp.zip") + publish_mattermost_notification("🔨 ✅ A new build has been done successfully") rescue => error publish_mattermost_notification("🔨 🚨 @channel Some issue occurred during the build step (:build)") @@ -368,7 +375,8 @@ platform :ios do end end - # Creates a Git tag at given commit through HTTP protocol to prevent proxy or firewalls to block SSH requests + # Creates a Git tag at given commit through HTTP protocol to prevent proxy or firewalls to block SSH requests. + # Not possible also to make repository mirroring because of the current purchased plan of the GitLab instance. def create_tag(tag) # Check personal access token for tag creation diff --git a/OrangeTheme/Sources/OrangeTheme/OrangeTheme.swift b/OrangeTheme/Sources/OrangeTheme/OrangeTheme.swift index 0ff37a93..f678c946 100644 --- a/OrangeTheme/Sources/OrangeTheme/OrangeTheme.swift +++ b/OrangeTheme/Sources/OrangeTheme/OrangeTheme.swift @@ -281,7 +281,6 @@ public struct OrangeThemeFactory { public let theme: ODSTheme public static let themeName = "OrangeTheme" - // swiftlint:disable function_body_length public init() { var theme = ODSTheme() @@ -346,19 +345,12 @@ public struct OrangeThemeFactory { } } - // Images for empty states - theme.emptyStateImages = ODSThemeEmptyStateImages(error: Image(decorative: "il_emptyStateError", bundle: .orangeTheme), - firstUse: Image(decorative: "il_emptyStateFirstUse", bundle: .orangeTheme), - noData: Image(decorative: "il_emptyStateNoData", bundle: .orangeTheme), - userCleared: Image(decorative: "il_emptyStateUserCleared", bundle: .orangeTheme)) - // Bundle theme.bundle = Bundle.orangeTheme // Read-to-use theme self.theme = theme } - // swiftlint:enable function_body_length } // ============== diff --git a/THIRD-PARTY.md b/THIRD-PARTY.md index c84711a4..79164e0a 100644 --- a/THIRD-PARTY.md +++ b/THIRD-PARTY.md @@ -106,7 +106,7 @@ You may download the source code on the [following website](https://github.com/m ### SwiftFormat -Version 0.53.3 +Version 0.53.5 Copyright 2016 Nick Lockwood. diff --git a/docs/1.0.0/about/Cookies.md b/docs/1.0.0/about/Cookies.md new file mode 100644 index 00000000..bbeca85f --- /dev/null +++ b/docs/1.0.0/about/Cookies.md @@ -0,0 +1,7 @@ +--- +layout: detail +title: "Cookies" +description: Manage cookies preferences. +--- + +At any time, you can manage your cookies preferences for this website from the cookies management panel. diff --git a/docs/1.0.0/about/Cookies_docs.md b/docs/1.0.0/about/Cookies_docs.md new file mode 100644 index 00000000..15499adc --- /dev/null +++ b/docs/1.0.0/about/Cookies_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Cookies +content_page: Cookies.md +--- diff --git a/docs/1.0.0/about/License.md b/docs/1.0.0/about/License.md new file mode 100644 index 00000000..8eb48c99 --- /dev/null +++ b/docs/1.0.0/about/License.md @@ -0,0 +1,35 @@ +--- +layout: detail +title: License +description: Commonly asked questions about ODS iOS open source license. +--- + +## ODS iOS license + +ODS iOS is released under the MIT license and is copyright Orange SA, which is released under MIT license. + +## It requires you to: + +- Keep the license and copyright notice included in ODS iOS Swift files when you use them in your works + +## It permits you to: + +- Freely download and use ODS iOS, in whole or in part, for personal, private, company internal, or commercial purposes +- Use ODS iOS in packages or distributions that you create +- Modify the source code +- Grant a sublicense to modify and distribute ODS iOS to third parties not included in the license + +## It forbids you to: + +- Hold the authors and license owners liable for damages as ODS iOS is provided without warranty +- Hold the creators or copyright holders of ODS iOS liable +- Redistribute any piece of ODS iOS without proper attribution +- Use any marks owned by Orange SA in any way that might state or imply that Orange SA endorses your distribution +- Use any marks owned by Orange SA in any way that might state or imply that you created the Orange SA software in question + +## It does not require you to: + +- Include the source of ODS iOS itself, or of any modifications you may have made to it, in any redistribution you may assemble that includes it +- Submit changes that you make to ODS iOS back to its project (though such feedback is encouraged) + +For more information, the full ODS iOS license is located [in the project repository](https://github.com/Orange-OpenSource/ods-ios/blob/main/LICENSE). diff --git a/docs/1.0.0/about/License_docs.md b/docs/1.0.0/about/License_docs.md new file mode 100644 index 00000000..18b9fd1f --- /dev/null +++ b/docs/1.0.0/about/License_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: License +content_page: License.md +--- diff --git a/docs/1.0.0/about/Team.md b/docs/1.0.0/about/Team.md new file mode 100644 index 00000000..71245c47 --- /dev/null +++ b/docs/1.0.0/about/Team.md @@ -0,0 +1,22 @@ +--- +layout: detail +title: Team +description: An overview of the founding team and core contributors to ODS iOS. +--- + +ODS iOS is maintained by the core team and a small group of invaluable core contributors, with the support and involvement of our community. + +{% if site.data.team.ODS_iOS[0] %} +
+ {% for team_member in site.data.team.ODS_iOS %} + + @{{ team_member.gh_pseudo }} + + {{ team_member.name }} @{{ team_member.gh_pseudo }} + + + {% endfor %} +
+{% endif %} + +Get involved with ODS iOS development by [opening an issue](https://github.com/Orange-OpenSource/ods-ios/issues/new/choose) or submitting a pull request. Read our [contributing guidelines](https://github.com/Orange-OpenSource/ods-ios/blob/main/CONTRIBUTING.md) for information on how we develop. diff --git a/docs/1.0.0/about/Team_docs.md b/docs/1.0.0/about/Team_docs.md new file mode 100644 index 00000000..92cde2e9 --- /dev/null +++ b/docs/1.0.0/about/Team_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Team +content_page: Team.md +--- diff --git a/docs/1.0.0/components/banners.md b/docs/1.0.0/components/banners.md new file mode 100644 index 00000000..35bd9176 --- /dev/null +++ b/docs/1.0.0/components/banners.md @@ -0,0 +1,103 @@ +--- +layout: detail +title: Banners +description: A banner displays an important message which requires an action to be dismissed. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +A banner displays an important, succinct message, and provides actions for users to address (or dismiss the banner). It requires a user action to be dismissed. + +Banners should be displayed at the top of the screen, below a top app bar. They’re persistent and nonmodal, allowing the user to either ignore them or interact with them at any time. Only one banner should be shown at a time + +![Banner light](images/banner-light.png) +![Banner dark](images/banner-dark.png) + +## Specifications references + +- [Design System Manager - Banners](https://system.design.orange.com/0c1af118d/p/85a52b-components/b/1497a4) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +### No button + +```swift +ODSBanner(text: "One to two lines is preferable on mobile and tablet.", + imageSource: .image(Image("placeholder", bundle: Bundle.ods))) +``` + +### One button + +The button is placed under the text. + +```swift +ODSBanner(text: "One to two lines is preferable on mobile and tablet.", + imageSource: .image(Image("placeholder", bundle: Bundle.ods))) { + Button("Button") { + // your action here + } +} +``` + +### Two buttons + +Button are placed under the text. + +```swift +ODSBanner(text: "One to two lines is preferable on mobile and tablet.", + imageSource: .image(Image("placeholder", bundle: Bundle.ods))) { + Button("Button 1") { + // your action here + } +} secondButton: { + Button("Button 1") { + // your action here + } +} +``` + +### Without image + +```swift +ODSBanner(text: "One to two lines is preferable on mobile and tablet.") { + Button("Button 1") { + // your action here + } +} secondButton: { + Button("Button 1") { + // your action here + } +} +``` + +### With image from url + +```swift + +let placeholder = Image("placeholder", bundle: Bundle.ods) +let url = URL(string: "https://images.unsplash.com/photo-1615735487485-e52b9af610c1?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=774&q=80") + +ODSBanner(text: "One to two lines is preferable on mobile and tablet.", + imageSource: .asyncImage(url, placeholder)) { + Button("Button 1") { + // your action here + } +} secondButton: { + Button("Button 1") { + // your action here + } +} +``` + + diff --git a/docs/1.0.0/components/banners_docs.md b/docs/1.0.0/components/banners_docs.md new file mode 100644 index 00000000..9d720197 --- /dev/null +++ b/docs/1.0.0/components/banners_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Banners +content_page: banners.md +--- diff --git a/docs/1.0.0/components/barsNavigation.md b/docs/1.0.0/components/barsNavigation.md new file mode 100644 index 00000000..79ae42da --- /dev/null +++ b/docs/1.0.0/components/barsNavigation.md @@ -0,0 +1,104 @@ +--- +layout: detail +title: Bars - navigation +description: Navigation bar with Orange branding +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Bars: navigation](https://system.design.orange.com/0c1af118d/p/34094d-bars-navigation/b/419eb1) +- [Apple guideline - Navigation bars](https://developer.apple.com/design/human-interface-guidelines/components/navigation-and-search/navigation-bars/) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Standard navigation bar + +![Navigation bar standard light](images/bars_navigation_standard_light.png) +![Navigation bar standard dark](images/bars_navigation_standard_dark.png) + +When using a navigation view, basic navigation is using 'inline' display mode by default. + +```swift +NavigationView { + NavigationLink(destination: Text("destination")) { + Text("Main view") + } + .navigationBarTitle("Standard", displayMode: .inline) +} + +``` + +## Navigation bar with large title + +![Navigation bar large light](images/bars_navigation_large_light.png) +![Navigation bar large dark](images/bars_navigation_large_dark.png) + +Use 'large' display mode to enable large titles when scrolling up. + +```swift +NavigationView { + NavigationLink(destination: Text("destination")) { + Text("Main view") + } + .navigationBarTitle("Standard", displayMode: .large) +} + +``` + +## Navigation bar with search bar + +![Navigation bar search light](images/bars_navigation_search_light.png) +![Navigation bar search dark](images/bars_navigation_search_dark.png) + + +Use .searchable modifier to add a search bar in the navigation view. + +```swift +@State var searchQuery = "" + +NavigationView { + NavigationLink(destination: Text("destination")) { + Text("Main view") + } + .navigationBarTitle("With search bar", displayMode: .inline) + .searchable(text: $searchQuery, placement: .navigationBarDrawer(displayMode: .always)) +} + +``` + +## Navigation bar with action item + +![Navigation bar items light](images/bars_navigation_items_light.png) +![Navigation bar items dark](images/bars_navigation_items_dark.png) + +You can add one or several buttons (trailing or leading) in the navigation view by using .toolbar modifier + +```swift +NavigationView { + NavigationLink(destination: Text("destination")) { + Text("Main view") + } + .navigationBarTitle("Standard", displayMode: .inline) + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button { + print("item action") + } label: { + Image(systemName: "ant.circle") + } + } + } +} + +``` diff --git a/docs/1.0.0/components/barsNavigation_docs.md b/docs/1.0.0/components/barsNavigation_docs.md new file mode 100644 index 00000000..11493173 --- /dev/null +++ b/docs/1.0.0/components/barsNavigation_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Bars - navigation +content_page: barsNavigation.md +--- diff --git a/docs/1.0.0/components/barsTab.md b/docs/1.0.0/components/barsTab.md new file mode 100644 index 00000000..2b95ab3c --- /dev/null +++ b/docs/1.0.0/components/barsTab.md @@ -0,0 +1,57 @@ +--- +layout: detail +title: Bars - tab +description: Tab bars with Orange branding +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Bars: tab](https://system.design.orange.com/0c1af118d/p/08dab8-bars-tab/b/778ed0) +- [Apple guideline - Tab bars](https://developer.apple.com/design/human-interface-guidelines/components/navigation-and-search/tab-bars/) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Standard tab bar + +![Tab bar light](images/bars_tab_light.png) +![Tab bar dark](images/bars_tab_dark.png) + +Tab bar is a standard iOS component. It uses bar items to navigate between views. +Bar Item contains an icon and a title. +An additonal badge can be also added with a count value or a text. + +Example with 4 bar items : + +```swift +TabView { + GuidelinesList() + .tabItem { + Label("Guidelines", image: "Guideline-DNA_32") + } + .badge("Text") + ComponentsList() + .tabItem { + Label("Components", image: "component-atom_32") + } + ModulesList() + .tabItem { + Label("Modules", image: "Module-molecule_32") + } + .badge(10) + ODSDemoAboutView() + .tabItem { + Label("About", image: "info_32") + } +} +``` diff --git a/docs/1.0.0/components/barsTab_docs.md b/docs/1.0.0/components/barsTab_docs.md new file mode 100644 index 00000000..55febdc2 --- /dev/null +++ b/docs/1.0.0/components/barsTab_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Bars - tab +content_page: barsTab.md +--- diff --git a/docs/1.0.0/components/barsTool.md b/docs/1.0.0/components/barsTool.md new file mode 100644 index 00000000..a229245f --- /dev/null +++ b/docs/1.0.0/components/barsTool.md @@ -0,0 +1,112 @@ +--- +layout: detail +title: Bars - tool +description: Tool bars with Orange branding +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Bars: tool](https://system.design.orange.com/0c1af118d/p/06c413-bars-tool/b/951e5c) +- [Apple guideline - Tool bars](https://developer.apple.com/design/human-interface-guidelines/ios/bars/toolbars/) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +A tool bar allows users to do specific actions regarding the entire page. It is placed at the bottom of the screen. It can display 2 to 5 icon controls or 2 to 3 label entries. + +### With label items + +![tool bar labels light](images/bars_tool_labels_light.png) ![tool bar labels dark](images/bars_tool_labels_dark.png) + +A tool bar can display 2 to 3 label entries. + +Example with 3 label entries in toolBar : + +```swift + +let description1 = ODSToolbarLabelDesription(text: "Action 1") { } +let description2 = ODSToolbarLabelDesription(text: "Action 2") { } +let description3 = ODSToolbarLabelDesription(text: "Action 3") { } + +let labelItems = ODSToolbarLabeledItems(description1: description1, + description2: description2, + description3: description3) +NavigationView { + ContentView() + .navigationBarTitle("", displayMode: .inline) + .navigationBarHidden(true) + .odsToolBar(items: labelItems) +} + +// To remove navigation bar, use following modifiers +// .navigationBarHidden(true) + +``` + +### With icon items + +![tool bar icons light](images/bars_tool_icons_light.png) ![tool bar icons dark](images/bars_tool_icons_dark.png) + +A tool bar can display 2 to 5 icon controls +```swift + +let description1 = ODSToolbarIconDesription(systemName: "plus") { } +let description2 = ODSToolbarIconDesription(systemName: "square.and.arrow.up") { } +let description3 = ODSToolbarIconDesription(systemName: "square.and.pencil") { } +let description4 = ODSToolbarIconDesription(systemName: "folder") { } +let description5 = ODSToolbarIconDesription(systemName: "trash") { } + +let iconItems = ODSToolbarIconsItems(description1: description1, + description2: description2, + description3: description3, + description4: description4, + description5: description5) +NavigationView { + ContentView() + .navigationBarTitle("", displayMode: .inline) + .navigationBarHidden(true) + .odsToolBar(items: iconItems) +} + +// To remove navigation bar, use following modifiers +// .navigationBarHidden(true) + +``` + +## Remarks + +As toolbar colors depends on theme, don't forget to add it to enviroment and call the view modifier __.toolBarColors(for:)__ to apply colors provided by the theme. + +Two solutions: + +- Directy on the root view + +```swift +let theme = YourTheme() + +ContentViewWithToolBar() +.environment(\.theme, theme) +.toolBarColors(for: theme) +``` + +- Or using __ODSThemeableView__ view as a root view: + +```swift +let theme = YourTheme() + +ODSThemeableView(theme: yourTheme) { + ContentViewWithToolBar() +} +``` diff --git a/docs/1.0.0/components/barsTool_docs.md b/docs/1.0.0/components/barsTool_docs.md new file mode 100644 index 00000000..a20e98aa --- /dev/null +++ b/docs/1.0.0/components/barsTool_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Bars - tool +content_page: barsTool.md +--- diff --git a/docs/1.0.0/components/buttons.md b/docs/1.0.0/components/buttons.md new file mode 100644 index 00000000..86013d1f --- /dev/null +++ b/docs/1.0.0/components/buttons.md @@ -0,0 +1,131 @@ +--- +layout: detail +title: Buttons +description: A button allows a user to perform an action or to navigate to another page. It contains a text label and a supporting icon can be displayed. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Buttons](https://system.design.orange.com/0c1af118d/p/278734-buttons-shape/b/536b5f) +- [Apple guideline - Buttons](https://developer.apple.com/design/human-interface-guidelines/components/menus-and-actions/buttons) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +### Emphasis button + +Button variants range in style to denote emphasis. Use different styles and not size to show the preferred choice. + +- **Layout** + +**Large** + +![Buttons high emphasis disabled](images/buttons_layout_large_with_icon.png) + +![Buttons high emphasis](images/buttons_layout_large_without_icon.png) + +**Small** + +![Buttons high emphasis disabled](images/buttons_layout_small_with_icon.png) + +![Buttons high emphasis](images/buttons_layout_small_without_icon.png) + + +- **Emphasis** + +**High emphasis** + +![Buttons high emphasis disabled](images/buttons_functionnal_disabled.png) +![Buttons high emphasis](images/buttons_emphasis_high.png) + +**Medium** + +![Buttons medium emphasis disabled](images/buttons_functionnal_disabled.png) +![Buttons medium emphasis](images/buttons_emphasis_medium.png) + +**Low emphasis** + +![Buttons low emphasis disabled](images/buttons_functionnal_disabled.png) +![Buttons low emphasis](images/buttons_emphasis_low.png) + +**Lowest emphasis** + +![Buttons lowest emphasis disabled](images/buttons_emphasis_lowest_disabled.png) +![Buttons lowest emphasis](images/buttons_emphasis_lowest.png) + +- **Implementation** + +```swift +// High emphasis +ODSButton(text: Text("Some text"), + image: Image("Add"), + emphasis: .high) {} + +// Lowest emphasis +ODSButton(text: Text("Some text"), + image: Image("Add"), + emphasis: .lowest) {} +``` + +### Functional button + +If required, colour versions can also be used to inform users of positive or negative destructive actions. + +**Positive** + +![Buttons functional positive disabled](images/buttons_functionnal_disabled.png) +![Buttons functional positive](images/buttons_functional_positive.png) + +**Negative** + +![Buttons functional negative disabled](images/buttons_functionnal_disabled.png) +![Buttons functional negative](images/buttons_functional_negative.png) + +```swift + // Negative button + ODSFunctionalButton(text: Text("Some text"), style: .negative) + { /* action: Do something */ } + + ODSFunctionalButton(text: Text("Some text"), image: Image("Add"), style: .negative) + { /* action: Do something */ } + + // Positive button + ODSFunctionalButton(text: Text("Some text") style: .positive) + { /* action: Do something */ } + + ODSFunctionalButton(text: Text("Some text"), image: Image("Add"), style: .positive) + { /* action: Do something */ } + + // To disable the button + ODSFunctionalButton(text: Text("Some text"), style: .positive) { /* action: Do something */ } + .disabled(true) +``` + +### Icon button + +Plain buttons are the most ubiquitous component found throughout applications. Consisting an icon, they are the most simple button style. + +![Buttons icon](images/buttons_icon.png) + +```swift +// icon with system asset +ODSIconButton(image: Image(systemName: "info.circle")) {} + +// icon with Solaris asset +ODSIconButton(image: Image("Add")) {} +``` + + + diff --git a/docs/1.0.0/components/buttons_docs.md b/docs/1.0.0/components/buttons_docs.md new file mode 100644 index 00000000..085cbe10 --- /dev/null +++ b/docs/1.0.0/components/buttons_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Buttons +content_page: buttons.md +--- diff --git a/docs/1.0.0/components/cards.md b/docs/1.0.0/components/cards.md new file mode 100644 index 00000000..633a1e92 --- /dev/null +++ b/docs/1.0.0/components/cards.md @@ -0,0 +1,209 @@ +--- +layout: detail +title: Cards +description: Cards contain content and actions about a single subject. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Cards](https://system.design.orange.com/0c1af118d/p/66bac5-cards/b/1591fb) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +Images in cards are considered as decorative, so they are ignored by Voice Over. + +## Variants + +Cards are a contained and independent element that can display content and actions on a single topic. + +There are a few ways cards can be presented. Ranging from a single title on its own for a simple card view or with more information shown in a subtitle and supporting text and actions at the bottom of the card. + + +### Vertical Image First Card + +This is a full width card displayed with an image as first element. + +This card is composed of two parts: +- Media: (today an image) +- Content: with a title, an optional subtitle an optional supporting text and optional buttons (zero up to two) + +![Vertical image first card light](images/card_vertical_image_first_light.png) ![Vertical image first card dark](images/card_vertical_image_first_dark.png) + +> **Implementation** + +Card is configured like this: + +```swift +ODSCardVerticalImageFirst( + title: Text("Title"), + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: Text("Subtitle"), + text: Text("A supporting text to describe something") +) { + Button("Button 1") { + // do something here + } +} secondButton: { + Button("Button 2") { + // do something here + } +} +``` + +### Vertical Header First Card + +This is a full width card displaying with a title and a thumbnail on top as first element. + +This card is composed of three parts: +- Header: with a title, an optional subtitle and an optional thmubnail +- Media: (today an image) +- Content: with an optional supporting text and optional buttons (zero up to two) + +![Vertical header first card light](images/card_vertical_header_first_light.png) ![Vertical header first card dark](images/card_vertical_header_first_dark.png) + +> **Implementation** + +Card is configured like this: + +```swift + +ODSCardVerticalHeaderFirst( + title: Text("Title"), + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: Text("Subtitle"), + thumbnailSource: .image(Image("placeholder", bundle: Bundle.ods)), + text: Text("A supporting text to describe something") +) { + Button("Button 1") { + // do something here + } +} secondButton: { + Button("Button 2") { + // do something here + } +} +``` + +### Horizontal Card + +This is a full width card displaying with image on left and content with texts on the right. Additonal action buttons can be added at the bottom of the card. + +Thes content is composed by: +- a title +- an optional subtitle +- an optional text for larger description + +![Horizontal card light](images/card_horizontal_light.png) ![Horizontal card dark](images/card_horizontal_dark.png) + +> **Implementation** + +Card is configured like this: + +```swift +ODSCardHorizontal( + title: Text("Title"), + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + imagePosition: .leading, + subtitle: Text("Subtitle"), + text: Text("A supporting text to describe something") +) { + + Button("Button 1") { + // do something here + } +} secondButton : { + Button("Button 1") { + // do something here + } +} +``` + +### Small Card + +The small card if prefered for two-column portrait mobile screen display. +As it is smaller than full-width cards, it contains only title and subtitle (optional) in one line (Truncated tail). + +![Small card light](images/card_small_light.png) ![Small card dark](images/card_small_dark.png) + +> **Implementation** + +Card is configured like this: + +```swift +ODSCardSmall( + title: Text("Title"), + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: Text("Subtitle") +) +``` + +How to add Small Card in Grid + +```swift +class Model { + let title: String + let subtitle: String? + let imageSource: ODSImage.Source + + init(title: String, imageSource: ODSImage.Source, subtitle: String? = nil) { + self.title = title + self.imageSource = imageSource + self.subtitle = subtitle + } +} + + +let models = [ + Model( + title: "Title 1", + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: "Subtitle 1" + ) + Model( + title: "Title 2", + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: "Subtitle 2" + ) + //... +] + +/// /!\ Don't forget to put the grid into a scrollview +ScrollView { + LazyVGrid(columns: columns, spacing: ODSSpacing.none) { + ForEach(models, id:\.title) { model in + ODSCardSmall( + title: Text(model.title), + imageSource: model.imageSource, + subtitle: Text(model.subtitle) + ) + } + } + .padding(.all, ODSSpacing.m) +} + +``` + +However for accessibility edge cases, like when text sizes are accessibility sizes, the behaviour is different for such components. They won't be displayed in one truncated line because the text will be too truncated and difficult to read. +If this choice is too impacting for your UI, it is possible to define the limit number of lines to use if a11y size are used + +```swift +ODSCardSmall( + title: Text("Title"), + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: Text("Subtitle"), + // Here 3 is the number of lines you want for such edge cases + titleAccessibleLineLimit: 3, + subtitleAccessibleLineLimit: 3 +) +``` diff --git a/docs/1.0.0/components/cards_docs.md b/docs/1.0.0/components/cards_docs.md new file mode 100644 index 00000000..193969dd --- /dev/null +++ b/docs/1.0.0/components/cards_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Cards +content_page: cards.md +--- diff --git a/docs/1.0.0/components/chips.md b/docs/1.0.0/components/chips.md new file mode 100644 index 00000000..264df252 --- /dev/null +++ b/docs/1.0.0/components/chips.md @@ -0,0 +1,162 @@ +--- +layout: detail +title: Chips +description: Chips are compact elements that represent an input, attribute, or action. +--- + +--- + +**Page summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager](https://system.design.orange.com/0c1af118d/p/85a52b-components/b/1497a4) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +Chips support dynamic types for accessibility. + +Chips support content labeling for accessibility and are readable by most screen readers. Text rendered in chips is automatically provided to accessibility services. Additional content labels are usually unnecessary. + +## Variants + +### Action chip + +Action chips offer actions related to primary content. They should appear dynamically and contextually in a UI. +An alternative to action chips are buttons, which should appear persistently and consistently. + +![Light action chip](images/chips_action_light.png) +![Dark action chip](images/chips_action_dark.png) + +``` swift +ODSActionChip( + text: Text("chip text"), + Image(systemname: "heart") + action: { doSomething() } +) +``` + +To disable the chip call the `.disabled` on View. + +### Input chip + +Input chips represent a complex piece of information in compact form, such as an entity (person, place, or thing) or text. They enable user input and verify that input by converting text into chips. + +![Light input chip](images/chips_input_light.png) +![Dark input chip](images/chips_input_dark.png) + +``` swift +// Input chip with leading filled with icon or image for resources + +ODSInputChip( + text: Text(vhip text), + leadingAvatar: .image(Image("Avatar")), + action: { doSomething() }, + removeAction: { doSomething() } +) +``` + +### Choice chip + +Choice chips allow selection of a single chip from a set of options. Choice chips clearly delineate and display options in a compact area. + +**Note: To display a set of choice chips please see ODSChoiceChipsPicker** + +![Light input chip](images/chips_choice_light.png) +![Dark input chip](images/chips_choice_dark.png) + +``` swift +enum Ingredient: String, CaseIterable { + case chocolate, vanilla, strawberry +} + +ODSChoiceChipView( + chip: ODSChoiceChip(text: Text("Chocolate"), value: .chocolate), + selected: false: + action: { doSomething() } +) +ODSChoiceChipView( + chip: ODSChoiceChip(text: Text("Vanilla"), value: .vanilla), + selected: true: + action: { doSomething() } +) +``` + +In order to display a set of choice chips you can follow this example: + +``` swift +@State var selection: Ingredient + +var body: some View { + ScrollView(.horizontal) { + ForEach(Ingredient.allCases, id: \.rawValue) { ingredient in + ODSChoiceChipView( + model: ODSChoiceChip(text: Text(ingredient.rawValue), value: ingredient), + selected: selection == ingredient, + action: { selection = ingredient } + ) + } + } +} +``` + +To simplify the chips placement and alignment, you can also use the __ODSChoiceChipsPicker__ like this: + +``` swift +@State var selection: Ingredient + +ODSChoiceChipPicker( + title: Text("Select your ingredient"), + chips: Ingredient.allCases.map { ODSChoiceChip(text: Text($0.rawValue), value: $0) + selection: $selection, + placement: .carousel +) +``` + +### Filter chip + +Filter chips use tags or descriptive words to filter content. Filter chips allow selection of a set of chips from a set of options. Its usage is usefull to apply a filtering on a list of elmeents. + +**Note: To display a set of filter chips please see ODSFilterChipsPicker** + +![Light filter chips](images/chips_filter_light.png) ![Dark filter chips](images/chips_filter_dark.png) + +![Light filter chips with avatar](images/chips_filter_avatar_light.png) ![Dark filter chips with avatar](images/chips_filter_avatar_dark.png) + + +``` swift +enum Ingredient: String, CaseIterable { + case chocolate, vanilla, strawberry + + var image: Image { + Image("self.rawValue") + } +} + +ODSFilterChipView( + chip: ODSFilterChip(text: Text("Chocolate"), leading: .image(Image("avatar")), value: .chocolate), + selected: false: + action: { doSomething() } +) +``` + +As the choice chip, to simplify the chips placement and alignment, you can also use the __ODSFilterChipsPicker__ like this: + +``` swift +@State var selection: [Ingredient] + +ODSFilterChipPicker( + title: Text("Select your ingredients"), + chips: Ingredient.allCases.map { ODSFilterChip(text: Text($0.rawValue), leading(.image($0.image)), value: $0) + selection: $selection, + placement: .carousel +) +``` + diff --git a/docs/1.0.0/components/chips_docs.md b/docs/1.0.0/components/chips_docs.md new file mode 100644 index 00000000..51287dad --- /dev/null +++ b/docs/1.0.0/components/chips_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Chips +content_page: chips.md +--- diff --git a/docs/1.0.0/components/images/activity_indicator.png b/docs/1.0.0/components/images/activity_indicator.png new file mode 100644 index 00000000..5567e614 Binary files /dev/null and b/docs/1.0.0/components/images/activity_indicator.png differ diff --git a/docs/1.0.0/components/images/banner-dark.png b/docs/1.0.0/components/images/banner-dark.png new file mode 100644 index 00000000..769144eb Binary files /dev/null and b/docs/1.0.0/components/images/banner-dark.png differ diff --git a/docs/1.0.0/components/images/banner-light.png b/docs/1.0.0/components/images/banner-light.png new file mode 100644 index 00000000..ec84c11f Binary files /dev/null and b/docs/1.0.0/components/images/banner-light.png differ diff --git a/docs/1.0.0/components/images/bars_navigation_items_dark.png b/docs/1.0.0/components/images/bars_navigation_items_dark.png new file mode 100644 index 00000000..e7124a46 Binary files /dev/null and b/docs/1.0.0/components/images/bars_navigation_items_dark.png differ diff --git a/docs/1.0.0/components/images/bars_navigation_items_light.png b/docs/1.0.0/components/images/bars_navigation_items_light.png new file mode 100644 index 00000000..8cc70e0d Binary files /dev/null and b/docs/1.0.0/components/images/bars_navigation_items_light.png differ diff --git a/docs/1.0.0/components/images/bars_navigation_large_dark.png b/docs/1.0.0/components/images/bars_navigation_large_dark.png new file mode 100644 index 00000000..97e823e5 Binary files /dev/null and b/docs/1.0.0/components/images/bars_navigation_large_dark.png differ diff --git a/docs/1.0.0/components/images/bars_navigation_large_light.png b/docs/1.0.0/components/images/bars_navigation_large_light.png new file mode 100644 index 00000000..320fcae0 Binary files /dev/null and b/docs/1.0.0/components/images/bars_navigation_large_light.png differ diff --git a/docs/1.0.0/components/images/bars_navigation_search_dark.png b/docs/1.0.0/components/images/bars_navigation_search_dark.png new file mode 100644 index 00000000..b5c851e4 Binary files /dev/null and b/docs/1.0.0/components/images/bars_navigation_search_dark.png differ diff --git a/docs/1.0.0/components/images/bars_navigation_search_light.png b/docs/1.0.0/components/images/bars_navigation_search_light.png new file mode 100644 index 00000000..915a2029 Binary files /dev/null and b/docs/1.0.0/components/images/bars_navigation_search_light.png differ diff --git a/docs/1.0.0/components/images/bars_navigation_standard_dark.png b/docs/1.0.0/components/images/bars_navigation_standard_dark.png new file mode 100644 index 00000000..d20b5a7a Binary files /dev/null and b/docs/1.0.0/components/images/bars_navigation_standard_dark.png differ diff --git a/docs/1.0.0/components/images/bars_navigation_standard_light.png b/docs/1.0.0/components/images/bars_navigation_standard_light.png new file mode 100644 index 00000000..9b9f93db Binary files /dev/null and b/docs/1.0.0/components/images/bars_navigation_standard_light.png differ diff --git a/docs/1.0.0/components/images/bars_tab_dark.png b/docs/1.0.0/components/images/bars_tab_dark.png new file mode 100644 index 00000000..25a09787 Binary files /dev/null and b/docs/1.0.0/components/images/bars_tab_dark.png differ diff --git a/docs/1.0.0/components/images/bars_tab_light.png b/docs/1.0.0/components/images/bars_tab_light.png new file mode 100644 index 00000000..da7e46bf Binary files /dev/null and b/docs/1.0.0/components/images/bars_tab_light.png differ diff --git a/docs/1.0.0/components/images/bars_tool_icons_dark.png b/docs/1.0.0/components/images/bars_tool_icons_dark.png new file mode 100644 index 00000000..3be894a5 Binary files /dev/null and b/docs/1.0.0/components/images/bars_tool_icons_dark.png differ diff --git a/docs/1.0.0/components/images/bars_tool_icons_light.png b/docs/1.0.0/components/images/bars_tool_icons_light.png new file mode 100644 index 00000000..758ecd9f Binary files /dev/null and b/docs/1.0.0/components/images/bars_tool_icons_light.png differ diff --git a/docs/1.0.0/components/images/bars_tool_labels_dark.png b/docs/1.0.0/components/images/bars_tool_labels_dark.png new file mode 100644 index 00000000..dda57849 Binary files /dev/null and b/docs/1.0.0/components/images/bars_tool_labels_dark.png differ diff --git a/docs/1.0.0/components/images/bars_tool_labels_light.png b/docs/1.0.0/components/images/bars_tool_labels_light.png new file mode 100644 index 00000000..d46cfe54 Binary files /dev/null and b/docs/1.0.0/components/images/bars_tool_labels_light.png differ diff --git a/docs/1.0.0/components/images/buttons_emphasis_high.png b/docs/1.0.0/components/images/buttons_emphasis_high.png new file mode 100644 index 00000000..c0a98b7f Binary files /dev/null and b/docs/1.0.0/components/images/buttons_emphasis_high.png differ diff --git a/docs/1.0.0/components/images/buttons_emphasis_low.png b/docs/1.0.0/components/images/buttons_emphasis_low.png new file mode 100644 index 00000000..e306cb0e Binary files /dev/null and b/docs/1.0.0/components/images/buttons_emphasis_low.png differ diff --git a/docs/1.0.0/components/images/buttons_emphasis_lowest.png b/docs/1.0.0/components/images/buttons_emphasis_lowest.png new file mode 100644 index 00000000..317dae96 Binary files /dev/null and b/docs/1.0.0/components/images/buttons_emphasis_lowest.png differ diff --git a/docs/1.0.0/components/images/buttons_emphasis_lowest_disabled.png b/docs/1.0.0/components/images/buttons_emphasis_lowest_disabled.png new file mode 100644 index 00000000..c9931849 Binary files /dev/null and b/docs/1.0.0/components/images/buttons_emphasis_lowest_disabled.png differ diff --git a/docs/1.0.0/components/images/buttons_emphasis_medium.png b/docs/1.0.0/components/images/buttons_emphasis_medium.png new file mode 100644 index 00000000..ef148b6e Binary files /dev/null and b/docs/1.0.0/components/images/buttons_emphasis_medium.png differ diff --git a/docs/1.0.0/components/images/buttons_functional_negative.png b/docs/1.0.0/components/images/buttons_functional_negative.png new file mode 100644 index 00000000..5d88a0fc Binary files /dev/null and b/docs/1.0.0/components/images/buttons_functional_negative.png differ diff --git a/docs/1.0.0/components/images/buttons_functional_positive.png b/docs/1.0.0/components/images/buttons_functional_positive.png new file mode 100644 index 00000000..330ef3d6 Binary files /dev/null and b/docs/1.0.0/components/images/buttons_functional_positive.png differ diff --git a/docs/1.0.0/components/images/buttons_functionnal_disabled.png b/docs/1.0.0/components/images/buttons_functionnal_disabled.png new file mode 100644 index 00000000..803d1200 Binary files /dev/null and b/docs/1.0.0/components/images/buttons_functionnal_disabled.png differ diff --git a/docs/1.0.0/components/images/buttons_icon.png b/docs/1.0.0/components/images/buttons_icon.png new file mode 100644 index 00000000..552dc955 Binary files /dev/null and b/docs/1.0.0/components/images/buttons_icon.png differ diff --git a/docs/1.0.0/components/images/buttons_layout_large_with_icon.png b/docs/1.0.0/components/images/buttons_layout_large_with_icon.png new file mode 100644 index 00000000..29d586ac Binary files /dev/null and b/docs/1.0.0/components/images/buttons_layout_large_with_icon.png differ diff --git a/docs/1.0.0/components/images/buttons_layout_large_without_icon.png b/docs/1.0.0/components/images/buttons_layout_large_without_icon.png new file mode 100644 index 00000000..e6f378d7 Binary files /dev/null and b/docs/1.0.0/components/images/buttons_layout_large_without_icon.png differ diff --git a/docs/1.0.0/components/images/buttons_layout_small_with_icon.png b/docs/1.0.0/components/images/buttons_layout_small_with_icon.png new file mode 100644 index 00000000..a0b7ae5c Binary files /dev/null and b/docs/1.0.0/components/images/buttons_layout_small_with_icon.png differ diff --git a/docs/1.0.0/components/images/buttons_layout_small_without_icon.png b/docs/1.0.0/components/images/buttons_layout_small_without_icon.png new file mode 100644 index 00000000..93ae02fd Binary files /dev/null and b/docs/1.0.0/components/images/buttons_layout_small_without_icon.png differ diff --git a/docs/1.0.0/components/images/card_horizontal_dark.png b/docs/1.0.0/components/images/card_horizontal_dark.png new file mode 100644 index 00000000..7fe518b8 Binary files /dev/null and b/docs/1.0.0/components/images/card_horizontal_dark.png differ diff --git a/docs/1.0.0/components/images/card_horizontal_light.png b/docs/1.0.0/components/images/card_horizontal_light.png new file mode 100644 index 00000000..fdd1bdb3 Binary files /dev/null and b/docs/1.0.0/components/images/card_horizontal_light.png differ diff --git a/docs/1.0.0/components/images/card_small_dark.png b/docs/1.0.0/components/images/card_small_dark.png new file mode 100644 index 00000000..211a72a9 Binary files /dev/null and b/docs/1.0.0/components/images/card_small_dark.png differ diff --git a/docs/1.0.0/components/images/card_small_light.png b/docs/1.0.0/components/images/card_small_light.png new file mode 100644 index 00000000..e2b9949b Binary files /dev/null and b/docs/1.0.0/components/images/card_small_light.png differ diff --git a/docs/1.0.0/components/images/card_vertical_header_first_dark.png b/docs/1.0.0/components/images/card_vertical_header_first_dark.png new file mode 100644 index 00000000..542c62eb Binary files /dev/null and b/docs/1.0.0/components/images/card_vertical_header_first_dark.png differ diff --git a/docs/1.0.0/components/images/card_vertical_header_first_light.png b/docs/1.0.0/components/images/card_vertical_header_first_light.png new file mode 100644 index 00000000..66460143 Binary files /dev/null and b/docs/1.0.0/components/images/card_vertical_header_first_light.png differ diff --git a/docs/1.0.0/components/images/card_vertical_image_first_dark.png b/docs/1.0.0/components/images/card_vertical_image_first_dark.png new file mode 100644 index 00000000..f9a5299d Binary files /dev/null and b/docs/1.0.0/components/images/card_vertical_image_first_dark.png differ diff --git a/docs/1.0.0/components/images/card_vertical_image_first_light.png b/docs/1.0.0/components/images/card_vertical_image_first_light.png new file mode 100644 index 00000000..58ee1f75 Binary files /dev/null and b/docs/1.0.0/components/images/card_vertical_image_first_light.png differ diff --git a/docs/1.0.0/components/images/chips_action_dark.png b/docs/1.0.0/components/images/chips_action_dark.png new file mode 100644 index 00000000..e0a50458 Binary files /dev/null and b/docs/1.0.0/components/images/chips_action_dark.png differ diff --git a/docs/1.0.0/components/images/chips_action_light.png b/docs/1.0.0/components/images/chips_action_light.png new file mode 100644 index 00000000..e2d8a9d6 Binary files /dev/null and b/docs/1.0.0/components/images/chips_action_light.png differ diff --git a/docs/1.0.0/components/images/chips_choice_dark.png b/docs/1.0.0/components/images/chips_choice_dark.png new file mode 100644 index 00000000..d848d8ad Binary files /dev/null and b/docs/1.0.0/components/images/chips_choice_dark.png differ diff --git a/docs/1.0.0/components/images/chips_choice_light.png b/docs/1.0.0/components/images/chips_choice_light.png new file mode 100644 index 00000000..37781814 Binary files /dev/null and b/docs/1.0.0/components/images/chips_choice_light.png differ diff --git a/docs/1.0.0/components/images/chips_filter_avatar_dark.png b/docs/1.0.0/components/images/chips_filter_avatar_dark.png new file mode 100644 index 00000000..e4269dcc Binary files /dev/null and b/docs/1.0.0/components/images/chips_filter_avatar_dark.png differ diff --git a/docs/1.0.0/components/images/chips_filter_avatar_light.png b/docs/1.0.0/components/images/chips_filter_avatar_light.png new file mode 100644 index 00000000..56857458 Binary files /dev/null and b/docs/1.0.0/components/images/chips_filter_avatar_light.png differ diff --git a/docs/1.0.0/components/images/chips_filter_dark.png b/docs/1.0.0/components/images/chips_filter_dark.png new file mode 100644 index 00000000..45fe2cf0 Binary files /dev/null and b/docs/1.0.0/components/images/chips_filter_dark.png differ diff --git a/docs/1.0.0/components/images/chips_filter_light.png b/docs/1.0.0/components/images/chips_filter_light.png new file mode 100644 index 00000000..d9c57620 Binary files /dev/null and b/docs/1.0.0/components/images/chips_filter_light.png differ diff --git a/docs/1.0.0/components/images/chips_input_dark.png b/docs/1.0.0/components/images/chips_input_dark.png new file mode 100644 index 00000000..315167eb Binary files /dev/null and b/docs/1.0.0/components/images/chips_input_dark.png differ diff --git a/docs/1.0.0/components/images/chips_input_light.png b/docs/1.0.0/components/images/chips_input_light.png new file mode 100644 index 00000000..6e928d1d Binary files /dev/null and b/docs/1.0.0/components/images/chips_input_light.png differ diff --git a/docs/1.0.0/components/images/list_items_selection_circle_dark.png b/docs/1.0.0/components/images/list_items_selection_circle_dark.png new file mode 100644 index 00000000..cef8cafe Binary files /dev/null and b/docs/1.0.0/components/images/list_items_selection_circle_dark.png differ diff --git a/docs/1.0.0/components/images/list_items_selection_circle_light.png b/docs/1.0.0/components/images/list_items_selection_circle_light.png new file mode 100644 index 00000000..871e26a4 Binary files /dev/null and b/docs/1.0.0/components/images/list_items_selection_circle_light.png differ diff --git a/docs/1.0.0/components/images/list_items_standard_square_dark.png b/docs/1.0.0/components/images/list_items_standard_square_dark.png new file mode 100644 index 00000000..7e6d2994 Binary files /dev/null and b/docs/1.0.0/components/images/list_items_standard_square_dark.png differ diff --git a/docs/1.0.0/components/images/list_items_standard_square_light.png b/docs/1.0.0/components/images/list_items_standard_square_light.png new file mode 100644 index 00000000..03dc9d15 Binary files /dev/null and b/docs/1.0.0/components/images/list_items_standard_square_light.png differ diff --git a/docs/1.0.0/components/images/progress_bar.png b/docs/1.0.0/components/images/progress_bar.png new file mode 100644 index 00000000..d571477e Binary files /dev/null and b/docs/1.0.0/components/images/progress_bar.png differ diff --git a/docs/1.0.0/components/images/sliders.png b/docs/1.0.0/components/images/sliders.png new file mode 100644 index 00000000..1a5c9c81 Binary files /dev/null and b/docs/1.0.0/components/images/sliders.png differ diff --git a/docs/1.0.0/components/listItem.md b/docs/1.0.0/components/listItem.md new file mode 100644 index 00000000..a56d4d25 --- /dev/null +++ b/docs/1.0.0/components/listItem.md @@ -0,0 +1,132 @@ +--- +layout: detail +title: List item +description: Lists are continuous, vertical indexes of text or images. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Lists](https://system.design.orange.com/0c1af118d/p/09a804-lists/b/669743) +- [Apple guideline - Lists and tables](https://developer.apple.com/design/human-interface-guidelines/components/layout-and-organization/lists-and-tables) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +Here we just propose a configuration for two types of list items: +- Standard with trailing actions +- Selection with trailing icons (selection indicators) + +All items are composed of: +- Title +- Subtitle (optional) +- Leading icon (optional) + +The leading icon is : +- icon or image from resources +- Image from url. During image loading a placeholder Image is needed. Three kinds of shape are proposed (circular, square or wide). + + +### Standard list item + +For standard items, trailing icons can be added. Two types of icons are proposed: +- with text +- with text and info button to make an action + +![List item standard square light](images/list_items_standard_square_light.png) +![List item standard square dark](images/list_items_standard_square_dark.png) + +The standard item can be used in a `NavigationLink` (for example, display more details) + +```swift + +// Build the List view using ODSListItem withount navigation +List { + // Items without navigation + ODSListItem(title: Text("Title Only")).odsListItemStyle() + ODSListItem(title: Text("Title with subtitle"), subtitle: Text("subtitle")).odsListItemStyle() + ODSListItem(title: Text("Title with leading icon"), leading: .icon(Image(systemName: "heart"))).odsListItemStyle() + ODSListItem(title: Text("Title with trailing text"), trailingText: Text("Details")).odsListItemStyle() + ODSListItem(title: Text("Title with trailing text and info button"), trailingText: Text("Details")) { + // Add info button action here + }.odsListItemStyle() + + // Item with navigation + NavigationLink { + Text("The destination view") + } label: { + ODSListItem(title: Text("Title without trailing element")) + }.odsListItemStyle() + + NavigationLink { + Text("The destination view") + } label: { + ODSListItem(title: Text("Title with trailing text"), trailingText: Text("Details")) + }.odsListItemStyle() + + NavigationLink { + Text("The destination view") + } label: { + ODSListItem(title: Text("Title with trailing text and info button"), trailingText: Text("Details")) { + // Add info button action here + } + }.odsListItemStyle() +} +``` + +### Selection list item + +![List item slection circle light](images/list_items_selection_circle_light.png) +![List item slection circle dark](images/list_items_selection_circle_dark.png) + +The selection list items can be used to enumerate data as list in order to select elements. + +```swift +struct MyMultipleOptionsSelection: View { + + @State private var optionA: Bool = false + @State private var optionB: Bool = false + + var body: some View { + List { + ODSListItem( + title: Text("Option A"), + subtitle: Text("Option A description"), + trailingCheckmarkIsSelected: optionA + ) + .odsListItemStyle() + .onTapGesture { + optionA.toggle() + } + + ODSListItem( + title: Text("Option B"), + subtitle: Text("Option B description"), + trailingCheckmarkIsSelected: optionB + ) + .odsListItemStyle() + .onTapGesture { + optionB.toggle() + } + } + } +} +``` + +**Note 1:** Don’t forget, if item is used in a `NavigationLink`, a chevron is automatically added by the system. For design purpose it is NOT recommended to add item with `trailingCheckmarkIsSelected` and `trailingToggleIsOn` parameters in a `NavigationLink`. + +**Note 2:**Don’t forget to apply the style on: +- __ODSListItem__ if it is not used with NavigationLink. +- NavigationLink if __ODSListItem__ is its label. + diff --git a/docs/1.0.0/components/listItem_docs.md b/docs/1.0.0/components/listItem_docs.md new file mode 100644 index 00000000..9caa65f1 --- /dev/null +++ b/docs/1.0.0/components/listItem_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: List item +content_page: listItem.md +--- diff --git a/docs/1.0.0/components/progressIndicator.md b/docs/1.0.0/components/progressIndicator.md new file mode 100644 index 00000000..4271e5d7 --- /dev/null +++ b/docs/1.0.0/components/progressIndicator.md @@ -0,0 +1,72 @@ +--- +layout: detail +title: Progress indicator +description: Progress indicators show users that elements or pages are loading +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Progress indicators](https://system.design.orange.com/0c1af118d/p/5969ab-progress-indicator) +- [Apple guideline - Progress indicators](https://developer.apple.com/design/human-interface-guidelines/components/status/progress-indicators) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +Progress indicators show users that elements or pages are loading. + +### Progress bar + +Progres bar is used to display **determinate** operations. It display the indicator increasing in width from 0 to 100% of the track, in sync with the process’s progress. + +To display the indicator as progress bar with a specific color use the `tint`. + +![Progress bar](images/progress_bar.png) + +We recommend to use the theme for that using the accent color as shown in following exemple. + +```swift +ProgressView("Downloading...", value: value, total: 100) + .tint(theme.componentColors.accent) +``` + +It is possible to display the current value to provide more context. + +```swift +ProgressView(value: value, total: 100) { + Text("Downloading...") +} currentValueLabel: { + let percent = String(format: "%0.2f", value) + Text("\(percent) %").frame(maxWidth: .infinity, alignment: .trailing) +} +.tint(theme.componentColors.accent) +``` + +### Activity indicators + +Activity indicator is used to display **Indeterminate** operations. It spins while a task is performed. + +![Activity indicator](images/activity_indicator.png) + +```swift +ProgressView() +``` + +An additional label can be added to provide more context. + +```swift +ProgressView { + Text("Loading...") +} +``` diff --git a/docs/1.0.0/components/progressIndicator_docs.md b/docs/1.0.0/components/progressIndicator_docs.md new file mode 100644 index 00000000..17b0c0b6 --- /dev/null +++ b/docs/1.0.0/components/progressIndicator_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Progress indicator +content_page: progressIndicator.md +--- diff --git a/docs/1.0.0/components/sheetsBottom.md b/docs/1.0.0/components/sheetsBottom.md new file mode 100644 index 00000000..552072e8 --- /dev/null +++ b/docs/1.0.0/components/sheetsBottom.md @@ -0,0 +1,85 @@ +--- +layout: detail +title: Bottom sheets +description: Bottom Sheets are surfaces anchored to the bottom of the screen that present users supplement content. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Bottom sheets](https://system.design.orange.com/0c1af118d/p/3347ca-sheets-bottom/b/83b619) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +Bottom sheets are surfaces anchored to the bottom of the screen that present users supplemental content. +It is useful for requesting a specific information or enabling a simple task related to the current context +of the current view or more globaly the application context. + +### Standard + +The standard bottom sheet must be used only with a "simple, basic" content. If a more complex content (scrollable) must be added prefer the Expanding variant. + +It defines two states: +- **closed**: The content is hidden +- **opened**: The content is visible (above the main view) + +A taps on the header, opens or closes the bottom sheet. + +```swift +struct BottomSheetPresentation: View { + @State private var isOpen = false + + var body: some View { + VStack { + // Main content goes here. + Text("Bottom sheet is \(isOpen ? "Opened": "Closed")") + } + .odsBottomSheetStandard(isOpen: $isOpen, title: "Customize") { + // Bottom sheet content goes here + } + } +} +``` + +You can also define accessibility hints and labels for this standard bottom sheet so as to make VoiceOver vocalize the state of this sheet (opended or closed) or to vocalize some hints to make it be opened or not. + +### Expanding + +The type of bottom must be used if the content is more complex and perhaps need to be scrollable. + +It defines three size: +- **small**: (closed) The content is hidden, only the header is visible +- **medium**: (parcially opened) The content is parcially visible (half screen above the main view) but not scrollable +- **large**: (opened) The content is visible and scrollable + +User can resize by tapping on dimming area (close), drag the content, or tap on the header to cycle through the available sizes. + +```swift + struct BottomSheetPresentation: View { + @State private var bottomSheetSize: ODSBottomSheetSize = .large + var body: some View { + VStack { + // Main content goes here. + Text("Bottom sheet size \(bottomSheetSize.rawValue)") + } + .odsBottomSheetExpanding(title: "Customize", bottomSheetSize: $bottomSheetSize) { + // Bottom sheet content goes here + } + } + } +``` + +**Remark**: In order to compute the resizing when user scrolls the content, the bottom sheet automatically adds the provided content is a scrollView. + diff --git a/docs/1.0.0/components/sheetsBottom_docs.md b/docs/1.0.0/components/sheetsBottom_docs.md new file mode 100644 index 00000000..03d56ceb --- /dev/null +++ b/docs/1.0.0/components/sheetsBottom_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Sheets - Bottom +content_page: sheetsBottom.md +--- diff --git a/docs/1.0.0/components/slider.md b/docs/1.0.0/components/slider.md new file mode 100644 index 00000000..9bb3f76f --- /dev/null +++ b/docs/1.0.0/components/slider.md @@ -0,0 +1,105 @@ +--- +layout: detail +title: Sliders +description: Sliders allow users to make selections from a range of values. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Sliders](https://system.design.orange.com/0c1af118d/p/7559da-sliders/b/253eea) +- [Apple guideline - Sliders](https://developer.apple.com/design/human-interface-guidelines/components/selection-and-input/sliders) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +As the `ODSSlider` is based on the native `Slider`, Voice Over is able to vocalize +However, if you want to set a description you need to add it using `.accessibilityLabel` on the `ODSSlider`. + +We recommend to not set information on `minimumValueLabel` and `maximumValueLabel` view using `.accessibilityHidden(true)` + +## Variants + +Slider is a system Slider component with accent color set to coreOrange. + +![Sliders](images/sliders.png) + +### Unlabeled slider + +Unlabelled sliders allow users to make easy selections that do not require any details or context. + +```swift +struct UnlabeledSlider: View { + + @State private var value = 50.0 + + var body: some View { + ODSSlider(value: $value, in: 0 ... 100) + } +} +``` + +### Labeled slider (with images) + +We recommand to not set information on `minimumValueLabel` and `maximumValueLabel` view using `.accessibilityHidden(true)`. You can do it like this: + +```swift +struct LabeledSlider: View { + + @State private var value = 50.0 + + var body: some View { + ODSSlider(value: $value, in: 0 ... 100) { + Text("Volume") + } minimumValueLabel: { + Image(systemName: "speaker.wave.1.fill").accessibilityHidden(true) + } maximumValueLabel: { + Image(systemName: "speaker.wave.3.fill").accessibilityHidden(true) + } + } +} +``` + +### Labeled slider (with text) + +We recommand to not set information on `minimumValueLabel` and `maximumValueLabel` view using `.accessibilityHidden(true)`. You can do it like this: + +```swift +ODSSlider(value: $value, in: 0 ... 100) { + Text("Volume") +} minimumValueLabel: { + Text("0").accessibilityHidden(true) +} maximumValueLabel: { + Text("100").accessibilityHidden(true) +} +``` + +### Stepped slider (with text and value display) + +We recommand to not set information on `minimumValueLabel` and `maximumValueLabel` view using `.accessibilityHidden(true)`. You can do it like this: + +```swift +struct SteppedSlider: View { + + @State private var value = 50.0 + + var body: some View { + ODSSlider(value: $value, in: 0 ... 100.0, step: 0.5) { + Text("Volume") + } minimumValueLabel: { + Image(systemName: "speaker.wave.1.fill").accessibilityHidden(true) + } maximumValueLabel: { + Image(systemName: "speaker.wave.3.fill").accessibilityHidden(true) + } + } +} +``` diff --git a/docs/1.0.0/components/slider_docs.md b/docs/1.0.0/components/slider_docs.md new file mode 100644 index 00000000..29743fb1 --- /dev/null +++ b/docs/1.0.0/components/slider_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Slider +content_page: slider.md +--- diff --git a/docs/1.0.0/components/textInput.md b/docs/1.0.0/components/textInput.md new file mode 100644 index 00000000..a57f46df --- /dev/null +++ b/docs/1.0.0/components/textInput.md @@ -0,0 +1,64 @@ +--- +layout: detail +title: Text fields and text editor +description: Text fields and text editor let users enter and edit text. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Text fields](https://system.design.orange.com/0c1af118d/p/47d389-text-fields/b/461794) +- [Apple guideline - Text fields](https://developer.apple.com/design/human-interface-guidelines/components/selection-and-input/text-fields) +- [Apple guideline - Edit Menu](https://developer.apple.com/design/human-interface-guidelines/components/menus-and-actions/edit-menus) +- [Apple doc - Text input](https://developer.apple.com/documentation/swiftui/text-input-and-output) +- [Apple doc - Text Field](https://developer.apple.com/documentation/swiftui/textfield) +- [Apple doc - Secure Text Field](https://developer.apple.com/documentation/swiftui/securefield) +- [Apple doc - Text Editor](https://developer.apple.com/documentation/swiftui/i/texteditor) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +For all variants, we provide the `odsTextFieldStyle` view modifier to apply font, collors (background, tint) provided by the theme. + +### Text field + +A control that displays an editable text interface. + +```swift +TextField("A text field", text: $textToEdit) + .odsTextFieldStyle() +``` + + ### Secure text field + +Use a `SecureField` when you want behavior similar to a ``TextField``, but you don't want the user's text to be visible. Typically, you use this for entering passwords and other sensitive information. + +```swift +SecureField("Secure text", text: $textToEdit) + .odsTextFieldStyle() +``` + +### Text editor + +A text editor view allows you to display and edit multiline, scrollable text in your app's user interface. + +```swift +TextEditor(text: $textToEdit) + .odsTextFieldStyle() +``` + +## Text selection + +Text selection is available when text field or text editor is entering in edition mode. This is not a custom component but just a way to apply right style (customize with colors, font provided by theme). + diff --git a/docs/1.0.0/components/textInput_docs.md b/docs/1.0.0/components/textInput_docs.md new file mode 100644 index 00000000..fabdf10a --- /dev/null +++ b/docs/1.0.0/components/textInput_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Text fields +content_page: textInput.md +--- diff --git a/docs/1.0.0/guidelines/colors.md b/docs/1.0.0/guidelines/colors.md new file mode 100644 index 00000000..601c632d --- /dev/null +++ b/docs/1.0.0/guidelines/colors.md @@ -0,0 +1,56 @@ +--- +layout: detail +title: Colors +--- +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Colour](https://system.design.orange.com/0c1af118d/p/73fa17-colour/b/025652) +- [Apple guideline - The color system](https://developer.apple.com/design/human-interface-guidelines/foundations/color) + +## Theme colors + +Colors are defined in theme and described using `ODSColorDecription`, by setting : +- the asset name, +- the bundle containing the asset +- the color names for light and dark modes (used by demo application) + +Colors will be different depending on whether they are displayed in light or in dark mode. + +## How to use + +### Using the color name + +You can get color in theme using its name like this: + +``` swift + // Don't forget get theme from environment + @Environment(\.theme) var theme + + Image(systemName: "checkmark").foregroundColor(theme.color("coreOrange")) + MyView().background(theme.color("functionalInfo")) +``` + +### Using components token + +You can get color in theme using components token like this: + +``` swift +// Don't forget get theme from environment +@Environment(\.theme) var theme + +Button { +} label: { + Text("Cancel") + .padding(ODSSpacing.m) +} +.background(theme.componentColors.functionalNegative) +``` diff --git a/docs/1.0.0/guidelines/colors_docs.md b/docs/1.0.0/guidelines/colors_docs.md new file mode 100644 index 00000000..c2c79e6f --- /dev/null +++ b/docs/1.0.0/guidelines/colors_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Colors +content_page: colors.md +--- diff --git a/docs/1.0.0/guidelines/spacings.md b/docs/1.0.0/guidelines/spacings.md new file mode 100644 index 00000000..485f004a --- /dev/null +++ b/docs/1.0.0/guidelines/spacings.md @@ -0,0 +1,56 @@ +--- +layout: detail +title: Spacings +--- +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Spacings](https://system.design.orange.com/0c1af118d/p/375be7-spacing) +- [Apple guideline - Layout](https://developer.apple.com/design/human-interface-guidelines/foundations/layout) + +## Usage + +The spacing scale increases in small increments needed to describe both internal and external spacing relationships. Spacing tokens can be applied as padding and margins. + +### Apply spacing for magin + +Apply the spacing to get magin arround element like this: + +``` swift +// Add a padding of 16px arround the text in the button + +Button { + // Add your action here +} label: { + Text("ButtonText") + .padding(.all, ODSSpacing.m) +} + + +// Add a magin of 16px (leading and trailing) +VStack { + Text("Title") + Text("A very long text for description in the main view") +} +.padding(.horizontal: ODSSpacing.m) // Add a margin to the + +``` + +### Apply spacing for padding + +Apply the spacing to separate elements like this: + +``` swift +HStack(spacing: ODSSpacing.m) { + Image(systemname: "heart") + Text("Some text") +} +``` diff --git a/docs/1.0.0/guidelines/spacings_docs.md b/docs/1.0.0/guidelines/spacings_docs.md new file mode 100644 index 00000000..9f829894 --- /dev/null +++ b/docs/1.0.0/guidelines/spacings_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Spacings +content_page: spacings.md +--- diff --git a/docs/1.0.0/guidelines/typography.md b/docs/1.0.0/guidelines/typography.md new file mode 100644 index 00000000..1e52d8d9 --- /dev/null +++ b/docs/1.0.0/guidelines/typography.md @@ -0,0 +1,48 @@ +--- +layout: detail +title: Typography +--- +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Typography](https://system.design.orange.com/0c1af118d/p/54fe27-typography) +- [Apple guideline - Typography](https://developer.apple.com/design/human-interface-guidelines/foundations/typography/) + +## Implementation + +ODS library defines its own font style. The font associated to the style is defined in the theme set in the environment. + +### Apply font style on text + +Apply the font style on text like this: + +``` swift + Text("Sample").odsFont(.titleS) + TextField("A text field", text: $textToEdit).odsFont(.titleS) +``` + +### Apply font style on view + +In the example below, the first text field has a font style set directly, while the font applied to the following container applies to all of the text views inside that container. + +``` swift +VStack { + Text("Font applied to a text view.") + .odsFont(.headlineL) + + VStack { + Text("These two text views have the same font") + Text("applied to their parent view.") + } + .odsFont(.titleS) +} +``` + diff --git a/docs/1.0.0/guidelines/typography_docs.md b/docs/1.0.0/guidelines/typography_docs.md new file mode 100644 index 00000000..da3bdf9a --- /dev/null +++ b/docs/1.0.0/guidelines/typography_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Typography +content_page: typography.md +--- diff --git a/docs/1.0.0/home_content.md b/docs/1.0.0/home_content.md new file mode 100644 index 00000000..3ead013c --- /dev/null +++ b/docs/1.0.0/home_content.md @@ -0,0 +1,27 @@ +## Introduction + +Orange is providing a full Design System to build Orange Mobile Application. The objective of the [Orange Design System](https://system.design.orange.com/0c1af118d/p/95b685-ios/) (ODS) is to propose a set of guidelines on how to apply the Orange Brand on mobile applications. The Orange design System also provides a series of components and modules that show in details how to use this in the Orange apps. + +The Orange Design System has been implemented in a code library that provides: +- a SwiftUI code library +- a demo app that can be launched to show the guidelines, components and modules +- this demo app also shows how to use the lib or style existing components + +Using these resources will allow you to create Orange branded applications faster and will inherit all the work that was done to make sure that all presented codes are fully tested regarding the brand and the accessibility compliance. + +The Orange Design System framework supports iOS 15 and later. + +## Instructions + +### Swift Package Manager + +The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler. + +Once you have your Swift package set up, adding ODS as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`. + +```swift +dependencies: [ + .package(url: "https://github.com/Orange-OpenSource/ods-ios.git", .upToNextMajor(from: "1.0.0")) +] +``` + diff --git a/docs/1.0.0/index.md b/docs/1.0.0/index.md new file mode 100644 index 00000000..ef70b2b0 --- /dev/null +++ b/docs/1.0.0/index.md @@ -0,0 +1,7 @@ +--- +layout: main +title: Integration +description: Getting started with Orange Design System for iOS +--- + +{% include_relative home_content.md %} diff --git a/docs/1.0.0/index_content.md b/docs/1.0.0/index_content.md new file mode 100644 index 00000000..8c4b2b1e --- /dev/null +++ b/docs/1.0.0/index_content.md @@ -0,0 +1,7 @@ +--- +layout: detail +title: Integration +description: Getting started with Orange Design System for iOS +--- + +{% include_relative home_content.md %} diff --git a/docs/1.0.0/modules/about.md b/docs/1.0.0/modules/about.md new file mode 100644 index 00000000..584e9acd --- /dev/null +++ b/docs/1.0.0/modules/about.md @@ -0,0 +1,310 @@ +--- +layout: detail +title: About +description: An about screen should be displayed in all Orange applications to display the application name, software version as well as all legal data protection, privacy, and terms of service compliance information. +--- +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Modules - About](https://system.design.orange.com/0c1af118d/p/39538b-about/b/55a5d2) + +## Overview + +This module should be added in all applications to display general application information (name, software version, description, privacy policy, terms of service, ...), to offer user actions (Rate the app, send feedbacks, ...), to get informaioon linked to the service (Application recirculation, App news ...). + +It is also possible to add to the module some specifc features linked to the service provided by the application (Suppport, How to, settings, ...) + +In order to have consistant prsentation of those elemnts in all applications, the __About__ module offers a structured and configrable layout. + +![AboutScreen](images/about_screen.png) + + +## About screen layout + +The main about screen is divided to three areas. + +### Illustration area + +The first area (at the top of the screen) allows you to set an image illustrating the about screen linked to the service. If no image is provided the default one is inserted automatically. + +### Application information area + +The second area is dedicated for the application description with various elements: +- The name (mandatory) +- The version (optional) +- A description in sevral lines (optional) + + +It is also possible to activate two buttons to offer to the user to: + +- _share the application_ via email, via sms, via social networks... This button opens the default system share sheet that presents a range of actions to share the application. To activate this button, the developper needs to prvide the url of the application on the store and a short text describing the context of the sharing. +- _send feedback_ to the support of the service. This button is displayed if the developper provides a callback called when button is clicked. This callback can do what it is expected (send email, send sms, open form, open web site, ...). + + +### List items area + +The last area (at the bottom) is a list of items that propose to the user to make actions or navigate to additionnal feetures. +All items have the same layout (icon and text). They are ordered in the list according to their priority set into the configuration. + +#### Mandatory items + +Some items are provided with the module. Three of them are mandatory and allways available in the list: +- Item to present the __Privacy Policy__ (only html content supported today) +- Item to display __Terms of Service__ (View provided by developper) +- Item to show the __Accessibility Statement__ of the application (not available yet) +As those items must be grouped in the list, their priority are fixed and can not be changed. + +#### Optionnal items + +As most of applications propose the same additonnal features (Rate the app, App News, ...), and in order to have consitency in about screens of all applications, additional items are proposed with the module. + +* Rate the app + +This item can be added in the list to redirect the user to the app page on the Apple Store to rate the application. + +* Apps news + +This item enumerates the application versions with small text describing new features available. + +* Legal inofrmation + +This item is used to display legal infomration. Today, there is not recomandation on the presentation. + +#### Custom items + +In addition, it is also possible to add into the list some custom items. Like previous ones, they must respect the layout and can set their own priority to be inserted in the right place in the list. + + +## How to configure the module + +To display the about screen, initialize the module using the __ODSAboutModule__ stucture. During the initialization, a set of configuration must to be provided. + +### Illustration area + +If the about page needs to display a specific illustration, set it like this: + +```swft +ODSAboutModule(headerIllustration: Image("AboutImage"), ...) +``` + +To keep the default illustration, initialize the module without overriding the `headerIllustration` parameter. + + +### Application section area + +To configure the application, fill out the `ODSAboutApplicationInformation` structure and provide it to the module initialization. + +- With name only + +```swift +let nameOnly = ODSAboutApplicationInformation(name: "Orange Design System Demo") +ODSAboutModule(applicationInformation: nameOnly, ...) +``` + +- With description + +```swift +let withDescription = ODSAboutApplicationInformation( + name: "Orange Design System Demo" + description: "In this app you'll find implemented code examples of the guidelines, components and modules, for the themes of the Orange Design System.") +ODSAboutModule(applicationInformation: withDescription, ...) +``` + +- With version + +```swift +let version = ODSApplicationVersion( + marketingVersion: Bundle.main.marketingVersion, // Mandatory + buildNumber: Bundle.main.buildNumber ?? "", // Optional + buildType: Bundle.main.buildType // Optional +) + +let withVersion = ODSAboutApplicationInformation( + name: "Orange Design System Demo", + version: version +) + +ODSAboutModule(applicationInformation: withVersion, ...) +``` + +- To activate the Share the application action + +```swift +ler shareTheApplicationConfiguration = ODSAboutShareTheApplication( + storeUrl: URL(string: "http://oran.ge/dsapp")!, + subject: "The Orange Design System", + description: "Here you will find the Orange Design System Mobile App that provides examples of design implementations" +) + +let withShareTheApp = ODSAboutApplicationInformation( + name: "Orange Design System Demo", + shareConfiguration: shareTheApplicationConfiguration +) +ODSAboutModule(applicationInformation: withShareTheApp, ...) +``` + +- To activate the feedback action + +```swift + +let withFeedback = ODSAboutApplicationInformation( + name: "Orange Design System Demo", + onFeedbackClicked: { + UIApplication.shared.open(URL(string: "https://github.com/Orange-OpenSource/ods-ios/issues/new/choose")!) + } +) + +ODSAboutModule(applicationInformation: withFeedback, ...) +``` + +### Lits items area + +#### Use mandatory items + +For the privacy policy display, only HTML content is supported today. A more structured content will be added soon. + +- Privacy policy + +```swift +// Initializes the privacy policy page with URL of the HTML file stored in resources. +let privacyPolicy = ODSPrivacyPolicy.webview(.url(Bundle.main.url(forResource: "PrivacyNotice", withExtension: "html")!)) +``` + +- The accessibility statement + +```swift +// Defines an item displaying as a title the "conformity status" text, parsing the file named "fileName" and sending user elsewhere for further details +let accessibilityStatement = ODSAboutAccessibilityStatement( + conformityStatus: "Accessibility: partially conform", + fileName: "AccessibilityStatement", + reportDetail: URL(string: "https://la-va11ydette.orange.com/")!) +``` + +- The Terms of service + +```swift +// Today, there is no recomandation how to display the content, so the module provides a view builder +// to build a native screen or a webview + +@ViewBuilder +private func termsOfService() -> some View { + Text("Add terms of service here") +} +``` + +Then initialize the module with those mandatory elements: + +```swift +ODSAboutModule(..., + privacyPolicy: privacyPolicy, + acessibilityStatement: accessibilityStatement, + termsOfService: termOfService +) +``` + +#### Add items to the list + +To insert additionnal items into the list, initialize the __listItemConfigurations__ array adding items following the __ODSAboutListItemConfig__ protocol. +To order the items in the list, initialize the items with the right priority. + +```swift +// Add all items in list +ODSAboutModule(..., + listItemConfigurations: [legalInfoItem, rateTheAppItem, appsNewItem] +) + +// see items description below +``` + +#### Use optional items + +- Rate the app + +To create this item, define the url of the application on the store and the priority (position) of the item in the list: + +```swift +// This item opens the store in the external browser +let rateTheAppItem = ODSAboutRateTheAppItemConfig( + priority: 501, + storeUrl: URL(string: "https://www.apple.com/app-store/")! +) +``` + +- Apps news + +To create this item, define the path to the json file containing the news. This file is embeded in the resources of the application. + +The model of the json file is: + +```json +[ + { + "version": "0.12.0", + "date": "2023-04-14", + "news": "A short description of news" + }, + ... +] +``` + +This is the code to create the item: + +```swift +// - Display the app News +let appNewFilePath = Bundle.main.path(forResource: "AppNews", ofType: "json")! +let appsNewItem = ODSAboutAppNewsItemConfig( + priorty: 502, + path: appNewFilePath +) +``` + +- Legal information + +Still there is not recomandation on the format of the presentation, this item needs a view builder to display the legal information. + +```swift +// Here, the legal information are displayed in a view with a single Text. + +let legalInformationItem = ODSAboutLegalInformationItemConfig(priority: 500) { + Text("This is Legal information content") +} +``` + +- Apps recirculation + +You can also add an item to let people discover other apps of Orange, by using the following item: + +```swift +let appsRecirculation = ODSRecirculationItemConfig(dataSource: yourDataSource) +``` + +The __dataSource__ can contain the URL of the backend to get the list of apps, (today the only supported backend is Orange proprietary backend _Apps Plus_) or a local json file. (for more details see the __Recirculation Module__. + +#### Create a custom item + +To create a custom item and associate a target, follow this example: + +```swift +public struct MyItemToDisplayText: ODSAboutListItemConfig { + public private(set) var title: String + public private(set) var icon: Image + public private(set) var target: ODSAboutListItemTarget + public private(set) var priority: ODSAboutListItemPriority + + public init(priority: ODSAboutListItemPriority = 100) { + self.priority = priority + self.title = "Fake Item" + self.icon = Image(systemName: "heart"), + self.target = .destination(AnyView(Text("This is the destination screen"))) + } +} +``` + diff --git a/docs/1.0.0/modules/about_docs.md b/docs/1.0.0/modules/about_docs.md new file mode 100644 index 00000000..68f62b7e --- /dev/null +++ b/docs/1.0.0/modules/about_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: About +content_page: about.md +--- + diff --git a/docs/1.0.0/modules/emptyState.md b/docs/1.0.0/modules/emptyState.md new file mode 100644 index 00000000..e7061cfe --- /dev/null +++ b/docs/1.0.0/modules/emptyState.md @@ -0,0 +1,52 @@ +--- +layout: detail +title: Empty states +description: An empty state can occur when no content or data is available to display in the UI. Avoid displaying completely empty screens. +--- + +An empty state display should inform the user of what is happening, why it's happening and what to do about it. + +
**On this page** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Empty states](https://system.design.orange.com/0c1af118d/p/177496-empty-states/b/454547) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/). + +The ODS Empty states module is built to support accessibility criteria and is readable by most screen readers, such as VoiceOver. + +## Integration + +![Empty state light](images/empty_state_light.png) ![Empty state dark](images/empty_state_dark.png) + +### SwiftUI + +To integrate an ODS Empty state into your app, you can use `ODSEmptyStateView` as shown below: + +```swift +ODSEmptyStateView( + title: Text("No result"), + text: Text("Try a new search"), + image: Image("il_emptyStateNoData"), + button: Button("Search") { + // Do something + } +) +``` + +#### ODSEmptyStateView API + +| Parameter | Default value | Description | +|-------------------------------------|-----------------------------------------------------------------------------------|-----------------------------------------------------------------------------------| +| `title: Text` | | The title of the screen displayed below the image. For example "File is missing". | +| `text: Text?` | `null` | Text displayed below the title | +| `image: Image` | `Image("il_emptyStateUserCleared", bundle: Bundle.ods)` | Image displayed centered in the composable | +| `button: Button?` | `null` | The button to add below the text | diff --git a/docs/1.0.0/modules/emptyState_docs.md b/docs/1.0.0/modules/emptyState_docs.md new file mode 100644 index 00000000..15db0e38 --- /dev/null +++ b/docs/1.0.0/modules/emptyState_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: Empty states +content_page: emptyState.md +--- + diff --git a/docs/1.0.0/modules/images/about_screen.png b/docs/1.0.0/modules/images/about_screen.png new file mode 100644 index 00000000..ea0628be Binary files /dev/null and b/docs/1.0.0/modules/images/about_screen.png differ diff --git a/docs/1.0.0/modules/images/empty_state_dark.png b/docs/1.0.0/modules/images/empty_state_dark.png new file mode 100644 index 00000000..7fcd8c2a Binary files /dev/null and b/docs/1.0.0/modules/images/empty_state_dark.png differ diff --git a/docs/1.0.0/modules/images/empty_state_light.png b/docs/1.0.0/modules/images/empty_state_light.png new file mode 100644 index 00000000..2208398f Binary files /dev/null and b/docs/1.0.0/modules/images/empty_state_light.png differ diff --git a/docs/1.0.0/modules/images/list_grouped_dark.png b/docs/1.0.0/modules/images/list_grouped_dark.png new file mode 100644 index 00000000..1cd3da2f Binary files /dev/null and b/docs/1.0.0/modules/images/list_grouped_dark.png differ diff --git a/docs/1.0.0/modules/images/list_grouped_light.png b/docs/1.0.0/modules/images/list_grouped_light.png new file mode 100644 index 00000000..0010570d Binary files /dev/null and b/docs/1.0.0/modules/images/list_grouped_light.png differ diff --git a/docs/1.0.0/modules/images/list_inset_dark.png b/docs/1.0.0/modules/images/list_inset_dark.png new file mode 100644 index 00000000..9edc8c7f Binary files /dev/null and b/docs/1.0.0/modules/images/list_inset_dark.png differ diff --git a/docs/1.0.0/modules/images/list_inset_grouped_dark.png b/docs/1.0.0/modules/images/list_inset_grouped_dark.png new file mode 100644 index 00000000..d7b1959a Binary files /dev/null and b/docs/1.0.0/modules/images/list_inset_grouped_dark.png differ diff --git a/docs/1.0.0/modules/images/list_inset_grouped_light.png b/docs/1.0.0/modules/images/list_inset_grouped_light.png new file mode 100644 index 00000000..f5afcd3f Binary files /dev/null and b/docs/1.0.0/modules/images/list_inset_grouped_light.png differ diff --git a/docs/1.0.0/modules/images/list_inset_light.png b/docs/1.0.0/modules/images/list_inset_light.png new file mode 100644 index 00000000..64c9b21e Binary files /dev/null and b/docs/1.0.0/modules/images/list_inset_light.png differ diff --git a/docs/1.0.0/modules/images/list_plain_dark.png b/docs/1.0.0/modules/images/list_plain_dark.png new file mode 100644 index 00000000..9b189afa Binary files /dev/null and b/docs/1.0.0/modules/images/list_plain_dark.png differ diff --git a/docs/1.0.0/modules/images/list_plain_light.png b/docs/1.0.0/modules/images/list_plain_light.png new file mode 100644 index 00000000..de89eb09 Binary files /dev/null and b/docs/1.0.0/modules/images/list_plain_light.png differ diff --git a/docs/1.0.0/modules/images/list_sidebar_dark.png b/docs/1.0.0/modules/images/list_sidebar_dark.png new file mode 100644 index 00000000..12b22797 Binary files /dev/null and b/docs/1.0.0/modules/images/list_sidebar_dark.png differ diff --git a/docs/1.0.0/modules/images/list_sidebar_light.png b/docs/1.0.0/modules/images/list_sidebar_light.png new file mode 100644 index 00000000..5ba12f6b Binary files /dev/null and b/docs/1.0.0/modules/images/list_sidebar_light.png differ diff --git a/docs/1.0.0/modules/list.md b/docs/1.0.0/modules/list.md new file mode 100644 index 00000000..d2fa73b9 --- /dev/null +++ b/docs/1.0.0/modules/list.md @@ -0,0 +1,194 @@ +--- +layout: detail +title: List +description: Lists are continuous, vertical indexes of text or images. +--- +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Lists](https://system.design.orange.com/0c1af118d/p/09a804-lists/b/669743) +- [Apple guideline - Lists and tables](https://developer.apple.com/design/human-interface-guidelines/components/layout-and-organization/lists-and-tables) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## List styles + +List propose the `.listStyle(_:)` modifier to change the style. For ios SwiftUI propose 6 types of style: +- automatic +- insetGrouped +- grouped +- inset +- plain +- sidebar + +The folowing code is used for all styles. The only difference is the list style specified in the `.listStyle(_:)` modifier. + +```swift +NavigationStack { + List { + // Section for recipes contain selected ingredients + Section { + ODSListItem( + title: Text("Summer Salad"), + subtitle: Text("21 mn"), + leading: .circularImage(source: .image(Image("summerSalad"))) + ) + ODSListItem( + title: Text("Salmon cury"), + subtitle: Text("31 mn"), + leading: .circularImage(source: .image(Image("salmonCury"))) + ) + ODSListItem( + title: Text("Feta Pizza"), + subtitle: Text("21 mn"), + leading: .circularImage(source: .image(Image("fetaPizza"))) + ) + } header: { + Text("Recipes") + } footer: { + Text("A set of recipes made with selected ingredients") + } + + // A set of ingredients + Section("Ingredients") { + ODSListItem(title: Text("tomato"), leading: .circularImage(source: .image(Image("tomato")))) + ODSListItem(title: Text("avocado"), leading: .circularImage(source: .image(Image("avocado")))) + } + } + .navigationTitle("List Style") + .listStyle(.automatic) +} +``` + +### Automatic style + +As mentioned earlier, SwiftUI will use Inset Grouped style when setting automatic (.automatic) or DefaultListStyle on iOS + +### Inset Grouped style + +Example of Inset Grouped .insetGrouped or InsetGroupedListStyle. + +```swift +List { + // ... +} +.listStyle(.insetGrouped) +``` + +![InsetGroupedLight](images/list_inset_grouped_light.png) +![InsetGroupedDark](images/list_inset_grouped_dark.png) + +### Grouped style + +Example of Grouped .grouped or GroupedListStyle. + +```swift +List { + // ... +} +.listStyle(.grouped) +``` + +![GroupedLight](images/list_grouped_light.png) +![GroupedDark](images/list_grouped_dark.png) + +### Inset style + +Example of Inset .inset or InsetListStyle. + +```swift +List { + // ... +} +.listStyle(.inset) +``` + +![InsetLight](images/list_inset_light.png) +![InsetDark](images/list_inset_dark.png) + + +### Plain style + +Example of Plain .plain or PlainListStyle. + +```swift +List { + // ... +} +.listStyle(.plain) +``` +![PlainLight](images/list_plain_light.png) +![PlainDark](images/list_plain_dark.png) + +### Sidebar style + +The sidebar list style displays disclosure indicators in the section headers that allow the user to collapse and expand sections. + +Tap on disclosure indicators in the section headers will collapse and expand that section. + +```swift +List { + // ... +} +.listStyle(.sidebar) +``` + +![SideBarLight](images/list_sidebar_light.png) +![SideBarDark](images/list_sidebar_dark.png) + + +* For iOS 17, a new API is proposed to manage the expandable state. + +```swift +@State var isExpanded = true + +List { + Section(isExpanded: $isExpanded) { + // ... + } header: { + Text("Recipes") + } +} +.listStyle(.sidebar) +``` + +When you create your Section with `isExpanded`, the chevron will appear as long as the list style is `.sidebar`. + +* On previous iOS versions, this interface is not available, so to do the same you can use following code: + +```swift +@State var isExpanded = true + +List { + Section { + if isExpanded { + // The content + } + } header: { + HStack { + Text("Recipes") // The header + + Spacer() + Image(systemName: "chevron.down") + .rotationEffect(isExpanded ? .zero : .degrees(-90)) + .onTapGesture { + withAnimation { + isExpanded.toggle() + } + } + } + } +} +.listStyle(.sidebar) +``` + diff --git a/docs/1.0.0/modules/list_docs.md b/docs/1.0.0/modules/list_docs.md new file mode 100644 index 00000000..52f13ec1 --- /dev/null +++ b/docs/1.0.0/modules/list_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: List +content_page: list.md +--- + diff --git a/docs/modules/recirculation.md b/docs/1.0.0/modules/recirculation.md similarity index 100% rename from docs/modules/recirculation.md rename to docs/1.0.0/modules/recirculation.md diff --git a/docs/modules/recirculation_docs.md b/docs/1.0.0/modules/recirculation_docs.md similarity index 100% rename from docs/modules/recirculation_docs.md rename to docs/1.0.0/modules/recirculation_docs.md diff --git a/docs/1.1.0/about/Cookies.md b/docs/1.1.0/about/Cookies.md new file mode 100644 index 00000000..bbeca85f --- /dev/null +++ b/docs/1.1.0/about/Cookies.md @@ -0,0 +1,7 @@ +--- +layout: detail +title: "Cookies" +description: Manage cookies preferences. +--- + +At any time, you can manage your cookies preferences for this website from the cookies management panel. diff --git a/docs/1.1.0/about/Cookies_docs.md b/docs/1.1.0/about/Cookies_docs.md new file mode 100644 index 00000000..15499adc --- /dev/null +++ b/docs/1.1.0/about/Cookies_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Cookies +content_page: Cookies.md +--- diff --git a/docs/1.1.0/about/License.md b/docs/1.1.0/about/License.md new file mode 100644 index 00000000..8eb48c99 --- /dev/null +++ b/docs/1.1.0/about/License.md @@ -0,0 +1,35 @@ +--- +layout: detail +title: License +description: Commonly asked questions about ODS iOS open source license. +--- + +## ODS iOS license + +ODS iOS is released under the MIT license and is copyright Orange SA, which is released under MIT license. + +## It requires you to: + +- Keep the license and copyright notice included in ODS iOS Swift files when you use them in your works + +## It permits you to: + +- Freely download and use ODS iOS, in whole or in part, for personal, private, company internal, or commercial purposes +- Use ODS iOS in packages or distributions that you create +- Modify the source code +- Grant a sublicense to modify and distribute ODS iOS to third parties not included in the license + +## It forbids you to: + +- Hold the authors and license owners liable for damages as ODS iOS is provided without warranty +- Hold the creators or copyright holders of ODS iOS liable +- Redistribute any piece of ODS iOS without proper attribution +- Use any marks owned by Orange SA in any way that might state or imply that Orange SA endorses your distribution +- Use any marks owned by Orange SA in any way that might state or imply that you created the Orange SA software in question + +## It does not require you to: + +- Include the source of ODS iOS itself, or of any modifications you may have made to it, in any redistribution you may assemble that includes it +- Submit changes that you make to ODS iOS back to its project (though such feedback is encouraged) + +For more information, the full ODS iOS license is located [in the project repository](https://github.com/Orange-OpenSource/ods-ios/blob/main/LICENSE). diff --git a/docs/1.1.0/about/License_docs.md b/docs/1.1.0/about/License_docs.md new file mode 100644 index 00000000..18b9fd1f --- /dev/null +++ b/docs/1.1.0/about/License_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: License +content_page: License.md +--- diff --git a/docs/1.1.0/about/Team.md b/docs/1.1.0/about/Team.md new file mode 100644 index 00000000..71245c47 --- /dev/null +++ b/docs/1.1.0/about/Team.md @@ -0,0 +1,22 @@ +--- +layout: detail +title: Team +description: An overview of the founding team and core contributors to ODS iOS. +--- + +ODS iOS is maintained by the core team and a small group of invaluable core contributors, with the support and involvement of our community. + +{% if site.data.team.ODS_iOS[0] %} +
+ {% for team_member in site.data.team.ODS_iOS %} + + @{{ team_member.gh_pseudo }} + + {{ team_member.name }} @{{ team_member.gh_pseudo }} + + + {% endfor %} +
+{% endif %} + +Get involved with ODS iOS development by [opening an issue](https://github.com/Orange-OpenSource/ods-ios/issues/new/choose) or submitting a pull request. Read our [contributing guidelines](https://github.com/Orange-OpenSource/ods-ios/blob/main/CONTRIBUTING.md) for information on how we develop. diff --git a/docs/1.1.0/about/Team_docs.md b/docs/1.1.0/about/Team_docs.md new file mode 100644 index 00000000..92cde2e9 --- /dev/null +++ b/docs/1.1.0/about/Team_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Team +content_page: Team.md +--- diff --git a/docs/1.1.0/components/banners.md b/docs/1.1.0/components/banners.md new file mode 100644 index 00000000..35bd9176 --- /dev/null +++ b/docs/1.1.0/components/banners.md @@ -0,0 +1,103 @@ +--- +layout: detail +title: Banners +description: A banner displays an important message which requires an action to be dismissed. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +A banner displays an important, succinct message, and provides actions for users to address (or dismiss the banner). It requires a user action to be dismissed. + +Banners should be displayed at the top of the screen, below a top app bar. They’re persistent and nonmodal, allowing the user to either ignore them or interact with them at any time. Only one banner should be shown at a time + +![Banner light](images/banner-light.png) +![Banner dark](images/banner-dark.png) + +## Specifications references + +- [Design System Manager - Banners](https://system.design.orange.com/0c1af118d/p/85a52b-components/b/1497a4) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +### No button + +```swift +ODSBanner(text: "One to two lines is preferable on mobile and tablet.", + imageSource: .image(Image("placeholder", bundle: Bundle.ods))) +``` + +### One button + +The button is placed under the text. + +```swift +ODSBanner(text: "One to two lines is preferable on mobile and tablet.", + imageSource: .image(Image("placeholder", bundle: Bundle.ods))) { + Button("Button") { + // your action here + } +} +``` + +### Two buttons + +Button are placed under the text. + +```swift +ODSBanner(text: "One to two lines is preferable on mobile and tablet.", + imageSource: .image(Image("placeholder", bundle: Bundle.ods))) { + Button("Button 1") { + // your action here + } +} secondButton: { + Button("Button 1") { + // your action here + } +} +``` + +### Without image + +```swift +ODSBanner(text: "One to two lines is preferable on mobile and tablet.") { + Button("Button 1") { + // your action here + } +} secondButton: { + Button("Button 1") { + // your action here + } +} +``` + +### With image from url + +```swift + +let placeholder = Image("placeholder", bundle: Bundle.ods) +let url = URL(string: "https://images.unsplash.com/photo-1615735487485-e52b9af610c1?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=774&q=80") + +ODSBanner(text: "One to two lines is preferable on mobile and tablet.", + imageSource: .asyncImage(url, placeholder)) { + Button("Button 1") { + // your action here + } +} secondButton: { + Button("Button 1") { + // your action here + } +} +``` + + diff --git a/docs/1.1.0/components/banners_docs.md b/docs/1.1.0/components/banners_docs.md new file mode 100644 index 00000000..9d720197 --- /dev/null +++ b/docs/1.1.0/components/banners_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Banners +content_page: banners.md +--- diff --git a/docs/1.1.0/components/barsNavigation.md b/docs/1.1.0/components/barsNavigation.md new file mode 100644 index 00000000..79ae42da --- /dev/null +++ b/docs/1.1.0/components/barsNavigation.md @@ -0,0 +1,104 @@ +--- +layout: detail +title: Bars - navigation +description: Navigation bar with Orange branding +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Bars: navigation](https://system.design.orange.com/0c1af118d/p/34094d-bars-navigation/b/419eb1) +- [Apple guideline - Navigation bars](https://developer.apple.com/design/human-interface-guidelines/components/navigation-and-search/navigation-bars/) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Standard navigation bar + +![Navigation bar standard light](images/bars_navigation_standard_light.png) +![Navigation bar standard dark](images/bars_navigation_standard_dark.png) + +When using a navigation view, basic navigation is using 'inline' display mode by default. + +```swift +NavigationView { + NavigationLink(destination: Text("destination")) { + Text("Main view") + } + .navigationBarTitle("Standard", displayMode: .inline) +} + +``` + +## Navigation bar with large title + +![Navigation bar large light](images/bars_navigation_large_light.png) +![Navigation bar large dark](images/bars_navigation_large_dark.png) + +Use 'large' display mode to enable large titles when scrolling up. + +```swift +NavigationView { + NavigationLink(destination: Text("destination")) { + Text("Main view") + } + .navigationBarTitle("Standard", displayMode: .large) +} + +``` + +## Navigation bar with search bar + +![Navigation bar search light](images/bars_navigation_search_light.png) +![Navigation bar search dark](images/bars_navigation_search_dark.png) + + +Use .searchable modifier to add a search bar in the navigation view. + +```swift +@State var searchQuery = "" + +NavigationView { + NavigationLink(destination: Text("destination")) { + Text("Main view") + } + .navigationBarTitle("With search bar", displayMode: .inline) + .searchable(text: $searchQuery, placement: .navigationBarDrawer(displayMode: .always)) +} + +``` + +## Navigation bar with action item + +![Navigation bar items light](images/bars_navigation_items_light.png) +![Navigation bar items dark](images/bars_navigation_items_dark.png) + +You can add one or several buttons (trailing or leading) in the navigation view by using .toolbar modifier + +```swift +NavigationView { + NavigationLink(destination: Text("destination")) { + Text("Main view") + } + .navigationBarTitle("Standard", displayMode: .inline) + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button { + print("item action") + } label: { + Image(systemName: "ant.circle") + } + } + } +} + +``` diff --git a/docs/1.1.0/components/barsNavigation_docs.md b/docs/1.1.0/components/barsNavigation_docs.md new file mode 100644 index 00000000..11493173 --- /dev/null +++ b/docs/1.1.0/components/barsNavigation_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Bars - navigation +content_page: barsNavigation.md +--- diff --git a/docs/1.1.0/components/barsTab.md b/docs/1.1.0/components/barsTab.md new file mode 100644 index 00000000..2b95ab3c --- /dev/null +++ b/docs/1.1.0/components/barsTab.md @@ -0,0 +1,57 @@ +--- +layout: detail +title: Bars - tab +description: Tab bars with Orange branding +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Bars: tab](https://system.design.orange.com/0c1af118d/p/08dab8-bars-tab/b/778ed0) +- [Apple guideline - Tab bars](https://developer.apple.com/design/human-interface-guidelines/components/navigation-and-search/tab-bars/) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Standard tab bar + +![Tab bar light](images/bars_tab_light.png) +![Tab bar dark](images/bars_tab_dark.png) + +Tab bar is a standard iOS component. It uses bar items to navigate between views. +Bar Item contains an icon and a title. +An additonal badge can be also added with a count value or a text. + +Example with 4 bar items : + +```swift +TabView { + GuidelinesList() + .tabItem { + Label("Guidelines", image: "Guideline-DNA_32") + } + .badge("Text") + ComponentsList() + .tabItem { + Label("Components", image: "component-atom_32") + } + ModulesList() + .tabItem { + Label("Modules", image: "Module-molecule_32") + } + .badge(10) + ODSDemoAboutView() + .tabItem { + Label("About", image: "info_32") + } +} +``` diff --git a/docs/1.1.0/components/barsTab_docs.md b/docs/1.1.0/components/barsTab_docs.md new file mode 100644 index 00000000..55febdc2 --- /dev/null +++ b/docs/1.1.0/components/barsTab_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Bars - tab +content_page: barsTab.md +--- diff --git a/docs/1.1.0/components/barsTool.md b/docs/1.1.0/components/barsTool.md new file mode 100644 index 00000000..a229245f --- /dev/null +++ b/docs/1.1.0/components/barsTool.md @@ -0,0 +1,112 @@ +--- +layout: detail +title: Bars - tool +description: Tool bars with Orange branding +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Bars: tool](https://system.design.orange.com/0c1af118d/p/06c413-bars-tool/b/951e5c) +- [Apple guideline - Tool bars](https://developer.apple.com/design/human-interface-guidelines/ios/bars/toolbars/) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +A tool bar allows users to do specific actions regarding the entire page. It is placed at the bottom of the screen. It can display 2 to 5 icon controls or 2 to 3 label entries. + +### With label items + +![tool bar labels light](images/bars_tool_labels_light.png) ![tool bar labels dark](images/bars_tool_labels_dark.png) + +A tool bar can display 2 to 3 label entries. + +Example with 3 label entries in toolBar : + +```swift + +let description1 = ODSToolbarLabelDesription(text: "Action 1") { } +let description2 = ODSToolbarLabelDesription(text: "Action 2") { } +let description3 = ODSToolbarLabelDesription(text: "Action 3") { } + +let labelItems = ODSToolbarLabeledItems(description1: description1, + description2: description2, + description3: description3) +NavigationView { + ContentView() + .navigationBarTitle("", displayMode: .inline) + .navigationBarHidden(true) + .odsToolBar(items: labelItems) +} + +// To remove navigation bar, use following modifiers +// .navigationBarHidden(true) + +``` + +### With icon items + +![tool bar icons light](images/bars_tool_icons_light.png) ![tool bar icons dark](images/bars_tool_icons_dark.png) + +A tool bar can display 2 to 5 icon controls +```swift + +let description1 = ODSToolbarIconDesription(systemName: "plus") { } +let description2 = ODSToolbarIconDesription(systemName: "square.and.arrow.up") { } +let description3 = ODSToolbarIconDesription(systemName: "square.and.pencil") { } +let description4 = ODSToolbarIconDesription(systemName: "folder") { } +let description5 = ODSToolbarIconDesription(systemName: "trash") { } + +let iconItems = ODSToolbarIconsItems(description1: description1, + description2: description2, + description3: description3, + description4: description4, + description5: description5) +NavigationView { + ContentView() + .navigationBarTitle("", displayMode: .inline) + .navigationBarHidden(true) + .odsToolBar(items: iconItems) +} + +// To remove navigation bar, use following modifiers +// .navigationBarHidden(true) + +``` + +## Remarks + +As toolbar colors depends on theme, don't forget to add it to enviroment and call the view modifier __.toolBarColors(for:)__ to apply colors provided by the theme. + +Two solutions: + +- Directy on the root view + +```swift +let theme = YourTheme() + +ContentViewWithToolBar() +.environment(\.theme, theme) +.toolBarColors(for: theme) +``` + +- Or using __ODSThemeableView__ view as a root view: + +```swift +let theme = YourTheme() + +ODSThemeableView(theme: yourTheme) { + ContentViewWithToolBar() +} +``` diff --git a/docs/1.1.0/components/barsTool_docs.md b/docs/1.1.0/components/barsTool_docs.md new file mode 100644 index 00000000..a20e98aa --- /dev/null +++ b/docs/1.1.0/components/barsTool_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Bars - tool +content_page: barsTool.md +--- diff --git a/docs/1.1.0/components/buttons.md b/docs/1.1.0/components/buttons.md new file mode 100644 index 00000000..86013d1f --- /dev/null +++ b/docs/1.1.0/components/buttons.md @@ -0,0 +1,131 @@ +--- +layout: detail +title: Buttons +description: A button allows a user to perform an action or to navigate to another page. It contains a text label and a supporting icon can be displayed. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Buttons](https://system.design.orange.com/0c1af118d/p/278734-buttons-shape/b/536b5f) +- [Apple guideline - Buttons](https://developer.apple.com/design/human-interface-guidelines/components/menus-and-actions/buttons) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +### Emphasis button + +Button variants range in style to denote emphasis. Use different styles and not size to show the preferred choice. + +- **Layout** + +**Large** + +![Buttons high emphasis disabled](images/buttons_layout_large_with_icon.png) + +![Buttons high emphasis](images/buttons_layout_large_without_icon.png) + +**Small** + +![Buttons high emphasis disabled](images/buttons_layout_small_with_icon.png) + +![Buttons high emphasis](images/buttons_layout_small_without_icon.png) + + +- **Emphasis** + +**High emphasis** + +![Buttons high emphasis disabled](images/buttons_functionnal_disabled.png) +![Buttons high emphasis](images/buttons_emphasis_high.png) + +**Medium** + +![Buttons medium emphasis disabled](images/buttons_functionnal_disabled.png) +![Buttons medium emphasis](images/buttons_emphasis_medium.png) + +**Low emphasis** + +![Buttons low emphasis disabled](images/buttons_functionnal_disabled.png) +![Buttons low emphasis](images/buttons_emphasis_low.png) + +**Lowest emphasis** + +![Buttons lowest emphasis disabled](images/buttons_emphasis_lowest_disabled.png) +![Buttons lowest emphasis](images/buttons_emphasis_lowest.png) + +- **Implementation** + +```swift +// High emphasis +ODSButton(text: Text("Some text"), + image: Image("Add"), + emphasis: .high) {} + +// Lowest emphasis +ODSButton(text: Text("Some text"), + image: Image("Add"), + emphasis: .lowest) {} +``` + +### Functional button + +If required, colour versions can also be used to inform users of positive or negative destructive actions. + +**Positive** + +![Buttons functional positive disabled](images/buttons_functionnal_disabled.png) +![Buttons functional positive](images/buttons_functional_positive.png) + +**Negative** + +![Buttons functional negative disabled](images/buttons_functionnal_disabled.png) +![Buttons functional negative](images/buttons_functional_negative.png) + +```swift + // Negative button + ODSFunctionalButton(text: Text("Some text"), style: .negative) + { /* action: Do something */ } + + ODSFunctionalButton(text: Text("Some text"), image: Image("Add"), style: .negative) + { /* action: Do something */ } + + // Positive button + ODSFunctionalButton(text: Text("Some text") style: .positive) + { /* action: Do something */ } + + ODSFunctionalButton(text: Text("Some text"), image: Image("Add"), style: .positive) + { /* action: Do something */ } + + // To disable the button + ODSFunctionalButton(text: Text("Some text"), style: .positive) { /* action: Do something */ } + .disabled(true) +``` + +### Icon button + +Plain buttons are the most ubiquitous component found throughout applications. Consisting an icon, they are the most simple button style. + +![Buttons icon](images/buttons_icon.png) + +```swift +// icon with system asset +ODSIconButton(image: Image(systemName: "info.circle")) {} + +// icon with Solaris asset +ODSIconButton(image: Image("Add")) {} +``` + + + diff --git a/docs/1.1.0/components/buttons_docs.md b/docs/1.1.0/components/buttons_docs.md new file mode 100644 index 00000000..085cbe10 --- /dev/null +++ b/docs/1.1.0/components/buttons_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Buttons +content_page: buttons.md +--- diff --git a/docs/1.1.0/components/cards.md b/docs/1.1.0/components/cards.md new file mode 100644 index 00000000..633a1e92 --- /dev/null +++ b/docs/1.1.0/components/cards.md @@ -0,0 +1,209 @@ +--- +layout: detail +title: Cards +description: Cards contain content and actions about a single subject. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Cards](https://system.design.orange.com/0c1af118d/p/66bac5-cards/b/1591fb) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +Images in cards are considered as decorative, so they are ignored by Voice Over. + +## Variants + +Cards are a contained and independent element that can display content and actions on a single topic. + +There are a few ways cards can be presented. Ranging from a single title on its own for a simple card view or with more information shown in a subtitle and supporting text and actions at the bottom of the card. + + +### Vertical Image First Card + +This is a full width card displayed with an image as first element. + +This card is composed of two parts: +- Media: (today an image) +- Content: with a title, an optional subtitle an optional supporting text and optional buttons (zero up to two) + +![Vertical image first card light](images/card_vertical_image_first_light.png) ![Vertical image first card dark](images/card_vertical_image_first_dark.png) + +> **Implementation** + +Card is configured like this: + +```swift +ODSCardVerticalImageFirst( + title: Text("Title"), + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: Text("Subtitle"), + text: Text("A supporting text to describe something") +) { + Button("Button 1") { + // do something here + } +} secondButton: { + Button("Button 2") { + // do something here + } +} +``` + +### Vertical Header First Card + +This is a full width card displaying with a title and a thumbnail on top as first element. + +This card is composed of three parts: +- Header: with a title, an optional subtitle and an optional thmubnail +- Media: (today an image) +- Content: with an optional supporting text and optional buttons (zero up to two) + +![Vertical header first card light](images/card_vertical_header_first_light.png) ![Vertical header first card dark](images/card_vertical_header_first_dark.png) + +> **Implementation** + +Card is configured like this: + +```swift + +ODSCardVerticalHeaderFirst( + title: Text("Title"), + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: Text("Subtitle"), + thumbnailSource: .image(Image("placeholder", bundle: Bundle.ods)), + text: Text("A supporting text to describe something") +) { + Button("Button 1") { + // do something here + } +} secondButton: { + Button("Button 2") { + // do something here + } +} +``` + +### Horizontal Card + +This is a full width card displaying with image on left and content with texts on the right. Additonal action buttons can be added at the bottom of the card. + +Thes content is composed by: +- a title +- an optional subtitle +- an optional text for larger description + +![Horizontal card light](images/card_horizontal_light.png) ![Horizontal card dark](images/card_horizontal_dark.png) + +> **Implementation** + +Card is configured like this: + +```swift +ODSCardHorizontal( + title: Text("Title"), + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + imagePosition: .leading, + subtitle: Text("Subtitle"), + text: Text("A supporting text to describe something") +) { + + Button("Button 1") { + // do something here + } +} secondButton : { + Button("Button 1") { + // do something here + } +} +``` + +### Small Card + +The small card if prefered for two-column portrait mobile screen display. +As it is smaller than full-width cards, it contains only title and subtitle (optional) in one line (Truncated tail). + +![Small card light](images/card_small_light.png) ![Small card dark](images/card_small_dark.png) + +> **Implementation** + +Card is configured like this: + +```swift +ODSCardSmall( + title: Text("Title"), + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: Text("Subtitle") +) +``` + +How to add Small Card in Grid + +```swift +class Model { + let title: String + let subtitle: String? + let imageSource: ODSImage.Source + + init(title: String, imageSource: ODSImage.Source, subtitle: String? = nil) { + self.title = title + self.imageSource = imageSource + self.subtitle = subtitle + } +} + + +let models = [ + Model( + title: "Title 1", + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: "Subtitle 1" + ) + Model( + title: "Title 2", + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: "Subtitle 2" + ) + //... +] + +/// /!\ Don't forget to put the grid into a scrollview +ScrollView { + LazyVGrid(columns: columns, spacing: ODSSpacing.none) { + ForEach(models, id:\.title) { model in + ODSCardSmall( + title: Text(model.title), + imageSource: model.imageSource, + subtitle: Text(model.subtitle) + ) + } + } + .padding(.all, ODSSpacing.m) +} + +``` + +However for accessibility edge cases, like when text sizes are accessibility sizes, the behaviour is different for such components. They won't be displayed in one truncated line because the text will be too truncated and difficult to read. +If this choice is too impacting for your UI, it is possible to define the limit number of lines to use if a11y size are used + +```swift +ODSCardSmall( + title: Text("Title"), + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: Text("Subtitle"), + // Here 3 is the number of lines you want for such edge cases + titleAccessibleLineLimit: 3, + subtitleAccessibleLineLimit: 3 +) +``` diff --git a/docs/1.1.0/components/cards_docs.md b/docs/1.1.0/components/cards_docs.md new file mode 100644 index 00000000..193969dd --- /dev/null +++ b/docs/1.1.0/components/cards_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Cards +content_page: cards.md +--- diff --git a/docs/1.1.0/components/chips.md b/docs/1.1.0/components/chips.md new file mode 100644 index 00000000..264df252 --- /dev/null +++ b/docs/1.1.0/components/chips.md @@ -0,0 +1,162 @@ +--- +layout: detail +title: Chips +description: Chips are compact elements that represent an input, attribute, or action. +--- + +--- + +**Page summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager](https://system.design.orange.com/0c1af118d/p/85a52b-components/b/1497a4) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +Chips support dynamic types for accessibility. + +Chips support content labeling for accessibility and are readable by most screen readers. Text rendered in chips is automatically provided to accessibility services. Additional content labels are usually unnecessary. + +## Variants + +### Action chip + +Action chips offer actions related to primary content. They should appear dynamically and contextually in a UI. +An alternative to action chips are buttons, which should appear persistently and consistently. + +![Light action chip](images/chips_action_light.png) +![Dark action chip](images/chips_action_dark.png) + +``` swift +ODSActionChip( + text: Text("chip text"), + Image(systemname: "heart") + action: { doSomething() } +) +``` + +To disable the chip call the `.disabled` on View. + +### Input chip + +Input chips represent a complex piece of information in compact form, such as an entity (person, place, or thing) or text. They enable user input and verify that input by converting text into chips. + +![Light input chip](images/chips_input_light.png) +![Dark input chip](images/chips_input_dark.png) + +``` swift +// Input chip with leading filled with icon or image for resources + +ODSInputChip( + text: Text(vhip text), + leadingAvatar: .image(Image("Avatar")), + action: { doSomething() }, + removeAction: { doSomething() } +) +``` + +### Choice chip + +Choice chips allow selection of a single chip from a set of options. Choice chips clearly delineate and display options in a compact area. + +**Note: To display a set of choice chips please see ODSChoiceChipsPicker** + +![Light input chip](images/chips_choice_light.png) +![Dark input chip](images/chips_choice_dark.png) + +``` swift +enum Ingredient: String, CaseIterable { + case chocolate, vanilla, strawberry +} + +ODSChoiceChipView( + chip: ODSChoiceChip(text: Text("Chocolate"), value: .chocolate), + selected: false: + action: { doSomething() } +) +ODSChoiceChipView( + chip: ODSChoiceChip(text: Text("Vanilla"), value: .vanilla), + selected: true: + action: { doSomething() } +) +``` + +In order to display a set of choice chips you can follow this example: + +``` swift +@State var selection: Ingredient + +var body: some View { + ScrollView(.horizontal) { + ForEach(Ingredient.allCases, id: \.rawValue) { ingredient in + ODSChoiceChipView( + model: ODSChoiceChip(text: Text(ingredient.rawValue), value: ingredient), + selected: selection == ingredient, + action: { selection = ingredient } + ) + } + } +} +``` + +To simplify the chips placement and alignment, you can also use the __ODSChoiceChipsPicker__ like this: + +``` swift +@State var selection: Ingredient + +ODSChoiceChipPicker( + title: Text("Select your ingredient"), + chips: Ingredient.allCases.map { ODSChoiceChip(text: Text($0.rawValue), value: $0) + selection: $selection, + placement: .carousel +) +``` + +### Filter chip + +Filter chips use tags or descriptive words to filter content. Filter chips allow selection of a set of chips from a set of options. Its usage is usefull to apply a filtering on a list of elmeents. + +**Note: To display a set of filter chips please see ODSFilterChipsPicker** + +![Light filter chips](images/chips_filter_light.png) ![Dark filter chips](images/chips_filter_dark.png) + +![Light filter chips with avatar](images/chips_filter_avatar_light.png) ![Dark filter chips with avatar](images/chips_filter_avatar_dark.png) + + +``` swift +enum Ingredient: String, CaseIterable { + case chocolate, vanilla, strawberry + + var image: Image { + Image("self.rawValue") + } +} + +ODSFilterChipView( + chip: ODSFilterChip(text: Text("Chocolate"), leading: .image(Image("avatar")), value: .chocolate), + selected: false: + action: { doSomething() } +) +``` + +As the choice chip, to simplify the chips placement and alignment, you can also use the __ODSFilterChipsPicker__ like this: + +``` swift +@State var selection: [Ingredient] + +ODSFilterChipPicker( + title: Text("Select your ingredients"), + chips: Ingredient.allCases.map { ODSFilterChip(text: Text($0.rawValue), leading(.image($0.image)), value: $0) + selection: $selection, + placement: .carousel +) +``` + diff --git a/docs/1.1.0/components/chips_docs.md b/docs/1.1.0/components/chips_docs.md new file mode 100644 index 00000000..51287dad --- /dev/null +++ b/docs/1.1.0/components/chips_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Chips +content_page: chips.md +--- diff --git a/docs/1.1.0/components/images/activity_indicator.png b/docs/1.1.0/components/images/activity_indicator.png new file mode 100644 index 00000000..5567e614 Binary files /dev/null and b/docs/1.1.0/components/images/activity_indicator.png differ diff --git a/docs/1.1.0/components/images/banner-dark.png b/docs/1.1.0/components/images/banner-dark.png new file mode 100644 index 00000000..769144eb Binary files /dev/null and b/docs/1.1.0/components/images/banner-dark.png differ diff --git a/docs/1.1.0/components/images/banner-light.png b/docs/1.1.0/components/images/banner-light.png new file mode 100644 index 00000000..ec84c11f Binary files /dev/null and b/docs/1.1.0/components/images/banner-light.png differ diff --git a/docs/1.1.0/components/images/bars_navigation_items_dark.png b/docs/1.1.0/components/images/bars_navigation_items_dark.png new file mode 100644 index 00000000..e7124a46 Binary files /dev/null and b/docs/1.1.0/components/images/bars_navigation_items_dark.png differ diff --git a/docs/1.1.0/components/images/bars_navigation_items_light.png b/docs/1.1.0/components/images/bars_navigation_items_light.png new file mode 100644 index 00000000..8cc70e0d Binary files /dev/null and b/docs/1.1.0/components/images/bars_navigation_items_light.png differ diff --git a/docs/1.1.0/components/images/bars_navigation_large_dark.png b/docs/1.1.0/components/images/bars_navigation_large_dark.png new file mode 100644 index 00000000..97e823e5 Binary files /dev/null and b/docs/1.1.0/components/images/bars_navigation_large_dark.png differ diff --git a/docs/1.1.0/components/images/bars_navigation_large_light.png b/docs/1.1.0/components/images/bars_navigation_large_light.png new file mode 100644 index 00000000..320fcae0 Binary files /dev/null and b/docs/1.1.0/components/images/bars_navigation_large_light.png differ diff --git a/docs/1.1.0/components/images/bars_navigation_search_dark.png b/docs/1.1.0/components/images/bars_navigation_search_dark.png new file mode 100644 index 00000000..b5c851e4 Binary files /dev/null and b/docs/1.1.0/components/images/bars_navigation_search_dark.png differ diff --git a/docs/1.1.0/components/images/bars_navigation_search_light.png b/docs/1.1.0/components/images/bars_navigation_search_light.png new file mode 100644 index 00000000..915a2029 Binary files /dev/null and b/docs/1.1.0/components/images/bars_navigation_search_light.png differ diff --git a/docs/1.1.0/components/images/bars_navigation_standard_dark.png b/docs/1.1.0/components/images/bars_navigation_standard_dark.png new file mode 100644 index 00000000..d20b5a7a Binary files /dev/null and b/docs/1.1.0/components/images/bars_navigation_standard_dark.png differ diff --git a/docs/1.1.0/components/images/bars_navigation_standard_light.png b/docs/1.1.0/components/images/bars_navigation_standard_light.png new file mode 100644 index 00000000..9b9f93db Binary files /dev/null and b/docs/1.1.0/components/images/bars_navigation_standard_light.png differ diff --git a/docs/1.1.0/components/images/bars_tab_dark.png b/docs/1.1.0/components/images/bars_tab_dark.png new file mode 100644 index 00000000..25a09787 Binary files /dev/null and b/docs/1.1.0/components/images/bars_tab_dark.png differ diff --git a/docs/1.1.0/components/images/bars_tab_light.png b/docs/1.1.0/components/images/bars_tab_light.png new file mode 100644 index 00000000..da7e46bf Binary files /dev/null and b/docs/1.1.0/components/images/bars_tab_light.png differ diff --git a/docs/1.1.0/components/images/bars_tool_icons_dark.png b/docs/1.1.0/components/images/bars_tool_icons_dark.png new file mode 100644 index 00000000..3be894a5 Binary files /dev/null and b/docs/1.1.0/components/images/bars_tool_icons_dark.png differ diff --git a/docs/1.1.0/components/images/bars_tool_icons_light.png b/docs/1.1.0/components/images/bars_tool_icons_light.png new file mode 100644 index 00000000..758ecd9f Binary files /dev/null and b/docs/1.1.0/components/images/bars_tool_icons_light.png differ diff --git a/docs/1.1.0/components/images/bars_tool_labels_dark.png b/docs/1.1.0/components/images/bars_tool_labels_dark.png new file mode 100644 index 00000000..dda57849 Binary files /dev/null and b/docs/1.1.0/components/images/bars_tool_labels_dark.png differ diff --git a/docs/1.1.0/components/images/bars_tool_labels_light.png b/docs/1.1.0/components/images/bars_tool_labels_light.png new file mode 100644 index 00000000..d46cfe54 Binary files /dev/null and b/docs/1.1.0/components/images/bars_tool_labels_light.png differ diff --git a/docs/1.1.0/components/images/buttons_emphasis_high.png b/docs/1.1.0/components/images/buttons_emphasis_high.png new file mode 100644 index 00000000..c0a98b7f Binary files /dev/null and b/docs/1.1.0/components/images/buttons_emphasis_high.png differ diff --git a/docs/1.1.0/components/images/buttons_emphasis_low.png b/docs/1.1.0/components/images/buttons_emphasis_low.png new file mode 100644 index 00000000..e306cb0e Binary files /dev/null and b/docs/1.1.0/components/images/buttons_emphasis_low.png differ diff --git a/docs/1.1.0/components/images/buttons_emphasis_lowest.png b/docs/1.1.0/components/images/buttons_emphasis_lowest.png new file mode 100644 index 00000000..317dae96 Binary files /dev/null and b/docs/1.1.0/components/images/buttons_emphasis_lowest.png differ diff --git a/docs/1.1.0/components/images/buttons_emphasis_lowest_disabled.png b/docs/1.1.0/components/images/buttons_emphasis_lowest_disabled.png new file mode 100644 index 00000000..c9931849 Binary files /dev/null and b/docs/1.1.0/components/images/buttons_emphasis_lowest_disabled.png differ diff --git a/docs/1.1.0/components/images/buttons_emphasis_medium.png b/docs/1.1.0/components/images/buttons_emphasis_medium.png new file mode 100644 index 00000000..ef148b6e Binary files /dev/null and b/docs/1.1.0/components/images/buttons_emphasis_medium.png differ diff --git a/docs/1.1.0/components/images/buttons_functional_negative.png b/docs/1.1.0/components/images/buttons_functional_negative.png new file mode 100644 index 00000000..5d88a0fc Binary files /dev/null and b/docs/1.1.0/components/images/buttons_functional_negative.png differ diff --git a/docs/1.1.0/components/images/buttons_functional_positive.png b/docs/1.1.0/components/images/buttons_functional_positive.png new file mode 100644 index 00000000..330ef3d6 Binary files /dev/null and b/docs/1.1.0/components/images/buttons_functional_positive.png differ diff --git a/docs/1.1.0/components/images/buttons_functionnal_disabled.png b/docs/1.1.0/components/images/buttons_functionnal_disabled.png new file mode 100644 index 00000000..803d1200 Binary files /dev/null and b/docs/1.1.0/components/images/buttons_functionnal_disabled.png differ diff --git a/docs/1.1.0/components/images/buttons_icon.png b/docs/1.1.0/components/images/buttons_icon.png new file mode 100644 index 00000000..552dc955 Binary files /dev/null and b/docs/1.1.0/components/images/buttons_icon.png differ diff --git a/docs/1.1.0/components/images/buttons_layout_large_with_icon.png b/docs/1.1.0/components/images/buttons_layout_large_with_icon.png new file mode 100644 index 00000000..29d586ac Binary files /dev/null and b/docs/1.1.0/components/images/buttons_layout_large_with_icon.png differ diff --git a/docs/1.1.0/components/images/buttons_layout_large_without_icon.png b/docs/1.1.0/components/images/buttons_layout_large_without_icon.png new file mode 100644 index 00000000..e6f378d7 Binary files /dev/null and b/docs/1.1.0/components/images/buttons_layout_large_without_icon.png differ diff --git a/docs/1.1.0/components/images/buttons_layout_small_with_icon.png b/docs/1.1.0/components/images/buttons_layout_small_with_icon.png new file mode 100644 index 00000000..a0b7ae5c Binary files /dev/null and b/docs/1.1.0/components/images/buttons_layout_small_with_icon.png differ diff --git a/docs/1.1.0/components/images/buttons_layout_small_without_icon.png b/docs/1.1.0/components/images/buttons_layout_small_without_icon.png new file mode 100644 index 00000000..93ae02fd Binary files /dev/null and b/docs/1.1.0/components/images/buttons_layout_small_without_icon.png differ diff --git a/docs/1.1.0/components/images/card_horizontal_dark.png b/docs/1.1.0/components/images/card_horizontal_dark.png new file mode 100644 index 00000000..7fe518b8 Binary files /dev/null and b/docs/1.1.0/components/images/card_horizontal_dark.png differ diff --git a/docs/1.1.0/components/images/card_horizontal_light.png b/docs/1.1.0/components/images/card_horizontal_light.png new file mode 100644 index 00000000..fdd1bdb3 Binary files /dev/null and b/docs/1.1.0/components/images/card_horizontal_light.png differ diff --git a/docs/1.1.0/components/images/card_small_dark.png b/docs/1.1.0/components/images/card_small_dark.png new file mode 100644 index 00000000..211a72a9 Binary files /dev/null and b/docs/1.1.0/components/images/card_small_dark.png differ diff --git a/docs/1.1.0/components/images/card_small_light.png b/docs/1.1.0/components/images/card_small_light.png new file mode 100644 index 00000000..e2b9949b Binary files /dev/null and b/docs/1.1.0/components/images/card_small_light.png differ diff --git a/docs/1.1.0/components/images/card_vertical_header_first_dark.png b/docs/1.1.0/components/images/card_vertical_header_first_dark.png new file mode 100644 index 00000000..542c62eb Binary files /dev/null and b/docs/1.1.0/components/images/card_vertical_header_first_dark.png differ diff --git a/docs/1.1.0/components/images/card_vertical_header_first_light.png b/docs/1.1.0/components/images/card_vertical_header_first_light.png new file mode 100644 index 00000000..66460143 Binary files /dev/null and b/docs/1.1.0/components/images/card_vertical_header_first_light.png differ diff --git a/docs/1.1.0/components/images/card_vertical_image_first_dark.png b/docs/1.1.0/components/images/card_vertical_image_first_dark.png new file mode 100644 index 00000000..f9a5299d Binary files /dev/null and b/docs/1.1.0/components/images/card_vertical_image_first_dark.png differ diff --git a/docs/1.1.0/components/images/card_vertical_image_first_light.png b/docs/1.1.0/components/images/card_vertical_image_first_light.png new file mode 100644 index 00000000..58ee1f75 Binary files /dev/null and b/docs/1.1.0/components/images/card_vertical_image_first_light.png differ diff --git a/docs/1.1.0/components/images/chips_action_dark.png b/docs/1.1.0/components/images/chips_action_dark.png new file mode 100644 index 00000000..e0a50458 Binary files /dev/null and b/docs/1.1.0/components/images/chips_action_dark.png differ diff --git a/docs/1.1.0/components/images/chips_action_light.png b/docs/1.1.0/components/images/chips_action_light.png new file mode 100644 index 00000000..e2d8a9d6 Binary files /dev/null and b/docs/1.1.0/components/images/chips_action_light.png differ diff --git a/docs/1.1.0/components/images/chips_choice_dark.png b/docs/1.1.0/components/images/chips_choice_dark.png new file mode 100644 index 00000000..d848d8ad Binary files /dev/null and b/docs/1.1.0/components/images/chips_choice_dark.png differ diff --git a/docs/1.1.0/components/images/chips_choice_light.png b/docs/1.1.0/components/images/chips_choice_light.png new file mode 100644 index 00000000..37781814 Binary files /dev/null and b/docs/1.1.0/components/images/chips_choice_light.png differ diff --git a/docs/1.1.0/components/images/chips_filter_avatar_dark.png b/docs/1.1.0/components/images/chips_filter_avatar_dark.png new file mode 100644 index 00000000..e4269dcc Binary files /dev/null and b/docs/1.1.0/components/images/chips_filter_avatar_dark.png differ diff --git a/docs/1.1.0/components/images/chips_filter_avatar_light.png b/docs/1.1.0/components/images/chips_filter_avatar_light.png new file mode 100644 index 00000000..56857458 Binary files /dev/null and b/docs/1.1.0/components/images/chips_filter_avatar_light.png differ diff --git a/docs/1.1.0/components/images/chips_filter_dark.png b/docs/1.1.0/components/images/chips_filter_dark.png new file mode 100644 index 00000000..45fe2cf0 Binary files /dev/null and b/docs/1.1.0/components/images/chips_filter_dark.png differ diff --git a/docs/1.1.0/components/images/chips_filter_light.png b/docs/1.1.0/components/images/chips_filter_light.png new file mode 100644 index 00000000..d9c57620 Binary files /dev/null and b/docs/1.1.0/components/images/chips_filter_light.png differ diff --git a/docs/1.1.0/components/images/chips_input_dark.png b/docs/1.1.0/components/images/chips_input_dark.png new file mode 100644 index 00000000..315167eb Binary files /dev/null and b/docs/1.1.0/components/images/chips_input_dark.png differ diff --git a/docs/1.1.0/components/images/chips_input_light.png b/docs/1.1.0/components/images/chips_input_light.png new file mode 100644 index 00000000..6e928d1d Binary files /dev/null and b/docs/1.1.0/components/images/chips_input_light.png differ diff --git a/docs/1.1.0/components/images/list_items_selection_circle_dark.png b/docs/1.1.0/components/images/list_items_selection_circle_dark.png new file mode 100644 index 00000000..cef8cafe Binary files /dev/null and b/docs/1.1.0/components/images/list_items_selection_circle_dark.png differ diff --git a/docs/1.1.0/components/images/list_items_selection_circle_light.png b/docs/1.1.0/components/images/list_items_selection_circle_light.png new file mode 100644 index 00000000..871e26a4 Binary files /dev/null and b/docs/1.1.0/components/images/list_items_selection_circle_light.png differ diff --git a/docs/1.1.0/components/images/list_items_standard_square_dark.png b/docs/1.1.0/components/images/list_items_standard_square_dark.png new file mode 100644 index 00000000..7e6d2994 Binary files /dev/null and b/docs/1.1.0/components/images/list_items_standard_square_dark.png differ diff --git a/docs/1.1.0/components/images/list_items_standard_square_light.png b/docs/1.1.0/components/images/list_items_standard_square_light.png new file mode 100644 index 00000000..03dc9d15 Binary files /dev/null and b/docs/1.1.0/components/images/list_items_standard_square_light.png differ diff --git a/docs/1.1.0/components/images/progress_bar.png b/docs/1.1.0/components/images/progress_bar.png new file mode 100644 index 00000000..d571477e Binary files /dev/null and b/docs/1.1.0/components/images/progress_bar.png differ diff --git a/docs/1.1.0/components/images/sliders.png b/docs/1.1.0/components/images/sliders.png new file mode 100644 index 00000000..1a5c9c81 Binary files /dev/null and b/docs/1.1.0/components/images/sliders.png differ diff --git a/docs/1.1.0/components/listItem.md b/docs/1.1.0/components/listItem.md new file mode 100644 index 00000000..a56d4d25 --- /dev/null +++ b/docs/1.1.0/components/listItem.md @@ -0,0 +1,132 @@ +--- +layout: detail +title: List item +description: Lists are continuous, vertical indexes of text or images. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Lists](https://system.design.orange.com/0c1af118d/p/09a804-lists/b/669743) +- [Apple guideline - Lists and tables](https://developer.apple.com/design/human-interface-guidelines/components/layout-and-organization/lists-and-tables) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +Here we just propose a configuration for two types of list items: +- Standard with trailing actions +- Selection with trailing icons (selection indicators) + +All items are composed of: +- Title +- Subtitle (optional) +- Leading icon (optional) + +The leading icon is : +- icon or image from resources +- Image from url. During image loading a placeholder Image is needed. Three kinds of shape are proposed (circular, square or wide). + + +### Standard list item + +For standard items, trailing icons can be added. Two types of icons are proposed: +- with text +- with text and info button to make an action + +![List item standard square light](images/list_items_standard_square_light.png) +![List item standard square dark](images/list_items_standard_square_dark.png) + +The standard item can be used in a `NavigationLink` (for example, display more details) + +```swift + +// Build the List view using ODSListItem withount navigation +List { + // Items without navigation + ODSListItem(title: Text("Title Only")).odsListItemStyle() + ODSListItem(title: Text("Title with subtitle"), subtitle: Text("subtitle")).odsListItemStyle() + ODSListItem(title: Text("Title with leading icon"), leading: .icon(Image(systemName: "heart"))).odsListItemStyle() + ODSListItem(title: Text("Title with trailing text"), trailingText: Text("Details")).odsListItemStyle() + ODSListItem(title: Text("Title with trailing text and info button"), trailingText: Text("Details")) { + // Add info button action here + }.odsListItemStyle() + + // Item with navigation + NavigationLink { + Text("The destination view") + } label: { + ODSListItem(title: Text("Title without trailing element")) + }.odsListItemStyle() + + NavigationLink { + Text("The destination view") + } label: { + ODSListItem(title: Text("Title with trailing text"), trailingText: Text("Details")) + }.odsListItemStyle() + + NavigationLink { + Text("The destination view") + } label: { + ODSListItem(title: Text("Title with trailing text and info button"), trailingText: Text("Details")) { + // Add info button action here + } + }.odsListItemStyle() +} +``` + +### Selection list item + +![List item slection circle light](images/list_items_selection_circle_light.png) +![List item slection circle dark](images/list_items_selection_circle_dark.png) + +The selection list items can be used to enumerate data as list in order to select elements. + +```swift +struct MyMultipleOptionsSelection: View { + + @State private var optionA: Bool = false + @State private var optionB: Bool = false + + var body: some View { + List { + ODSListItem( + title: Text("Option A"), + subtitle: Text("Option A description"), + trailingCheckmarkIsSelected: optionA + ) + .odsListItemStyle() + .onTapGesture { + optionA.toggle() + } + + ODSListItem( + title: Text("Option B"), + subtitle: Text("Option B description"), + trailingCheckmarkIsSelected: optionB + ) + .odsListItemStyle() + .onTapGesture { + optionB.toggle() + } + } + } +} +``` + +**Note 1:** Don’t forget, if item is used in a `NavigationLink`, a chevron is automatically added by the system. For design purpose it is NOT recommended to add item with `trailingCheckmarkIsSelected` and `trailingToggleIsOn` parameters in a `NavigationLink`. + +**Note 2:**Don’t forget to apply the style on: +- __ODSListItem__ if it is not used with NavigationLink. +- NavigationLink if __ODSListItem__ is its label. + diff --git a/docs/1.1.0/components/listItem_docs.md b/docs/1.1.0/components/listItem_docs.md new file mode 100644 index 00000000..9caa65f1 --- /dev/null +++ b/docs/1.1.0/components/listItem_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: List item +content_page: listItem.md +--- diff --git a/docs/1.1.0/components/progressIndicator.md b/docs/1.1.0/components/progressIndicator.md new file mode 100644 index 00000000..4271e5d7 --- /dev/null +++ b/docs/1.1.0/components/progressIndicator.md @@ -0,0 +1,72 @@ +--- +layout: detail +title: Progress indicator +description: Progress indicators show users that elements or pages are loading +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Progress indicators](https://system.design.orange.com/0c1af118d/p/5969ab-progress-indicator) +- [Apple guideline - Progress indicators](https://developer.apple.com/design/human-interface-guidelines/components/status/progress-indicators) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +Progress indicators show users that elements or pages are loading. + +### Progress bar + +Progres bar is used to display **determinate** operations. It display the indicator increasing in width from 0 to 100% of the track, in sync with the process’s progress. + +To display the indicator as progress bar with a specific color use the `tint`. + +![Progress bar](images/progress_bar.png) + +We recommend to use the theme for that using the accent color as shown in following exemple. + +```swift +ProgressView("Downloading...", value: value, total: 100) + .tint(theme.componentColors.accent) +``` + +It is possible to display the current value to provide more context. + +```swift +ProgressView(value: value, total: 100) { + Text("Downloading...") +} currentValueLabel: { + let percent = String(format: "%0.2f", value) + Text("\(percent) %").frame(maxWidth: .infinity, alignment: .trailing) +} +.tint(theme.componentColors.accent) +``` + +### Activity indicators + +Activity indicator is used to display **Indeterminate** operations. It spins while a task is performed. + +![Activity indicator](images/activity_indicator.png) + +```swift +ProgressView() +``` + +An additional label can be added to provide more context. + +```swift +ProgressView { + Text("Loading...") +} +``` diff --git a/docs/1.1.0/components/progressIndicator_docs.md b/docs/1.1.0/components/progressIndicator_docs.md new file mode 100644 index 00000000..17b0c0b6 --- /dev/null +++ b/docs/1.1.0/components/progressIndicator_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Progress indicator +content_page: progressIndicator.md +--- diff --git a/docs/1.1.0/components/sheetsBottom.md b/docs/1.1.0/components/sheetsBottom.md new file mode 100644 index 00000000..552072e8 --- /dev/null +++ b/docs/1.1.0/components/sheetsBottom.md @@ -0,0 +1,85 @@ +--- +layout: detail +title: Bottom sheets +description: Bottom Sheets are surfaces anchored to the bottom of the screen that present users supplement content. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Bottom sheets](https://system.design.orange.com/0c1af118d/p/3347ca-sheets-bottom/b/83b619) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +Bottom sheets are surfaces anchored to the bottom of the screen that present users supplemental content. +It is useful for requesting a specific information or enabling a simple task related to the current context +of the current view or more globaly the application context. + +### Standard + +The standard bottom sheet must be used only with a "simple, basic" content. If a more complex content (scrollable) must be added prefer the Expanding variant. + +It defines two states: +- **closed**: The content is hidden +- **opened**: The content is visible (above the main view) + +A taps on the header, opens or closes the bottom sheet. + +```swift +struct BottomSheetPresentation: View { + @State private var isOpen = false + + var body: some View { + VStack { + // Main content goes here. + Text("Bottom sheet is \(isOpen ? "Opened": "Closed")") + } + .odsBottomSheetStandard(isOpen: $isOpen, title: "Customize") { + // Bottom sheet content goes here + } + } +} +``` + +You can also define accessibility hints and labels for this standard bottom sheet so as to make VoiceOver vocalize the state of this sheet (opended or closed) or to vocalize some hints to make it be opened or not. + +### Expanding + +The type of bottom must be used if the content is more complex and perhaps need to be scrollable. + +It defines three size: +- **small**: (closed) The content is hidden, only the header is visible +- **medium**: (parcially opened) The content is parcially visible (half screen above the main view) but not scrollable +- **large**: (opened) The content is visible and scrollable + +User can resize by tapping on dimming area (close), drag the content, or tap on the header to cycle through the available sizes. + +```swift + struct BottomSheetPresentation: View { + @State private var bottomSheetSize: ODSBottomSheetSize = .large + var body: some View { + VStack { + // Main content goes here. + Text("Bottom sheet size \(bottomSheetSize.rawValue)") + } + .odsBottomSheetExpanding(title: "Customize", bottomSheetSize: $bottomSheetSize) { + // Bottom sheet content goes here + } + } + } +``` + +**Remark**: In order to compute the resizing when user scrolls the content, the bottom sheet automatically adds the provided content is a scrollView. + diff --git a/docs/1.1.0/components/sheetsBottom_docs.md b/docs/1.1.0/components/sheetsBottom_docs.md new file mode 100644 index 00000000..03d56ceb --- /dev/null +++ b/docs/1.1.0/components/sheetsBottom_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Sheets - Bottom +content_page: sheetsBottom.md +--- diff --git a/docs/1.1.0/components/slider.md b/docs/1.1.0/components/slider.md new file mode 100644 index 00000000..9bb3f76f --- /dev/null +++ b/docs/1.1.0/components/slider.md @@ -0,0 +1,105 @@ +--- +layout: detail +title: Sliders +description: Sliders allow users to make selections from a range of values. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Sliders](https://system.design.orange.com/0c1af118d/p/7559da-sliders/b/253eea) +- [Apple guideline - Sliders](https://developer.apple.com/design/human-interface-guidelines/components/selection-and-input/sliders) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +As the `ODSSlider` is based on the native `Slider`, Voice Over is able to vocalize +However, if you want to set a description you need to add it using `.accessibilityLabel` on the `ODSSlider`. + +We recommend to not set information on `minimumValueLabel` and `maximumValueLabel` view using `.accessibilityHidden(true)` + +## Variants + +Slider is a system Slider component with accent color set to coreOrange. + +![Sliders](images/sliders.png) + +### Unlabeled slider + +Unlabelled sliders allow users to make easy selections that do not require any details or context. + +```swift +struct UnlabeledSlider: View { + + @State private var value = 50.0 + + var body: some View { + ODSSlider(value: $value, in: 0 ... 100) + } +} +``` + +### Labeled slider (with images) + +We recommand to not set information on `minimumValueLabel` and `maximumValueLabel` view using `.accessibilityHidden(true)`. You can do it like this: + +```swift +struct LabeledSlider: View { + + @State private var value = 50.0 + + var body: some View { + ODSSlider(value: $value, in: 0 ... 100) { + Text("Volume") + } minimumValueLabel: { + Image(systemName: "speaker.wave.1.fill").accessibilityHidden(true) + } maximumValueLabel: { + Image(systemName: "speaker.wave.3.fill").accessibilityHidden(true) + } + } +} +``` + +### Labeled slider (with text) + +We recommand to not set information on `minimumValueLabel` and `maximumValueLabel` view using `.accessibilityHidden(true)`. You can do it like this: + +```swift +ODSSlider(value: $value, in: 0 ... 100) { + Text("Volume") +} minimumValueLabel: { + Text("0").accessibilityHidden(true) +} maximumValueLabel: { + Text("100").accessibilityHidden(true) +} +``` + +### Stepped slider (with text and value display) + +We recommand to not set information on `minimumValueLabel` and `maximumValueLabel` view using `.accessibilityHidden(true)`. You can do it like this: + +```swift +struct SteppedSlider: View { + + @State private var value = 50.0 + + var body: some View { + ODSSlider(value: $value, in: 0 ... 100.0, step: 0.5) { + Text("Volume") + } minimumValueLabel: { + Image(systemName: "speaker.wave.1.fill").accessibilityHidden(true) + } maximumValueLabel: { + Image(systemName: "speaker.wave.3.fill").accessibilityHidden(true) + } + } +} +``` diff --git a/docs/1.1.0/components/slider_docs.md b/docs/1.1.0/components/slider_docs.md new file mode 100644 index 00000000..29743fb1 --- /dev/null +++ b/docs/1.1.0/components/slider_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Slider +content_page: slider.md +--- diff --git a/docs/1.1.0/components/textInput.md b/docs/1.1.0/components/textInput.md new file mode 100644 index 00000000..a57f46df --- /dev/null +++ b/docs/1.1.0/components/textInput.md @@ -0,0 +1,64 @@ +--- +layout: detail +title: Text fields and text editor +description: Text fields and text editor let users enter and edit text. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Text fields](https://system.design.orange.com/0c1af118d/p/47d389-text-fields/b/461794) +- [Apple guideline - Text fields](https://developer.apple.com/design/human-interface-guidelines/components/selection-and-input/text-fields) +- [Apple guideline - Edit Menu](https://developer.apple.com/design/human-interface-guidelines/components/menus-and-actions/edit-menus) +- [Apple doc - Text input](https://developer.apple.com/documentation/swiftui/text-input-and-output) +- [Apple doc - Text Field](https://developer.apple.com/documentation/swiftui/textfield) +- [Apple doc - Secure Text Field](https://developer.apple.com/documentation/swiftui/securefield) +- [Apple doc - Text Editor](https://developer.apple.com/documentation/swiftui/i/texteditor) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +For all variants, we provide the `odsTextFieldStyle` view modifier to apply font, collors (background, tint) provided by the theme. + +### Text field + +A control that displays an editable text interface. + +```swift +TextField("A text field", text: $textToEdit) + .odsTextFieldStyle() +``` + + ### Secure text field + +Use a `SecureField` when you want behavior similar to a ``TextField``, but you don't want the user's text to be visible. Typically, you use this for entering passwords and other sensitive information. + +```swift +SecureField("Secure text", text: $textToEdit) + .odsTextFieldStyle() +``` + +### Text editor + +A text editor view allows you to display and edit multiline, scrollable text in your app's user interface. + +```swift +TextEditor(text: $textToEdit) + .odsTextFieldStyle() +``` + +## Text selection + +Text selection is available when text field or text editor is entering in edition mode. This is not a custom component but just a way to apply right style (customize with colors, font provided by theme). + diff --git a/docs/1.1.0/components/textInput_docs.md b/docs/1.1.0/components/textInput_docs.md new file mode 100644 index 00000000..fabdf10a --- /dev/null +++ b/docs/1.1.0/components/textInput_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Text fields +content_page: textInput.md +--- diff --git a/docs/1.1.0/guidelines/colors.md b/docs/1.1.0/guidelines/colors.md new file mode 100644 index 00000000..601c632d --- /dev/null +++ b/docs/1.1.0/guidelines/colors.md @@ -0,0 +1,56 @@ +--- +layout: detail +title: Colors +--- +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Colour](https://system.design.orange.com/0c1af118d/p/73fa17-colour/b/025652) +- [Apple guideline - The color system](https://developer.apple.com/design/human-interface-guidelines/foundations/color) + +## Theme colors + +Colors are defined in theme and described using `ODSColorDecription`, by setting : +- the asset name, +- the bundle containing the asset +- the color names for light and dark modes (used by demo application) + +Colors will be different depending on whether they are displayed in light or in dark mode. + +## How to use + +### Using the color name + +You can get color in theme using its name like this: + +``` swift + // Don't forget get theme from environment + @Environment(\.theme) var theme + + Image(systemName: "checkmark").foregroundColor(theme.color("coreOrange")) + MyView().background(theme.color("functionalInfo")) +``` + +### Using components token + +You can get color in theme using components token like this: + +``` swift +// Don't forget get theme from environment +@Environment(\.theme) var theme + +Button { +} label: { + Text("Cancel") + .padding(ODSSpacing.m) +} +.background(theme.componentColors.functionalNegative) +``` diff --git a/docs/1.1.0/guidelines/colors_docs.md b/docs/1.1.0/guidelines/colors_docs.md new file mode 100644 index 00000000..c2c79e6f --- /dev/null +++ b/docs/1.1.0/guidelines/colors_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Colors +content_page: colors.md +--- diff --git a/docs/1.1.0/guidelines/spacings.md b/docs/1.1.0/guidelines/spacings.md new file mode 100644 index 00000000..485f004a --- /dev/null +++ b/docs/1.1.0/guidelines/spacings.md @@ -0,0 +1,56 @@ +--- +layout: detail +title: Spacings +--- +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Spacings](https://system.design.orange.com/0c1af118d/p/375be7-spacing) +- [Apple guideline - Layout](https://developer.apple.com/design/human-interface-guidelines/foundations/layout) + +## Usage + +The spacing scale increases in small increments needed to describe both internal and external spacing relationships. Spacing tokens can be applied as padding and margins. + +### Apply spacing for magin + +Apply the spacing to get magin arround element like this: + +``` swift +// Add a padding of 16px arround the text in the button + +Button { + // Add your action here +} label: { + Text("ButtonText") + .padding(.all, ODSSpacing.m) +} + + +// Add a magin of 16px (leading and trailing) +VStack { + Text("Title") + Text("A very long text for description in the main view") +} +.padding(.horizontal: ODSSpacing.m) // Add a margin to the + +``` + +### Apply spacing for padding + +Apply the spacing to separate elements like this: + +``` swift +HStack(spacing: ODSSpacing.m) { + Image(systemname: "heart") + Text("Some text") +} +``` diff --git a/docs/1.1.0/guidelines/spacings_docs.md b/docs/1.1.0/guidelines/spacings_docs.md new file mode 100644 index 00000000..9f829894 --- /dev/null +++ b/docs/1.1.0/guidelines/spacings_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Spacings +content_page: spacings.md +--- diff --git a/docs/1.1.0/guidelines/typography.md b/docs/1.1.0/guidelines/typography.md new file mode 100644 index 00000000..1e52d8d9 --- /dev/null +++ b/docs/1.1.0/guidelines/typography.md @@ -0,0 +1,48 @@ +--- +layout: detail +title: Typography +--- +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Typography](https://system.design.orange.com/0c1af118d/p/54fe27-typography) +- [Apple guideline - Typography](https://developer.apple.com/design/human-interface-guidelines/foundations/typography/) + +## Implementation + +ODS library defines its own font style. The font associated to the style is defined in the theme set in the environment. + +### Apply font style on text + +Apply the font style on text like this: + +``` swift + Text("Sample").odsFont(.titleS) + TextField("A text field", text: $textToEdit).odsFont(.titleS) +``` + +### Apply font style on view + +In the example below, the first text field has a font style set directly, while the font applied to the following container applies to all of the text views inside that container. + +``` swift +VStack { + Text("Font applied to a text view.") + .odsFont(.headlineL) + + VStack { + Text("These two text views have the same font") + Text("applied to their parent view.") + } + .odsFont(.titleS) +} +``` + diff --git a/docs/1.1.0/guidelines/typography_docs.md b/docs/1.1.0/guidelines/typography_docs.md new file mode 100644 index 00000000..da3bdf9a --- /dev/null +++ b/docs/1.1.0/guidelines/typography_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Typography +content_page: typography.md +--- diff --git a/docs/1.1.0/home_content.md b/docs/1.1.0/home_content.md new file mode 100644 index 00000000..c85da878 --- /dev/null +++ b/docs/1.1.0/home_content.md @@ -0,0 +1,27 @@ +## Introduction + +Orange is providing a full Design System to build Orange Mobile Application. The objective of the [Orange Design System](https://system.design.orange.com/0c1af118d/p/95b685-ios/) (ODS) is to propose a set of guidelines on how to apply the Orange Brand on mobile applications. The Orange design System also provides a series of components and modules that show in details how to use this in the Orange apps. + +The Orange Design System has been implemented in a code library that provides: +- a SwiftUI code library +- a demo app that can be launched to show the guidelines, components and modules +- this demo app also shows how to use the lib or style existing components + +Using these resources will allow you to create Orange branded applications faster and will inherit all the work that was done to make sure that all presented codes are fully tested regarding the brand and the accessibility compliance. + +The Orange Design System framework supports iOS 15 and later. + +## Instructions + +### Swift Package Manager + +The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler. + +Once you have your Swift package set up, adding ODS as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`. + +```swift +dependencies: [ + .package(url: "https://github.com/Orange-OpenSource/ods-ios.git", .upToNextMajor(from: "1.1.0")) +] +``` + diff --git a/docs/1.1.0/index.md b/docs/1.1.0/index.md new file mode 100644 index 00000000..ef70b2b0 --- /dev/null +++ b/docs/1.1.0/index.md @@ -0,0 +1,7 @@ +--- +layout: main +title: Integration +description: Getting started with Orange Design System for iOS +--- + +{% include_relative home_content.md %} diff --git a/docs/1.1.0/index_content.md b/docs/1.1.0/index_content.md new file mode 100644 index 00000000..8c4b2b1e --- /dev/null +++ b/docs/1.1.0/index_content.md @@ -0,0 +1,7 @@ +--- +layout: detail +title: Integration +description: Getting started with Orange Design System for iOS +--- + +{% include_relative home_content.md %} diff --git a/docs/1.1.0/modules/about.md b/docs/1.1.0/modules/about.md new file mode 100644 index 00000000..584e9acd --- /dev/null +++ b/docs/1.1.0/modules/about.md @@ -0,0 +1,310 @@ +--- +layout: detail +title: About +description: An about screen should be displayed in all Orange applications to display the application name, software version as well as all legal data protection, privacy, and terms of service compliance information. +--- +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Modules - About](https://system.design.orange.com/0c1af118d/p/39538b-about/b/55a5d2) + +## Overview + +This module should be added in all applications to display general application information (name, software version, description, privacy policy, terms of service, ...), to offer user actions (Rate the app, send feedbacks, ...), to get informaioon linked to the service (Application recirculation, App news ...). + +It is also possible to add to the module some specifc features linked to the service provided by the application (Suppport, How to, settings, ...) + +In order to have consistant prsentation of those elemnts in all applications, the __About__ module offers a structured and configrable layout. + +![AboutScreen](images/about_screen.png) + + +## About screen layout + +The main about screen is divided to three areas. + +### Illustration area + +The first area (at the top of the screen) allows you to set an image illustrating the about screen linked to the service. If no image is provided the default one is inserted automatically. + +### Application information area + +The second area is dedicated for the application description with various elements: +- The name (mandatory) +- The version (optional) +- A description in sevral lines (optional) + + +It is also possible to activate two buttons to offer to the user to: + +- _share the application_ via email, via sms, via social networks... This button opens the default system share sheet that presents a range of actions to share the application. To activate this button, the developper needs to prvide the url of the application on the store and a short text describing the context of the sharing. +- _send feedback_ to the support of the service. This button is displayed if the developper provides a callback called when button is clicked. This callback can do what it is expected (send email, send sms, open form, open web site, ...). + + +### List items area + +The last area (at the bottom) is a list of items that propose to the user to make actions or navigate to additionnal feetures. +All items have the same layout (icon and text). They are ordered in the list according to their priority set into the configuration. + +#### Mandatory items + +Some items are provided with the module. Three of them are mandatory and allways available in the list: +- Item to present the __Privacy Policy__ (only html content supported today) +- Item to display __Terms of Service__ (View provided by developper) +- Item to show the __Accessibility Statement__ of the application (not available yet) +As those items must be grouped in the list, their priority are fixed and can not be changed. + +#### Optionnal items + +As most of applications propose the same additonnal features (Rate the app, App News, ...), and in order to have consitency in about screens of all applications, additional items are proposed with the module. + +* Rate the app + +This item can be added in the list to redirect the user to the app page on the Apple Store to rate the application. + +* Apps news + +This item enumerates the application versions with small text describing new features available. + +* Legal inofrmation + +This item is used to display legal infomration. Today, there is not recomandation on the presentation. + +#### Custom items + +In addition, it is also possible to add into the list some custom items. Like previous ones, they must respect the layout and can set their own priority to be inserted in the right place in the list. + + +## How to configure the module + +To display the about screen, initialize the module using the __ODSAboutModule__ stucture. During the initialization, a set of configuration must to be provided. + +### Illustration area + +If the about page needs to display a specific illustration, set it like this: + +```swft +ODSAboutModule(headerIllustration: Image("AboutImage"), ...) +``` + +To keep the default illustration, initialize the module without overriding the `headerIllustration` parameter. + + +### Application section area + +To configure the application, fill out the `ODSAboutApplicationInformation` structure and provide it to the module initialization. + +- With name only + +```swift +let nameOnly = ODSAboutApplicationInformation(name: "Orange Design System Demo") +ODSAboutModule(applicationInformation: nameOnly, ...) +``` + +- With description + +```swift +let withDescription = ODSAboutApplicationInformation( + name: "Orange Design System Demo" + description: "In this app you'll find implemented code examples of the guidelines, components and modules, for the themes of the Orange Design System.") +ODSAboutModule(applicationInformation: withDescription, ...) +``` + +- With version + +```swift +let version = ODSApplicationVersion( + marketingVersion: Bundle.main.marketingVersion, // Mandatory + buildNumber: Bundle.main.buildNumber ?? "", // Optional + buildType: Bundle.main.buildType // Optional +) + +let withVersion = ODSAboutApplicationInformation( + name: "Orange Design System Demo", + version: version +) + +ODSAboutModule(applicationInformation: withVersion, ...) +``` + +- To activate the Share the application action + +```swift +ler shareTheApplicationConfiguration = ODSAboutShareTheApplication( + storeUrl: URL(string: "http://oran.ge/dsapp")!, + subject: "The Orange Design System", + description: "Here you will find the Orange Design System Mobile App that provides examples of design implementations" +) + +let withShareTheApp = ODSAboutApplicationInformation( + name: "Orange Design System Demo", + shareConfiguration: shareTheApplicationConfiguration +) +ODSAboutModule(applicationInformation: withShareTheApp, ...) +``` + +- To activate the feedback action + +```swift + +let withFeedback = ODSAboutApplicationInformation( + name: "Orange Design System Demo", + onFeedbackClicked: { + UIApplication.shared.open(URL(string: "https://github.com/Orange-OpenSource/ods-ios/issues/new/choose")!) + } +) + +ODSAboutModule(applicationInformation: withFeedback, ...) +``` + +### Lits items area + +#### Use mandatory items + +For the privacy policy display, only HTML content is supported today. A more structured content will be added soon. + +- Privacy policy + +```swift +// Initializes the privacy policy page with URL of the HTML file stored in resources. +let privacyPolicy = ODSPrivacyPolicy.webview(.url(Bundle.main.url(forResource: "PrivacyNotice", withExtension: "html")!)) +``` + +- The accessibility statement + +```swift +// Defines an item displaying as a title the "conformity status" text, parsing the file named "fileName" and sending user elsewhere for further details +let accessibilityStatement = ODSAboutAccessibilityStatement( + conformityStatus: "Accessibility: partially conform", + fileName: "AccessibilityStatement", + reportDetail: URL(string: "https://la-va11ydette.orange.com/")!) +``` + +- The Terms of service + +```swift +// Today, there is no recomandation how to display the content, so the module provides a view builder +// to build a native screen or a webview + +@ViewBuilder +private func termsOfService() -> some View { + Text("Add terms of service here") +} +``` + +Then initialize the module with those mandatory elements: + +```swift +ODSAboutModule(..., + privacyPolicy: privacyPolicy, + acessibilityStatement: accessibilityStatement, + termsOfService: termOfService +) +``` + +#### Add items to the list + +To insert additionnal items into the list, initialize the __listItemConfigurations__ array adding items following the __ODSAboutListItemConfig__ protocol. +To order the items in the list, initialize the items with the right priority. + +```swift +// Add all items in list +ODSAboutModule(..., + listItemConfigurations: [legalInfoItem, rateTheAppItem, appsNewItem] +) + +// see items description below +``` + +#### Use optional items + +- Rate the app + +To create this item, define the url of the application on the store and the priority (position) of the item in the list: + +```swift +// This item opens the store in the external browser +let rateTheAppItem = ODSAboutRateTheAppItemConfig( + priority: 501, + storeUrl: URL(string: "https://www.apple.com/app-store/")! +) +``` + +- Apps news + +To create this item, define the path to the json file containing the news. This file is embeded in the resources of the application. + +The model of the json file is: + +```json +[ + { + "version": "0.12.0", + "date": "2023-04-14", + "news": "A short description of news" + }, + ... +] +``` + +This is the code to create the item: + +```swift +// - Display the app News +let appNewFilePath = Bundle.main.path(forResource: "AppNews", ofType: "json")! +let appsNewItem = ODSAboutAppNewsItemConfig( + priorty: 502, + path: appNewFilePath +) +``` + +- Legal information + +Still there is not recomandation on the format of the presentation, this item needs a view builder to display the legal information. + +```swift +// Here, the legal information are displayed in a view with a single Text. + +let legalInformationItem = ODSAboutLegalInformationItemConfig(priority: 500) { + Text("This is Legal information content") +} +``` + +- Apps recirculation + +You can also add an item to let people discover other apps of Orange, by using the following item: + +```swift +let appsRecirculation = ODSRecirculationItemConfig(dataSource: yourDataSource) +``` + +The __dataSource__ can contain the URL of the backend to get the list of apps, (today the only supported backend is Orange proprietary backend _Apps Plus_) or a local json file. (for more details see the __Recirculation Module__. + +#### Create a custom item + +To create a custom item and associate a target, follow this example: + +```swift +public struct MyItemToDisplayText: ODSAboutListItemConfig { + public private(set) var title: String + public private(set) var icon: Image + public private(set) var target: ODSAboutListItemTarget + public private(set) var priority: ODSAboutListItemPriority + + public init(priority: ODSAboutListItemPriority = 100) { + self.priority = priority + self.title = "Fake Item" + self.icon = Image(systemName: "heart"), + self.target = .destination(AnyView(Text("This is the destination screen"))) + } +} +``` + diff --git a/docs/1.1.0/modules/about_docs.md b/docs/1.1.0/modules/about_docs.md new file mode 100644 index 00000000..68f62b7e --- /dev/null +++ b/docs/1.1.0/modules/about_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: About +content_page: about.md +--- + diff --git a/docs/1.1.0/modules/emptyState.md b/docs/1.1.0/modules/emptyState.md new file mode 100644 index 00000000..e7061cfe --- /dev/null +++ b/docs/1.1.0/modules/emptyState.md @@ -0,0 +1,52 @@ +--- +layout: detail +title: Empty states +description: An empty state can occur when no content or data is available to display in the UI. Avoid displaying completely empty screens. +--- + +An empty state display should inform the user of what is happening, why it's happening and what to do about it. + +
**On this page** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Empty states](https://system.design.orange.com/0c1af118d/p/177496-empty-states/b/454547) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/). + +The ODS Empty states module is built to support accessibility criteria and is readable by most screen readers, such as VoiceOver. + +## Integration + +![Empty state light](images/empty_state_light.png) ![Empty state dark](images/empty_state_dark.png) + +### SwiftUI + +To integrate an ODS Empty state into your app, you can use `ODSEmptyStateView` as shown below: + +```swift +ODSEmptyStateView( + title: Text("No result"), + text: Text("Try a new search"), + image: Image("il_emptyStateNoData"), + button: Button("Search") { + // Do something + } +) +``` + +#### ODSEmptyStateView API + +| Parameter | Default value | Description | +|-------------------------------------|-----------------------------------------------------------------------------------|-----------------------------------------------------------------------------------| +| `title: Text` | | The title of the screen displayed below the image. For example "File is missing". | +| `text: Text?` | `null` | Text displayed below the title | +| `image: Image` | `Image("il_emptyStateUserCleared", bundle: Bundle.ods)` | Image displayed centered in the composable | +| `button: Button?` | `null` | The button to add below the text | diff --git a/docs/1.1.0/modules/emptyState_docs.md b/docs/1.1.0/modules/emptyState_docs.md new file mode 100644 index 00000000..15db0e38 --- /dev/null +++ b/docs/1.1.0/modules/emptyState_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: Empty states +content_page: emptyState.md +--- + diff --git a/docs/1.1.0/modules/images/about_screen.png b/docs/1.1.0/modules/images/about_screen.png new file mode 100644 index 00000000..ea0628be Binary files /dev/null and b/docs/1.1.0/modules/images/about_screen.png differ diff --git a/docs/1.1.0/modules/images/empty_state_dark.png b/docs/1.1.0/modules/images/empty_state_dark.png new file mode 100644 index 00000000..7fcd8c2a Binary files /dev/null and b/docs/1.1.0/modules/images/empty_state_dark.png differ diff --git a/docs/1.1.0/modules/images/empty_state_light.png b/docs/1.1.0/modules/images/empty_state_light.png new file mode 100644 index 00000000..2208398f Binary files /dev/null and b/docs/1.1.0/modules/images/empty_state_light.png differ diff --git a/docs/1.1.0/modules/images/list_grouped_dark.png b/docs/1.1.0/modules/images/list_grouped_dark.png new file mode 100644 index 00000000..1cd3da2f Binary files /dev/null and b/docs/1.1.0/modules/images/list_grouped_dark.png differ diff --git a/docs/1.1.0/modules/images/list_grouped_light.png b/docs/1.1.0/modules/images/list_grouped_light.png new file mode 100644 index 00000000..0010570d Binary files /dev/null and b/docs/1.1.0/modules/images/list_grouped_light.png differ diff --git a/docs/1.1.0/modules/images/list_inset_dark.png b/docs/1.1.0/modules/images/list_inset_dark.png new file mode 100644 index 00000000..9edc8c7f Binary files /dev/null and b/docs/1.1.0/modules/images/list_inset_dark.png differ diff --git a/docs/1.1.0/modules/images/list_inset_grouped_dark.png b/docs/1.1.0/modules/images/list_inset_grouped_dark.png new file mode 100644 index 00000000..d7b1959a Binary files /dev/null and b/docs/1.1.0/modules/images/list_inset_grouped_dark.png differ diff --git a/docs/1.1.0/modules/images/list_inset_grouped_light.png b/docs/1.1.0/modules/images/list_inset_grouped_light.png new file mode 100644 index 00000000..f5afcd3f Binary files /dev/null and b/docs/1.1.0/modules/images/list_inset_grouped_light.png differ diff --git a/docs/1.1.0/modules/images/list_inset_light.png b/docs/1.1.0/modules/images/list_inset_light.png new file mode 100644 index 00000000..64c9b21e Binary files /dev/null and b/docs/1.1.0/modules/images/list_inset_light.png differ diff --git a/docs/1.1.0/modules/images/list_plain_dark.png b/docs/1.1.0/modules/images/list_plain_dark.png new file mode 100644 index 00000000..9b189afa Binary files /dev/null and b/docs/1.1.0/modules/images/list_plain_dark.png differ diff --git a/docs/1.1.0/modules/images/list_plain_light.png b/docs/1.1.0/modules/images/list_plain_light.png new file mode 100644 index 00000000..de89eb09 Binary files /dev/null and b/docs/1.1.0/modules/images/list_plain_light.png differ diff --git a/docs/1.1.0/modules/images/list_sidebar_dark.png b/docs/1.1.0/modules/images/list_sidebar_dark.png new file mode 100644 index 00000000..12b22797 Binary files /dev/null and b/docs/1.1.0/modules/images/list_sidebar_dark.png differ diff --git a/docs/1.1.0/modules/images/list_sidebar_light.png b/docs/1.1.0/modules/images/list_sidebar_light.png new file mode 100644 index 00000000..5ba12f6b Binary files /dev/null and b/docs/1.1.0/modules/images/list_sidebar_light.png differ diff --git a/docs/1.1.0/modules/list.md b/docs/1.1.0/modules/list.md new file mode 100644 index 00000000..d2fa73b9 --- /dev/null +++ b/docs/1.1.0/modules/list.md @@ -0,0 +1,194 @@ +--- +layout: detail +title: List +description: Lists are continuous, vertical indexes of text or images. +--- +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Lists](https://system.design.orange.com/0c1af118d/p/09a804-lists/b/669743) +- [Apple guideline - Lists and tables](https://developer.apple.com/design/human-interface-guidelines/components/layout-and-organization/lists-and-tables) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## List styles + +List propose the `.listStyle(_:)` modifier to change the style. For ios SwiftUI propose 6 types of style: +- automatic +- insetGrouped +- grouped +- inset +- plain +- sidebar + +The folowing code is used for all styles. The only difference is the list style specified in the `.listStyle(_:)` modifier. + +```swift +NavigationStack { + List { + // Section for recipes contain selected ingredients + Section { + ODSListItem( + title: Text("Summer Salad"), + subtitle: Text("21 mn"), + leading: .circularImage(source: .image(Image("summerSalad"))) + ) + ODSListItem( + title: Text("Salmon cury"), + subtitle: Text("31 mn"), + leading: .circularImage(source: .image(Image("salmonCury"))) + ) + ODSListItem( + title: Text("Feta Pizza"), + subtitle: Text("21 mn"), + leading: .circularImage(source: .image(Image("fetaPizza"))) + ) + } header: { + Text("Recipes") + } footer: { + Text("A set of recipes made with selected ingredients") + } + + // A set of ingredients + Section("Ingredients") { + ODSListItem(title: Text("tomato"), leading: .circularImage(source: .image(Image("tomato")))) + ODSListItem(title: Text("avocado"), leading: .circularImage(source: .image(Image("avocado")))) + } + } + .navigationTitle("List Style") + .listStyle(.automatic) +} +``` + +### Automatic style + +As mentioned earlier, SwiftUI will use Inset Grouped style when setting automatic (.automatic) or DefaultListStyle on iOS + +### Inset Grouped style + +Example of Inset Grouped .insetGrouped or InsetGroupedListStyle. + +```swift +List { + // ... +} +.listStyle(.insetGrouped) +``` + +![InsetGroupedLight](images/list_inset_grouped_light.png) +![InsetGroupedDark](images/list_inset_grouped_dark.png) + +### Grouped style + +Example of Grouped .grouped or GroupedListStyle. + +```swift +List { + // ... +} +.listStyle(.grouped) +``` + +![GroupedLight](images/list_grouped_light.png) +![GroupedDark](images/list_grouped_dark.png) + +### Inset style + +Example of Inset .inset or InsetListStyle. + +```swift +List { + // ... +} +.listStyle(.inset) +``` + +![InsetLight](images/list_inset_light.png) +![InsetDark](images/list_inset_dark.png) + + +### Plain style + +Example of Plain .plain or PlainListStyle. + +```swift +List { + // ... +} +.listStyle(.plain) +``` +![PlainLight](images/list_plain_light.png) +![PlainDark](images/list_plain_dark.png) + +### Sidebar style + +The sidebar list style displays disclosure indicators in the section headers that allow the user to collapse and expand sections. + +Tap on disclosure indicators in the section headers will collapse and expand that section. + +```swift +List { + // ... +} +.listStyle(.sidebar) +``` + +![SideBarLight](images/list_sidebar_light.png) +![SideBarDark](images/list_sidebar_dark.png) + + +* For iOS 17, a new API is proposed to manage the expandable state. + +```swift +@State var isExpanded = true + +List { + Section(isExpanded: $isExpanded) { + // ... + } header: { + Text("Recipes") + } +} +.listStyle(.sidebar) +``` + +When you create your Section with `isExpanded`, the chevron will appear as long as the list style is `.sidebar`. + +* On previous iOS versions, this interface is not available, so to do the same you can use following code: + +```swift +@State var isExpanded = true + +List { + Section { + if isExpanded { + // The content + } + } header: { + HStack { + Text("Recipes") // The header + + Spacer() + Image(systemName: "chevron.down") + .rotationEffect(isExpanded ? .zero : .degrees(-90)) + .onTapGesture { + withAnimation { + isExpanded.toggle() + } + } + } + } +} +.listStyle(.sidebar) +``` + diff --git a/docs/1.1.0/modules/list_docs.md b/docs/1.1.0/modules/list_docs.md new file mode 100644 index 00000000..52f13ec1 --- /dev/null +++ b/docs/1.1.0/modules/list_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: List +content_page: list.md +--- + diff --git a/docs/1.1.0/modules/recirculation.md b/docs/1.1.0/modules/recirculation.md new file mode 100644 index 00000000..abbecf8c --- /dev/null +++ b/docs/1.1.0/modules/recirculation.md @@ -0,0 +1,109 @@ +--- +layout: detail +title: Recirculation +description: Displays a list of applications can be downloaded and used by user. +--- +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Modules - Recirculation](https://system.design.orange.com/0c1af118d/p/37aa79-recirculation) + +## Overview + +The _Recirculation_ module exposes a feature allowing the final users to get the available apps they can use. +This feature is based today only on the Orange proprietary _Apps Plus_ backend which provides a JSON file with list of apps and sections of apps. +This service today is based on a simple URL containing both a lang parameter and an API key. + +**This API key will define the type of data returned by the backend ; maybe you should have your own API key which matches the suitable filters to get only a subgroup of apps.** + +## Implementation + +To be able to call this service and display the list of available apps, you have to use the `ODSRecirculation`. +This _View_ has a `dataSource` parameter of type `ODSRecirculationDataSource` which must contain the type of source of data to display the apps: + +```swift + // Get data from the Apps Plus backend + ODSRecirculationView(dataSource: .remote(url: "https://url-to-appsplus-backend/get?apikey=SomeKey&lang=fr")) + + // Get data for some local files + ODSRecirculationView(dataSource: .local(path: somePathToJSONFileInResources)) +``` + +Note also that the data picked from the _Apps Plus_ service is saved in cache directory so as to be used if the device is offline +or if an error occured. + +If you want to flatten the list of apps without displaying categories, set the _flattenApps_ flag in the configuration: + +```swift + ODSRecirculationView(dataSource: ..., flattenApps: true) +``` + +The apps icons displayed in the list of apps can also be cached. +If you do not want to see these values put in cache, meaning e.g. displaying instead a placeholder if no network, use: + +```swift + ODSRecirculationView(dataSource: ..., cacheAppsIcons: false) +``` + +The list of apps can trigger also haptic notifications, e.g. vibrations when the data have been lodaded or if an error occured. +By default this feature is enabled, but it can be disabled: + +```swift + ODSRecirculationView(dataSource: ..., enableHaptics: false) +``` + +### Example about definiton of Apps Plus credentials + +You can for example for your app use a _.xcconfig_ configuration settings file to store such credentials. +A key named **APPS_PLUS_URL** can be defined with the URL (containing the API key) to call. +Then the **Info.plist** file of your app must have an entry with the same name. +Of course the _.xcconfig_ file should not be versionned in Git, ensure this with [Gitleaks](https://github.com/gitleaks/gitleaks) for example. + +See the example for the _.xcconfig_: + +```text +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 +// See also https://medium.com/swift-india/secure-secrets-in-ios-app-9f66085800b4 + +APPS_PLUS_API_KEY = SoMeApIkEy +APPS_PLUS_URL = https:/$()/url-to-api?apikey=$(APPS_PLUS_API_KEY) + +// Here $() prevents the // to be interpreted as comment, we suppose the URL has an apikey parameter and is GET only +``` + +And the entry for the _Info.plist_: + +```text + APPS_PLUS_URL + ${APPS_PLUS_URL} +``` + +Then in your code you can read the URL, get the locale, and forge the final URL to give to `ODSMoreAppsItemConfig`. +We could have choosen this implemention deeper in the repository but wanted to let ODS lib users choose their own way to deal with the URL. + +```swift + private func buildAppsPlusURL() -> URL { + guard let appsPlusURL = Bundle.main.infoDictionary?["APPS_PLUS_URL"] else { + fatalError("No Apps Plus URL found in app settings") + } + let currentLocale = Bundle.main.preferredLocalizations[0] + let requestURL = "\(appsPlusURL)&lang=\(currentLocale)" + guard let feedURL = URL(string: requestURL) else { + fatalError("Failed to forge the service URL to get more apps") + } + return feedURL + } + + // And then ODSRecirculationView(dataSource: .remote(url: buildAppsPlusURL())) +``` + +In some CI/CD chain like our GitLab CI runner, we can use a _Fastlane_ lane to read some previously environment variable and fill the _Info.Plist_ file in the suitable row. diff --git a/docs/1.1.0/modules/recirculation_docs.md b/docs/1.1.0/modules/recirculation_docs.md new file mode 100644 index 00000000..b1cb97c8 --- /dev/null +++ b/docs/1.1.0/modules/recirculation_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: Recirculation +content_page: recirculation.md +--- + diff --git a/docs/1.2.0/about/Cookies.md b/docs/1.2.0/about/Cookies.md new file mode 100644 index 00000000..bbeca85f --- /dev/null +++ b/docs/1.2.0/about/Cookies.md @@ -0,0 +1,7 @@ +--- +layout: detail +title: "Cookies" +description: Manage cookies preferences. +--- + +At any time, you can manage your cookies preferences for this website from the cookies management panel. diff --git a/docs/1.2.0/about/Cookies_docs.md b/docs/1.2.0/about/Cookies_docs.md new file mode 100644 index 00000000..d0a88dd9 --- /dev/null +++ b/docs/1.2.0/about/Cookies_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: Cookies +content_page: Cookies.md +back-to-top: false +--- diff --git a/docs/1.2.0/about/License.md b/docs/1.2.0/about/License.md new file mode 100644 index 00000000..8eb48c99 --- /dev/null +++ b/docs/1.2.0/about/License.md @@ -0,0 +1,35 @@ +--- +layout: detail +title: License +description: Commonly asked questions about ODS iOS open source license. +--- + +## ODS iOS license + +ODS iOS is released under the MIT license and is copyright Orange SA, which is released under MIT license. + +## It requires you to: + +- Keep the license and copyright notice included in ODS iOS Swift files when you use them in your works + +## It permits you to: + +- Freely download and use ODS iOS, in whole or in part, for personal, private, company internal, or commercial purposes +- Use ODS iOS in packages or distributions that you create +- Modify the source code +- Grant a sublicense to modify and distribute ODS iOS to third parties not included in the license + +## It forbids you to: + +- Hold the authors and license owners liable for damages as ODS iOS is provided without warranty +- Hold the creators or copyright holders of ODS iOS liable +- Redistribute any piece of ODS iOS without proper attribution +- Use any marks owned by Orange SA in any way that might state or imply that Orange SA endorses your distribution +- Use any marks owned by Orange SA in any way that might state or imply that you created the Orange SA software in question + +## It does not require you to: + +- Include the source of ODS iOS itself, or of any modifications you may have made to it, in any redistribution you may assemble that includes it +- Submit changes that you make to ODS iOS back to its project (though such feedback is encouraged) + +For more information, the full ODS iOS license is located [in the project repository](https://github.com/Orange-OpenSource/ods-ios/blob/main/LICENSE). diff --git a/docs/1.2.0/about/License_docs.md b/docs/1.2.0/about/License_docs.md new file mode 100644 index 00000000..0948a327 --- /dev/null +++ b/docs/1.2.0/about/License_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: License +content_page: License.md +back-to-top: false +--- diff --git a/docs/1.2.0/about/Team.md b/docs/1.2.0/about/Team.md new file mode 100644 index 00000000..28e0ca7c --- /dev/null +++ b/docs/1.2.0/about/Team.md @@ -0,0 +1,29 @@ +--- +layout: detail +title: Team +description: An overview of the founding team and core contributors to ODS iOS. +--- + +ODS iOS is maintained by the core team and a small group of invaluable core contributors, with the support and involvement of our community. + +{% if page.version == "" %} +{% assign key_suffix = "" %} +{% else %} +{% capture key_suffix %}_{{ page.version | replace: '.', '_' }}{% endcapture %} +{% endif %} +{% capture team_key %}team{{ key_suffix }}{% endcapture %} +{% assign team = site.data[team_key] %} +{% if team.ODS_iOS[0] %} +
+ {% for team_member in team.ODS_iOS %} + + @{{ team_member.gh_pseudo }} + + {{ team_member.name }} @{{ team_member.gh_pseudo }} + + + {% endfor %} +
+{% endif %} + +Get involved with ODS iOS development by [opening an issue](https://github.com/Orange-OpenSource/ods-ios/issues/new/choose) or submitting a pull request. Read our [contributing guidelines](https://github.com/Orange-OpenSource/ods-ios/blob/main/CONTRIBUTING.md) for information on how we develop. diff --git a/docs/1.2.0/about/Team_docs.md b/docs/1.2.0/about/Team_docs.md new file mode 100644 index 00000000..63d62250 --- /dev/null +++ b/docs/1.2.0/about/Team_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: Team +content_page: Team.md +back-to-top: false +--- diff --git a/docs/1.2.0/accessibilityStatement/boosted-grid.min.css b/docs/1.2.0/accessibilityStatement/boosted-grid.min.css new file mode 100644 index 00000000..06e19d4d --- /dev/null +++ b/docs/1.2.0/accessibilityStatement/boosted-grid.min.css @@ -0,0 +1,12 @@ +/*! + * Boosted Grid v4.6.0 (https://boosted.orange.com) + * Copyright 2014-2019 The Boosted Authors + * Copyright 2014-2019 Orange + * Licensed under MIT (https://github.com/orange-opensource/orange-boosted-bootstrap/blob/master/LICENSE) + * This a fork of Bootstrap : Initial license below + * Bootstrap Grid v4.6.0 (https://getbootstrap.com) + * Copyright 2011-2019 The Bootstrap Authors + * Copyright 2011-2019 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */html{box-sizing:border-box;-ms-overflow-style:scrollbar}*,::after,::before{box-sizing:inherit}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xs,.container-xxl{width:100%;padding-right:.3125rem;padding-left:.3125rem;margin-right:auto;margin-left:auto}@media (min-width:768px){.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xs,.container-xxl{padding-right:.625rem;padding-left:.625rem}}.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xs,.container-xxl{max-width:97.5%}@media (min-width:480px){.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xs,.container-xxl{max-width:97.5%}}@media (min-width:768px){.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xs,.container-xxl{max-width:96.875%}}@media (min-width:1024px){.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xs,.container-xxl{max-width:93.75%}}@media (min-width:1280px){.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xs,.container-xxl{max-width:93.75%}}@media (min-width:1440px){.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xs,.container-xxl{max-width:91.66666%}}.container{max-width:312px}@media (min-width:480px){.container,.container-sm{max-width:468px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:744px}}@media (min-width:1024px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1280px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1200px}}@media (min-width:1440px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}.row{display:flex;flex-wrap:wrap;margin-right:-.3125rem;margin-left:-.3125rem}@media (min-width:768px){.row{margin-right:-.625rem;margin-left:-.625rem}}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto,.col-xxl,.col-xxl-1,.col-xxl-10,.col-xxl-11,.col-xxl-12,.col-xxl-2,.col-xxl-3,.col-xxl-4,.col-xxl-5,.col-xxl-6,.col-xxl-7,.col-xxl-8,.col-xxl-9,.col-xxl-auto{position:relative;width:100%;padding-right:.3125rem;padding-left:.3125rem}@media (min-width:768px){.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto,.col-xxl,.col-xxl-1,.col-xxl-10,.col-xxl-11,.col-xxl-12,.col-xxl-2,.col-xxl-3,.col-xxl-4,.col-xxl-5,.col-xxl-6,.col-xxl-7,.col-xxl-8,.col-xxl-9,.col-xxl-auto{padding-right:.625rem;padding-left:.625rem}}.col{flex-basis:0;flex-grow:1;max-width:100%}.row-cols-1>*{flex:0 0 100%;max-width:100%}.row-cols-2>*{flex:0 0 50%;max-width:50%}.row-cols-3>*{flex:0 0 33.333333%;max-width:33.333333%}.row-cols-4>*{flex:0 0 25%;max-width:25%}.row-cols-5>*{flex:0 0 20%;max-width:20%}.row-cols-6>*{flex:0 0 16.666667%;max-width:16.666667%}.col-auto{flex:0 0 auto;width:auto;max-width:100%}.col-1{flex:0 0 8.333333%;max-width:8.333333%}.col-2{flex:0 0 16.666667%;max-width:16.666667%}.col-3{flex:0 0 25%;max-width:25%}.col-4{flex:0 0 33.333333%;max-width:33.333333%}.col-5{flex:0 0 41.666667%;max-width:41.666667%}.col-6{flex:0 0 50%;max-width:50%}.col-7{flex:0 0 58.333333%;max-width:58.333333%}.col-8{flex:0 0 66.666667%;max-width:66.666667%}.col-9{flex:0 0 75%;max-width:75%}.col-10{flex:0 0 83.333333%;max-width:83.333333%}.col-11{flex:0 0 91.666667%;max-width:91.666667%}.col-12{flex:0 0 100%;max-width:100%}.order-first{order:-1}.order-last{order:13}.order-0{order:0}.order-1{order:1}.order-2{order:2}.order-3{order:3}.order-4{order:4}.order-5{order:5}.order-6{order:6}.order-7{order:7}.order-8{order:8}.order-9{order:9}.order-10{order:10}.order-11{order:11}.order-12{order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:480px){.col-sm{flex-basis:0;flex-grow:1;max-width:100%}.row-cols-sm-1>*{flex:0 0 100%;max-width:100%}.row-cols-sm-2>*{flex:0 0 50%;max-width:50%}.row-cols-sm-3>*{flex:0 0 33.333333%;max-width:33.333333%}.row-cols-sm-4>*{flex:0 0 25%;max-width:25%}.row-cols-sm-5>*{flex:0 0 20%;max-width:20%}.row-cols-sm-6>*{flex:0 0 16.666667%;max-width:16.666667%}.col-sm-auto{flex:0 0 auto;width:auto;max-width:100%}.col-sm-1{flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{flex:0 0 25%;max-width:25%}.col-sm-4{flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{flex:0 0 50%;max-width:50%}.col-sm-7{flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{flex:0 0 75%;max-width:75%}.col-sm-10{flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{flex:0 0 100%;max-width:100%}.order-sm-first{order:-1}.order-sm-last{order:13}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{flex-basis:0;flex-grow:1;max-width:100%}.row-cols-md-1>*{flex:0 0 100%;max-width:100%}.row-cols-md-2>*{flex:0 0 50%;max-width:50%}.row-cols-md-3>*{flex:0 0 33.333333%;max-width:33.333333%}.row-cols-md-4>*{flex:0 0 25%;max-width:25%}.row-cols-md-5>*{flex:0 0 20%;max-width:20%}.row-cols-md-6>*{flex:0 0 16.666667%;max-width:16.666667%}.col-md-auto{flex:0 0 auto;width:auto;max-width:100%}.col-md-1{flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{flex:0 0 25%;max-width:25%}.col-md-4{flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{flex:0 0 50%;max-width:50%}.col-md-7{flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{flex:0 0 75%;max-width:75%}.col-md-10{flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{flex:0 0 100%;max-width:100%}.order-md-first{order:-1}.order-md-last{order:13}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:1024px){.col-lg{flex-basis:0;flex-grow:1;max-width:100%}.row-cols-lg-1>*{flex:0 0 100%;max-width:100%}.row-cols-lg-2>*{flex:0 0 50%;max-width:50%}.row-cols-lg-3>*{flex:0 0 33.333333%;max-width:33.333333%}.row-cols-lg-4>*{flex:0 0 25%;max-width:25%}.row-cols-lg-5>*{flex:0 0 20%;max-width:20%}.row-cols-lg-6>*{flex:0 0 16.666667%;max-width:16.666667%}.col-lg-auto{flex:0 0 auto;width:auto;max-width:100%}.col-lg-1{flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{flex:0 0 25%;max-width:25%}.col-lg-4{flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{flex:0 0 50%;max-width:50%}.col-lg-7{flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{flex:0 0 75%;max-width:75%}.col-lg-10{flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{flex:0 0 100%;max-width:100%}.order-lg-first{order:-1}.order-lg-last{order:13}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1280px){.col-xl{flex-basis:0;flex-grow:1;max-width:100%}.row-cols-xl-1>*{flex:0 0 100%;max-width:100%}.row-cols-xl-2>*{flex:0 0 50%;max-width:50%}.row-cols-xl-3>*{flex:0 0 33.333333%;max-width:33.333333%}.row-cols-xl-4>*{flex:0 0 25%;max-width:25%}.row-cols-xl-5>*{flex:0 0 20%;max-width:20%}.row-cols-xl-6>*{flex:0 0 16.666667%;max-width:16.666667%}.col-xl-auto{flex:0 0 auto;width:auto;max-width:100%}.col-xl-1{flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{flex:0 0 25%;max-width:25%}.col-xl-4{flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{flex:0 0 50%;max-width:50%}.col-xl-7{flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{flex:0 0 75%;max-width:75%}.col-xl-10{flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{flex:0 0 100%;max-width:100%}.order-xl-first{order:-1}.order-xl-last{order:13}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}@media (min-width:1440px){.col-xxl{flex-basis:0;flex-grow:1;max-width:100%}.row-cols-xxl-1>*{flex:0 0 100%;max-width:100%}.row-cols-xxl-2>*{flex:0 0 50%;max-width:50%}.row-cols-xxl-3>*{flex:0 0 33.333333%;max-width:33.333333%}.row-cols-xxl-4>*{flex:0 0 25%;max-width:25%}.row-cols-xxl-5>*{flex:0 0 20%;max-width:20%}.row-cols-xxl-6>*{flex:0 0 16.666667%;max-width:16.666667%}.col-xxl-auto{flex:0 0 auto;width:auto;max-width:100%}.col-xxl-1{flex:0 0 8.333333%;max-width:8.333333%}.col-xxl-2{flex:0 0 16.666667%;max-width:16.666667%}.col-xxl-3{flex:0 0 25%;max-width:25%}.col-xxl-4{flex:0 0 33.333333%;max-width:33.333333%}.col-xxl-5{flex:0 0 41.666667%;max-width:41.666667%}.col-xxl-6{flex:0 0 50%;max-width:50%}.col-xxl-7{flex:0 0 58.333333%;max-width:58.333333%}.col-xxl-8{flex:0 0 66.666667%;max-width:66.666667%}.col-xxl-9{flex:0 0 75%;max-width:75%}.col-xxl-10{flex:0 0 83.333333%;max-width:83.333333%}.col-xxl-11{flex:0 0 91.666667%;max-width:91.666667%}.col-xxl-12{flex:0 0 100%;max-width:100%}.order-xxl-first{order:-1}.order-xxl-last{order:13}.order-xxl-0{order:0}.order-xxl-1{order:1}.order-xxl-2{order:2}.order-xxl-3{order:3}.order-xxl-4{order:4}.order-xxl-5{order:5}.order-xxl-6{order:6}.order-xxl-7{order:7}.order-xxl-8{order:8}.order-xxl-9{order:9}.order-xxl-10{order:10}.order-xxl-11{order:11}.order-xxl-12{order:12}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.333333%}.offset-xxl-2{margin-left:16.666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.333333%}.offset-xxl-5{margin-left:41.666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.333333%}.offset-xxl-8{margin-left:66.666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.333333%}.offset-xxl-11{margin-left:91.666667%}}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}@media (min-width:480px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}}@media (min-width:1024px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}}@media (min-width:1280px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}}@media (min-width:1440px){.d-xxl-none{display:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-fill{flex:1 1 auto!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}@media (min-width:480px){.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}}@media (min-width:768px){.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}}@media (min-width:1024px){.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}}@media (min-width:1280px){.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}}@media (min-width:1440px){.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.3125rem!important}.mt-1,.my-1{margin-top:.3125rem!important}.mr-1,.mx-1{margin-right:.3125rem!important}.mb-1,.my-1{margin-bottom:.3125rem!important}.ml-1,.mx-1{margin-left:.3125rem!important}.m-2{margin:.625rem!important}.mt-2,.my-2{margin-top:.625rem!important}.mr-2,.mx-2{margin-right:.625rem!important}.mb-2,.my-2{margin-bottom:.625rem!important}.ml-2,.mx-2{margin-left:.625rem!important}.m-3{margin:1.25rem!important}.mt-3,.my-3{margin-top:1.25rem!important}.mr-3,.mx-3{margin-right:1.25rem!important}.mb-3,.my-3{margin-bottom:1.25rem!important}.ml-3,.mx-3{margin-left:1.25rem!important}.m-4{margin:1.875rem!important}.mt-4,.my-4{margin-top:1.875rem!important}.mr-4,.mx-4{margin-right:1.875rem!important}.mb-4,.my-4{margin-bottom:1.875rem!important}.ml-4,.mx-4{margin-left:1.875rem!important}.m-5{margin:3.75rem!important}.mt-5,.my-5{margin-top:3.75rem!important}.mr-5,.mx-5{margin-right:3.75rem!important}.mb-5,.my-5{margin-bottom:3.75rem!important}.ml-5,.mx-5{margin-left:3.75rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.3125rem!important}.pt-1,.py-1{padding-top:.3125rem!important}.pr-1,.px-1{padding-right:.3125rem!important}.pb-1,.py-1{padding-bottom:.3125rem!important}.pl-1,.px-1{padding-left:.3125rem!important}.p-2{padding:.625rem!important}.pt-2,.py-2{padding-top:.625rem!important}.pr-2,.px-2{padding-right:.625rem!important}.pb-2,.py-2{padding-bottom:.625rem!important}.pl-2,.px-2{padding-left:.625rem!important}.p-3{padding:1.25rem!important}.pt-3,.py-3{padding-top:1.25rem!important}.pr-3,.px-3{padding-right:1.25rem!important}.pb-3,.py-3{padding-bottom:1.25rem!important}.pl-3,.px-3{padding-left:1.25rem!important}.p-4{padding:1.875rem!important}.pt-4,.py-4{padding-top:1.875rem!important}.pr-4,.px-4{padding-right:1.875rem!important}.pb-4,.py-4{padding-bottom:1.875rem!important}.pl-4,.px-4{padding-left:1.875rem!important}.p-5{padding:3.75rem!important}.pt-5,.py-5{padding-top:3.75rem!important}.pr-5,.px-5{padding-right:3.75rem!important}.pb-5,.py-5{padding-bottom:3.75rem!important}.pl-5,.px-5{padding-left:3.75rem!important}.m-n1{margin:-.3125rem!important}.mt-n1,.my-n1{margin-top:-.3125rem!important}.mr-n1,.mx-n1{margin-right:-.3125rem!important}.mb-n1,.my-n1{margin-bottom:-.3125rem!important}.ml-n1,.mx-n1{margin-left:-.3125rem!important}.m-n2{margin:-.625rem!important}.mt-n2,.my-n2{margin-top:-.625rem!important}.mr-n2,.mx-n2{margin-right:-.625rem!important}.mb-n2,.my-n2{margin-bottom:-.625rem!important}.ml-n2,.mx-n2{margin-left:-.625rem!important}.m-n3{margin:-1.25rem!important}.mt-n3,.my-n3{margin-top:-1.25rem!important}.mr-n3,.mx-n3{margin-right:-1.25rem!important}.mb-n3,.my-n3{margin-bottom:-1.25rem!important}.ml-n3,.mx-n3{margin-left:-1.25rem!important}.m-n4{margin:-1.875rem!important}.mt-n4,.my-n4{margin-top:-1.875rem!important}.mr-n4,.mx-n4{margin-right:-1.875rem!important}.mb-n4,.my-n4{margin-bottom:-1.875rem!important}.ml-n4,.mx-n4{margin-left:-1.875rem!important}.m-n5{margin:-3.75rem!important}.mt-n5,.my-n5{margin-top:-3.75rem!important}.mr-n5,.mx-n5{margin-right:-3.75rem!important}.mb-n5,.my-n5{margin-bottom:-3.75rem!important}.ml-n5,.mx-n5{margin-left:-3.75rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:480px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.3125rem!important}.mt-sm-1,.my-sm-1{margin-top:.3125rem!important}.mr-sm-1,.mx-sm-1{margin-right:.3125rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.3125rem!important}.ml-sm-1,.mx-sm-1{margin-left:.3125rem!important}.m-sm-2{margin:.625rem!important}.mt-sm-2,.my-sm-2{margin-top:.625rem!important}.mr-sm-2,.mx-sm-2{margin-right:.625rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.625rem!important}.ml-sm-2,.mx-sm-2{margin-left:.625rem!important}.m-sm-3{margin:1.25rem!important}.mt-sm-3,.my-sm-3{margin-top:1.25rem!important}.mr-sm-3,.mx-sm-3{margin-right:1.25rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1.25rem!important}.ml-sm-3,.mx-sm-3{margin-left:1.25rem!important}.m-sm-4{margin:1.875rem!important}.mt-sm-4,.my-sm-4{margin-top:1.875rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.875rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.875rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.875rem!important}.m-sm-5{margin:3.75rem!important}.mt-sm-5,.my-sm-5{margin-top:3.75rem!important}.mr-sm-5,.mx-sm-5{margin-right:3.75rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3.75rem!important}.ml-sm-5,.mx-sm-5{margin-left:3.75rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.3125rem!important}.pt-sm-1,.py-sm-1{padding-top:.3125rem!important}.pr-sm-1,.px-sm-1{padding-right:.3125rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.3125rem!important}.pl-sm-1,.px-sm-1{padding-left:.3125rem!important}.p-sm-2{padding:.625rem!important}.pt-sm-2,.py-sm-2{padding-top:.625rem!important}.pr-sm-2,.px-sm-2{padding-right:.625rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.625rem!important}.pl-sm-2,.px-sm-2{padding-left:.625rem!important}.p-sm-3{padding:1.25rem!important}.pt-sm-3,.py-sm-3{padding-top:1.25rem!important}.pr-sm-3,.px-sm-3{padding-right:1.25rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1.25rem!important}.pl-sm-3,.px-sm-3{padding-left:1.25rem!important}.p-sm-4{padding:1.875rem!important}.pt-sm-4,.py-sm-4{padding-top:1.875rem!important}.pr-sm-4,.px-sm-4{padding-right:1.875rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.875rem!important}.pl-sm-4,.px-sm-4{padding-left:1.875rem!important}.p-sm-5{padding:3.75rem!important}.pt-sm-5,.py-sm-5{padding-top:3.75rem!important}.pr-sm-5,.px-sm-5{padding-right:3.75rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3.75rem!important}.pl-sm-5,.px-sm-5{padding-left:3.75rem!important}.m-sm-n1{margin:-.3125rem!important}.mt-sm-n1,.my-sm-n1{margin-top:-.3125rem!important}.mr-sm-n1,.mx-sm-n1{margin-right:-.3125rem!important}.mb-sm-n1,.my-sm-n1{margin-bottom:-.3125rem!important}.ml-sm-n1,.mx-sm-n1{margin-left:-.3125rem!important}.m-sm-n2{margin:-.625rem!important}.mt-sm-n2,.my-sm-n2{margin-top:-.625rem!important}.mr-sm-n2,.mx-sm-n2{margin-right:-.625rem!important}.mb-sm-n2,.my-sm-n2{margin-bottom:-.625rem!important}.ml-sm-n2,.mx-sm-n2{margin-left:-.625rem!important}.m-sm-n3{margin:-1.25rem!important}.mt-sm-n3,.my-sm-n3{margin-top:-1.25rem!important}.mr-sm-n3,.mx-sm-n3{margin-right:-1.25rem!important}.mb-sm-n3,.my-sm-n3{margin-bottom:-1.25rem!important}.ml-sm-n3,.mx-sm-n3{margin-left:-1.25rem!important}.m-sm-n4{margin:-1.875rem!important}.mt-sm-n4,.my-sm-n4{margin-top:-1.875rem!important}.mr-sm-n4,.mx-sm-n4{margin-right:-1.875rem!important}.mb-sm-n4,.my-sm-n4{margin-bottom:-1.875rem!important}.ml-sm-n4,.mx-sm-n4{margin-left:-1.875rem!important}.m-sm-n5{margin:-3.75rem!important}.mt-sm-n5,.my-sm-n5{margin-top:-3.75rem!important}.mr-sm-n5,.mx-sm-n5{margin-right:-3.75rem!important}.mb-sm-n5,.my-sm-n5{margin-bottom:-3.75rem!important}.ml-sm-n5,.mx-sm-n5{margin-left:-3.75rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.3125rem!important}.mt-md-1,.my-md-1{margin-top:.3125rem!important}.mr-md-1,.mx-md-1{margin-right:.3125rem!important}.mb-md-1,.my-md-1{margin-bottom:.3125rem!important}.ml-md-1,.mx-md-1{margin-left:.3125rem!important}.m-md-2{margin:.625rem!important}.mt-md-2,.my-md-2{margin-top:.625rem!important}.mr-md-2,.mx-md-2{margin-right:.625rem!important}.mb-md-2,.my-md-2{margin-bottom:.625rem!important}.ml-md-2,.mx-md-2{margin-left:.625rem!important}.m-md-3{margin:1.25rem!important}.mt-md-3,.my-md-3{margin-top:1.25rem!important}.mr-md-3,.mx-md-3{margin-right:1.25rem!important}.mb-md-3,.my-md-3{margin-bottom:1.25rem!important}.ml-md-3,.mx-md-3{margin-left:1.25rem!important}.m-md-4{margin:1.875rem!important}.mt-md-4,.my-md-4{margin-top:1.875rem!important}.mr-md-4,.mx-md-4{margin-right:1.875rem!important}.mb-md-4,.my-md-4{margin-bottom:1.875rem!important}.ml-md-4,.mx-md-4{margin-left:1.875rem!important}.m-md-5{margin:3.75rem!important}.mt-md-5,.my-md-5{margin-top:3.75rem!important}.mr-md-5,.mx-md-5{margin-right:3.75rem!important}.mb-md-5,.my-md-5{margin-bottom:3.75rem!important}.ml-md-5,.mx-md-5{margin-left:3.75rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.3125rem!important}.pt-md-1,.py-md-1{padding-top:.3125rem!important}.pr-md-1,.px-md-1{padding-right:.3125rem!important}.pb-md-1,.py-md-1{padding-bottom:.3125rem!important}.pl-md-1,.px-md-1{padding-left:.3125rem!important}.p-md-2{padding:.625rem!important}.pt-md-2,.py-md-2{padding-top:.625rem!important}.pr-md-2,.px-md-2{padding-right:.625rem!important}.pb-md-2,.py-md-2{padding-bottom:.625rem!important}.pl-md-2,.px-md-2{padding-left:.625rem!important}.p-md-3{padding:1.25rem!important}.pt-md-3,.py-md-3{padding-top:1.25rem!important}.pr-md-3,.px-md-3{padding-right:1.25rem!important}.pb-md-3,.py-md-3{padding-bottom:1.25rem!important}.pl-md-3,.px-md-3{padding-left:1.25rem!important}.p-md-4{padding:1.875rem!important}.pt-md-4,.py-md-4{padding-top:1.875rem!important}.pr-md-4,.px-md-4{padding-right:1.875rem!important}.pb-md-4,.py-md-4{padding-bottom:1.875rem!important}.pl-md-4,.px-md-4{padding-left:1.875rem!important}.p-md-5{padding:3.75rem!important}.pt-md-5,.py-md-5{padding-top:3.75rem!important}.pr-md-5,.px-md-5{padding-right:3.75rem!important}.pb-md-5,.py-md-5{padding-bottom:3.75rem!important}.pl-md-5,.px-md-5{padding-left:3.75rem!important}.m-md-n1{margin:-.3125rem!important}.mt-md-n1,.my-md-n1{margin-top:-.3125rem!important}.mr-md-n1,.mx-md-n1{margin-right:-.3125rem!important}.mb-md-n1,.my-md-n1{margin-bottom:-.3125rem!important}.ml-md-n1,.mx-md-n1{margin-left:-.3125rem!important}.m-md-n2{margin:-.625rem!important}.mt-md-n2,.my-md-n2{margin-top:-.625rem!important}.mr-md-n2,.mx-md-n2{margin-right:-.625rem!important}.mb-md-n2,.my-md-n2{margin-bottom:-.625rem!important}.ml-md-n2,.mx-md-n2{margin-left:-.625rem!important}.m-md-n3{margin:-1.25rem!important}.mt-md-n3,.my-md-n3{margin-top:-1.25rem!important}.mr-md-n3,.mx-md-n3{margin-right:-1.25rem!important}.mb-md-n3,.my-md-n3{margin-bottom:-1.25rem!important}.ml-md-n3,.mx-md-n3{margin-left:-1.25rem!important}.m-md-n4{margin:-1.875rem!important}.mt-md-n4,.my-md-n4{margin-top:-1.875rem!important}.mr-md-n4,.mx-md-n4{margin-right:-1.875rem!important}.mb-md-n4,.my-md-n4{margin-bottom:-1.875rem!important}.ml-md-n4,.mx-md-n4{margin-left:-1.875rem!important}.m-md-n5{margin:-3.75rem!important}.mt-md-n5,.my-md-n5{margin-top:-3.75rem!important}.mr-md-n5,.mx-md-n5{margin-right:-3.75rem!important}.mb-md-n5,.my-md-n5{margin-bottom:-3.75rem!important}.ml-md-n5,.mx-md-n5{margin-left:-3.75rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:1024px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.3125rem!important}.mt-lg-1,.my-lg-1{margin-top:.3125rem!important}.mr-lg-1,.mx-lg-1{margin-right:.3125rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.3125rem!important}.ml-lg-1,.mx-lg-1{margin-left:.3125rem!important}.m-lg-2{margin:.625rem!important}.mt-lg-2,.my-lg-2{margin-top:.625rem!important}.mr-lg-2,.mx-lg-2{margin-right:.625rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.625rem!important}.ml-lg-2,.mx-lg-2{margin-left:.625rem!important}.m-lg-3{margin:1.25rem!important}.mt-lg-3,.my-lg-3{margin-top:1.25rem!important}.mr-lg-3,.mx-lg-3{margin-right:1.25rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1.25rem!important}.ml-lg-3,.mx-lg-3{margin-left:1.25rem!important}.m-lg-4{margin:1.875rem!important}.mt-lg-4,.my-lg-4{margin-top:1.875rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.875rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.875rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.875rem!important}.m-lg-5{margin:3.75rem!important}.mt-lg-5,.my-lg-5{margin-top:3.75rem!important}.mr-lg-5,.mx-lg-5{margin-right:3.75rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3.75rem!important}.ml-lg-5,.mx-lg-5{margin-left:3.75rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.3125rem!important}.pt-lg-1,.py-lg-1{padding-top:.3125rem!important}.pr-lg-1,.px-lg-1{padding-right:.3125rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.3125rem!important}.pl-lg-1,.px-lg-1{padding-left:.3125rem!important}.p-lg-2{padding:.625rem!important}.pt-lg-2,.py-lg-2{padding-top:.625rem!important}.pr-lg-2,.px-lg-2{padding-right:.625rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.625rem!important}.pl-lg-2,.px-lg-2{padding-left:.625rem!important}.p-lg-3{padding:1.25rem!important}.pt-lg-3,.py-lg-3{padding-top:1.25rem!important}.pr-lg-3,.px-lg-3{padding-right:1.25rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1.25rem!important}.pl-lg-3,.px-lg-3{padding-left:1.25rem!important}.p-lg-4{padding:1.875rem!important}.pt-lg-4,.py-lg-4{padding-top:1.875rem!important}.pr-lg-4,.px-lg-4{padding-right:1.875rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.875rem!important}.pl-lg-4,.px-lg-4{padding-left:1.875rem!important}.p-lg-5{padding:3.75rem!important}.pt-lg-5,.py-lg-5{padding-top:3.75rem!important}.pr-lg-5,.px-lg-5{padding-right:3.75rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3.75rem!important}.pl-lg-5,.px-lg-5{padding-left:3.75rem!important}.m-lg-n1{margin:-.3125rem!important}.mt-lg-n1,.my-lg-n1{margin-top:-.3125rem!important}.mr-lg-n1,.mx-lg-n1{margin-right:-.3125rem!important}.mb-lg-n1,.my-lg-n1{margin-bottom:-.3125rem!important}.ml-lg-n1,.mx-lg-n1{margin-left:-.3125rem!important}.m-lg-n2{margin:-.625rem!important}.mt-lg-n2,.my-lg-n2{margin-top:-.625rem!important}.mr-lg-n2,.mx-lg-n2{margin-right:-.625rem!important}.mb-lg-n2,.my-lg-n2{margin-bottom:-.625rem!important}.ml-lg-n2,.mx-lg-n2{margin-left:-.625rem!important}.m-lg-n3{margin:-1.25rem!important}.mt-lg-n3,.my-lg-n3{margin-top:-1.25rem!important}.mr-lg-n3,.mx-lg-n3{margin-right:-1.25rem!important}.mb-lg-n3,.my-lg-n3{margin-bottom:-1.25rem!important}.ml-lg-n3,.mx-lg-n3{margin-left:-1.25rem!important}.m-lg-n4{margin:-1.875rem!important}.mt-lg-n4,.my-lg-n4{margin-top:-1.875rem!important}.mr-lg-n4,.mx-lg-n4{margin-right:-1.875rem!important}.mb-lg-n4,.my-lg-n4{margin-bottom:-1.875rem!important}.ml-lg-n4,.mx-lg-n4{margin-left:-1.875rem!important}.m-lg-n5{margin:-3.75rem!important}.mt-lg-n5,.my-lg-n5{margin-top:-3.75rem!important}.mr-lg-n5,.mx-lg-n5{margin-right:-3.75rem!important}.mb-lg-n5,.my-lg-n5{margin-bottom:-3.75rem!important}.ml-lg-n5,.mx-lg-n5{margin-left:-3.75rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1280px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.3125rem!important}.mt-xl-1,.my-xl-1{margin-top:.3125rem!important}.mr-xl-1,.mx-xl-1{margin-right:.3125rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.3125rem!important}.ml-xl-1,.mx-xl-1{margin-left:.3125rem!important}.m-xl-2{margin:.625rem!important}.mt-xl-2,.my-xl-2{margin-top:.625rem!important}.mr-xl-2,.mx-xl-2{margin-right:.625rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.625rem!important}.ml-xl-2,.mx-xl-2{margin-left:.625rem!important}.m-xl-3{margin:1.25rem!important}.mt-xl-3,.my-xl-3{margin-top:1.25rem!important}.mr-xl-3,.mx-xl-3{margin-right:1.25rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1.25rem!important}.ml-xl-3,.mx-xl-3{margin-left:1.25rem!important}.m-xl-4{margin:1.875rem!important}.mt-xl-4,.my-xl-4{margin-top:1.875rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.875rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.875rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.875rem!important}.m-xl-5{margin:3.75rem!important}.mt-xl-5,.my-xl-5{margin-top:3.75rem!important}.mr-xl-5,.mx-xl-5{margin-right:3.75rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3.75rem!important}.ml-xl-5,.mx-xl-5{margin-left:3.75rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.3125rem!important}.pt-xl-1,.py-xl-1{padding-top:.3125rem!important}.pr-xl-1,.px-xl-1{padding-right:.3125rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.3125rem!important}.pl-xl-1,.px-xl-1{padding-left:.3125rem!important}.p-xl-2{padding:.625rem!important}.pt-xl-2,.py-xl-2{padding-top:.625rem!important}.pr-xl-2,.px-xl-2{padding-right:.625rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.625rem!important}.pl-xl-2,.px-xl-2{padding-left:.625rem!important}.p-xl-3{padding:1.25rem!important}.pt-xl-3,.py-xl-3{padding-top:1.25rem!important}.pr-xl-3,.px-xl-3{padding-right:1.25rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1.25rem!important}.pl-xl-3,.px-xl-3{padding-left:1.25rem!important}.p-xl-4{padding:1.875rem!important}.pt-xl-4,.py-xl-4{padding-top:1.875rem!important}.pr-xl-4,.px-xl-4{padding-right:1.875rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.875rem!important}.pl-xl-4,.px-xl-4{padding-left:1.875rem!important}.p-xl-5{padding:3.75rem!important}.pt-xl-5,.py-xl-5{padding-top:3.75rem!important}.pr-xl-5,.px-xl-5{padding-right:3.75rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3.75rem!important}.pl-xl-5,.px-xl-5{padding-left:3.75rem!important}.m-xl-n1{margin:-.3125rem!important}.mt-xl-n1,.my-xl-n1{margin-top:-.3125rem!important}.mr-xl-n1,.mx-xl-n1{margin-right:-.3125rem!important}.mb-xl-n1,.my-xl-n1{margin-bottom:-.3125rem!important}.ml-xl-n1,.mx-xl-n1{margin-left:-.3125rem!important}.m-xl-n2{margin:-.625rem!important}.mt-xl-n2,.my-xl-n2{margin-top:-.625rem!important}.mr-xl-n2,.mx-xl-n2{margin-right:-.625rem!important}.mb-xl-n2,.my-xl-n2{margin-bottom:-.625rem!important}.ml-xl-n2,.mx-xl-n2{margin-left:-.625rem!important}.m-xl-n3{margin:-1.25rem!important}.mt-xl-n3,.my-xl-n3{margin-top:-1.25rem!important}.mr-xl-n3,.mx-xl-n3{margin-right:-1.25rem!important}.mb-xl-n3,.my-xl-n3{margin-bottom:-1.25rem!important}.ml-xl-n3,.mx-xl-n3{margin-left:-1.25rem!important}.m-xl-n4{margin:-1.875rem!important}.mt-xl-n4,.my-xl-n4{margin-top:-1.875rem!important}.mr-xl-n4,.mx-xl-n4{margin-right:-1.875rem!important}.mb-xl-n4,.my-xl-n4{margin-bottom:-1.875rem!important}.ml-xl-n4,.mx-xl-n4{margin-left:-1.875rem!important}.m-xl-n5{margin:-3.75rem!important}.mt-xl-n5,.my-xl-n5{margin-top:-3.75rem!important}.mr-xl-n5,.mx-xl-n5{margin-right:-3.75rem!important}.mb-xl-n5,.my-xl-n5{margin-bottom:-3.75rem!important}.ml-xl-n5,.mx-xl-n5{margin-left:-3.75rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}@media (min-width:1440px){.m-xxl-0{margin:0!important}.mt-xxl-0,.my-xxl-0{margin-top:0!important}.mr-xxl-0,.mx-xxl-0{margin-right:0!important}.mb-xxl-0,.my-xxl-0{margin-bottom:0!important}.ml-xxl-0,.mx-xxl-0{margin-left:0!important}.m-xxl-1{margin:.3125rem!important}.mt-xxl-1,.my-xxl-1{margin-top:.3125rem!important}.mr-xxl-1,.mx-xxl-1{margin-right:.3125rem!important}.mb-xxl-1,.my-xxl-1{margin-bottom:.3125rem!important}.ml-xxl-1,.mx-xxl-1{margin-left:.3125rem!important}.m-xxl-2{margin:.625rem!important}.mt-xxl-2,.my-xxl-2{margin-top:.625rem!important}.mr-xxl-2,.mx-xxl-2{margin-right:.625rem!important}.mb-xxl-2,.my-xxl-2{margin-bottom:.625rem!important}.ml-xxl-2,.mx-xxl-2{margin-left:.625rem!important}.m-xxl-3{margin:1.25rem!important}.mt-xxl-3,.my-xxl-3{margin-top:1.25rem!important}.mr-xxl-3,.mx-xxl-3{margin-right:1.25rem!important}.mb-xxl-3,.my-xxl-3{margin-bottom:1.25rem!important}.ml-xxl-3,.mx-xxl-3{margin-left:1.25rem!important}.m-xxl-4{margin:1.875rem!important}.mt-xxl-4,.my-xxl-4{margin-top:1.875rem!important}.mr-xxl-4,.mx-xxl-4{margin-right:1.875rem!important}.mb-xxl-4,.my-xxl-4{margin-bottom:1.875rem!important}.ml-xxl-4,.mx-xxl-4{margin-left:1.875rem!important}.m-xxl-5{margin:3.75rem!important}.mt-xxl-5,.my-xxl-5{margin-top:3.75rem!important}.mr-xxl-5,.mx-xxl-5{margin-right:3.75rem!important}.mb-xxl-5,.my-xxl-5{margin-bottom:3.75rem!important}.ml-xxl-5,.mx-xxl-5{margin-left:3.75rem!important}.p-xxl-0{padding:0!important}.pt-xxl-0,.py-xxl-0{padding-top:0!important}.pr-xxl-0,.px-xxl-0{padding-right:0!important}.pb-xxl-0,.py-xxl-0{padding-bottom:0!important}.pl-xxl-0,.px-xxl-0{padding-left:0!important}.p-xxl-1{padding:.3125rem!important}.pt-xxl-1,.py-xxl-1{padding-top:.3125rem!important}.pr-xxl-1,.px-xxl-1{padding-right:.3125rem!important}.pb-xxl-1,.py-xxl-1{padding-bottom:.3125rem!important}.pl-xxl-1,.px-xxl-1{padding-left:.3125rem!important}.p-xxl-2{padding:.625rem!important}.pt-xxl-2,.py-xxl-2{padding-top:.625rem!important}.pr-xxl-2,.px-xxl-2{padding-right:.625rem!important}.pb-xxl-2,.py-xxl-2{padding-bottom:.625rem!important}.pl-xxl-2,.px-xxl-2{padding-left:.625rem!important}.p-xxl-3{padding:1.25rem!important}.pt-xxl-3,.py-xxl-3{padding-top:1.25rem!important}.pr-xxl-3,.px-xxl-3{padding-right:1.25rem!important}.pb-xxl-3,.py-xxl-3{padding-bottom:1.25rem!important}.pl-xxl-3,.px-xxl-3{padding-left:1.25rem!important}.p-xxl-4{padding:1.875rem!important}.pt-xxl-4,.py-xxl-4{padding-top:1.875rem!important}.pr-xxl-4,.px-xxl-4{padding-right:1.875rem!important}.pb-xxl-4,.py-xxl-4{padding-bottom:1.875rem!important}.pl-xxl-4,.px-xxl-4{padding-left:1.875rem!important}.p-xxl-5{padding:3.75rem!important}.pt-xxl-5,.py-xxl-5{padding-top:3.75rem!important}.pr-xxl-5,.px-xxl-5{padding-right:3.75rem!important}.pb-xxl-5,.py-xxl-5{padding-bottom:3.75rem!important}.pl-xxl-5,.px-xxl-5{padding-left:3.75rem!important}.m-xxl-n1{margin:-.3125rem!important}.mt-xxl-n1,.my-xxl-n1{margin-top:-.3125rem!important}.mr-xxl-n1,.mx-xxl-n1{margin-right:-.3125rem!important}.mb-xxl-n1,.my-xxl-n1{margin-bottom:-.3125rem!important}.ml-xxl-n1,.mx-xxl-n1{margin-left:-.3125rem!important}.m-xxl-n2{margin:-.625rem!important}.mt-xxl-n2,.my-xxl-n2{margin-top:-.625rem!important}.mr-xxl-n2,.mx-xxl-n2{margin-right:-.625rem!important}.mb-xxl-n2,.my-xxl-n2{margin-bottom:-.625rem!important}.ml-xxl-n2,.mx-xxl-n2{margin-left:-.625rem!important}.m-xxl-n3{margin:-1.25rem!important}.mt-xxl-n3,.my-xxl-n3{margin-top:-1.25rem!important}.mr-xxl-n3,.mx-xxl-n3{margin-right:-1.25rem!important}.mb-xxl-n3,.my-xxl-n3{margin-bottom:-1.25rem!important}.ml-xxl-n3,.mx-xxl-n3{margin-left:-1.25rem!important}.m-xxl-n4{margin:-1.875rem!important}.mt-xxl-n4,.my-xxl-n4{margin-top:-1.875rem!important}.mr-xxl-n4,.mx-xxl-n4{margin-right:-1.875rem!important}.mb-xxl-n4,.my-xxl-n4{margin-bottom:-1.875rem!important}.ml-xxl-n4,.mx-xxl-n4{margin-left:-1.875rem!important}.m-xxl-n5{margin:-3.75rem!important}.mt-xxl-n5,.my-xxl-n5{margin-top:-3.75rem!important}.mr-xxl-n5,.mx-xxl-n5{margin-right:-3.75rem!important}.mb-xxl-n5,.my-xxl-n5{margin-bottom:-3.75rem!important}.ml-xxl-n5,.mx-xxl-n5{margin-left:-3.75rem!important}.m-xxl-auto{margin:auto!important}.mt-xxl-auto,.my-xxl-auto{margin-top:auto!important}.mr-xxl-auto,.mx-xxl-auto{margin-right:auto!important}.mb-xxl-auto,.my-xxl-auto{margin-bottom:auto!important}.ml-xxl-auto,.mx-xxl-auto{margin-left:auto!important}} +/*# sourceMappingURL=boosted-grid.min.css.map */ \ No newline at end of file diff --git a/docs/1.2.0/accessibilityStatement/favicon.ico b/docs/1.2.0/accessibilityStatement/favicon.ico new file mode 100644 index 00000000..7f6945a4 Binary files /dev/null and b/docs/1.2.0/accessibilityStatement/favicon.ico differ diff --git a/docs/1.2.0/accessibilityStatement/orange-design-system.html b/docs/1.2.0/accessibilityStatement/orange-design-system.html new file mode 100644 index 00000000..d9bb8a8d --- /dev/null +++ b/docs/1.2.0/accessibilityStatement/orange-design-system.html @@ -0,0 +1,472 @@ + + + + + + + + + + + + Accessibility statement - Orange Design System + + + + +
+

Accessibility statement : Orange Design System

+ +
+ +
+ + + +
+ +

Context

+

[Name of the organization] undertakes to make its websites internet, intranet, extranet and its mobile applications accessible in accordance with article 47 of Law No. 2005-102 of February 11, 2005.

+

To this end, it implements the following strategy and actions :

+

the pluri-annual accessibility framework (French).

+

This accessibility statement applies to [Project name or URL].

+ + +
+ +
+ +
+ +
+
+ +

Conformity level:

+

"Orange Design System" is partially compliant to the criteria with WCAG version 2.2, level AA.

+ +

The Orange Group Accessibility Skills Center refers to the WCAG international recommendations. Here is the correspondence link between the RGAA and the WCAG.

+

The audit was carried out via la Va11ydette.

+ +

Tests result

+
+

+ Global compliance + 80% +

+ +

Global compliance +

+
+
+

+ Average compliance + 99% +

+ +

Average compliance

+
+

The compliance audit carried out by The Orange Group Accessibility Skills Center reveals that :

+
    +
  • 80% of WCAG level A and AA criteria are met.
  • +
  • The average compliance rate of the online service is 99%.
  • +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Summary by levels
LevelAAATotal
Number of criteria322456
Compliant111324
Non-compliant426
Not applicable17926
Compliance + 73% + + 87% + + 80% +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Compliance rate by pages according to the two levels of criteria A and AA
Criteria / LevelCompliant / ACompliant / AANon-compliant / ANon-compliant / AANot applicable / ANot applicable / AACompliance rate
Page : Guidelines1313001911100 %
Page : Components1313001911100 %
Page : Modules1313001911100 %
Page : About111420191093 %
Page : Guidelines-Colour1312001912100 %
Page : Guidelines-Typography101310211196 %
Page : Guidelines-Spacing1313001911100 %
Page : Components - Banner1313001911100 %
Page : Components - Bars Navigation1313001911100 %
Page : Components - Bars tools121410191096 %
Page : Components - Bars tabs1313001911100 %
Page : Components - Button1313001911100 %
Page : Components - Cards1414001810100 %
Page : Components - Chips1314001910100 %
Page : Components - Lists1313001911100 %
Page : Components - Progress indicators1314001910100 %
Page : Components - Sheets111112201188 %
Page : Components - Sliders121310191196 %
Page : Components - Text field1313001911100 %
Page : Modules - List1413001811100 %
Page : Modules - About1313001911100 %
Page : Modules - Card collections1213002011100 %
+
+ +
+
+ +
+ +

Content not accessible

+ +

The contents listed below are not accessible for the following reasons.

+ +

Non-compliances

+

List of non-compliant WCAG criteria :

+
    +
  • + 1.1.1 Non-text Content, Level A +
  • +
  • + 1.4.4 Resize text, Level AA +
  • +
  • + 1.4.10 Reflow, Level AA +
  • +
  • + 2.1.1 Keyboard, Level A +
  • +
  • + 2.5.1 Pointer Gestures, Level A +
  • +
  • + 3.2.2 On Input, Level A +
  • +
+
+
+ +
+ +
+

Establishment of this accessibility statement

+

This declaration was established on 2/29/2024.

+
+
+
+
+ + +

Technical specifications of the site

+
    +
  • SwiftUI
  • +
+ + +

Testing environment

+

The verifications were performed with the following software combinations:

+
    + +
+ +

Methods and Tools to evaluate accessibility

+
    +
  • Automatic testing: Accessibility Inspector, Colour Contrat Analyzer
  • +
  • Functional testing: Voice Over, Switch Control, Keyboard navigation
  • +
+ +
+
+ +
+
+

Pages which have been the subject of compliance verification

+

The verification audit was performed on the following pages using the Orange va11ydette:

+ +
    +
  1. Guidelines :
  2. +
  3. Components :
  4. +
  5. Modules :
  6. +
  7. About :
  8. +
  9. Guidelines-Colour :
  10. +
  11. Guidelines-Typography :
  12. +
  13. Guidelines-Spacing :
  14. +
  15. Components - Banner :
  16. +
  17. Components - Bars Navigation :
  18. +
  19. Components - Bars tools :
  20. +
  21. Components - Bars tabs :
  22. +
  23. Components - Button :
  24. +
  25. Components - Cards :
  26. +
  27. Components - Chips :
  28. +
  29. Components - Lists :
  30. +
  31. Components - Progress indicators :
  32. +
  33. Components - Sheets :
  34. +
  35. Components - Sliders :
  36. +
  37. Components - Text field :
  38. +
  39. Modules - List :
  40. +
  41. Modules - About :
  42. +
  43. Modules - Card collections :
  44. +
+
+
+ +
+ +

Feedback and contact information

+

If you are unable to access content or a service, you can contact the site manager to be directed to an accessible alternative or obtain the content in another form.

+ +

We welcome your feedback on the accessibility of this site. Please let us know if you encounter accessibility problems by sending an email to XXX@orange.com.

+ + +
+
+
+ +
+ +

Legal remedies

+

You have reported to the website manager an accessibility problem that prevents you from accessing content or one of the portal's services and you have not received a satisfactory response, in this case:

+ + +
+
+
+ + + \ No newline at end of file diff --git a/docs/1.2.0/accessibilityStatement/orange-logo.svg b/docs/1.2.0/accessibilityStatement/orange-logo.svg new file mode 100644 index 00000000..a0cd3f28 --- /dev/null +++ b/docs/1.2.0/accessibilityStatement/orange-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/1.2.0/accessibilityStatement/pie.css b/docs/1.2.0/accessibilityStatement/pie.css new file mode 100644 index 00000000..40b1478d --- /dev/null +++ b/docs/1.2.0/accessibilityStatement/pie.css @@ -0,0 +1,236 @@ +.pie { + position: relative; + width: 200px; + height: 200px; + border-radius: 50%; + background: #eee; + background-image: linear-gradient(to right, transparent 50%, #F16E00 0); +} + +.pie:after, +.pie:before { + content: ''; + position: absolute; + display: block; + margin-left: 50%; + width: 50%; + height: 100%; + border-radius: 0 100% 100% 0 / 50%; + background-color: inherit; + transform-origin: left; +} + +.pie:after { background-color: #F16E00 } + +.pie-val { + position: absolute; + top: 15px; + bottom: 15px; + left: 15px; + right: 15px; + z-index: 2; + border-radius: 50%; + background-color: #fff; + padding-top: 25%; +} + +.pie[data-value="1"]:before { transform: rotate(3.6deg) } +.pie[data-value="1"]:after { display: none } +.pie[data-value="2"]:before { transform: rotate(7.2deg) } +.pie[data-value="2"]:after { display: none } +.pie[data-value="3"]:before { transform: rotate(10.8deg) } +.pie[data-value="3"]:after { display: none } +.pie[data-value="4"]:before { transform: rotate(14.4deg) } +.pie[data-value="4"]:after { display: none } +.pie[data-value="5"]:before { transform: rotate(18deg) } +.pie[data-value="5"]:after { display: none } +.pie[data-value="6"]:before { transform: rotate(21.6deg) } +.pie[data-value="6"]:after { display: none } +.pie[data-value="7"]:before { transform: rotate(25.2deg) } +.pie[data-value="7"]:after { display: none } +.pie[data-value="8"]:before { transform: rotate(28.8deg) } +.pie[data-value="8"]:after { display: none } +.pie[data-value="9"]:before { transform: rotate(32.4deg) } +.pie[data-value="9"]:after { display: none } +.pie[data-value="10"]:before { transform: rotate(36deg) } +.pie[data-value="10"]:after { display: none } +.pie[data-value="11"]:before { transform: rotate(39.6deg) } +.pie[data-value="11"]:after { display: none } +.pie[data-value="12"]:before { transform: rotate(43.2deg) } +.pie[data-value="12"]:after { display: none } +.pie[data-value="13"]:before { transform: rotate(46.8deg) } +.pie[data-value="13"]:after { display: none } +.pie[data-value="14"]:before { transform: rotate(50.4deg) } +.pie[data-value="14"]:after { display: none } +.pie[data-value="15"]:before { transform: rotate(54deg) } +.pie[data-value="15"]:after { display: none } +.pie[data-value="16"]:before { transform: rotate(57.6deg) } +.pie[data-value="16"]:after { display: none } +.pie[data-value="17"]:before { transform: rotate(61.2deg) } +.pie[data-value="17"]:after { display: none } +.pie[data-value="18"]:before { transform: rotate(64.8deg) } +.pie[data-value="18"]:after { display: none } +.pie[data-value="19"]:before { transform: rotate(68.4deg) } +.pie[data-value="19"]:after { display: none } +.pie[data-value="20"]:before { transform: rotate(72deg) } +.pie[data-value="20"]:after { display: none } +.pie[data-value="21"]:before { transform: rotate(75.6deg) } +.pie[data-value="21"]:after { display: none } +.pie[data-value="22"]:before { transform: rotate(79.2deg) } +.pie[data-value="22"]:after { display: none } +.pie[data-value="23"]:before { transform: rotate(82.8deg) } +.pie[data-value="23"]:after { display: none } +.pie[data-value="24"]:before { transform: rotate(86.4deg) } +.pie[data-value="24"]:after { display: none } +.pie[data-value="25"]:before { transform: rotate(90deg) } +.pie[data-value="25"]:after { display: none } +.pie[data-value="26"]:before { transform: rotate(93.6deg) } +.pie[data-value="26"]:after { display: none } +.pie[data-value="27"]:before { transform: rotate(97.2deg) } +.pie[data-value="27"]:after { display: none } +.pie[data-value="28"]:before { transform: rotate(100.8deg) } +.pie[data-value="28"]:after { display: none } +.pie[data-value="29"]:before { transform: rotate(104.4deg) } +.pie[data-value="29"]:after { display: none } +.pie[data-value="30"]:before { transform: rotate(108deg) } +.pie[data-value="30"]:after { display: none } +.pie[data-value="31"]:before { transform: rotate(111.6deg) } +.pie[data-value="31"]:after { display: none } +.pie[data-value="32"]:before { transform: rotate(115.2deg) } +.pie[data-value="32"]:after { display: none } +.pie[data-value="33"]:before { transform: rotate(118.8deg) } +.pie[data-value="33"]:after { display: none } +.pie[data-value="34"]:before { transform: rotate(122.4deg) } +.pie[data-value="34"]:after { display: none } +.pie[data-value="35"]:before { transform: rotate(126deg) } +.pie[data-value="35"]:after { display: none } +.pie[data-value="36"]:before { transform: rotate(129.6deg) } +.pie[data-value="36"]:after { display: none } +.pie[data-value="37"]:before { transform: rotate(133.2deg) } +.pie[data-value="37"]:after { display: none } +.pie[data-value="38"]:before { transform: rotate(136.8deg) } +.pie[data-value="38"]:after { display: none } +.pie[data-value="39"]:before { transform: rotate(140.4deg) } +.pie[data-value="39"]:after { display: none } +.pie[data-value="40"]:before { transform: rotate(144deg) } +.pie[data-value="40"]:after { display: none } +.pie[data-value="41"]:before { transform: rotate(147.6deg) } +.pie[data-value="41"]:after { display: none } +.pie[data-value="42"]:before { transform: rotate(151.2deg) } +.pie[data-value="42"]:after { display: none } +.pie[data-value="43"]:before { transform: rotate(154.8deg) } +.pie[data-value="43"]:after { display: none } +.pie[data-value="44"]:before { transform: rotate(158.4deg) } +.pie[data-value="44"]:after { display: none } +.pie[data-value="45"]:before { transform: rotate(162deg) } +.pie[data-value="45"]:after { display: none } +.pie[data-value="46"]:before { transform: rotate(165.6deg) } +.pie[data-value="46"]:after { display: none } +.pie[data-value="47"]:before { transform: rotate(169.2deg) } +.pie[data-value="47"]:after { display: none } +.pie[data-value="48"]:before { transform: rotate(172.8deg) } +.pie[data-value="48"]:after { display: none } +.pie[data-value="49"]:before { transform: rotate(176.4deg) } +.pie[data-value="49"]:after { display: none } +.pie[data-value="50"]:before { transform: rotate(180deg) } +.pie[data-value="50"]:after { display: none } +.pie[data-value="51"]:after { transform: rotate(3.6deg) } +.pie[data-value="51"]:before { display: none } +.pie[data-value="52"]:after { transform: rotate(7.2deg) } +.pie[data-value="52"]:before { display: none } +.pie[data-value="53"]:after { transform: rotate(10.8deg) } +.pie[data-value="53"]:before { display: none } +.pie[data-value="54"]:after { transform: rotate(14.4deg) } +.pie[data-value="54"]:before { display: none } +.pie[data-value="55"]:after { transform: rotate(18deg) } +.pie[data-value="55"]:before { display: none } +.pie[data-value="56"]:after { transform: rotate(21.6deg) } +.pie[data-value="56"]:before { display: none } +.pie[data-value="57"]:after { transform: rotate(25.2deg) } +.pie[data-value="57"]:before { display: none } +.pie[data-value="58"]:after { transform: rotate(28.8deg) } +.pie[data-value="58"]:before { display: none } +.pie[data-value="59"]:after { transform: rotate(32.4deg) } +.pie[data-value="59"]:before { display: none } +.pie[data-value="60"]:after { transform: rotate(36deg) } +.pie[data-value="60"]:before { display: none } +.pie[data-value="61"]:after { transform: rotate(39.6deg) } +.pie[data-value="61"]:before { display: none } +.pie[data-value="62"]:after { transform: rotate(43.2deg) } +.pie[data-value="62"]:before { display: none } +.pie[data-value="63"]:after { transform: rotate(46.8deg) } +.pie[data-value="63"]:before { display: none } +.pie[data-value="64"]:after { transform: rotate(50.4deg) } +.pie[data-value="64"]:before { display: none } +.pie[data-value="65"]:after { transform: rotate(54deg) } +.pie[data-value="65"]:before { display: none } +.pie[data-value="66"]:after { transform: rotate(57.6deg) } +.pie[data-value="66"]:before { display: none } +.pie[data-value="67"]:after { transform: rotate(61.2deg) } +.pie[data-value="67"]:before { display: none } +.pie[data-value="68"]:after { transform: rotate(64.8deg) } +.pie[data-value="68"]:before { display: none } +.pie[data-value="69"]:after { transform: rotate(68.4deg) } +.pie[data-value="69"]:before { display: none } +.pie[data-value="70"]:after { transform: rotate(72deg) } +.pie[data-value="70"]:before { display: none } +.pie[data-value="71"]:after { transform: rotate(75.6deg) } +.pie[data-value="71"]:before { display: none } +.pie[data-value="72"]:after { transform: rotate(79.2deg) } +.pie[data-value="72"]:before { display: none } +.pie[data-value="73"]:after { transform: rotate(82.8deg) } +.pie[data-value="73"]:before { display: none } +.pie[data-value="74"]:after { transform: rotate(86.4deg) } +.pie[data-value="74"]:before { display: none } +.pie[data-value="75"]:after { transform: rotate(90deg) } +.pie[data-value="75"]:before { display: none } +.pie[data-value="76"]:after { transform: rotate(93.6deg) } +.pie[data-value="76"]:before { display: none } +.pie[data-value="77"]:after { transform: rotate(97.2deg) } +.pie[data-value="77"]:before { display: none } +.pie[data-value="78"]:after { transform: rotate(100.8deg) } +.pie[data-value="78"]:before { display: none } +.pie[data-value="79"]:after { transform: rotate(104.4deg) } +.pie[data-value="79"]:before { display: none } +.pie[data-value="80"]:after { transform: rotate(108deg) } +.pie[data-value="80"]:before { display: none } +.pie[data-value="81"]:after { transform: rotate(111.6deg) } +.pie[data-value="81"]:before { display: none } +.pie[data-value="82"]:after { transform: rotate(115.2deg) } +.pie[data-value="82"]:before { display: none } +.pie[data-value="83"]:after { transform: rotate(118.8deg) } +.pie[data-value="83"]:before { display: none } +.pie[data-value="84"]:after { transform: rotate(122.4deg) } +.pie[data-value="84"]:before { display: none } +.pie[data-value="85"]:after { transform: rotate(126deg) } +.pie[data-value="85"]:before { display: none } +.pie[data-value="86"]:after { transform: rotate(129.6deg) } +.pie[data-value="86"]:before { display: none } +.pie[data-value="87"]:after { transform: rotate(133.2deg) } +.pie[data-value="87"]:before { display: none } +.pie[data-value="88"]:after { transform: rotate(136.8deg) } +.pie[data-value="88"]:before { display: none } +.pie[data-value="89"]:after { transform: rotate(140.4deg) } +.pie[data-value="89"]:before { display: none } +.pie[data-value="90"]:after { transform: rotate(144deg) } +.pie[data-value="90"]:before { display: none } +.pie[data-value="91"]:after { transform: rotate(147.6deg) } +.pie[data-value="91"]:before { display: none } +.pie[data-value="92"]:after { transform: rotate(151.2deg) } +.pie[data-value="92"]:before { display: none } +.pie[data-value="93"]:after { transform: rotate(154.8deg) } +.pie[data-value="93"]:before { display: none } +.pie[data-value="94"]:after { transform: rotate(158.4deg) } +.pie[data-value="94"]:before { display: none } +.pie[data-value="95"]:after { transform: rotate(162deg) } +.pie[data-value="95"]:before { display: none } +.pie[data-value="96"]:after { transform: rotate(165.6deg) } +.pie[data-value="96"]:before { display: none } +.pie[data-value="97"]:after { transform: rotate(169.2deg) } +.pie[data-value="97"]:before { display: none } +.pie[data-value="98"]:after { transform: rotate(172.8deg) } +.pie[data-value="98"]:before { display: none } +.pie[data-value="99"]:after { transform: rotate(176.4deg) } +.pie[data-value="99"]:before { display: none } +.pie[data-value="100"]:after { transform: rotate(180deg) } +.pie[data-value="100"]:before { display: none } diff --git a/docs/1.2.0/accessibilityStatement/style.css b/docs/1.2.0/accessibilityStatement/style.css new file mode 100644 index 00000000..dd162300 --- /dev/null +++ b/docs/1.2.0/accessibilityStatement/style.css @@ -0,0 +1,117 @@ +body { + font-family: "Arial"; + color: #000000; + background: #eee; + margin: 0; +} + +.content { + background-color: #fff; + padding-bottom: 3em; +} + +em { + color: #e00; + font-weight: bold; + font-style: normal; +} + +.underover { + text-decoration: underline overline #FF3028; +} + +.lead { + font-weight: bold; +} + +.row > [class*="col-"] { + padding-right: 30px; + padding-left: 30px; +} + +h1 { + background-image: url(orange-logo.svg); + background-size: 3.5rem 3.5rem; + background-repeat: no-repeat; + background-position: 1rem 1.5rem; + margin: 0; + padding: 2rem 2rem 2rem 8rem; +} + +h2 { + font-size: 1.2em; + margin-top: 3rem; +} + +.summary h4 { + text-align: center; + font-size: 1em; + border-bottom: 0; +} + +.summary h4 span { + font-size: 3em; +} + +.pie-noncompliant{ + font-size: 1.75em !important; +} + +h3 { + margin-top: 1.5rem; + font-size: 1em; +} + +.table-responsive{ + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +table { + width: 100%; + margin-bottom: 1.25rem; + border-collapse: collapse; + text-align: center; + overflow-x:auto; +} + + +table tr { + border-bottom: 1px solid #ccc; +} + +table th { + font-size: .875rem; + font-weight: bold; + padding: .5rem; +} + +table td { + padding: .5rem; + font-size: .875rem; + line-height: 1rem; +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; /* added line */ + border: 0; +} + +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; /* added line */ + border: 0; +} \ No newline at end of file diff --git a/docs/1.2.0/components/banners.md b/docs/1.2.0/components/banners.md new file mode 100644 index 00000000..68a05df0 --- /dev/null +++ b/docs/1.2.0/components/banners.md @@ -0,0 +1,136 @@ +--- +layout: detail +title: Banners +description: A banner displays an important message which requires an action to be dismissed. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +A banner displays an important, succinct message, and provides actions for users to address (or dismiss the banner). It requires a user action to be dismissed. + +Banners should be displayed at the top of the screen, below a top app bar. They’re persistent and nonmodal, allowing the user to either ignore them or interact with them at any time. Only one banner should be shown at a time + +![Banner light](images/banner-light.png) +![Banner dark](images/banner-dark.png) + +## Specifications references + +- [Design System Manager - Banners](https://system.design.orange.com/0c1af118d/p/85a52b-components/b/1497a4) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +### Two buttons + +Button are placed under the text. + +#### SwiftUI examples + +- Without image + +```swift +ODSBanner(text: "One to two lines is preferable on mobile and tablet.") { + Button("Button 1") { + // your action here + } +} secondButton: { + Button("Button 1") { + // your action here + } +} +``` + +- With image from resourcess + +```swift +ODSBanner(text: "One to two lines is preferable on mobile and tablet.", + imageSource: .image(Image("placeholder", bundle: Bundle.ods))) { + Button("Button 1") { + // your action here + } +} secondButton: { + Button("Button 1") { + // your action here + } +} +``` + + +- With image from URL + +```swift + +let placeholder = Image("placeholder", bundle: Bundle.ods) +let url = URL(string: "https://images.unsplash.com/photo-1615735487485-e52b9af610c1?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=774&q=80") + +ODSBanner(text: "One to two lines is preferable on mobile and tablet.", + imageSource: .asyncImage(url, placeholder)) { + Button("Button 1") { + // your action here + } +} secondButton: { + Button("Button 1") { + // your action here + } +} +``` + +#### ODSBanner API + +| Parameter | Default value | Description | +|-------------------------------- |---------------------|------------------------------------------------------------------------------- | +| `text: Text` | | Text displayed into the banner. | +| `imageSource: ODSImage.Source?` | `nil` | Image displayed in the banner in a circle shape. | +| `firstButton: Button` | | Primary (leading) button displayed in the banner. | +| `secondButton: Button` | | Secondary (trailing) button displayed into the banner next to the primary one. | + +### One button + +The button is placed under the text. + +#### SwiftUI example + +```swift +ODSBanner(text: "One to two lines is preferable on mobile and tablet.", + imageSource: .image(Image("placeholder", bundle: Bundle.ods))) { + Button("Button") { + // your action here + } +} +``` + +#### ODSBanner API + +| Parameter | Default value | Description | +|---------------------------------|--------------------|--------------------------------------------------| +| `text: Text` | | Text displayed into the banner. | +| `imageSource: ODSImage.Source?` | `nil` | Image displayed in the banner in a circle shape. | +| `button: Button` | | Primary button displayed in the banner. | + + +### No button + +#### SwiftUI example + +```swift +ODSBanner(text: "One to two lines is preferable on mobile and tablet.", + imageSource: .image(Image("placeholder", bundle: Bundle.ods))) +``` + +#### ODSBanner API + +| Parameter | Default value | Description | +|---------------------------------|--------------------|--------------------------------------------------| +| `text: Text` | | Text displayed into the banner. | +| `imageSource: ODSImage.Source?` | `nil` | Image displayed in the banner in a circle shape. | + diff --git a/docs/1.2.0/components/banners_docs.md b/docs/1.2.0/components/banners_docs.md new file mode 100644 index 00000000..9d720197 --- /dev/null +++ b/docs/1.2.0/components/banners_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Banners +content_page: banners.md +--- diff --git a/docs/1.2.0/components/barsNavigation.md b/docs/1.2.0/components/barsNavigation.md new file mode 100644 index 00000000..79ae42da --- /dev/null +++ b/docs/1.2.0/components/barsNavigation.md @@ -0,0 +1,104 @@ +--- +layout: detail +title: Bars - navigation +description: Navigation bar with Orange branding +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Bars: navigation](https://system.design.orange.com/0c1af118d/p/34094d-bars-navigation/b/419eb1) +- [Apple guideline - Navigation bars](https://developer.apple.com/design/human-interface-guidelines/components/navigation-and-search/navigation-bars/) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Standard navigation bar + +![Navigation bar standard light](images/bars_navigation_standard_light.png) +![Navigation bar standard dark](images/bars_navigation_standard_dark.png) + +When using a navigation view, basic navigation is using 'inline' display mode by default. + +```swift +NavigationView { + NavigationLink(destination: Text("destination")) { + Text("Main view") + } + .navigationBarTitle("Standard", displayMode: .inline) +} + +``` + +## Navigation bar with large title + +![Navigation bar large light](images/bars_navigation_large_light.png) +![Navigation bar large dark](images/bars_navigation_large_dark.png) + +Use 'large' display mode to enable large titles when scrolling up. + +```swift +NavigationView { + NavigationLink(destination: Text("destination")) { + Text("Main view") + } + .navigationBarTitle("Standard", displayMode: .large) +} + +``` + +## Navigation bar with search bar + +![Navigation bar search light](images/bars_navigation_search_light.png) +![Navigation bar search dark](images/bars_navigation_search_dark.png) + + +Use .searchable modifier to add a search bar in the navigation view. + +```swift +@State var searchQuery = "" + +NavigationView { + NavigationLink(destination: Text("destination")) { + Text("Main view") + } + .navigationBarTitle("With search bar", displayMode: .inline) + .searchable(text: $searchQuery, placement: .navigationBarDrawer(displayMode: .always)) +} + +``` + +## Navigation bar with action item + +![Navigation bar items light](images/bars_navigation_items_light.png) +![Navigation bar items dark](images/bars_navigation_items_dark.png) + +You can add one or several buttons (trailing or leading) in the navigation view by using .toolbar modifier + +```swift +NavigationView { + NavigationLink(destination: Text("destination")) { + Text("Main view") + } + .navigationBarTitle("Standard", displayMode: .inline) + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button { + print("item action") + } label: { + Image(systemName: "ant.circle") + } + } + } +} + +``` diff --git a/docs/1.2.0/components/barsNavigation_docs.md b/docs/1.2.0/components/barsNavigation_docs.md new file mode 100644 index 00000000..11493173 --- /dev/null +++ b/docs/1.2.0/components/barsNavigation_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Bars - navigation +content_page: barsNavigation.md +--- diff --git a/docs/1.2.0/components/barsTab.md b/docs/1.2.0/components/barsTab.md new file mode 100644 index 00000000..2b95ab3c --- /dev/null +++ b/docs/1.2.0/components/barsTab.md @@ -0,0 +1,57 @@ +--- +layout: detail +title: Bars - tab +description: Tab bars with Orange branding +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Bars: tab](https://system.design.orange.com/0c1af118d/p/08dab8-bars-tab/b/778ed0) +- [Apple guideline - Tab bars](https://developer.apple.com/design/human-interface-guidelines/components/navigation-and-search/tab-bars/) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Standard tab bar + +![Tab bar light](images/bars_tab_light.png) +![Tab bar dark](images/bars_tab_dark.png) + +Tab bar is a standard iOS component. It uses bar items to navigate between views. +Bar Item contains an icon and a title. +An additonal badge can be also added with a count value or a text. + +Example with 4 bar items : + +```swift +TabView { + GuidelinesList() + .tabItem { + Label("Guidelines", image: "Guideline-DNA_32") + } + .badge("Text") + ComponentsList() + .tabItem { + Label("Components", image: "component-atom_32") + } + ModulesList() + .tabItem { + Label("Modules", image: "Module-molecule_32") + } + .badge(10) + ODSDemoAboutView() + .tabItem { + Label("About", image: "info_32") + } +} +``` diff --git a/docs/1.2.0/components/barsTab_docs.md b/docs/1.2.0/components/barsTab_docs.md new file mode 100644 index 00000000..9ae1d60d --- /dev/null +++ b/docs/1.2.0/components/barsTab_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: Bars - tab +content_page: barsTab.md +back-to-top: false +--- diff --git a/docs/1.2.0/components/barsTool.md b/docs/1.2.0/components/barsTool.md new file mode 100644 index 00000000..f0c848c0 --- /dev/null +++ b/docs/1.2.0/components/barsTool.md @@ -0,0 +1,162 @@ +--- +layout: detail +title: Bars - tool +description: Tool bars with Orange branding +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Bars: tool](https://system.design.orange.com/0c1af118d/p/06c413-bars-tool/b/951e5c) +- [Apple guideline - Tool bars](https://developer.apple.com/design/human-interface-guidelines/ios/bars/toolbars/) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +A tool bar allows users to do specific actions regarding the entire page. It is placed at the bottom of the screen. It can display 2 to 5 icon controls or 2 to 3 label entries. + +### With label items + +![tool bar labels light](images/bars_tool_labels_light.png) ![tool bar labels dark](images/bars_tool_labels_dark.png) + +A tool bar can display 2 to 3 label entries. + +Example with 3 label entries in toolBar : + +```swift + +let description1 = ODSToolbarLabelDesription(text: "Action 1") { } +let description2 = ODSToolbarLabelDesription(text: "Action 2") { } +let description3 = ODSToolbarLabelDesription(text: "Action 3") { } + +let labelItems = ODSToolbarLabeledItems(description1: description1, + description2: description2, + description3: description3) +NavigationView { + ContentView() + .navigationBarTitle("", displayMode: .inline) + .navigationBarHidden(true) + .odsToolBar(items: labelItems) +} + +// To remove navigation bar, use following modifiers +// .navigationBarHidden(true) + +``` + +#### odsToolBar Modifier API + +| Parameter | Default value | Description | +|---------------------------------|--------------------|---------------------------------------| +| `items: ODSToolbarLabeledItems` | | Text items displayed into the banner. | + + +#### ODSToolbarLabeledItems API + +| Parameter | Default value | Description | +|-------------------------------------------|--------------------|---------------------------------------------------- | +| `description1: ODSToolbarLabelDesription` | | Primary description of item in tool bar | +| `description2: ODSToolbarLabelDesription` | | Secondary description of item in tool bar | +| `description3: ODSToolbarLabelDesription?`| `nil` | Terciary (optional) description of item in tool bar | + +#### ODSToolbarLabelDesriptionF API + +| Parameter | Default value | Description | +|--------------------------------|--------------------|-----------------------------| +| `text: String | | Text displayed in the item | +| `action: @escaping () -> Void` | | Action when item is clicked | +
+ +### With icon items + +![tool bar icons light](images/bars_tool_icons_light.png) ![tool bar icons dark](images/bars_tool_icons_dark.png) + +A tool bar can display 2 to 5 icon controls +```swift + +let description1 = ODSToolbarIconDesription(systemName: "plus") { } +let description2 = ODSToolbarIconDesription(systemName: "square.and.arrow.up") { } +let description3 = ODSToolbarIconDesription(systemName: "square.and.pencil") { } +let description4 = ODSToolbarIconDesription(systemName: "folder") { } +let description5 = ODSToolbarIconDesription(systemName: "trash") { } + +let iconItems = ODSToolbarIconsItems(description1: description1, + description2: description2, + description3: description3, + description4: description4, + description5: description5) +NavigationView { + ContentView() + .navigationBarTitle("", displayMode: .inline) + .navigationBarHidden(true) + .odsToolBar(items: iconItems) +} + +// To remove navigation bar, use following modifiers +// .navigationBarHidden(true) + +``` + +#### odsToolBar Modifier API + +| Parameter | Default value | Description | +|------------------------------|----------------|---------------------------------------| +| `items: ODSToolbarIconItems` | | Icon items displayed into the banner. | + + +#### ODSToolbarIconsItems API + +| Parameter | Default value | Description | +|------------------------------------------|---------------|----------------------------------------------------| +| `description1: ODSToolbarIconDesription` | | First description of item in tool bar | +| `description2: ODSToolbarIconDesription` | | Second description of item in tool bar | +| `description3: ODSToolbarIconDesription?`| `nil` | Third (optional) description of item in tool bar | +| `description4: ODSToolbarIconDesription?`| `nil` | Fourth (optional) description of item in tool bar | +| `description5: ODSToolbarIconDesription?`| `nil` | Fifth (optional) description of item in tool bar | + + +#### ODSToolbarIconDesription API + +| Parameter | Default value | Description | +|--------------------------------|---------------|-----------------------------| +| `systemName: String | | System name of the image | +| `action: @escaping () -> Void` | | Action when item is clicked | +
+ + +## Remarks + +As toolbar colors depends on theme, don't forget to add it to enviroment and call the view modifier __.toolBarColors(for:)__ to apply colors provided by the theme. + +Two solutions: + +- Directy on the root view + +```swift +let theme = YourTheme() + +ContentViewWithToolBar() +.environment(\.theme, theme) +.toolBarColors(for: theme) +``` + +- Or using __ODSThemeableView__ view as a root view: + +```swift +let theme = YourTheme() + +ODSThemeableView(theme: yourTheme) { + ContentViewWithToolBar() +} +``` diff --git a/docs/1.2.0/components/barsTool_docs.md b/docs/1.2.0/components/barsTool_docs.md new file mode 100644 index 00000000..a20e98aa --- /dev/null +++ b/docs/1.2.0/components/barsTool_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Bars - tool +content_page: barsTool.md +--- diff --git a/docs/1.2.0/components/buttons.md b/docs/1.2.0/components/buttons.md new file mode 100644 index 00000000..e37ef536 --- /dev/null +++ b/docs/1.2.0/components/buttons.md @@ -0,0 +1,164 @@ +--- +layout: detail +title: Buttons +description: A button allows a user to perform an action or to navigate to another page. It contains a text label and a supporting icon can be displayed. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Buttons](https://system.design.orange.com/0c1af118d/p/278734-buttons-shape/b/536b5f) +- [Apple guideline - Buttons](https://developer.apple.com/design/human-interface-guidelines/components/menus-and-actions/buttons) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +### Emphasis button + +Button variants range in style to denote emphasis. Use different styles and not size to show the preferred choice. + +- **Layout** + +**Large** + +![Buttons high emphasis disabled](images/buttons_layout_large_with_icon.png) + +![Buttons high emphasis](images/buttons_layout_large_without_icon.png) + +**Small** + +![Buttons high emphasis disabled](images/buttons_layout_small_with_icon.png) + +![Buttons high emphasis](images/buttons_layout_small_without_icon.png) + + +- **Emphasis** + +**High emphasis** + +![Buttons high emphasis disabled](images/buttons_functionnal_disabled.png) +![Buttons high emphasis](images/buttons_emphasis_high.png) + +**Medium** + +![Buttons medium emphasis disabled](images/buttons_functionnal_disabled.png) +![Buttons medium emphasis](images/buttons_emphasis_medium.png) + +**Low emphasis** + +![Buttons low emphasis disabled](images/buttons_functionnal_disabled.png) +![Buttons low emphasis](images/buttons_emphasis_low.png) + +**Lowest emphasis** + +![Buttons lowest emphasis disabled](images/buttons_emphasis_lowest_disabled.png) +![Buttons lowest emphasis](images/buttons_emphasis_lowest.png) + +#### SwiftUI example + +```swift +// High emphasis +ODSButton(text: Text("Some text"), + image: Image("Add"), + emphasis: .high) {} + +// Lowest emphasis +ODSButton(text: Text("Some text"), + image: Image("Add"), + emphasis: .lowest) {} +``` + +#### ODSButton API + +| Parameter | Default value | Description | +|-----------------------------|--------------------|-----------------------------------------------------------------------------------| +| `text: Text` | | Text displayed into the banner. | +| `image: Image?` | `nil` | Icon displayed in the button before the text. | +| `emphasis: Emphasis` | | The button's emphasis'. | +| `fullWidth: Bool` | `false` | Defines the size of the button layout. Set to `true` means button takes all available space horizontally. Set to `false`, the size of the button is limited to the size of the text added by a padding round it. +| `action: () -> Void` | | Callback invoked on button click. | + +
+ +### Functional button + +If required, colour versions can also be used to inform users of positive or negative destructive actions. + +**Positive** + +![Buttons functional positive disabled](images/buttons_functionnal_disabled.png) +![Buttons functional positive](images/buttons_functional_positive.png) + +**Negative** + +![Buttons functional negative disabled](images/buttons_functionnal_disabled.png) +![Buttons functional negative](images/buttons_functional_negative.png) + +#### SwiftUI example + +```swift + // Negative button + ODSFunctionalButton(text: Text("Some text"), style: .negative) + { /* action: Do something */ } + + ODSFunctionalButton(text: Text("Some text"), image: Image("Add"), style: .negative) + { /* action: Do something */ } + + // Positive button + ODSFunctionalButton(text: Text("Some text") style: .positive) + { /* action: Do something */ } + + ODSFunctionalButton(text: Text("Some text"), image: Image("Add"), style: .positive) + { /* action: Do something */ } + + // To disable the button + ODSFunctionalButton(text: Text("Some text"), style: .positive) { /* action: Do something */ } + .disabled(true) +``` + +#### ODSFunctionalButton API + + +| Parameter | Default value | Description | +|-------------------------------------------|--------------------|-----------------------------------------------------------------------------------| +| `text: Text` | | Text displayed into the banner. | +| `image: Image?` | `nil` | Icon displayed in the button before the text. | +| `style: ODSFunctionalButton.Style` | | Controls the style of the button. Use `ODSFunctionalButton.Style.positive`/`ODSFunctionalButton.Style.negative` to get a green/red button. +| `fullWidth: Bool` | `false` | Defines the size of the button layout. Set to `true` means button takes all available space horizontally. Set to `false`, the size of the button is limited to the size of the text added by a padding round it. +| `action: () -> Void` | | Callback invoked on button click. | +
+ + +### Icon button + +Plain buttons are the most ubiquitous component found throughout applications. Consisting an icon, they are the most simple button style. + +![Buttons icon](images/buttons_icon.png) + +#### SwiftUI example + +```swift +// icon with system asset +ODSIconButton(image: Image(systemName: "info.circle")) {} + +// icon with Solaris asset +ODSIconButton(image: Image("Add")) {} +``` + +#### ODSIconButton API + +| Parameter | Default value | Description | +|-----------------------------|---------------|-----------------------------------| +| `image: Image` | | Icon displayed in the button. | +| `action: () -> Void` | | Callback invoked on button click. | diff --git a/docs/1.2.0/components/buttons_docs.md b/docs/1.2.0/components/buttons_docs.md new file mode 100644 index 00000000..085cbe10 --- /dev/null +++ b/docs/1.2.0/components/buttons_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Buttons +content_page: buttons.md +--- diff --git a/docs/1.2.0/components/cards.md b/docs/1.2.0/components/cards.md new file mode 100644 index 00000000..056ccef4 --- /dev/null +++ b/docs/1.2.0/components/cards.md @@ -0,0 +1,273 @@ +--- +layout: detail +title: Cards +description: Cards contain content and actions about a single subject. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Cards](https://system.design.orange.com/0c1af118d/p/66bac5-cards/b/1591fb) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +Images in cards are considered as decorative, so they are ignored by Voice Over. + +## Variants + +Cards are a contained and independent element that can display content and actions on a single topic. + +There are a few ways cards can be presented. Ranging from a single title on its own for a simple card view or with more information shown in a subtitle and supporting text and actions at the bottom of the card. + + +### Vertical Image First Card + +This is a full width card displayed with an image as first element. + +This card is composed of two parts: +- Media: (today an image) +- Content: with a title, an optional subtitle an optional supporting text and optional buttons (zero up to two) + +![Vertical image first card light](images/card_vertical_image_first_light.png) ![Vertical image first card dark](images/card_vertical_image_first_dark.png) + +#### SwiftUI example + +Card is configured like this: + +```swift +ODSCardVerticalImageFirst( + title: Text("Title"), + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: Text("Subtitle"), + text: Text("A supporting text to describe something") +) { + Button("Button 1") { + // do something here + } +} secondButton: { + Button("Button 2") { + // do something here + } +} +``` + +#### ODSCardVerticalImageFirst API + +| Parameter | Default value | Description | +|-------------------------------------|--------------------|-----------------------------------------------------------------------------------| +| `title: Text` | | Title displayed into the card. | +| `imageSource: ODSImage.Source` | | Image displayed in the card. | +| `subtitle: Text?` | `nil` | Subtitle (optional) displayed into the card. | +| `text: Text` | `nil` | Text (optional) displayed into the card. | +| `firstButton: Button` | | Primary (leading) button displayed in the card. | +| `secondButton: Button` | | Secondary (trailing) button displayed into the card next to the first one. | + +**Remarks:** +- To get a card without button, use the right initializer without `firstButton` and `secondButton`. +- To handle action when card is clicked, add it into a `Button` or in `NnavigationLink` or add a `.onTapGesture` modifier.

+ + +### Vertical Header First Card + +This is a full width card displaying with a title and a thumbnail on top as first element. + +This card is composed of three parts: +- Header: with a title, an optional subtitle and an optional thmubnail +- Media: (today an image) +- Content: with an optional supporting text and optional buttons (zero up to two) + +![Vertical header first card light](images/card_vertical_header_first_light.png) ![Vertical header first card dark](images/card_vertical_header_first_dark.png) + +#### SwiftUI example + +Card is configured like this: + +```swift + +ODSCardVerticalHeaderFirst( + title: Text("Title"), + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: Text("Subtitle"), + thumbnailSource: .image(Image("placeholder", bundle: Bundle.ods)), + text: Text("A supporting text to describe something") +) { + Button("Button 1") { + // do something here + } +} secondButton: { + Button("Button 2") { + // do something here + } +} +``` + +#### ODSCardVerticalHeaderFirst API + +| Parameter | Default value | Description | +|-------------------------------------|------------------- |-----------------------------------------------------------------------------------| +| `title: Text` | | Title displayed into the card. | +| `imageSource: ODSImage.Source` | | Image displayed in the card. | +| `subtitle: Text?` | `nil` | Subtitle (optional) displayed into the card. | +| `thumbnailSource: ODSImage.Source?` | `nil` | Thumbnail displayed into the card next to the title: avatar, logo or icon. | +| `text: Text` | `nil` | Text (optional) displayed into the card. | +| `firstButton: Button` | | Primary (leading) button displayed in the card. | +| `secondButton: Button` | | Secondary (trailing) button displayed into the card next to the first one. | + +**Remarks:** +- To get a card without button, use the right initializer without `firstButton` and `secondButton`. +- To handle action when card is clicked, add it into a `Button` or in `NnavigationLink` or add a `.onTapGesture` modifier.

+ + +### Horizontal Card + +This is a full width card displaying with image on left and content with texts on the right. Additonal action buttons can be added at the bottom of the card. + +Thes content is composed by: +- a title +- an optional subtitle +- an optional text for larger description + +![Horizontal card light](images/card_horizontal_light.png) ![Horizontal card dark](images/card_horizontal_dark.png) + +#### SwiftUI example + +Card is configured like this: + +```swift +ODSCardHorizontal( + title: Text("Title"), + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + imagePosition: .leading, + subtitle: Text("Subtitle"), + text: Text("A supporting text to describe something") +) { + + Button("Button 1") { + // do something here + } +} secondButton : { + Button("Button 1") { + // do something here + } +} +``` + +#### ODSCardHorizontal API + +| Parameter | Default value | Description | +|-------------------------------------|--------------------|-----------------------------------------------------------------------------------| +| `title: Text` | | Title displayed into the card. | +| `imageSource: ODSImage.Source` | | Image displayed in the card. | +| `imagePosition: Self.ImagePosition` | `.leading` | The side where image is placed. | +| `subtitle: Text?` | `nil` | Subtitle (optional) displayed into the card. | +| `text: Text` | `nil` | Text (optional) displayed into the card. | +| `firstButton: Button` | | Primary (leading) button displayed in the card. | +| `secondButton: Button` | | Secondary (trailing) button displayed into the card next to the first one. | + +**Remarks:** +- To get a card without button, use the right initializer without `firstButton` and `secondButton`. +- To handle action when card is clicked, add it into a `Button` or in `NnavigationLink` or add a `.onTapGesture` modifier.

+ + +### Small Card + +The small card if prefered for two-column portrait mobile screen display. +As it is smaller than full-width cards, it contains only title and subtitle (optional) in one line (Truncated tail). + +![Small card light](images/card_small_light.png) ![Small card dark](images/card_small_dark.png) + +#### SwiftUI example + +Card is configured like this: + +```swift +ODSCardSmall( + title: Text("Title"), + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: Text("Subtitle") +) +``` + +#### ODSCardSmall API + +| Parameter | Default value | Description | +|-------------------------------------|--------------------|------------------------------------------------------------------------------------| +| `title: Text` | | Title displayed into the card. | +| `imageSource: ODSImage.Source` | | Image displayed in the card. | +| `subtitle: Text?` | `nil` | Subtitle (optional) displayed into the card. | +| `titleAccessibleLineLimit: Int?` | `nil` | The line limit to apply to the title if size category is accessibility category | +| `subtitleAccessibleLineLimit: Int?` | `nil` | The line limit to apply to the subtitle if size category is accessibility category | + +**Remark:** +- To handle action when card is clicked, add it into a `Button` or in `NnavigationLink` or add a `.onTapGesture` modifier.

+ + +#### How to add Small Card in Grid + +```swift +class Model { + let title: String + let subtitle: String? + let imageSource: ODSImage.Source + + init(title: String, imageSource: ODSImage.Source, subtitle: String? = nil) { + self.title = title + self.imageSource = imageSource + self.subtitle = subtitle + } +} + + +let models = [ + Model( + title: "Title 1", + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: "Subtitle 1" + ) + Model( + title: "Title 2", + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: "Subtitle 2" + ) + //... +] + +/// /!\ Don't forget to put the grid into a scrollview +ScrollView { + LazyVGrid(columns: columns, spacing: ODSSpacing.none) { + ForEach(models, id:\.title) { model in + ODSCardSmall( + title: Text(model.title), + imageSource: model.imageSource, + subtitle: Text(model.subtitle) + ) + } + } + .padding(.all, ODSSpacing.m) +} + +``` + +However for accessibility edge cases, like when text sizes are accessibility sizes, the behaviour is different for such components. They won't be displayed in one truncated line because the text will be too truncated and difficult to read. +If this choice is too impacting for your UI, it is possible to define the limit number of lines to use if a11y size are used + +```swift +ODSCardSmall( + title: Text("Title"), + imageSource: .image(Image("placeholder", bundle: Bundle.ods)), + subtitle: Text("Subtitle"), + // Here 3 is the number of lines you want for such edge cases + titleAccessibleLineLimit: 3, + subtitleAccessibleLineLimit: 3 +) +``` diff --git a/docs/1.2.0/components/cards_docs.md b/docs/1.2.0/components/cards_docs.md new file mode 100644 index 00000000..193969dd --- /dev/null +++ b/docs/1.2.0/components/cards_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Cards +content_page: cards.md +--- diff --git a/docs/1.2.0/components/chips.md b/docs/1.2.0/components/chips.md new file mode 100644 index 00000000..65ebb912 --- /dev/null +++ b/docs/1.2.0/components/chips.md @@ -0,0 +1,227 @@ +--- +layout: detail +title: Chips +description: Chips are compact elements that represent an input, attribute, or action. +--- + +--- + +**Page summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager](https://system.design.orange.com/0c1af118d/p/85a52b-components/b/1497a4) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +Chips support dynamic types for accessibility. + +Chips support content labeling for accessibility and are readable by most screen readers. Text rendered in chips is automatically provided to accessibility services. Additional content labels are usually unnecessary. + +## Variants + +### Action chip + +Action chips offer actions related to primary content. They should appear dynamically and contextually in a UI. +An alternative to action chips are buttons, which should appear persistently and consistently. + +![Light action chip](images/chips_action_light.png) +![Dark action chip](images/chips_action_dark.png) + +#### SwiftUI example + +``` swift +ODSActionChip( + text: Text("chip text"), + Image(systemname: "heart") + action: { doSomething() } +) +``` + + +#### ODSActionChip API + +| Parameter | Default value | Description | +|-----------------------------|--------------------|---------------------------------------------------------------------------------------------| +| `text: Text` | | Text to be displayed into the chip. | +| `leadingIcon: Image?` | `nil` | Optional leading icon to be displayed at the start of the chip, preceding the content text. | +| `action: () -> Void` | | The action when chip is clicked. | + +**Remarks:** +- To disable the chip call the `.disabled` on View.

+ + +### Input chip + +Input chips represent a complex piece of information in compact form, such as an entity (person, place, or thing) or text. They enable user input and verify that input by converting text into chips. + +![Light input chip](images/chips_input_light.png) +![Dark input chip](images/chips_input_dark.png) + +#### SwiftUI example + +``` swift +// Input chip with leading filled with icon or image for resources + +ODSInputChip( + text: Text(vhip text), + leadingAvatar: .image(Image("Avatar")), + action: { doSomething() }, + removeAction: { doSomething() } +) +``` + +#### ODSInputChip API + +| Parameter | Default value | Description | +|-----------------------------------|--------------------|-----------------------------------------------------------------------------------------------------------------| +| `text: Text` | | Text to be displayed into the chip. | +| `leadingAvatar: ODSImage.Source?` | `nil` | Optional leading avatar to be displayed in a circle shape at the start of the chip, preceding the content text. | +| `action: () -> Void` | | The action when chip is clicked. | +| `removeAction: () -> Void` | | The action when cross is clicked. | + +
+ + +### Choice chip + +Choice chips allow selection of a single chip from a set of options. Choice chips clearly delineate and display options in a compact area. + +**Note: To display a set of choice chips please see ODSChoiceChipsPicker** + +![Light input chip](images/chips_choice_light.png) +![Dark input chip](images/chips_choice_dark.png) + +#### SwiftUI example + +``` swift +enum Ingredient: String, CaseIterable { + case chocolate, vanilla, strawberry +} + +ODSChoiceChipView( + chip: ODSChoiceChip(text: Text("Chocolate"), value: .chocolate), + selected: false: + action: { doSomething() } +) +ODSChoiceChipView( + chip: ODSChoiceChip(text: Text("Vanilla"), value: .vanilla), + selected: true: + action: { doSomething() } +) +``` + +#### ODSChoiceChipView API + +| Parameter | Default value | Description | +|-----------------------------------|--------------------|-------------------------------------------------| +| `ODSChoiceChip` | | The chip value and associated text description. | +| `selected: Bool` | | Controls the selected state of the chip. | +| `action: () -> Void` | | The action when chip is clicked. | + + +**ODSChoiceChipPicker** + +In order to display a set of choice chips you can follow this example: + +``` swift +@State var selection: Ingredient + +var body: some View { + ScrollView(.horizontal) { + ForEach(Ingredient.allCases, id: \.rawValue) { ingredient in + ODSChoiceChipView( + model: ODSChoiceChip(text: Text(ingredient.rawValue), value: ingredient), + selected: selection == ingredient, + action: { selection = ingredient } + ) + } + } +} +``` + +To simplify the chips placement and alignment, you can also use the __ODSChoiceChipsPicker__ like this: + +``` swift +@State var selection: Ingredient + +ODSChoiceChipPicker( + title: Text("Select your ingredient"), + chips: Ingredient.allCases.map { ODSChoiceChip(text: Text($0.rawValue), value: $0) + selection: $selection, + placement: .carousel +) +``` + +
+ +### Filter chip + +Filter chips use tags or descriptive words to filter content. Filter chips allow selection of a set of chips from a set of options. Its usage is usefull to apply a filtering on a list of elmeents. + +**Note: To display a set of filter chips please see ODSFilterChipsPicker** + +![Light filter chips](images/chips_filter_light.png) ![Dark filter chips](images/chips_filter_dark.png) + +![Light filter chips with avatar](images/chips_filter_avatar_light.png) ![Dark filter chips with avatar](images/chips_filter_avatar_dark.png) + + +#### SwiftUI example + +``` swift +enum Ingredient: String, CaseIterable { + case chocolate, vanilla, strawberry + + var image: Image { + Image("self.rawValue") + } +} + +ODSFilterChipView( + chip: ODSFilterChip(text: Text("Chocolate"), leading: .image(Image("avatar")), value: .chocolate), + selected: false: + action: { doSomething() } +) +``` + +#### ODSFilterChipView API + +| Parameter | Default value | Description | +|-----------------------------------|--------------------|--------------------------------------------------------------------| +| `chip: ODSFilterChip` | | The chip value and associated text description and leading avatar. | +| `selected: Bool` | | Controls the selected state of the chip. | +| `action: () -> Void` | | The action when chip is clicked. | + + +#### ODSFilterChip API + +| Parameter | Default value | Description | +|--------------------------------|--------------------|---------------------------------------------------------------| +| `text: Text` | | Text to be displayed into the chip | +| `leading: ODSImage.Source?` | `nil` | Avatar to be displayed in a circle shape, preceding the text. | +| `value: Value` | | The value associated to the chip. | +| `disabled: Bool` | `false` | Controls the disbaled state of the chip. | + + +**ODSFilterChipPicker** + +As the choice chip, to simplify the chips placement and alignment, you can also use the __ODSFilterChipsPicker__ like this: + +``` swift +@State var selection: [Ingredient] + +ODSFilterChipPicker( + title: Text("Select your ingredients"), + chips: Ingredient.allCases.map { ODSFilterChip(text: Text($0.rawValue), leading(.image($0.image)), value: $0) + selection: $selection, + placement: .carousel +) +``` + diff --git a/docs/1.2.0/components/chips_docs.md b/docs/1.2.0/components/chips_docs.md new file mode 100644 index 00000000..51287dad --- /dev/null +++ b/docs/1.2.0/components/chips_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Chips +content_page: chips.md +--- diff --git a/docs/1.2.0/components/images/activity_indicator.png b/docs/1.2.0/components/images/activity_indicator.png new file mode 100644 index 00000000..5567e614 Binary files /dev/null and b/docs/1.2.0/components/images/activity_indicator.png differ diff --git a/docs/1.2.0/components/images/banner-dark.png b/docs/1.2.0/components/images/banner-dark.png new file mode 100644 index 00000000..769144eb Binary files /dev/null and b/docs/1.2.0/components/images/banner-dark.png differ diff --git a/docs/1.2.0/components/images/banner-light.png b/docs/1.2.0/components/images/banner-light.png new file mode 100644 index 00000000..ec84c11f Binary files /dev/null and b/docs/1.2.0/components/images/banner-light.png differ diff --git a/docs/1.2.0/components/images/bars_navigation_items_dark.png b/docs/1.2.0/components/images/bars_navigation_items_dark.png new file mode 100644 index 00000000..e7124a46 Binary files /dev/null and b/docs/1.2.0/components/images/bars_navigation_items_dark.png differ diff --git a/docs/1.2.0/components/images/bars_navigation_items_light.png b/docs/1.2.0/components/images/bars_navigation_items_light.png new file mode 100644 index 00000000..8cc70e0d Binary files /dev/null and b/docs/1.2.0/components/images/bars_navigation_items_light.png differ diff --git a/docs/1.2.0/components/images/bars_navigation_large_dark.png b/docs/1.2.0/components/images/bars_navigation_large_dark.png new file mode 100644 index 00000000..97e823e5 Binary files /dev/null and b/docs/1.2.0/components/images/bars_navigation_large_dark.png differ diff --git a/docs/1.2.0/components/images/bars_navigation_large_light.png b/docs/1.2.0/components/images/bars_navigation_large_light.png new file mode 100644 index 00000000..320fcae0 Binary files /dev/null and b/docs/1.2.0/components/images/bars_navigation_large_light.png differ diff --git a/docs/1.2.0/components/images/bars_navigation_search_dark.png b/docs/1.2.0/components/images/bars_navigation_search_dark.png new file mode 100644 index 00000000..b5c851e4 Binary files /dev/null and b/docs/1.2.0/components/images/bars_navigation_search_dark.png differ diff --git a/docs/1.2.0/components/images/bars_navigation_search_light.png b/docs/1.2.0/components/images/bars_navigation_search_light.png new file mode 100644 index 00000000..915a2029 Binary files /dev/null and b/docs/1.2.0/components/images/bars_navigation_search_light.png differ diff --git a/docs/1.2.0/components/images/bars_navigation_standard_dark.png b/docs/1.2.0/components/images/bars_navigation_standard_dark.png new file mode 100644 index 00000000..d20b5a7a Binary files /dev/null and b/docs/1.2.0/components/images/bars_navigation_standard_dark.png differ diff --git a/docs/1.2.0/components/images/bars_navigation_standard_light.png b/docs/1.2.0/components/images/bars_navigation_standard_light.png new file mode 100644 index 00000000..9b9f93db Binary files /dev/null and b/docs/1.2.0/components/images/bars_navigation_standard_light.png differ diff --git a/docs/1.2.0/components/images/bars_tab_dark.png b/docs/1.2.0/components/images/bars_tab_dark.png new file mode 100644 index 00000000..25a09787 Binary files /dev/null and b/docs/1.2.0/components/images/bars_tab_dark.png differ diff --git a/docs/1.2.0/components/images/bars_tab_light.png b/docs/1.2.0/components/images/bars_tab_light.png new file mode 100644 index 00000000..da7e46bf Binary files /dev/null and b/docs/1.2.0/components/images/bars_tab_light.png differ diff --git a/docs/1.2.0/components/images/bars_tool_icons_dark.png b/docs/1.2.0/components/images/bars_tool_icons_dark.png new file mode 100644 index 00000000..3be894a5 Binary files /dev/null and b/docs/1.2.0/components/images/bars_tool_icons_dark.png differ diff --git a/docs/1.2.0/components/images/bars_tool_icons_light.png b/docs/1.2.0/components/images/bars_tool_icons_light.png new file mode 100644 index 00000000..758ecd9f Binary files /dev/null and b/docs/1.2.0/components/images/bars_tool_icons_light.png differ diff --git a/docs/1.2.0/components/images/bars_tool_labels_dark.png b/docs/1.2.0/components/images/bars_tool_labels_dark.png new file mode 100644 index 00000000..dda57849 Binary files /dev/null and b/docs/1.2.0/components/images/bars_tool_labels_dark.png differ diff --git a/docs/1.2.0/components/images/bars_tool_labels_light.png b/docs/1.2.0/components/images/bars_tool_labels_light.png new file mode 100644 index 00000000..d46cfe54 Binary files /dev/null and b/docs/1.2.0/components/images/bars_tool_labels_light.png differ diff --git a/docs/1.2.0/components/images/buttons_emphasis_high.png b/docs/1.2.0/components/images/buttons_emphasis_high.png new file mode 100644 index 00000000..c0a98b7f Binary files /dev/null and b/docs/1.2.0/components/images/buttons_emphasis_high.png differ diff --git a/docs/1.2.0/components/images/buttons_emphasis_low.png b/docs/1.2.0/components/images/buttons_emphasis_low.png new file mode 100644 index 00000000..e306cb0e Binary files /dev/null and b/docs/1.2.0/components/images/buttons_emphasis_low.png differ diff --git a/docs/1.2.0/components/images/buttons_emphasis_lowest.png b/docs/1.2.0/components/images/buttons_emphasis_lowest.png new file mode 100644 index 00000000..317dae96 Binary files /dev/null and b/docs/1.2.0/components/images/buttons_emphasis_lowest.png differ diff --git a/docs/1.2.0/components/images/buttons_emphasis_lowest_disabled.png b/docs/1.2.0/components/images/buttons_emphasis_lowest_disabled.png new file mode 100644 index 00000000..c9931849 Binary files /dev/null and b/docs/1.2.0/components/images/buttons_emphasis_lowest_disabled.png differ diff --git a/docs/1.2.0/components/images/buttons_emphasis_medium.png b/docs/1.2.0/components/images/buttons_emphasis_medium.png new file mode 100644 index 00000000..ef148b6e Binary files /dev/null and b/docs/1.2.0/components/images/buttons_emphasis_medium.png differ diff --git a/docs/1.2.0/components/images/buttons_functional_negative.png b/docs/1.2.0/components/images/buttons_functional_negative.png new file mode 100644 index 00000000..5d88a0fc Binary files /dev/null and b/docs/1.2.0/components/images/buttons_functional_negative.png differ diff --git a/docs/1.2.0/components/images/buttons_functional_positive.png b/docs/1.2.0/components/images/buttons_functional_positive.png new file mode 100644 index 00000000..330ef3d6 Binary files /dev/null and b/docs/1.2.0/components/images/buttons_functional_positive.png differ diff --git a/docs/1.2.0/components/images/buttons_functionnal_disabled.png b/docs/1.2.0/components/images/buttons_functionnal_disabled.png new file mode 100644 index 00000000..803d1200 Binary files /dev/null and b/docs/1.2.0/components/images/buttons_functionnal_disabled.png differ diff --git a/docs/1.2.0/components/images/buttons_icon.png b/docs/1.2.0/components/images/buttons_icon.png new file mode 100644 index 00000000..552dc955 Binary files /dev/null and b/docs/1.2.0/components/images/buttons_icon.png differ diff --git a/docs/1.2.0/components/images/buttons_layout_large_with_icon.png b/docs/1.2.0/components/images/buttons_layout_large_with_icon.png new file mode 100644 index 00000000..29d586ac Binary files /dev/null and b/docs/1.2.0/components/images/buttons_layout_large_with_icon.png differ diff --git a/docs/1.2.0/components/images/buttons_layout_large_without_icon.png b/docs/1.2.0/components/images/buttons_layout_large_without_icon.png new file mode 100644 index 00000000..e6f378d7 Binary files /dev/null and b/docs/1.2.0/components/images/buttons_layout_large_without_icon.png differ diff --git a/docs/1.2.0/components/images/buttons_layout_small_with_icon.png b/docs/1.2.0/components/images/buttons_layout_small_with_icon.png new file mode 100644 index 00000000..a0b7ae5c Binary files /dev/null and b/docs/1.2.0/components/images/buttons_layout_small_with_icon.png differ diff --git a/docs/1.2.0/components/images/buttons_layout_small_without_icon.png b/docs/1.2.0/components/images/buttons_layout_small_without_icon.png new file mode 100644 index 00000000..93ae02fd Binary files /dev/null and b/docs/1.2.0/components/images/buttons_layout_small_without_icon.png differ diff --git a/docs/1.2.0/components/images/card_horizontal_dark.png b/docs/1.2.0/components/images/card_horizontal_dark.png new file mode 100644 index 00000000..7fe518b8 Binary files /dev/null and b/docs/1.2.0/components/images/card_horizontal_dark.png differ diff --git a/docs/1.2.0/components/images/card_horizontal_light.png b/docs/1.2.0/components/images/card_horizontal_light.png new file mode 100644 index 00000000..fdd1bdb3 Binary files /dev/null and b/docs/1.2.0/components/images/card_horizontal_light.png differ diff --git a/docs/1.2.0/components/images/card_small_dark.png b/docs/1.2.0/components/images/card_small_dark.png new file mode 100644 index 00000000..211a72a9 Binary files /dev/null and b/docs/1.2.0/components/images/card_small_dark.png differ diff --git a/docs/1.2.0/components/images/card_small_light.png b/docs/1.2.0/components/images/card_small_light.png new file mode 100644 index 00000000..e2b9949b Binary files /dev/null and b/docs/1.2.0/components/images/card_small_light.png differ diff --git a/docs/1.2.0/components/images/card_vertical_header_first_dark.png b/docs/1.2.0/components/images/card_vertical_header_first_dark.png new file mode 100644 index 00000000..542c62eb Binary files /dev/null and b/docs/1.2.0/components/images/card_vertical_header_first_dark.png differ diff --git a/docs/1.2.0/components/images/card_vertical_header_first_light.png b/docs/1.2.0/components/images/card_vertical_header_first_light.png new file mode 100644 index 00000000..66460143 Binary files /dev/null and b/docs/1.2.0/components/images/card_vertical_header_first_light.png differ diff --git a/docs/1.2.0/components/images/card_vertical_image_first_dark.png b/docs/1.2.0/components/images/card_vertical_image_first_dark.png new file mode 100644 index 00000000..f9a5299d Binary files /dev/null and b/docs/1.2.0/components/images/card_vertical_image_first_dark.png differ diff --git a/docs/1.2.0/components/images/card_vertical_image_first_light.png b/docs/1.2.0/components/images/card_vertical_image_first_light.png new file mode 100644 index 00000000..58ee1f75 Binary files /dev/null and b/docs/1.2.0/components/images/card_vertical_image_first_light.png differ diff --git a/docs/1.2.0/components/images/chips_action_dark.png b/docs/1.2.0/components/images/chips_action_dark.png new file mode 100644 index 00000000..e0a50458 Binary files /dev/null and b/docs/1.2.0/components/images/chips_action_dark.png differ diff --git a/docs/1.2.0/components/images/chips_action_light.png b/docs/1.2.0/components/images/chips_action_light.png new file mode 100644 index 00000000..e2d8a9d6 Binary files /dev/null and b/docs/1.2.0/components/images/chips_action_light.png differ diff --git a/docs/1.2.0/components/images/chips_choice_dark.png b/docs/1.2.0/components/images/chips_choice_dark.png new file mode 100644 index 00000000..d848d8ad Binary files /dev/null and b/docs/1.2.0/components/images/chips_choice_dark.png differ diff --git a/docs/1.2.0/components/images/chips_choice_light.png b/docs/1.2.0/components/images/chips_choice_light.png new file mode 100644 index 00000000..37781814 Binary files /dev/null and b/docs/1.2.0/components/images/chips_choice_light.png differ diff --git a/docs/1.2.0/components/images/chips_filter_avatar_dark.png b/docs/1.2.0/components/images/chips_filter_avatar_dark.png new file mode 100644 index 00000000..e4269dcc Binary files /dev/null and b/docs/1.2.0/components/images/chips_filter_avatar_dark.png differ diff --git a/docs/1.2.0/components/images/chips_filter_avatar_light.png b/docs/1.2.0/components/images/chips_filter_avatar_light.png new file mode 100644 index 00000000..56857458 Binary files /dev/null and b/docs/1.2.0/components/images/chips_filter_avatar_light.png differ diff --git a/docs/1.2.0/components/images/chips_filter_dark.png b/docs/1.2.0/components/images/chips_filter_dark.png new file mode 100644 index 00000000..45fe2cf0 Binary files /dev/null and b/docs/1.2.0/components/images/chips_filter_dark.png differ diff --git a/docs/1.2.0/components/images/chips_filter_light.png b/docs/1.2.0/components/images/chips_filter_light.png new file mode 100644 index 00000000..d9c57620 Binary files /dev/null and b/docs/1.2.0/components/images/chips_filter_light.png differ diff --git a/docs/1.2.0/components/images/chips_input_dark.png b/docs/1.2.0/components/images/chips_input_dark.png new file mode 100644 index 00000000..315167eb Binary files /dev/null and b/docs/1.2.0/components/images/chips_input_dark.png differ diff --git a/docs/1.2.0/components/images/chips_input_light.png b/docs/1.2.0/components/images/chips_input_light.png new file mode 100644 index 00000000..6e928d1d Binary files /dev/null and b/docs/1.2.0/components/images/chips_input_light.png differ diff --git a/docs/1.2.0/components/images/list_items_selection_circle_dark.png b/docs/1.2.0/components/images/list_items_selection_circle_dark.png new file mode 100644 index 00000000..cef8cafe Binary files /dev/null and b/docs/1.2.0/components/images/list_items_selection_circle_dark.png differ diff --git a/docs/1.2.0/components/images/list_items_selection_circle_light.png b/docs/1.2.0/components/images/list_items_selection_circle_light.png new file mode 100644 index 00000000..871e26a4 Binary files /dev/null and b/docs/1.2.0/components/images/list_items_selection_circle_light.png differ diff --git a/docs/1.2.0/components/images/list_items_standard_square_dark.png b/docs/1.2.0/components/images/list_items_standard_square_dark.png new file mode 100644 index 00000000..7e6d2994 Binary files /dev/null and b/docs/1.2.0/components/images/list_items_standard_square_dark.png differ diff --git a/docs/1.2.0/components/images/list_items_standard_square_light.png b/docs/1.2.0/components/images/list_items_standard_square_light.png new file mode 100644 index 00000000..03dc9d15 Binary files /dev/null and b/docs/1.2.0/components/images/list_items_standard_square_light.png differ diff --git a/docs/1.2.0/components/images/progress_bar.png b/docs/1.2.0/components/images/progress_bar.png new file mode 100644 index 00000000..d571477e Binary files /dev/null and b/docs/1.2.0/components/images/progress_bar.png differ diff --git a/docs/1.2.0/components/images/sliders.png b/docs/1.2.0/components/images/sliders.png new file mode 100644 index 00000000..1a5c9c81 Binary files /dev/null and b/docs/1.2.0/components/images/sliders.png differ diff --git a/docs/1.2.0/components/listItem.md b/docs/1.2.0/components/listItem.md new file mode 100644 index 00000000..287d2539 --- /dev/null +++ b/docs/1.2.0/components/listItem.md @@ -0,0 +1,147 @@ +--- +layout: detail +title: List item +description: Lists are continuous, vertical indexes of text or images. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Lists](https://system.design.orange.com/0c1af118d/p/09a804-lists/b/669743) +- [Apple guideline - Lists and tables](https://developer.apple.com/design/human-interface-guidelines/components/layout-and-organization/lists-and-tables) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +Here we just propose a configuration for two types of list items: +- Standard with trailing actions +- Selection with trailing icons (selection indicators) + +All items are composed of: +- Title +- Subtitle (optional) +- Leading icon (optional) + +The leading icon is : +- icon or image from resources +- Image from url. During image loading a placeholder Image is needed. Three kinds of shape are proposed (circular, square or wide). + + +### Standard list item + +For standard items, trailing icons can be added. Two types of icons are proposed: +- with text +- with text and info button to make an action + +![List item standard square light](images/list_items_standard_square_light.png) +![List item standard square dark](images/list_items_standard_square_dark.png) + +The standard item can be used in a `NavigationLink` (for example, display more details) + +#### SwiftUI example + +```swift + +// Build the List view using ODSListItem withount navigation +List { + // Items without navigation + ODSListItem(title: Text("Title Only")).odsListItemStyle() + ODSListItem(title: Text("Title with subtitle"), subtitle: Text("subtitle")).odsListItemStyle() + ODSListItem(title: Text("Title with leading icon"), leading: .icon(Image(systemName: "heart"))).odsListItemStyle() + ODSListItem(title: Text("Title with trailing text"), trailingText: Text("Details")).odsListItemStyle() + ODSListItem(title: Text("Title with trailing text and info button"), trailingText: Text("Details")) { + // Add info button action here + }.odsListItemStyle() + + // Item with navigation + NavigationLink { + Text("The destination view") + } label: { + ODSListItem(title: Text("Title without trailing element")) + }.odsListItemStyle() + + NavigationLink { + Text("The destination view") + } label: { + ODSListItem(title: Text("Title with trailing text"), trailingText: Text("Details")) + }.odsListItemStyle() + + NavigationLink { + Text("The destination view") + } label: { + ODSListItem(title: Text("Title with trailing text and info button"), trailingText: Text("Details")) { + // Add info button action here + } + }.odsListItemStyle() +} +``` + +### Selection list item + +![List item slection circle light](images/list_items_selection_circle_light.png) +![List item slection circle dark](images/list_items_selection_circle_dark.png) + +The selection list items can be used to enumerate data as list in order to select elements. + +#### SwiftUI example + +```swift +struct MyMultipleOptionsSelection: View { + + @State private var optionA: Bool = false + @State private var optionB: Bool = false + + var body: some View { + List { + ODSListItem( + title: Text("Option A"), + subtitle: Text("Option A description"), + trailingCheckmarkIsSelected: optionA + ) + .odsListItemStyle() + .onTapGesture { + optionA.toggle() + } + + ODSListItem( + title: Text("Option B"), + subtitle: Text("Option B description"), + trailingCheckmarkIsSelected: optionB + ) + .odsListItemStyle() + .onTapGesture { + optionB.toggle() + } + } + } +} +``` + + +#### ODSListItem API + +| Parameter | Default value | Description | +|-------------------------------------------------|--------------------|---------------------------------------------------| +| `title: Text` | | The primary text of the list item. | +| `subtitle: Text?` | `nil` | The secondary (optional) text of the list item. | +| `subtitleNumberOfLines: SubtitleNumberOfLines?` | `.one` | To limit the subtitle text to 1 or 2 lines. | +| `leading: Self.Leading?` | `nil` | The leading icon (optional) of the list item. | +| `trailing: Self.Trailing?` | `nil` | The trailing element (optional) of the list item. | + +**Note 1:** Don’t forget, if item is used in a `NavigationLink`, a chevron is automatically added by the system. For design purpose it is NOT recommended to add item with `trailingCheckmarkIsSelected` and `trailingToggleIsOn` parameters in a `NavigationLink`. + +**Note 2:**Don’t forget to apply the style on: +- __ODSListItem__ if it is not used with NavigationLink. +- NavigationLink if __ODSListItem__ is its label. + diff --git a/docs/1.2.0/components/listItem_docs.md b/docs/1.2.0/components/listItem_docs.md new file mode 100644 index 00000000..9caa65f1 --- /dev/null +++ b/docs/1.2.0/components/listItem_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: List item +content_page: listItem.md +--- diff --git a/docs/1.2.0/components/progressIndicator.md b/docs/1.2.0/components/progressIndicator.md new file mode 100644 index 00000000..4271e5d7 --- /dev/null +++ b/docs/1.2.0/components/progressIndicator.md @@ -0,0 +1,72 @@ +--- +layout: detail +title: Progress indicator +description: Progress indicators show users that elements or pages are loading +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Progress indicators](https://system.design.orange.com/0c1af118d/p/5969ab-progress-indicator) +- [Apple guideline - Progress indicators](https://developer.apple.com/design/human-interface-guidelines/components/status/progress-indicators) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +Progress indicators show users that elements or pages are loading. + +### Progress bar + +Progres bar is used to display **determinate** operations. It display the indicator increasing in width from 0 to 100% of the track, in sync with the process’s progress. + +To display the indicator as progress bar with a specific color use the `tint`. + +![Progress bar](images/progress_bar.png) + +We recommend to use the theme for that using the accent color as shown in following exemple. + +```swift +ProgressView("Downloading...", value: value, total: 100) + .tint(theme.componentColors.accent) +``` + +It is possible to display the current value to provide more context. + +```swift +ProgressView(value: value, total: 100) { + Text("Downloading...") +} currentValueLabel: { + let percent = String(format: "%0.2f", value) + Text("\(percent) %").frame(maxWidth: .infinity, alignment: .trailing) +} +.tint(theme.componentColors.accent) +``` + +### Activity indicators + +Activity indicator is used to display **Indeterminate** operations. It spins while a task is performed. + +![Activity indicator](images/activity_indicator.png) + +```swift +ProgressView() +``` + +An additional label can be added to provide more context. + +```swift +ProgressView { + Text("Loading...") +} +``` diff --git a/docs/1.2.0/components/progressIndicator_docs.md b/docs/1.2.0/components/progressIndicator_docs.md new file mode 100644 index 00000000..17b0c0b6 --- /dev/null +++ b/docs/1.2.0/components/progressIndicator_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Progress indicator +content_page: progressIndicator.md +--- diff --git a/docs/1.2.0/components/sheetsBottom.md b/docs/1.2.0/components/sheetsBottom.md new file mode 100644 index 00000000..552072e8 --- /dev/null +++ b/docs/1.2.0/components/sheetsBottom.md @@ -0,0 +1,85 @@ +--- +layout: detail +title: Bottom sheets +description: Bottom Sheets are surfaces anchored to the bottom of the screen that present users supplement content. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Bottom sheets](https://system.design.orange.com/0c1af118d/p/3347ca-sheets-bottom/b/83b619) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +Bottom sheets are surfaces anchored to the bottom of the screen that present users supplemental content. +It is useful for requesting a specific information or enabling a simple task related to the current context +of the current view or more globaly the application context. + +### Standard + +The standard bottom sheet must be used only with a "simple, basic" content. If a more complex content (scrollable) must be added prefer the Expanding variant. + +It defines two states: +- **closed**: The content is hidden +- **opened**: The content is visible (above the main view) + +A taps on the header, opens or closes the bottom sheet. + +```swift +struct BottomSheetPresentation: View { + @State private var isOpen = false + + var body: some View { + VStack { + // Main content goes here. + Text("Bottom sheet is \(isOpen ? "Opened": "Closed")") + } + .odsBottomSheetStandard(isOpen: $isOpen, title: "Customize") { + // Bottom sheet content goes here + } + } +} +``` + +You can also define accessibility hints and labels for this standard bottom sheet so as to make VoiceOver vocalize the state of this sheet (opended or closed) or to vocalize some hints to make it be opened or not. + +### Expanding + +The type of bottom must be used if the content is more complex and perhaps need to be scrollable. + +It defines three size: +- **small**: (closed) The content is hidden, only the header is visible +- **medium**: (parcially opened) The content is parcially visible (half screen above the main view) but not scrollable +- **large**: (opened) The content is visible and scrollable + +User can resize by tapping on dimming area (close), drag the content, or tap on the header to cycle through the available sizes. + +```swift + struct BottomSheetPresentation: View { + @State private var bottomSheetSize: ODSBottomSheetSize = .large + var body: some View { + VStack { + // Main content goes here. + Text("Bottom sheet size \(bottomSheetSize.rawValue)") + } + .odsBottomSheetExpanding(title: "Customize", bottomSheetSize: $bottomSheetSize) { + // Bottom sheet content goes here + } + } + } +``` + +**Remark**: In order to compute the resizing when user scrolls the content, the bottom sheet automatically adds the provided content is a scrollView. + diff --git a/docs/1.2.0/components/sheetsBottom_docs.md b/docs/1.2.0/components/sheetsBottom_docs.md new file mode 100644 index 00000000..03d56ceb --- /dev/null +++ b/docs/1.2.0/components/sheetsBottom_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Sheets - Bottom +content_page: sheetsBottom.md +--- diff --git a/docs/1.2.0/components/slider.md b/docs/1.2.0/components/slider.md new file mode 100644 index 00000000..9bb3f76f --- /dev/null +++ b/docs/1.2.0/components/slider.md @@ -0,0 +1,105 @@ +--- +layout: detail +title: Sliders +description: Sliders allow users to make selections from a range of values. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Sliders](https://system.design.orange.com/0c1af118d/p/7559da-sliders/b/253eea) +- [Apple guideline - Sliders](https://developer.apple.com/design/human-interface-guidelines/components/selection-and-input/sliders) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +As the `ODSSlider` is based on the native `Slider`, Voice Over is able to vocalize +However, if you want to set a description you need to add it using `.accessibilityLabel` on the `ODSSlider`. + +We recommend to not set information on `minimumValueLabel` and `maximumValueLabel` view using `.accessibilityHidden(true)` + +## Variants + +Slider is a system Slider component with accent color set to coreOrange. + +![Sliders](images/sliders.png) + +### Unlabeled slider + +Unlabelled sliders allow users to make easy selections that do not require any details or context. + +```swift +struct UnlabeledSlider: View { + + @State private var value = 50.0 + + var body: some View { + ODSSlider(value: $value, in: 0 ... 100) + } +} +``` + +### Labeled slider (with images) + +We recommand to not set information on `minimumValueLabel` and `maximumValueLabel` view using `.accessibilityHidden(true)`. You can do it like this: + +```swift +struct LabeledSlider: View { + + @State private var value = 50.0 + + var body: some View { + ODSSlider(value: $value, in: 0 ... 100) { + Text("Volume") + } minimumValueLabel: { + Image(systemName: "speaker.wave.1.fill").accessibilityHidden(true) + } maximumValueLabel: { + Image(systemName: "speaker.wave.3.fill").accessibilityHidden(true) + } + } +} +``` + +### Labeled slider (with text) + +We recommand to not set information on `minimumValueLabel` and `maximumValueLabel` view using `.accessibilityHidden(true)`. You can do it like this: + +```swift +ODSSlider(value: $value, in: 0 ... 100) { + Text("Volume") +} minimumValueLabel: { + Text("0").accessibilityHidden(true) +} maximumValueLabel: { + Text("100").accessibilityHidden(true) +} +``` + +### Stepped slider (with text and value display) + +We recommand to not set information on `minimumValueLabel` and `maximumValueLabel` view using `.accessibilityHidden(true)`. You can do it like this: + +```swift +struct SteppedSlider: View { + + @State private var value = 50.0 + + var body: some View { + ODSSlider(value: $value, in: 0 ... 100.0, step: 0.5) { + Text("Volume") + } minimumValueLabel: { + Image(systemName: "speaker.wave.1.fill").accessibilityHidden(true) + } maximumValueLabel: { + Image(systemName: "speaker.wave.3.fill").accessibilityHidden(true) + } + } +} +``` diff --git a/docs/1.2.0/components/slider_docs.md b/docs/1.2.0/components/slider_docs.md new file mode 100644 index 00000000..29743fb1 --- /dev/null +++ b/docs/1.2.0/components/slider_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Slider +content_page: slider.md +--- diff --git a/docs/1.2.0/components/textInput.md b/docs/1.2.0/components/textInput.md new file mode 100644 index 00000000..a57f46df --- /dev/null +++ b/docs/1.2.0/components/textInput.md @@ -0,0 +1,64 @@ +--- +layout: detail +title: Text fields and text editor +description: Text fields and text editor let users enter and edit text. +--- + +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Text fields](https://system.design.orange.com/0c1af118d/p/47d389-text-fields/b/461794) +- [Apple guideline - Text fields](https://developer.apple.com/design/human-interface-guidelines/components/selection-and-input/text-fields) +- [Apple guideline - Edit Menu](https://developer.apple.com/design/human-interface-guidelines/components/menus-and-actions/edit-menus) +- [Apple doc - Text input](https://developer.apple.com/documentation/swiftui/text-input-and-output) +- [Apple doc - Text Field](https://developer.apple.com/documentation/swiftui/textfield) +- [Apple doc - Secure Text Field](https://developer.apple.com/documentation/swiftui/securefield) +- [Apple doc - Text Editor](https://developer.apple.com/documentation/swiftui/i/texteditor) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## Variants + +For all variants, we provide the `odsTextFieldStyle` view modifier to apply font, collors (background, tint) provided by the theme. + +### Text field + +A control that displays an editable text interface. + +```swift +TextField("A text field", text: $textToEdit) + .odsTextFieldStyle() +``` + + ### Secure text field + +Use a `SecureField` when you want behavior similar to a ``TextField``, but you don't want the user's text to be visible. Typically, you use this for entering passwords and other sensitive information. + +```swift +SecureField("Secure text", text: $textToEdit) + .odsTextFieldStyle() +``` + +### Text editor + +A text editor view allows you to display and edit multiline, scrollable text in your app's user interface. + +```swift +TextEditor(text: $textToEdit) + .odsTextFieldStyle() +``` + +## Text selection + +Text selection is available when text field or text editor is entering in edition mode. This is not a custom component but just a way to apply right style (customize with colors, font provided by theme). + diff --git a/docs/1.2.0/components/textInput_docs.md b/docs/1.2.0/components/textInput_docs.md new file mode 100644 index 00000000..fabdf10a --- /dev/null +++ b/docs/1.2.0/components/textInput_docs.md @@ -0,0 +1,5 @@ +--- +layout: main +title: Text fields +content_page: textInput.md +--- diff --git a/docs/1.2.0/guidelines/colors.md b/docs/1.2.0/guidelines/colors.md new file mode 100644 index 00000000..601c632d --- /dev/null +++ b/docs/1.2.0/guidelines/colors.md @@ -0,0 +1,56 @@ +--- +layout: detail +title: Colors +--- +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Colour](https://system.design.orange.com/0c1af118d/p/73fa17-colour/b/025652) +- [Apple guideline - The color system](https://developer.apple.com/design/human-interface-guidelines/foundations/color) + +## Theme colors + +Colors are defined in theme and described using `ODSColorDecription`, by setting : +- the asset name, +- the bundle containing the asset +- the color names for light and dark modes (used by demo application) + +Colors will be different depending on whether they are displayed in light or in dark mode. + +## How to use + +### Using the color name + +You can get color in theme using its name like this: + +``` swift + // Don't forget get theme from environment + @Environment(\.theme) var theme + + Image(systemName: "checkmark").foregroundColor(theme.color("coreOrange")) + MyView().background(theme.color("functionalInfo")) +``` + +### Using components token + +You can get color in theme using components token like this: + +``` swift +// Don't forget get theme from environment +@Environment(\.theme) var theme + +Button { +} label: { + Text("Cancel") + .padding(ODSSpacing.m) +} +.background(theme.componentColors.functionalNegative) +``` diff --git a/docs/1.2.0/guidelines/colors_docs.md b/docs/1.2.0/guidelines/colors_docs.md new file mode 100644 index 00000000..2c2b0ceb --- /dev/null +++ b/docs/1.2.0/guidelines/colors_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: Colors +content_page: colors.md +back-to-top: false +--- diff --git a/docs/1.2.0/guidelines/spacings.md b/docs/1.2.0/guidelines/spacings.md new file mode 100644 index 00000000..485f004a --- /dev/null +++ b/docs/1.2.0/guidelines/spacings.md @@ -0,0 +1,56 @@ +--- +layout: detail +title: Spacings +--- +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Spacings](https://system.design.orange.com/0c1af118d/p/375be7-spacing) +- [Apple guideline - Layout](https://developer.apple.com/design/human-interface-guidelines/foundations/layout) + +## Usage + +The spacing scale increases in small increments needed to describe both internal and external spacing relationships. Spacing tokens can be applied as padding and margins. + +### Apply spacing for magin + +Apply the spacing to get magin arround element like this: + +``` swift +// Add a padding of 16px arround the text in the button + +Button { + // Add your action here +} label: { + Text("ButtonText") + .padding(.all, ODSSpacing.m) +} + + +// Add a magin of 16px (leading and trailing) +VStack { + Text("Title") + Text("A very long text for description in the main view") +} +.padding(.horizontal: ODSSpacing.m) // Add a margin to the + +``` + +### Apply spacing for padding + +Apply the spacing to separate elements like this: + +``` swift +HStack(spacing: ODSSpacing.m) { + Image(systemname: "heart") + Text("Some text") +} +``` diff --git a/docs/1.2.0/guidelines/spacings_docs.md b/docs/1.2.0/guidelines/spacings_docs.md new file mode 100644 index 00000000..c2aac711 --- /dev/null +++ b/docs/1.2.0/guidelines/spacings_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: Spacings +content_page: spacings.md +back-to-top: false +--- diff --git a/docs/1.2.0/guidelines/typography.md b/docs/1.2.0/guidelines/typography.md new file mode 100644 index 00000000..1e52d8d9 --- /dev/null +++ b/docs/1.2.0/guidelines/typography.md @@ -0,0 +1,48 @@ +--- +layout: detail +title: Typography +--- +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Typography](https://system.design.orange.com/0c1af118d/p/54fe27-typography) +- [Apple guideline - Typography](https://developer.apple.com/design/human-interface-guidelines/foundations/typography/) + +## Implementation + +ODS library defines its own font style. The font associated to the style is defined in the theme set in the environment. + +### Apply font style on text + +Apply the font style on text like this: + +``` swift + Text("Sample").odsFont(.titleS) + TextField("A text field", text: $textToEdit).odsFont(.titleS) +``` + +### Apply font style on view + +In the example below, the first text field has a font style set directly, while the font applied to the following container applies to all of the text views inside that container. + +``` swift +VStack { + Text("Font applied to a text view.") + .odsFont(.headlineL) + + VStack { + Text("These two text views have the same font") + Text("applied to their parent view.") + } + .odsFont(.titleS) +} +``` + diff --git a/docs/1.2.0/guidelines/typography_docs.md b/docs/1.2.0/guidelines/typography_docs.md new file mode 100644 index 00000000..9b2544d8 --- /dev/null +++ b/docs/1.2.0/guidelines/typography_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: Typography +content_page: typography.md +back-to-top: false +--- diff --git a/docs/1.2.0/home_content.md b/docs/1.2.0/home_content.md new file mode 100644 index 00000000..240af33e --- /dev/null +++ b/docs/1.2.0/home_content.md @@ -0,0 +1,27 @@ +## Introduction + +Orange is providing a full Design System to build Orange Mobile Application. The objective of the [Orange Design System](https://system.design.orange.com/0c1af118d/p/95b685-ios/) (ODS) is to propose a set of guidelines on how to apply the Orange Brand on mobile applications. The Orange design System also provides a series of components and modules that show in details how to use this in the Orange apps. + +The Orange Design System has been implemented in a code library that provides: +- a SwiftUI code library +- a demo app that can be launched to show the guidelines, components and modules +- this demo app also shows how to use the lib or style existing components + +Using these resources will allow you to create Orange branded applications faster and will inherit all the work that was done to make sure that all presented codes are fully tested regarding the brand and the accessibility compliance. + +The Orange Design System framework supports iOS 15 and later. + +## Instructions + +### Swift Package Manager + +The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler. + +Once you have your Swift package set up, adding ODS as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`. + +```swift +dependencies: [ + .package(url: "https://github.com/Orange-OpenSource/ods-ios.git", .upToNextMajor(from: "1.2.0")) +] +``` + diff --git a/docs/1.2.0/index.md b/docs/1.2.0/index.md new file mode 100644 index 00000000..ef70b2b0 --- /dev/null +++ b/docs/1.2.0/index.md @@ -0,0 +1,7 @@ +--- +layout: main +title: Integration +description: Getting started with Orange Design System for iOS +--- + +{% include_relative home_content.md %} diff --git a/docs/1.2.0/index_content.md b/docs/1.2.0/index_content.md new file mode 100644 index 00000000..8c4b2b1e --- /dev/null +++ b/docs/1.2.0/index_content.md @@ -0,0 +1,7 @@ +--- +layout: detail +title: Integration +description: Getting started with Orange Design System for iOS +--- + +{% include_relative home_content.md %} diff --git a/docs/1.2.0/modules/about.md b/docs/1.2.0/modules/about.md new file mode 100644 index 00000000..584e9acd --- /dev/null +++ b/docs/1.2.0/modules/about.md @@ -0,0 +1,310 @@ +--- +layout: detail +title: About +description: An about screen should be displayed in all Orange applications to display the application name, software version as well as all legal data protection, privacy, and terms of service compliance information. +--- +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Modules - About](https://system.design.orange.com/0c1af118d/p/39538b-about/b/55a5d2) + +## Overview + +This module should be added in all applications to display general application information (name, software version, description, privacy policy, terms of service, ...), to offer user actions (Rate the app, send feedbacks, ...), to get informaioon linked to the service (Application recirculation, App news ...). + +It is also possible to add to the module some specifc features linked to the service provided by the application (Suppport, How to, settings, ...) + +In order to have consistant prsentation of those elemnts in all applications, the __About__ module offers a structured and configrable layout. + +![AboutScreen](images/about_screen.png) + + +## About screen layout + +The main about screen is divided to three areas. + +### Illustration area + +The first area (at the top of the screen) allows you to set an image illustrating the about screen linked to the service. If no image is provided the default one is inserted automatically. + +### Application information area + +The second area is dedicated for the application description with various elements: +- The name (mandatory) +- The version (optional) +- A description in sevral lines (optional) + + +It is also possible to activate two buttons to offer to the user to: + +- _share the application_ via email, via sms, via social networks... This button opens the default system share sheet that presents a range of actions to share the application. To activate this button, the developper needs to prvide the url of the application on the store and a short text describing the context of the sharing. +- _send feedback_ to the support of the service. This button is displayed if the developper provides a callback called when button is clicked. This callback can do what it is expected (send email, send sms, open form, open web site, ...). + + +### List items area + +The last area (at the bottom) is a list of items that propose to the user to make actions or navigate to additionnal feetures. +All items have the same layout (icon and text). They are ordered in the list according to their priority set into the configuration. + +#### Mandatory items + +Some items are provided with the module. Three of them are mandatory and allways available in the list: +- Item to present the __Privacy Policy__ (only html content supported today) +- Item to display __Terms of Service__ (View provided by developper) +- Item to show the __Accessibility Statement__ of the application (not available yet) +As those items must be grouped in the list, their priority are fixed and can not be changed. + +#### Optionnal items + +As most of applications propose the same additonnal features (Rate the app, App News, ...), and in order to have consitency in about screens of all applications, additional items are proposed with the module. + +* Rate the app + +This item can be added in the list to redirect the user to the app page on the Apple Store to rate the application. + +* Apps news + +This item enumerates the application versions with small text describing new features available. + +* Legal inofrmation + +This item is used to display legal infomration. Today, there is not recomandation on the presentation. + +#### Custom items + +In addition, it is also possible to add into the list some custom items. Like previous ones, they must respect the layout and can set their own priority to be inserted in the right place in the list. + + +## How to configure the module + +To display the about screen, initialize the module using the __ODSAboutModule__ stucture. During the initialization, a set of configuration must to be provided. + +### Illustration area + +If the about page needs to display a specific illustration, set it like this: + +```swft +ODSAboutModule(headerIllustration: Image("AboutImage"), ...) +``` + +To keep the default illustration, initialize the module without overriding the `headerIllustration` parameter. + + +### Application section area + +To configure the application, fill out the `ODSAboutApplicationInformation` structure and provide it to the module initialization. + +- With name only + +```swift +let nameOnly = ODSAboutApplicationInformation(name: "Orange Design System Demo") +ODSAboutModule(applicationInformation: nameOnly, ...) +``` + +- With description + +```swift +let withDescription = ODSAboutApplicationInformation( + name: "Orange Design System Demo" + description: "In this app you'll find implemented code examples of the guidelines, components and modules, for the themes of the Orange Design System.") +ODSAboutModule(applicationInformation: withDescription, ...) +``` + +- With version + +```swift +let version = ODSApplicationVersion( + marketingVersion: Bundle.main.marketingVersion, // Mandatory + buildNumber: Bundle.main.buildNumber ?? "", // Optional + buildType: Bundle.main.buildType // Optional +) + +let withVersion = ODSAboutApplicationInformation( + name: "Orange Design System Demo", + version: version +) + +ODSAboutModule(applicationInformation: withVersion, ...) +``` + +- To activate the Share the application action + +```swift +ler shareTheApplicationConfiguration = ODSAboutShareTheApplication( + storeUrl: URL(string: "http://oran.ge/dsapp")!, + subject: "The Orange Design System", + description: "Here you will find the Orange Design System Mobile App that provides examples of design implementations" +) + +let withShareTheApp = ODSAboutApplicationInformation( + name: "Orange Design System Demo", + shareConfiguration: shareTheApplicationConfiguration +) +ODSAboutModule(applicationInformation: withShareTheApp, ...) +``` + +- To activate the feedback action + +```swift + +let withFeedback = ODSAboutApplicationInformation( + name: "Orange Design System Demo", + onFeedbackClicked: { + UIApplication.shared.open(URL(string: "https://github.com/Orange-OpenSource/ods-ios/issues/new/choose")!) + } +) + +ODSAboutModule(applicationInformation: withFeedback, ...) +``` + +### Lits items area + +#### Use mandatory items + +For the privacy policy display, only HTML content is supported today. A more structured content will be added soon. + +- Privacy policy + +```swift +// Initializes the privacy policy page with URL of the HTML file stored in resources. +let privacyPolicy = ODSPrivacyPolicy.webview(.url(Bundle.main.url(forResource: "PrivacyNotice", withExtension: "html")!)) +``` + +- The accessibility statement + +```swift +// Defines an item displaying as a title the "conformity status" text, parsing the file named "fileName" and sending user elsewhere for further details +let accessibilityStatement = ODSAboutAccessibilityStatement( + conformityStatus: "Accessibility: partially conform", + fileName: "AccessibilityStatement", + reportDetail: URL(string: "https://la-va11ydette.orange.com/")!) +``` + +- The Terms of service + +```swift +// Today, there is no recomandation how to display the content, so the module provides a view builder +// to build a native screen or a webview + +@ViewBuilder +private func termsOfService() -> some View { + Text("Add terms of service here") +} +``` + +Then initialize the module with those mandatory elements: + +```swift +ODSAboutModule(..., + privacyPolicy: privacyPolicy, + acessibilityStatement: accessibilityStatement, + termsOfService: termOfService +) +``` + +#### Add items to the list + +To insert additionnal items into the list, initialize the __listItemConfigurations__ array adding items following the __ODSAboutListItemConfig__ protocol. +To order the items in the list, initialize the items with the right priority. + +```swift +// Add all items in list +ODSAboutModule(..., + listItemConfigurations: [legalInfoItem, rateTheAppItem, appsNewItem] +) + +// see items description below +``` + +#### Use optional items + +- Rate the app + +To create this item, define the url of the application on the store and the priority (position) of the item in the list: + +```swift +// This item opens the store in the external browser +let rateTheAppItem = ODSAboutRateTheAppItemConfig( + priority: 501, + storeUrl: URL(string: "https://www.apple.com/app-store/")! +) +``` + +- Apps news + +To create this item, define the path to the json file containing the news. This file is embeded in the resources of the application. + +The model of the json file is: + +```json +[ + { + "version": "0.12.0", + "date": "2023-04-14", + "news": "A short description of news" + }, + ... +] +``` + +This is the code to create the item: + +```swift +// - Display the app News +let appNewFilePath = Bundle.main.path(forResource: "AppNews", ofType: "json")! +let appsNewItem = ODSAboutAppNewsItemConfig( + priorty: 502, + path: appNewFilePath +) +``` + +- Legal information + +Still there is not recomandation on the format of the presentation, this item needs a view builder to display the legal information. + +```swift +// Here, the legal information are displayed in a view with a single Text. + +let legalInformationItem = ODSAboutLegalInformationItemConfig(priority: 500) { + Text("This is Legal information content") +} +``` + +- Apps recirculation + +You can also add an item to let people discover other apps of Orange, by using the following item: + +```swift +let appsRecirculation = ODSRecirculationItemConfig(dataSource: yourDataSource) +``` + +The __dataSource__ can contain the URL of the backend to get the list of apps, (today the only supported backend is Orange proprietary backend _Apps Plus_) or a local json file. (for more details see the __Recirculation Module__. + +#### Create a custom item + +To create a custom item and associate a target, follow this example: + +```swift +public struct MyItemToDisplayText: ODSAboutListItemConfig { + public private(set) var title: String + public private(set) var icon: Image + public private(set) var target: ODSAboutListItemTarget + public private(set) var priority: ODSAboutListItemPriority + + public init(priority: ODSAboutListItemPriority = 100) { + self.priority = priority + self.title = "Fake Item" + self.icon = Image(systemName: "heart"), + self.target = .destination(AnyView(Text("This is the destination screen"))) + } +} +``` + diff --git a/docs/1.2.0/modules/about_docs.md b/docs/1.2.0/modules/about_docs.md new file mode 100644 index 00000000..68f62b7e --- /dev/null +++ b/docs/1.2.0/modules/about_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: About +content_page: about.md +--- + diff --git a/docs/1.2.0/modules/emptyState.md b/docs/1.2.0/modules/emptyState.md new file mode 100644 index 00000000..dcade1c7 --- /dev/null +++ b/docs/1.2.0/modules/emptyState.md @@ -0,0 +1,52 @@ +--- +layout: detail +title: Empty states +description: An empty state can occur when no content or data is available to display in the UI. Avoid displaying completely empty screens. +--- + +An empty state display should inform the user of what is happening, why it's happening and what to do about it. + +
**On this page** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Empty states](https://system.design.orange.com/0c1af118d/p/177496-empty-states/b/454547) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/). + +The ODS Empty states module is built to support accessibility criteria and is readable by most screen readers, such as VoiceOver. + +## Integration + +![Empty state light](images/empty_state_light.png) ![Empty state dark](images/empty_state_dark.png) + +### SwiftUI example + +To integrate an ODS Empty state into your app, you can use `ODSEmptyStateView` as shown below: + +```swift +ODSEmptyStateView( + title: Text("No result"), + text: Text("Try a new search"), + image: Image("il_emptyStateNoData"), + button: Button("Search") { + // Do something + } +) +``` + +#### ODSEmptyStateView API + +| Parameter | Default value | Description | +|-----------------------------------|-----------------------------------------------------------------------------------|-----------------------------------------------------------------------------------| +| `title: Text` | | The title of the screen displayed below the image. For example "File is missing". | +| `text: Text?` | `nil` | Text displayed below the title | +| `image: Image` | `Image("il_emptyStateUserCleared", bundle: Bundle.ods)` | Image displayed centered in the view | +| `button: Button?` | `nil` | The button to add below the text | diff --git a/docs/1.2.0/modules/emptyState_docs.md b/docs/1.2.0/modules/emptyState_docs.md new file mode 100644 index 00000000..15db0e38 --- /dev/null +++ b/docs/1.2.0/modules/emptyState_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: Empty states +content_page: emptyState.md +--- + diff --git a/docs/1.2.0/modules/images/about_screen.png b/docs/1.2.0/modules/images/about_screen.png new file mode 100644 index 00000000..ea0628be Binary files /dev/null and b/docs/1.2.0/modules/images/about_screen.png differ diff --git a/docs/1.2.0/modules/images/empty_state_dark.png b/docs/1.2.0/modules/images/empty_state_dark.png new file mode 100644 index 00000000..7fcd8c2a Binary files /dev/null and b/docs/1.2.0/modules/images/empty_state_dark.png differ diff --git a/docs/1.2.0/modules/images/empty_state_light.png b/docs/1.2.0/modules/images/empty_state_light.png new file mode 100644 index 00000000..2208398f Binary files /dev/null and b/docs/1.2.0/modules/images/empty_state_light.png differ diff --git a/docs/1.2.0/modules/images/list_grouped_dark.png b/docs/1.2.0/modules/images/list_grouped_dark.png new file mode 100644 index 00000000..1cd3da2f Binary files /dev/null and b/docs/1.2.0/modules/images/list_grouped_dark.png differ diff --git a/docs/1.2.0/modules/images/list_grouped_light.png b/docs/1.2.0/modules/images/list_grouped_light.png new file mode 100644 index 00000000..0010570d Binary files /dev/null and b/docs/1.2.0/modules/images/list_grouped_light.png differ diff --git a/docs/1.2.0/modules/images/list_inset_dark.png b/docs/1.2.0/modules/images/list_inset_dark.png new file mode 100644 index 00000000..9edc8c7f Binary files /dev/null and b/docs/1.2.0/modules/images/list_inset_dark.png differ diff --git a/docs/1.2.0/modules/images/list_inset_grouped_dark.png b/docs/1.2.0/modules/images/list_inset_grouped_dark.png new file mode 100644 index 00000000..d7b1959a Binary files /dev/null and b/docs/1.2.0/modules/images/list_inset_grouped_dark.png differ diff --git a/docs/1.2.0/modules/images/list_inset_grouped_light.png b/docs/1.2.0/modules/images/list_inset_grouped_light.png new file mode 100644 index 00000000..f5afcd3f Binary files /dev/null and b/docs/1.2.0/modules/images/list_inset_grouped_light.png differ diff --git a/docs/1.2.0/modules/images/list_inset_light.png b/docs/1.2.0/modules/images/list_inset_light.png new file mode 100644 index 00000000..64c9b21e Binary files /dev/null and b/docs/1.2.0/modules/images/list_inset_light.png differ diff --git a/docs/1.2.0/modules/images/list_plain_dark.png b/docs/1.2.0/modules/images/list_plain_dark.png new file mode 100644 index 00000000..9b189afa Binary files /dev/null and b/docs/1.2.0/modules/images/list_plain_dark.png differ diff --git a/docs/1.2.0/modules/images/list_plain_light.png b/docs/1.2.0/modules/images/list_plain_light.png new file mode 100644 index 00000000..de89eb09 Binary files /dev/null and b/docs/1.2.0/modules/images/list_plain_light.png differ diff --git a/docs/1.2.0/modules/images/list_sidebar_dark.png b/docs/1.2.0/modules/images/list_sidebar_dark.png new file mode 100644 index 00000000..12b22797 Binary files /dev/null and b/docs/1.2.0/modules/images/list_sidebar_dark.png differ diff --git a/docs/1.2.0/modules/images/list_sidebar_light.png b/docs/1.2.0/modules/images/list_sidebar_light.png new file mode 100644 index 00000000..5ba12f6b Binary files /dev/null and b/docs/1.2.0/modules/images/list_sidebar_light.png differ diff --git a/docs/1.2.0/modules/list.md b/docs/1.2.0/modules/list.md new file mode 100644 index 00000000..d2fa73b9 --- /dev/null +++ b/docs/1.2.0/modules/list.md @@ -0,0 +1,194 @@ +--- +layout: detail +title: List +description: Lists are continuous, vertical indexes of text or images. +--- +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Lists](https://system.design.orange.com/0c1af118d/p/09a804-lists/b/669743) +- [Apple guideline - Lists and tables](https://developer.apple.com/design/human-interface-guidelines/components/layout-and-organization/lists-and-tables) + +## Accessibility + +Please follow [accessibility criteria for development](https://a11y-guidelines.orange.com/en/mobile/ios/) + +## List styles + +List propose the `.listStyle(_:)` modifier to change the style. For ios SwiftUI propose 6 types of style: +- automatic +- insetGrouped +- grouped +- inset +- plain +- sidebar + +The folowing code is used for all styles. The only difference is the list style specified in the `.listStyle(_:)` modifier. + +```swift +NavigationStack { + List { + // Section for recipes contain selected ingredients + Section { + ODSListItem( + title: Text("Summer Salad"), + subtitle: Text("21 mn"), + leading: .circularImage(source: .image(Image("summerSalad"))) + ) + ODSListItem( + title: Text("Salmon cury"), + subtitle: Text("31 mn"), + leading: .circularImage(source: .image(Image("salmonCury"))) + ) + ODSListItem( + title: Text("Feta Pizza"), + subtitle: Text("21 mn"), + leading: .circularImage(source: .image(Image("fetaPizza"))) + ) + } header: { + Text("Recipes") + } footer: { + Text("A set of recipes made with selected ingredients") + } + + // A set of ingredients + Section("Ingredients") { + ODSListItem(title: Text("tomato"), leading: .circularImage(source: .image(Image("tomato")))) + ODSListItem(title: Text("avocado"), leading: .circularImage(source: .image(Image("avocado")))) + } + } + .navigationTitle("List Style") + .listStyle(.automatic) +} +``` + +### Automatic style + +As mentioned earlier, SwiftUI will use Inset Grouped style when setting automatic (.automatic) or DefaultListStyle on iOS + +### Inset Grouped style + +Example of Inset Grouped .insetGrouped or InsetGroupedListStyle. + +```swift +List { + // ... +} +.listStyle(.insetGrouped) +``` + +![InsetGroupedLight](images/list_inset_grouped_light.png) +![InsetGroupedDark](images/list_inset_grouped_dark.png) + +### Grouped style + +Example of Grouped .grouped or GroupedListStyle. + +```swift +List { + // ... +} +.listStyle(.grouped) +``` + +![GroupedLight](images/list_grouped_light.png) +![GroupedDark](images/list_grouped_dark.png) + +### Inset style + +Example of Inset .inset or InsetListStyle. + +```swift +List { + // ... +} +.listStyle(.inset) +``` + +![InsetLight](images/list_inset_light.png) +![InsetDark](images/list_inset_dark.png) + + +### Plain style + +Example of Plain .plain or PlainListStyle. + +```swift +List { + // ... +} +.listStyle(.plain) +``` +![PlainLight](images/list_plain_light.png) +![PlainDark](images/list_plain_dark.png) + +### Sidebar style + +The sidebar list style displays disclosure indicators in the section headers that allow the user to collapse and expand sections. + +Tap on disclosure indicators in the section headers will collapse and expand that section. + +```swift +List { + // ... +} +.listStyle(.sidebar) +``` + +![SideBarLight](images/list_sidebar_light.png) +![SideBarDark](images/list_sidebar_dark.png) + + +* For iOS 17, a new API is proposed to manage the expandable state. + +```swift +@State var isExpanded = true + +List { + Section(isExpanded: $isExpanded) { + // ... + } header: { + Text("Recipes") + } +} +.listStyle(.sidebar) +``` + +When you create your Section with `isExpanded`, the chevron will appear as long as the list style is `.sidebar`. + +* On previous iOS versions, this interface is not available, so to do the same you can use following code: + +```swift +@State var isExpanded = true + +List { + Section { + if isExpanded { + // The content + } + } header: { + HStack { + Text("Recipes") // The header + + Spacer() + Image(systemName: "chevron.down") + .rotationEffect(isExpanded ? .zero : .degrees(-90)) + .onTapGesture { + withAnimation { + isExpanded.toggle() + } + } + } + } +} +.listStyle(.sidebar) +``` + diff --git a/docs/1.2.0/modules/list_docs.md b/docs/1.2.0/modules/list_docs.md new file mode 100644 index 00000000..52f13ec1 --- /dev/null +++ b/docs/1.2.0/modules/list_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: List +content_page: list.md +--- + diff --git a/docs/1.2.0/modules/moreApps.md b/docs/1.2.0/modules/moreApps.md new file mode 100644 index 00000000..dc7632cc --- /dev/null +++ b/docs/1.2.0/modules/moreApps.md @@ -0,0 +1,109 @@ +--- +layout: detail +title: MoreApps +description: Displays a list of applications can be downloaded and used by user. +--- +--- + +**Page Summary** + +* Table of contents +{:toc} + +--- + +## Specifications references + +- [Design System Manager - Modules - MoreApps](https://system.design.orange.com/0c1af118d/p/37aa79-recirculation) + +## Overview + +The _MoreApps_ module exposes a feature allowing the final users to get the available apps they can use. +This feature is based today only on the Orange proprietary _Apps Plus_ backend which provides a JSON file with list of apps and sections of apps. +This service today is based on a simple URL containing both a lang parameter and an API key. + +**This API key will define the type of data returned by the backend ; maybe you should have your own API key which matches the suitable filters to get only a subgroup of apps.** + +## Implementation + +To be able to call this service and display the list of available apps, you have to use the `ODSMoreAppsView`. +This _View_ has a `dataSource` parameter of type `ODSMoreAppsDataSource` which must contain the type of source of data to display the apps: + +```swift + // Get data from the Apps Plus backend + ODSMoreAppsView(dataSource: .remote(url: "https://url-to-appsplus-backend/get?apikey=SomeKey&lang=fr")) + + // Get data for some local files + ODSMoreAppsView(dataSource: .local(path: somePathToJSONFileInResources)) +``` + +Note also that the data picked from the _Apps Plus_ service is saved in cache directory so as to be used if the device is offline +or if an error occured. + +If you want to flatten the list of apps without displaying categories, set the _flattenApps_ flag in the configuration: + +```swift + ODSMoreAppsView(dataSource: ..., flattenApps: true) +``` + +The apps icons displayed in the list of apps can also be cached. +If you do not want to see these values put in cache, meaning e.g. displaying instead a placeholder if no network, use: + +```swift + ODSMoreAppsView(dataSource: ..., cacheAppsIcons: false) +``` + +The list of apps can trigger also haptic notifications, e.g. vibrations when the data have been lodaded or if an error occured. +By default this feature is enabled, but it can be disabled: + +```swift + ODSMoreAppsView(dataSource: ..., enableHaptics: false) +``` + +### Example about definiton of Apps Plus credentials + +You can for example for your app use a _.xcconfig_ configuration settings file to store such credentials. +A key named **APPS_PLUS_URL** can be defined with the URL (containing the API key) to call. +Then the **Info.plist** file of your app must have an entry with the same name. +Of course the _.xcconfig_ file should not be versionned in Git, ensure this with [Gitleaks](https://github.com/gitleaks/gitleaks) for example. + +See the example for the _.xcconfig_: + +```text +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 +// See also https://medium.com/swift-india/secure-secrets-in-ios-app-9f66085800b4 + +APPS_PLUS_API_KEY = SoMeApIkEy +APPS_PLUS_URL = https:/$()/url-to-api?apikey=$(APPS_PLUS_API_KEY) + +// Here $() prevents the // to be interpreted as comment, we suppose the URL has an apikey parameter and is GET only +``` + +And the entry for the _Info.plist_: + +```text + APPS_PLUS_URL + ${APPS_PLUS_URL} +``` + +Then in your code you can read the URL, get the locale, and forge the final URL to give to `ODSMoreAppsItemConfig`. +We could have choosen this implemention deeper in the repository but wanted to let ODS lib users choose their own way to deal with the URL. + +```swift + private func buildAppsPlusURL() -> URL { + guard let appsPlusURL = Bundle.main.infoDictionary?["APPS_PLUS_URL"] else { + fatalError("No Apps Plus URL found in app settings") + } + let currentLocale = Bundle.main.preferredLocalizations[0] + let requestURL = "\(appsPlusURL)&lang=\(currentLocale)" + guard let feedURL = URL(string: requestURL) else { + fatalError("Failed to forge the service URL to get more apps") + } + return feedURL + } + + // And then ODSMoreAppsView(dataSource: .remote(url: buildAppsPlusURL())) +``` + +In some CI/CD chain like our GitLab CI runner, we can use a _Fastlane_ lane to read some previously environment variable and fill the _Info.Plist_ file in the suitable row. diff --git a/docs/1.2.0/modules/moreApps_docs.md b/docs/1.2.0/modules/moreApps_docs.md new file mode 100644 index 00000000..d11c15ec --- /dev/null +++ b/docs/1.2.0/modules/moreApps_docs.md @@ -0,0 +1,6 @@ +--- +layout: main +title: MoreApps +content_page: moreApps.md +--- + diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 817af8cf..e87caecd 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -58,9 +58,14 @@ GEM jekyll (>= 3.5, < 5.0) jekyll-feed (~> 0.9) jekyll-seo-tag (~> 2.1) + nokogiri (1.15.6-arm64-darwin) + racc (~> 1.4) + nokogiri (1.15.6-x86_64-darwin) + racc (~> 1.4) pathutil (0.16.2) forwardable-extended (~> 2.6) public_suffix (5.0.4) + racc (1.7.3) rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) @@ -88,6 +93,7 @@ DEPENDENCIES jekyll-relative-links jekyll-remote-theme minima (~> 2.5) + nokogiri tzinfo (~> 2.0) tzinfo-data wdm (~> 0.1.1) diff --git a/docs/_config.yml b/docs/_config.yml index 2a443795..22630a1f 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,30 +1,26 @@ - -# Build settings -baseurl: /ods-ios +# If you update this file, please also update _config_netlify.yml with the exact same changes +plugins: +- jekyll-feed +- jekyll-relative-links relative_links: enabled: true collections: true remote_theme: Orange-OpenSource/ods-jekyll-theme -plugins: - - jekyll-feed - - jekyll-relative-links - -# Exclude from processing. -# The following items will not be processed, by default. -# Any item listed under the `exclude:` key here will be automatically added to -# the internal "default list". -# -# Excluded items can be processed by explicitly listing the directories or -# their entries' file path in the `include:` list. -# -exclude: - - .sass-cache/ - - .jekyll-cache/ - - gemfiles/ - - Gemfile - - Gemfile.lock - - node_modules/ - - vendor/bundle/ - - vendor/cache/ - - vendor/gems/ - - vendor/ruby/ +baseurl: /ods-ios +defaults: + - scope: + path: "" + values: + version: "" + - scope: + path: "1.2.0" + values: + version: "1.2.0" + - scope: + path: "1.1.0" + values: + version: "1.1.0" + - scope: + path: "1.0.0" + values: + version: "1.0.0" diff --git a/docs/_config_netlify.yml b/docs/_config_netlify.yml index a24a26cf..51dedc0e 100644 --- a/docs/_config_netlify.yml +++ b/docs/_config_netlify.yml @@ -1,29 +1,26 @@ - -# Build settings +# If you update this file, please also update _config.yml with the exact same changes +plugins: +- jekyll-feed +- jekyll-relative-links relative_links: enabled: true collections: true remote_theme: Orange-OpenSource/ods-jekyll-theme -plugins: - - jekyll-feed - - jekyll-relative-links - -# Exclude from processing. -# The following items will not be processed, by default. -# Any item listed under the `exclude:` key here will be automatically added to -# the internal "default list". -# -# Excluded items can be processed by explicitly listing the directories or -# their entries' file path in the `include:` list. -# -exclude: - - .sass-cache/ - - .jekyll-cache/ - - gemfiles/ - - Gemfile - - Gemfile.lock - - node_modules/ - - vendor/bundle/ - - vendor/cache/ - - vendor/gems/ - - vendor/ruby/ +baseurl: /ods-ios +defaults: + - scope: + path: "" + values: + version: "" + - scope: + path: "1.2.0" + values: + version: "1.2.0" + - scope: + path: "1.1.0" + values: + version: "1.1.0" + - scope: + path: "1.0.0" + values: + version: "1.0.0" diff --git a/docs/_data/data_menu.yml b/docs/_data/data_menu.yml new file mode 100644 index 00000000..36be7a1f --- /dev/null +++ b/docs/_data/data_menu.yml @@ -0,0 +1,62 @@ +version: "" +toc2: + - title: Get Started + subfolderitems: + - page: Integration + url: /index.html + + - title: Guidelines + subfolderitems: + - page: Colors + url: /guidelines/colors_docs + - page: Spacings + url: /guidelines/spacings_docs + - page: Typography + url: /guidelines/typography_docs + + - title: Components + subfolderitems: + - page: Banners + url: /components/banners_docs + - page: Bars - navigation + url: /components/barsNavigation_docs + - page: Bars - tab + url: /components/barsTab_docs + - page: Bars - tool + url: /components/barsTool_docs + - page: Buttons + url: /components/buttons_docs + - page: Cards + url: /components/cards_docs + - page: Chips + url: /components/chips_docs + - page: List item + url: /components/listItem_docs + - page: Progress indicator + url: /components/progressIndicator_docs + - page: Slider + url: /components/slider_docs + - page: Sheets - Bottom + url: /components/sheetsBottom_docs + - page: Text fields + url: /components/textInput_docs + + - title: Modules + subfolderitems: + - page: About + url: /modules/about_docs + - page: Empty states + url: /modules/emptyState_docs + - page: List + url: /modules/list_docs + - page: MoreApps + url: /modules/moreApps_docs + + - title: About + subfolderitems: + - page: "License" + url: /about/License_docs + - page: "Team" + url: /about/Team_docs + - page: "Cookies" + url: /about/Cookies_docs diff --git a/docs/_data/data_menu_1_0_0.yml b/docs/_data/data_menu_1_0_0.yml new file mode 100644 index 00000000..9cc4c277 --- /dev/null +++ b/docs/_data/data_menu_1_0_0.yml @@ -0,0 +1,62 @@ +version: "1.0.0" +toc2: + - title: Get Started + subfolderitems: + - page: Integration + url: /index.html + + - title: Guidelines + subfolderitems: + - page: Colors + url: /guidelines/colors_docs + - page: Spacings + url: /guidelines/spacings_docs + - page: Typography + url: /guidelines/typography_docs + + - title: Components + subfolderitems: + - page: Banners + url: /components/banners_docs + - page: Bars - navigation + url: /components/barsNavigation_docs + - page: Bars - tab + url: /components/barsTab_docs + - page: Bars - tool + url: /components/barsTool_docs + - page: Buttons + url: /components/buttons_docs + - page: Cards + url: /components/cards_docs + - page: Chips + url: /components/chips_docs + - page: List item + url: /components/listItem_docs + - page: Progress indicator + url: /components/progressIndicator_docs + - page: Slider + url: /components/slider_docs + - page: Sheets - Bottom + url: /components/sheetsBottom_docs + - page: Text fields + url: /components/textInput_docs + + - title: Modules + subfolderitems: + - page: About + url: /modules/about_docs + - page: Empty states + url: /modules/emptyState_docs + - page: List + url: /modules/list_docs + - page: Recirculation + url: /modules/recirculation_docs + + - title: About + subfolderitems: + - page: "License" + url: /about/License_docs + - page: "Team" + url: /about/Team_docs + - page: "Cookies" + url: /about/Cookies_docs diff --git a/docs/_data/data_menu_1_1_0..yml b/docs/_data/data_menu_1_1_0..yml new file mode 100644 index 00000000..6ab57b3f --- /dev/null +++ b/docs/_data/data_menu_1_1_0..yml @@ -0,0 +1,62 @@ +version: "1.1.0" +toc2: + - title: Get Started + subfolderitems: + - page: Integration + url: /index.html + + - title: Guidelines + subfolderitems: + - page: Colors + url: /guidelines/colors_docs + - page: Spacings + url: /guidelines/spacings_docs + - page: Typography + url: /guidelines/typography_docs + + - title: Components + subfolderitems: + - page: Banners + url: /components/banners_docs + - page: Bars - navigation + url: /components/barsNavigation_docs + - page: Bars - tab + url: /components/barsTab_docs + - page: Bars - tool + url: /components/barsTool_docs + - page: Buttons + url: /components/buttons_docs + - page: Cards + url: /components/cards_docs + - page: Chips + url: /components/chips_docs + - page: List item + url: /components/listItem_docs + - page: Progress indicator + url: /components/progressIndicator_docs + - page: Slider + url: /components/slider_docs + - page: Sheets - Bottom + url: /components/sheetsBottom_docs + - page: Text fields + url: /components/textInput_docs + + - title: Modules + subfolderitems: + - page: About + url: /modules/about_docs + - page: Empty states + url: /modules/emptyState_docs + - page: List + url: /modules/list_docs + - page: Recirculation + url: /modules/recirculation_docs + + - title: About + subfolderitems: + - page: "License" + url: /about/License_docs + - page: "Team" + url: /about/Team_docs + - page: "Cookies" + url: /about/Cookies_docs diff --git a/docs/_data/data_menu_1_2_0.yml b/docs/_data/data_menu_1_2_0.yml new file mode 100644 index 00000000..36be7a1f --- /dev/null +++ b/docs/_data/data_menu_1_2_0.yml @@ -0,0 +1,62 @@ +version: "" +toc2: + - title: Get Started + subfolderitems: + - page: Integration + url: /index.html + + - title: Guidelines + subfolderitems: + - page: Colors + url: /guidelines/colors_docs + - page: Spacings + url: /guidelines/spacings_docs + - page: Typography + url: /guidelines/typography_docs + + - title: Components + subfolderitems: + - page: Banners + url: /components/banners_docs + - page: Bars - navigation + url: /components/barsNavigation_docs + - page: Bars - tab + url: /components/barsTab_docs + - page: Bars - tool + url: /components/barsTool_docs + - page: Buttons + url: /components/buttons_docs + - page: Cards + url: /components/cards_docs + - page: Chips + url: /components/chips_docs + - page: List item + url: /components/listItem_docs + - page: Progress indicator + url: /components/progressIndicator_docs + - page: Slider + url: /components/slider_docs + - page: Sheets - Bottom + url: /components/sheetsBottom_docs + - page: Text fields + url: /components/textInput_docs + + - title: Modules + subfolderitems: + - page: About + url: /modules/about_docs + - page: Empty states + url: /modules/emptyState_docs + - page: List + url: /modules/list_docs + - page: MoreApps + url: /modules/moreApps_docs + + - title: About + subfolderitems: + - page: "License" + url: /about/License_docs + - page: "Team" + url: /about/Team_docs + - page: "Cookies" + url: /about/Cookies_docs diff --git a/docs/_data/data_menus.yml b/docs/_data/data_menus.yml deleted file mode 100644 index 56c63c0b..00000000 --- a/docs/_data/data_menus.yml +++ /dev/null @@ -1,62 +0,0 @@ -# Edit this file to update the documentation menu -toc2: - - title: Get Started - subfolderitems: - - page: Integration - url: index.html - - - title: Guidelines - subfolderitems: - - page: Colors - url: guidelines/colors_docs - - page: Spacings - url: guidelines/spacings_docs - - page: Typography - url: guidelines/typography_docs - - - title: Components - subfolderitems: - - page: Banners - url: components/banners_docs - - page: Bars - navigation - url: components/barsNavigation_docs - - page: Bars - tab - url: components/barsTab_docs - - page: Bars - tool - url: components/barsTool_docs - - page: Buttons - url: components/buttons_docs - - page: Cards - url: components/cards_docs - - page: Chips - url: components/chips_docs - - page: List item - url: components/listItem_docs - - page: Progress indicator - url: components/progressIndicator_docs - - page: Slider - url: components/slider_docs - - page: Sheets - Bottom - url: components/sheetsBottom_docs - - page: Text fields - url: components/textInput_docs - - - title: Modules - subfolderitems: - - page: About - url: modules/about_docs - - page: Empty states - url: modules/emptyState_docs - - page: List - url: modules/list_docs - - page: Recirculation - url: modules/recirculation_docs - - - title: About - subfolderitems: - - page: "License" - url: about/License_docs - - page: "Team" - url: about/Team_docs - - page: "Cookies" - url: about/Cookies_docs diff --git a/docs/_data/team.yml b/docs/_data/team.yml index 3fe29d63..34a4566e 100644 --- a/docs/_data/team.yml +++ b/docs/_data/team.yml @@ -1,3 +1,4 @@ +version: "" ODS_iOS: - name: Lapersonne Pierre-Yves gh_pseudo: pylapp diff --git a/docs/_data/team_1_0_0.yml b/docs/_data/team_1_0_0.yml new file mode 100644 index 00000000..b028e9a1 --- /dev/null +++ b/docs/_data/team_1_0_0.yml @@ -0,0 +1,6 @@ +version: "1.0.0" +ODS_iOS: + - name: Lapersonne Pierre-Yves + gh_pseudo: pylapp + - name: Pinel Ludovic + gh_pseudo: ludovic35 \ No newline at end of file diff --git a/docs/_includes/footer.html b/docs/_includes/footer.html index 1fa44d16..784c07e9 100644 --- a/docs/_includes/footer.html +++ b/docs/_includes/footer.html @@ -13,12 +13,6 @@

Sitemap & information

- -