{"id":13871870,"url":"https://github.com/AvdLee/Roadmap","last_synced_at":"2025-07-16T01:32:05.659Z","repository":{"id":70371075,"uuid":"603465364","full_name":"AvdLee/Roadmap","owner":"AvdLee","description":"Publish your roadmap inside your app and allow users to vote for upcoming features","archived":false,"fork":false,"pushed_at":"2024-03-22T10:39:34.000Z","size":327,"stargazers_count":766,"open_issues_count":19,"forks_count":48,"subscribers_count":11,"default_branch":"main","last_synced_at":"2024-05-02T04:54:10.731Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AvdLee.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-02-18T15:46:20.000Z","updated_at":"2024-08-06T00:34:22.211Z","dependencies_parsed_at":"2023-03-05T23:15:29.405Z","dependency_job_id":"92342c0a-65ee-4da1-bfd9-5baf4a554ba1","html_url":"https://github.com/AvdLee/Roadmap","commit_stats":{"total_commits":92,"total_committers":12,"mean_commits":7.666666666666667,"dds":0.6956521739130435,"last_synced_commit":"70cf13c048aaeb802e18d0237bc7da11d78c2d61"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AvdLee%2FRoadmap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AvdLee%2FRoadmap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AvdLee%2FRoadmap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AvdLee%2FRoadmap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AvdLee","download_url":"https://codeload.github.com/AvdLee/Roadmap/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225942780,"owners_count":17549088,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-05T23:00:28.875Z","updated_at":"2025-07-16T01:32:05.639Z","avatar_url":"https://github.com/AvdLee.png","language":"Swift","readme":"![RoadmapHeader Copy@1x](https://user-images.githubusercontent.com/5016984/220204032-55fada28-ca90-4dc9-a931-65242bb6060c.png)\n\n⚠️ The countAPI which we use in Roadmap to let users vote has been down for six weeks or so. They're looking into it, but currently roadmap is unfortunately not working. The provider of the countapi has let us know that they don't expect the API to be fixed anytime soon, so we are looking for alternatives.\n\nHave a look at this PR for an alternative that we might introduce as the default soon!\nhttps://github.com/AvdLee/Roadmap/pull/71\n\nHere's a step by step guide to host your own server with Vapor (Swift):\nhttps://github.com/valentin-mille/RoadmapBackend\n\n# Roadmap\nPublish your roadmap inside your app and allow users to vote for upcoming features, without having to create a backend!\n\n\n## Example\n![RoadmapHeader@1x](https://user-images.githubusercontent.com/5016984/220204046-edec7519-5b1e-4764-9243-5fa6d768b69d.png)\n\n## Setting up Roadmap\n### Create a Roadmap JSON\nRoadmap works with a remote JSON configuration listing all features and their statuses. We recommend hosting it on GitHub Pages or [simplejsoncms.com](https://simplejsoncms.com).\n\nAn example JSON looks as follows:\n\n```json\n[\n    {\n        \"id\": \"1\",\n        \"title\": \"Combine sentences\",\n        \"status\": \"planned\",\n        \"description\" : \"You can add a little bit of extra context here.\"\n    },\n    {\n        \"id\": \"2\",\n        \"title\": \"Open with Finder support\",\n        \"status\": \"planned\"\n    },\n    {\n        \"id\": \"3\",\n        \"title\": \"Initial Launch\",\n        \"status\": \"finished\",\n        \"description\" : \"Release v1 to the public.\",\n        \"isFinished\": true\n    }\n]\n```\n\nThe keys `id`, `title` are mandatory and all have to be strings. You can use any value for `status` or `description`.\n\n#### Support For Localization \nIf you are looking to support localization, then you need to add extra optional parameters in your JSON `localizedTitle`, `localizedDescription` and `localizedStatus` like:\n```json\n[\n  {\n    \"id\": \"0\",\n    \"title\": \"Adding a map\",\n    \"localizedTitle\": [\n      {\n        \"language\": \"ar\",\n        \"value\": \"اضافة خارطة\"\n      },\n      {\n        \"language\": \"en\",\n        \"value\": \"Adding a map\"\n      }\n    ],\n    \"status\": \"planned\",\n    \"localizedStatus\": [\n      {\n        \"language\": \"ar\",\n        \"value\": \"مجدولة\"\n      },\n      {\n        \"language\": \"en\",\n        \"value\": \"Planned\"\n      }\n    ],\n    \"description\": \"some description\",\n    \"localizedDescription\": [\n      {\n        \"language\": \"ar\",\n        \"value\": \"اضافة خارطة لمعرفة الاماكن القريبة\"\n      },\n      {\n        \"language\": \"en\",\n        \"value\": \"Adding a map to view nearby places\"\n      }\n    ]\n  }\n]\n```\n\n#### Keep a list of finished features\nIf you add `isFinished` as `true` to a feature in your JSON, the voting view will be hidden for the users \u0026 no API call will be made to fetch votes. This is an optional value and it's default value is `false`.\n\n### Add Roadmap using Swift Package Manager\n\nAdd `https://github.com/AvdLee/Roadmap.git` within Xcode's package manager.\n\n### Create a Roadmap Configuration instance\n\nCreate a new Roadmap configuration following the documentation:\n\n```swift\nlet configuration = RoadmapConfiguration(\n    roadmapJSONURL: URL(string: \"https://simplejsoncms.com/api/k2f11wikc6\")!\n)\n```\n\nOptional you can also handover a request for more advanced endpoints, for example protected by OAuth: \n\n```swift\n\nvar request = URLRequest(url: URL(string: \"https://simplejsoncms.com/api/k2f11wikc6\")!)\nrequest.setValue(\"application/json\", forHTTPHeaderField: \"Content-Type\")\nrequest.setValue(\"Bearer 1234567890\", forHTTPHeaderField: \"Authorization\")\n\nlet configuration = RoadmapConfiguration(\n    roadmapRequest: request\n)\n```\n\n### Use the configuration to construct the view\nAnd use the configuration inside the `RoadmapView`:\n\n```swift\nstruct ContentView: View {\n    let configuration = RoadmapConfiguration(\n        roadmapJSONURL: URL(string: \"https://simplejsoncms.com/api/k2f11wikc6\")!,\n        namespace: \"yourappname\" // Defaults to your apps bundle id\n        allowVotes: true, // Present the roadmap in read-only mode by setting this to false\n        allowSearching: false // Allow users to filter the features list by adding a searchbar\n    )\n\n    var body: some View {\n        RoadmapView(configuration: configuration)\n    }\n}\n```\n\n\n![Post Portrait@1x](https://user-images.githubusercontent.com/5016984/220203876-48e5d745-f0cf-4f2a-a4a2-2b801f1407e9.png)\n## Styling\nBy initializing the `RoadmapConfiguration` with a `RoadmapStyle` you can create your own styling.\n\n\n```swift\npublic struct RoadmapStyle {\n    /// The image used for the upvote button\n    let upvoteIcon : Image\n    \n    /// The image used for the unvote button\n    let unvoteIcon : Image\n    \n    /// The font used for the feature\n    let titleFont : Font\n    \n    /// The font used for the count label\n    let numberFont : Font\n    \n    /// The font used for the status views\n    let statusFont : Font\n    \n    /// The tint color of the status view\n    let statusTintColor: (String) -\u003e Color\n    \n    /// The corner radius for the upvote button\n    let radius : CGFloat\n    \n    /// The backgroundColor of each cell\n    let cellColor : Color\n    \n    /// The color of the text and icon when voted\n    let selectedForegroundColor : Color\n    \n    /// The main tintColor for the roadmap views.\n    let tintColor : Color\n    \n    public init(upvoteIcon: Image,\n                unvoteIcon: Image,\n                titleFont: Font,\n                numberFont: Font,\n                statusFont: Font,\n                statusTintColor: @escaping (String) -\u003e Color = { _ in Color.primary },\n                cornerRadius: CGFloat,\n                cellColor: Color = Color.defaultCellColor,\n                selectedColor: Color = .white,\n                tint: Color = .accentColor) {\n        \n        self.upvoteIcon = icon\n        self.titleFont = titleFont\n        self.numberFont = numberFont\n        self.statusFont = statusFont\n        self.statusTintColor = statusTintColor\n        self.radius = cornerRadius\n        self.cellColor = cellColor\n        self.selectedForegroundColor = selectedColor\n        self.tintColor = tint\n        \n    }\n}\n\n```\n![Post Portrait Copy@1x](https://user-images.githubusercontent.com/5016984/220203716-2e4a90ad-dd80-4acb-a240-ad26adfca2ef.png)\n\n### Templates\nIf you don't wan't to configure your own style you can also use one of the templates. You have the option between `Standard`, `Playful`, `Classy` and `Technical` so pick whichever works best for your app. \n\n\nExample\n\n```swift\nstruct ContentView: View {\n    let configuration = RoadmapConfiguration(\n        roadmapJSONURL: URL(string: \"https://simplejsoncms.com/api/k2f11wikc6\")!,\n        namespace: \"roadmap\",\n        style: RoadmapTemplate.playful.style, // You can also create your own RoadmapStyle\n    )\n\n    var body: some View {\n        RoadmapView(configuration: configuration)\n    }\n}\n```\n\n## Persisting Votes\nBy default, Roadmap will utilise the [Free Counting API](https://countapi.xyz/) to store votes, you can check out their website for more information. A namespace is provided for you, utilising your application's bundle identifier, but you can override this when initalising the `RoadmapConfiguration`.\n\n```swift\nlet configuration = RoadmapConfiguration(\n    roadmapJSONURL: URL(string: \"https://simplejsoncms.com/api/k2f11wikc6\")!,\n    namespace: \"my-custom-namespace\"\n)\n```\n\n### Defining Custom Voter Service\nIf you'd rather use your own API, you may create a new struct conforming to `FeatureVoter`. This has two required functions in order to retrieve the current vote count and to cast a new vote.\n\n```swift\nstruct CustomFeatureVoter: FeatureVoter {\n    var count = 0\n\n    func fetch(for feature: RoadmapFeature) async -\u003e Int {\n        // query data from your API here\n        return count\n    }\n    \n    func vote(for feature: RoadmapFeature) async -\u003e Int? {\n        // push data to your API here\n        count += 1\n        return count\n    }\n}\n```\n\nYou may then pass an instance of this struct to the `RoadmapConfiguration`.\n\n```swift\nlet configuration = RoadmapConfiguration(\n    roadmapJSONURL: URL(string: \"https://simplejsoncms.com/api/k2f11wikc6\")!,\n    voter: CustomFeatureVoter()\n)\n```\n\n## FAQ\n### Does Roadmap prevent users from voting multiple times?\nYes, if a user has voted on a feature they won't be able to vote again from within your app. Users can intercept your network traffic and replay the api call if they're really desperate to manipulate your votes.\n\n### Can Roadmap be customized to fit the look and feel of my app?\nRoadmap comes with four different preconfigured styles to match most apps. You can change the tintColor, upvote image and more.\n\n### What OS versions are supported?\nTo keep development of Roadmap easy and fun, we've decided to support iOS 15 \u0026 above, macOS Monterey \u0026 Ventura and visionOS for now.\n\n### Can I sort my roadmap by most voted?\nRight now the list of features is loaded in random order. Our thinking is that this will prevent bias for the top voted features. We'll look into ways to make this possible in the future but since the votes are retrieved after the view has been loaded we'll need to look into it.\n\n### Do I need to make changes to my app privacy report if I use Roadmap?\nRoadmap does not do any analytics or tracking. If a user voted on a feature it will increment a number on the count api. No identifiers are stored, not even anonymous ones.\n### Is it possible for stupid people to manipulate my roadmap?\nYes, we wanted to keep Roadmap as simple as possible to setup. If you're worried about competitors (or a user that really wants a specific feature) messing with your priority list, maybe use something else.\n\n### Can I help contribute?\nYes, please! We would love to invite you to pick up any of the open issues. We'll review your Pull Requests accordingly.\n\n## Projects using Roadmap\n- [MacWhisper](https://www.macwhisper.com)\n- [RocketSim](https://www.rocketsim.app)\n- [NowPlaying](https://apps.apple.com/us/app/nowplaying-record-display/id1596487035?l=en)\n- [Stuny](https://apple.co/3HM88Pv)\n- [Stock Analyzer](https://apps.apple.com/nl/app/stock-analyzer/id1614853142)\n- [Super Coder](https://supercoder.lessimore.cn)\n- [SF Symbols Game](https://apps.apple.com/in/app/sf-symbols-game/id1507692602)\n- [Gola](https://apps.apple.com/us/app/gola-goal-tracking/id1661833753?l=en)\n- [Rahhal | رحَّال](https://apps.apple.com/app/id1672846506)\n- [Cronica](https://apps.apple.com/app/id1614950275)\n- [Photo Club Waalre](https://apps.apple.com/nl/app/fotogroep-waalre/id1178324330)\n- [Leximio](https://apps.apple.com/app/leximio/id1671844955)\n- [Discretion](https://apps.apple.com/app/discretion/id1635616662)\n\nIf you've integrated Roadmap into your app and you want to add it to this list, please make a Pull Request.\n\n## Authors\nThis library is created in collaboration between [Jordi Bruin](https://twitter.com/jordibruin), [Hidde van der Ploeg](https://twitter.com/hiddevdploeg), and [Antoine van der Lee](https://www.twitter.com/twannl)\n\n## License\n\nRoadmap is available under the MIT license. See the LICENSE file for more info.\n\n","funding_links":[],"categories":["Swift"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAvdLee%2FRoadmap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FAvdLee%2FRoadmap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAvdLee%2FRoadmap/lists"}