designmd-forge 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +119 -0
- package/dist/__tests__/designStore.test.js +41 -0
- package/dist/__tests__/linter.test.js +23 -0
- package/dist/__tests__/sectionParser.test.js +60 -0
- package/dist/__tests__/server.test.js +129 -0
- package/dist/constants.js +12 -0
- package/dist/data/authoring-guide.md +113 -0
- package/dist/data/designs/airbnb.md +545 -0
- package/dist/data/designs/airtable.md +554 -0
- package/dist/data/designs/apple.md +562 -0
- package/dist/data/designs/binance.md +634 -0
- package/dist/data/designs/bmw-m.md +503 -0
- package/dist/data/designs/bmw.md +544 -0
- package/dist/data/designs/bugatti.md +454 -0
- package/dist/data/designs/cal.md +542 -0
- package/dist/data/designs/card-heavy.md +250 -0
- package/dist/data/designs/claude.md +589 -0
- package/dist/data/designs/clay.md +541 -0
- package/dist/data/designs/clickhouse.md +544 -0
- package/dist/data/designs/cohere.md +451 -0
- package/dist/data/designs/coinbase.md +570 -0
- package/dist/data/designs/composio.md +506 -0
- package/dist/data/designs/content-first.md +236 -0
- package/dist/data/designs/cursor.md +537 -0
- package/dist/data/designs/data-dashboard.md +300 -0
- package/dist/data/designs/dell-1996.md +632 -0
- package/dist/data/designs/elevenlabs.md +504 -0
- package/dist/data/designs/enterprise-neutral.md +252 -0
- package/dist/data/designs/expo.md +526 -0
- package/dist/data/designs/ferrari.md +531 -0
- package/dist/data/designs/figma.md +578 -0
- package/dist/data/designs/framer.md +544 -0
- package/dist/data/designs/hashicorp.md +575 -0
- package/dist/data/designs/hp.md +670 -0
- package/dist/data/designs/ibm.md +550 -0
- package/dist/data/designs/intercom.md +546 -0
- package/dist/data/designs/ios-acorns-android.md +430 -0
- package/dist/data/designs/ios-acorns-expo.md +381 -0
- package/dist/data/designs/ios-acorns-swiftui.md +378 -0
- package/dist/data/designs/ios-acorns.md +384 -0
- package/dist/data/designs/ios-airbnb-android.md +658 -0
- package/dist/data/designs/ios-airbnb-expo.md +457 -0
- package/dist/data/designs/ios-airbnb-swiftui.md +464 -0
- package/dist/data/designs/ios-airbnb.md +410 -0
- package/dist/data/designs/ios-alltrails-android.md +451 -0
- package/dist/data/designs/ios-alltrails-expo.md +400 -0
- package/dist/data/designs/ios-alltrails-swiftui.md +343 -0
- package/dist/data/designs/ios-alltrails.md +344 -0
- package/dist/data/designs/ios-amazon-android.md +686 -0
- package/dist/data/designs/ios-amazon-expo.md +433 -0
- package/dist/data/designs/ios-amazon-music-android.md +416 -0
- package/dist/data/designs/ios-amazon-music-expo.md +368 -0
- package/dist/data/designs/ios-amazon-music-swiftui.md +436 -0
- package/dist/data/designs/ios-amazon-music.md +389 -0
- package/dist/data/designs/ios-amazon-swiftui.md +460 -0
- package/dist/data/designs/ios-amazon.md +440 -0
- package/dist/data/designs/ios-apple-fitness-android.md +462 -0
- package/dist/data/designs/ios-apple-fitness-expo.md +373 -0
- package/dist/data/designs/ios-apple-fitness-swiftui.md +373 -0
- package/dist/data/designs/ios-apple-fitness.md +399 -0
- package/dist/data/designs/ios-apple-maps-android.md +646 -0
- package/dist/data/designs/ios-apple-maps-expo.md +557 -0
- package/dist/data/designs/ios-apple-maps-swiftui.md +588 -0
- package/dist/data/designs/ios-apple-maps.md +447 -0
- package/dist/data/designs/ios-apple-music-android.md +737 -0
- package/dist/data/designs/ios-apple-music-expo.md +596 -0
- package/dist/data/designs/ios-apple-music-swiftui.md +578 -0
- package/dist/data/designs/ios-apple-music.md +494 -0
- package/dist/data/designs/ios-apple-notes-android.md +675 -0
- package/dist/data/designs/ios-apple-notes-expo.md +468 -0
- package/dist/data/designs/ios-apple-notes-swiftui.md +489 -0
- package/dist/data/designs/ios-apple-notes.md +413 -0
- package/dist/data/designs/ios-apple-tv-android.md +405 -0
- package/dist/data/designs/ios-apple-tv-expo.md +341 -0
- package/dist/data/designs/ios-apple-tv-swiftui.md +348 -0
- package/dist/data/designs/ios-apple-tv.md +390 -0
- package/dist/data/designs/ios-apple-wallet-android.md +617 -0
- package/dist/data/designs/ios-apple-wallet-expo.md +487 -0
- package/dist/data/designs/ios-apple-wallet-swiftui.md +425 -0
- package/dist/data/designs/ios-apple-wallet.md +360 -0
- package/dist/data/designs/ios-asana-android.md +435 -0
- package/dist/data/designs/ios-asana-expo.md +411 -0
- package/dist/data/designs/ios-asana-swiftui.md +416 -0
- package/dist/data/designs/ios-asana.md +433 -0
- package/dist/data/designs/ios-audible-android.md +450 -0
- package/dist/data/designs/ios-audible-expo.md +328 -0
- package/dist/data/designs/ios-audible-swiftui.md +418 -0
- package/dist/data/designs/ios-audible.md +364 -0
- package/dist/data/designs/ios-bandcamp-android.md +471 -0
- package/dist/data/designs/ios-bandcamp-expo.md +378 -0
- package/dist/data/designs/ios-bandcamp-swiftui.md +374 -0
- package/dist/data/designs/ios-bandcamp.md +372 -0
- package/dist/data/designs/ios-bear-android.md +496 -0
- package/dist/data/designs/ios-bear-expo.md +449 -0
- package/dist/data/designs/ios-bear-swiftui.md +479 -0
- package/dist/data/designs/ios-bear.md +412 -0
- package/dist/data/designs/ios-bereal-android.md +392 -0
- package/dist/data/designs/ios-bereal-expo.md +299 -0
- package/dist/data/designs/ios-bereal-swiftui.md +319 -0
- package/dist/data/designs/ios-bereal.md +336 -0
- package/dist/data/designs/ios-binance-android.md +481 -0
- package/dist/data/designs/ios-binance-expo.md +404 -0
- package/dist/data/designs/ios-binance-swiftui.md +418 -0
- package/dist/data/designs/ios-binance.md +410 -0
- package/dist/data/designs/ios-bluesky-android.md +442 -0
- package/dist/data/designs/ios-bluesky-expo.md +362 -0
- package/dist/data/designs/ios-bluesky-swiftui.md +328 -0
- package/dist/data/designs/ios-bluesky.md +338 -0
- package/dist/data/designs/ios-booking-android.md +471 -0
- package/dist/data/designs/ios-booking-expo.md +364 -0
- package/dist/data/designs/ios-booking-swiftui.md +377 -0
- package/dist/data/designs/ios-booking.md +346 -0
- package/dist/data/designs/ios-bumble-android.md +756 -0
- package/dist/data/designs/ios-bumble-expo.md +629 -0
- package/dist/data/designs/ios-bumble-swiftui.md +546 -0
- package/dist/data/designs/ios-bumble.md +424 -0
- package/dist/data/designs/ios-cal-ai-android.md +664 -0
- package/dist/data/designs/ios-cal-ai-expo.md +415 -0
- package/dist/data/designs/ios-cal-ai-swiftui.md +486 -0
- package/dist/data/designs/ios-cal-ai.md +387 -0
- package/dist/data/designs/ios-calm-android.md +431 -0
- package/dist/data/designs/ios-calm-expo.md +384 -0
- package/dist/data/designs/ios-calm-swiftui.md +327 -0
- package/dist/data/designs/ios-calm.md +356 -0
- package/dist/data/designs/ios-canva-android.md +469 -0
- package/dist/data/designs/ios-canva-expo.md +374 -0
- package/dist/data/designs/ios-canva-swiftui.md +422 -0
- package/dist/data/designs/ios-canva.md +395 -0
- package/dist/data/designs/ios-cash-app-android.md +601 -0
- package/dist/data/designs/ios-cash-app-expo.md +453 -0
- package/dist/data/designs/ios-cash-app-swiftui.md +463 -0
- package/dist/data/designs/ios-cash-app.md +365 -0
- package/dist/data/designs/ios-character-ai-android.md +489 -0
- package/dist/data/designs/ios-character-ai-expo.md +420 -0
- package/dist/data/designs/ios-character-ai-swiftui.md +417 -0
- package/dist/data/designs/ios-character-ai.md +392 -0
- package/dist/data/designs/ios-charles-schwab-android.md +454 -0
- package/dist/data/designs/ios-charles-schwab-expo.md +388 -0
- package/dist/data/designs/ios-charles-schwab-swiftui.md +394 -0
- package/dist/data/designs/ios-charles-schwab.md +380 -0
- package/dist/data/designs/ios-chatgpt-android.md +753 -0
- package/dist/data/designs/ios-chatgpt-expo.md +644 -0
- package/dist/data/designs/ios-chatgpt-swiftui.md +653 -0
- package/dist/data/designs/ios-chatgpt.md +466 -0
- package/dist/data/designs/ios-chime-android.md +438 -0
- package/dist/data/designs/ios-chime-expo.md +419 -0
- package/dist/data/designs/ios-chime-swiftui.md +383 -0
- package/dist/data/designs/ios-chime.md +389 -0
- package/dist/data/designs/ios-chipotle-android.md +397 -0
- package/dist/data/designs/ios-chipotle-expo.md +301 -0
- package/dist/data/designs/ios-chipotle-swiftui.md +345 -0
- package/dist/data/designs/ios-chipotle.md +340 -0
- package/dist/data/designs/ios-citymapper-android.md +466 -0
- package/dist/data/designs/ios-citymapper-expo.md +420 -0
- package/dist/data/designs/ios-citymapper-swiftui.md +424 -0
- package/dist/data/designs/ios-citymapper.md +394 -0
- package/dist/data/designs/ios-claude-android.md +625 -0
- package/dist/data/designs/ios-claude-expo.md +671 -0
- package/dist/data/designs/ios-claude-swiftui.md +649 -0
- package/dist/data/designs/ios-claude.md +447 -0
- package/dist/data/designs/ios-clickup-android.md +484 -0
- package/dist/data/designs/ios-clickup-expo.md +423 -0
- package/dist/data/designs/ios-clickup-swiftui.md +416 -0
- package/dist/data/designs/ios-clickup.md +431 -0
- package/dist/data/designs/ios-clubhouse-android.md +524 -0
- package/dist/data/designs/ios-clubhouse-expo.md +425 -0
- package/dist/data/designs/ios-clubhouse-swiftui.md +447 -0
- package/dist/data/designs/ios-clubhouse.md +406 -0
- package/dist/data/designs/ios-coffee-meets-bagel-android.md +461 -0
- package/dist/data/designs/ios-coffee-meets-bagel-expo.md +372 -0
- package/dist/data/designs/ios-coffee-meets-bagel-swiftui.md +368 -0
- package/dist/data/designs/ios-coffee-meets-bagel.md +376 -0
- package/dist/data/designs/ios-coinbase-android.md +611 -0
- package/dist/data/designs/ios-coinbase-expo.md +500 -0
- package/dist/data/designs/ios-coinbase-swiftui.md +490 -0
- package/dist/data/designs/ios-coinbase.md +409 -0
- package/dist/data/designs/ios-copilot-android.md +625 -0
- package/dist/data/designs/ios-copilot-expo.md +423 -0
- package/dist/data/designs/ios-copilot-swiftui.md +471 -0
- package/dist/data/designs/ios-copilot.md +367 -0
- package/dist/data/designs/ios-craft-android.md +459 -0
- package/dist/data/designs/ios-craft-expo.md +417 -0
- package/dist/data/designs/ios-craft-swiftui.md +449 -0
- package/dist/data/designs/ios-craft.md +449 -0
- package/dist/data/designs/ios-crunchyroll-android.md +432 -0
- package/dist/data/designs/ios-crunchyroll-expo.md +388 -0
- package/dist/data/designs/ios-crunchyroll-swiftui.md +417 -0
- package/dist/data/designs/ios-crunchyroll.md +388 -0
- package/dist/data/designs/ios-crypto-com-android.md +461 -0
- package/dist/data/designs/ios-crypto-com-expo.md +404 -0
- package/dist/data/designs/ios-crypto-com-swiftui.md +419 -0
- package/dist/data/designs/ios-crypto-com.md +410 -0
- package/dist/data/designs/ios-deepseek-android.md +471 -0
- package/dist/data/designs/ios-deepseek-expo.md +391 -0
- package/dist/data/designs/ios-deepseek-swiftui.md +354 -0
- package/dist/data/designs/ios-deepseek.md +393 -0
- package/dist/data/designs/ios-deezer-android.md +475 -0
- package/dist/data/designs/ios-deezer-expo.md +400 -0
- package/dist/data/designs/ios-deezer-swiftui.md +430 -0
- package/dist/data/designs/ios-deezer.md +388 -0
- package/dist/data/designs/ios-deliveroo-android.md +493 -0
- package/dist/data/designs/ios-deliveroo-expo.md +424 -0
- package/dist/data/designs/ios-deliveroo-swiftui.md +398 -0
- package/dist/data/designs/ios-deliveroo.md +420 -0
- package/dist/data/designs/ios-delta-android.md +439 -0
- package/dist/data/designs/ios-delta-expo.md +381 -0
- package/dist/data/designs/ios-delta-swiftui.md +400 -0
- package/dist/data/designs/ios-delta.md +397 -0
- package/dist/data/designs/ios-discord-android.md +611 -0
- package/dist/data/designs/ios-discord-expo.md +618 -0
- package/dist/data/designs/ios-discord-swiftui.md +630 -0
- package/dist/data/designs/ios-discord.md +451 -0
- package/dist/data/designs/ios-disney-plus-android.md +464 -0
- package/dist/data/designs/ios-disney-plus-expo.md +358 -0
- package/dist/data/designs/ios-disney-plus-swiftui.md +412 -0
- package/dist/data/designs/ios-disney-plus.md +355 -0
- package/dist/data/designs/ios-dominos-android.md +417 -0
- package/dist/data/designs/ios-dominos-expo.md +316 -0
- package/dist/data/designs/ios-dominos-swiftui.md +340 -0
- package/dist/data/designs/ios-dominos.md +347 -0
- package/dist/data/designs/ios-doordash-android.md +527 -0
- package/dist/data/designs/ios-doordash-expo.md +323 -0
- package/dist/data/designs/ios-doordash-swiftui.md +301 -0
- package/dist/data/designs/ios-doordash.md +393 -0
- package/dist/data/designs/ios-dropbox-android.md +522 -0
- package/dist/data/designs/ios-dropbox-expo.md +393 -0
- package/dist/data/designs/ios-dropbox-swiftui.md +400 -0
- package/dist/data/designs/ios-dropbox.md +374 -0
- package/dist/data/designs/ios-duolingo-android.md +641 -0
- package/dist/data/designs/ios-duolingo-expo.md +597 -0
- package/dist/data/designs/ios-duolingo-swiftui.md +539 -0
- package/dist/data/designs/ios-duolingo.md +409 -0
- package/dist/data/designs/ios-ebay-android.md +436 -0
- package/dist/data/designs/ios-ebay-expo.md +344 -0
- package/dist/data/designs/ios-ebay-swiftui.md +308 -0
- package/dist/data/designs/ios-ebay.md +355 -0
- package/dist/data/designs/ios-espn-android.md +468 -0
- package/dist/data/designs/ios-espn-expo.md +387 -0
- package/dist/data/designs/ios-espn-swiftui.md +410 -0
- package/dist/data/designs/ios-espn.md +384 -0
- package/dist/data/designs/ios-etsy-android.md +439 -0
- package/dist/data/designs/ios-etsy-expo.md +351 -0
- package/dist/data/designs/ios-etsy-swiftui.md +296 -0
- package/dist/data/designs/ios-etsy.md +355 -0
- package/dist/data/designs/ios-evernote-android.md +419 -0
- package/dist/data/designs/ios-evernote-expo.md +379 -0
- package/dist/data/designs/ios-evernote-swiftui.md +380 -0
- package/dist/data/designs/ios-evernote.md +416 -0
- package/dist/data/designs/ios-expedia-android.md +451 -0
- package/dist/data/designs/ios-expedia-expo.md +433 -0
- package/dist/data/designs/ios-expedia-swiftui.md +399 -0
- package/dist/data/designs/ios-expedia.md +431 -0
- package/dist/data/designs/ios-facebook-android.md +628 -0
- package/dist/data/designs/ios-facebook-expo.md +471 -0
- package/dist/data/designs/ios-facebook-swiftui.md +459 -0
- package/dist/data/designs/ios-facebook.md +452 -0
- package/dist/data/designs/ios-feeld-android.md +431 -0
- package/dist/data/designs/ios-feeld-expo.md +379 -0
- package/dist/data/designs/ios-feeld-swiftui.md +401 -0
- package/dist/data/designs/ios-feeld.md +378 -0
- package/dist/data/designs/ios-fidelity-android.md +426 -0
- package/dist/data/designs/ios-fidelity-expo.md +396 -0
- package/dist/data/designs/ios-fidelity-swiftui.md +398 -0
- package/dist/data/designs/ios-fidelity.md +387 -0
- package/dist/data/designs/ios-figma-android.md +578 -0
- package/dist/data/designs/ios-figma-expo.md +504 -0
- package/dist/data/designs/ios-figma-swiftui.md +542 -0
- package/dist/data/designs/ios-figma.md +404 -0
- package/dist/data/designs/ios-fitbit-android.md +439 -0
- package/dist/data/designs/ios-fitbit-expo.md +389 -0
- package/dist/data/designs/ios-fitbit-swiftui.md +380 -0
- package/dist/data/designs/ios-fitbit.md +396 -0
- package/dist/data/designs/ios-flickr-android.md +506 -0
- package/dist/data/designs/ios-flickr-expo.md +434 -0
- package/dist/data/designs/ios-flickr-swiftui.md +421 -0
- package/dist/data/designs/ios-flickr.md +394 -0
- package/dist/data/designs/ios-flighty-android.md +418 -0
- package/dist/data/designs/ios-flighty-expo.md +353 -0
- package/dist/data/designs/ios-flighty-swiftui.md +337 -0
- package/dist/data/designs/ios-flighty.md +357 -0
- package/dist/data/designs/ios-flo-android.md +447 -0
- package/dist/data/designs/ios-flo-expo.md +363 -0
- package/dist/data/designs/ios-flo-swiftui.md +355 -0
- package/dist/data/designs/ios-flo.md +351 -0
- package/dist/data/designs/ios-garmin-connect-android.md +531 -0
- package/dist/data/designs/ios-garmin-connect-expo.md +429 -0
- package/dist/data/designs/ios-garmin-connect-swiftui.md +459 -0
- package/dist/data/designs/ios-garmin-connect.md +419 -0
- package/dist/data/designs/ios-gas-android.md +438 -0
- package/dist/data/designs/ios-gas-expo.md +350 -0
- package/dist/data/designs/ios-gas-swiftui.md +329 -0
- package/dist/data/designs/ios-gas.md +387 -0
- package/dist/data/designs/ios-gemini-android.md +568 -0
- package/dist/data/designs/ios-gemini-expo.md +416 -0
- package/dist/data/designs/ios-gemini-swiftui.md +424 -0
- package/dist/data/designs/ios-gemini.md +351 -0
- package/dist/data/designs/ios-github-android.md +507 -0
- package/dist/data/designs/ios-github-expo.md +486 -0
- package/dist/data/designs/ios-github-swiftui.md +459 -0
- package/dist/data/designs/ios-github.md +394 -0
- package/dist/data/designs/ios-gmail-android.md +548 -0
- package/dist/data/designs/ios-gmail-expo.md +457 -0
- package/dist/data/designs/ios-gmail-swiftui.md +470 -0
- package/dist/data/designs/ios-gmail.md +441 -0
- package/dist/data/designs/ios-goodreads-android.md +436 -0
- package/dist/data/designs/ios-goodreads-expo.md +407 -0
- package/dist/data/designs/ios-goodreads-swiftui.md +378 -0
- package/dist/data/designs/ios-goodreads.md +385 -0
- package/dist/data/designs/ios-google-calendar-android.md +565 -0
- package/dist/data/designs/ios-google-calendar-expo.md +616 -0
- package/dist/data/designs/ios-google-calendar-swiftui.md +585 -0
- package/dist/data/designs/ios-google-calendar.md +431 -0
- package/dist/data/designs/ios-google-maps-android.md +614 -0
- package/dist/data/designs/ios-google-maps-expo.md +515 -0
- package/dist/data/designs/ios-google-maps-swiftui.md +484 -0
- package/dist/data/designs/ios-google-maps.md +451 -0
- package/dist/data/designs/ios-grammarly-android.md +449 -0
- package/dist/data/designs/ios-grammarly-expo.md +383 -0
- package/dist/data/designs/ios-grammarly-swiftui.md +381 -0
- package/dist/data/designs/ios-grammarly.md +392 -0
- package/dist/data/designs/ios-grindr-android.md +494 -0
- package/dist/data/designs/ios-grindr-expo.md +358 -0
- package/dist/data/designs/ios-grindr-swiftui.md +357 -0
- package/dist/data/designs/ios-grindr.md +356 -0
- package/dist/data/designs/ios-grok-android.md +471 -0
- package/dist/data/designs/ios-grok-expo.md +388 -0
- package/dist/data/designs/ios-grok-swiftui.md +397 -0
- package/dist/data/designs/ios-grok.md +357 -0
- package/dist/data/designs/ios-groupme-android.md +551 -0
- package/dist/data/designs/ios-groupme-expo.md +442 -0
- package/dist/data/designs/ios-groupme-swiftui.md +439 -0
- package/dist/data/designs/ios-groupme.md +424 -0
- package/dist/data/designs/ios-grubhub-android.md +506 -0
- package/dist/data/designs/ios-grubhub-expo.md +428 -0
- package/dist/data/designs/ios-grubhub-swiftui.md +408 -0
- package/dist/data/designs/ios-grubhub.md +427 -0
- package/dist/data/designs/ios-happn-android.md +464 -0
- package/dist/data/designs/ios-happn-expo.md +411 -0
- package/dist/data/designs/ios-happn-swiftui.md +401 -0
- package/dist/data/designs/ios-happn.md +400 -0
- package/dist/data/designs/ios-headspace-android.md +688 -0
- package/dist/data/designs/ios-headspace-expo.md +574 -0
- package/dist/data/designs/ios-headspace-swiftui.md +498 -0
- package/dist/data/designs/ios-headspace.md +430 -0
- package/dist/data/designs/ios-hevy-android.md +473 -0
- package/dist/data/designs/ios-hevy-expo.md +405 -0
- package/dist/data/designs/ios-hevy-swiftui.md +367 -0
- package/dist/data/designs/ios-hevy.md +410 -0
- package/dist/data/designs/ios-hinge-android.md +743 -0
- package/dist/data/designs/ios-hinge-expo.md +580 -0
- package/dist/data/designs/ios-hinge-swiftui.md +512 -0
- package/dist/data/designs/ios-hinge.md +405 -0
- package/dist/data/designs/ios-hopper-android.md +440 -0
- package/dist/data/designs/ios-hopper-expo.md +353 -0
- package/dist/data/designs/ios-hopper-swiftui.md +340 -0
- package/dist/data/designs/ios-hopper.md +354 -0
- package/dist/data/designs/ios-hulu-android.md +435 -0
- package/dist/data/designs/ios-hulu-expo.md +331 -0
- package/dist/data/designs/ios-hulu-swiftui.md +374 -0
- package/dist/data/designs/ios-hulu.md +353 -0
- package/dist/data/designs/ios-iheartradio-android.md +481 -0
- package/dist/data/designs/ios-iheartradio-expo.md +417 -0
- package/dist/data/designs/ios-iheartradio-swiftui.md +423 -0
- package/dist/data/designs/ios-iheartradio.md +381 -0
- package/dist/data/designs/ios-imessage-android.md +426 -0
- package/dist/data/designs/ios-imessage-expo.md +384 -0
- package/dist/data/designs/ios-imessage-swiftui.md +378 -0
- package/dist/data/designs/ios-imessage.md +394 -0
- package/dist/data/designs/ios-instacart-android.md +471 -0
- package/dist/data/designs/ios-instacart-expo.md +349 -0
- package/dist/data/designs/ios-instacart-swiftui.md +378 -0
- package/dist/data/designs/ios-instacart.md +360 -0
- package/dist/data/designs/ios-instagram-android.md +646 -0
- package/dist/data/designs/ios-instagram-expo.md +310 -0
- package/dist/data/designs/ios-instagram-swiftui.md +333 -0
- package/dist/data/designs/ios-instagram.md +376 -0
- package/dist/data/designs/ios-jira-android.md +432 -0
- package/dist/data/designs/ios-jira-expo.md +375 -0
- package/dist/data/designs/ios-jira-swiftui.md +433 -0
- package/dist/data/designs/ios-jira.md +424 -0
- package/dist/data/designs/ios-kakaotalk-android.md +491 -0
- package/dist/data/designs/ios-kakaotalk-expo.md +418 -0
- package/dist/data/designs/ios-kakaotalk-swiftui.md +406 -0
- package/dist/data/designs/ios-kakaotalk.md +414 -0
- package/dist/data/designs/ios-kayak-android.md +466 -0
- package/dist/data/designs/ios-kayak-expo.md +407 -0
- package/dist/data/designs/ios-kayak-swiftui.md +426 -0
- package/dist/data/designs/ios-kayak.md +392 -0
- package/dist/data/designs/ios-kick-android.md +487 -0
- package/dist/data/designs/ios-kick-expo.md +434 -0
- package/dist/data/designs/ios-kick-swiftui.md +429 -0
- package/dist/data/designs/ios-kick.md +389 -0
- package/dist/data/designs/ios-kik-android.md +433 -0
- package/dist/data/designs/ios-kik-expo.md +363 -0
- package/dist/data/designs/ios-kik-swiftui.md +363 -0
- package/dist/data/designs/ios-kik.md +392 -0
- package/dist/data/designs/ios-kindle-android.md +439 -0
- package/dist/data/designs/ios-kindle-expo.md +356 -0
- package/dist/data/designs/ios-kindle-swiftui.md +372 -0
- package/dist/data/designs/ios-kindle.md +369 -0
- package/dist/data/designs/ios-klarna-android.md +420 -0
- package/dist/data/designs/ios-klarna-expo.md +349 -0
- package/dist/data/designs/ios-klarna-swiftui.md +360 -0
- package/dist/data/designs/ios-klarna.md +356 -0
- package/dist/data/designs/ios-lemon8-android.md +492 -0
- package/dist/data/designs/ios-lemon8-expo.md +413 -0
- package/dist/data/designs/ios-lemon8-swiftui.md +428 -0
- package/dist/data/designs/ios-lemon8.md +378 -0
- package/dist/data/designs/ios-life360-android.md +474 -0
- package/dist/data/designs/ios-life360-expo.md +375 -0
- package/dist/data/designs/ios-life360-swiftui.md +390 -0
- package/dist/data/designs/ios-life360.md +402 -0
- package/dist/data/designs/ios-line-android.md +517 -0
- package/dist/data/designs/ios-line-expo.md +402 -0
- package/dist/data/designs/ios-line-swiftui.md +361 -0
- package/dist/data/designs/ios-line.md +362 -0
- package/dist/data/designs/ios-linear-android.md +457 -0
- package/dist/data/designs/ios-linear-expo.md +367 -0
- package/dist/data/designs/ios-linear-swiftui.md +401 -0
- package/dist/data/designs/ios-linear.md +368 -0
- package/dist/data/designs/ios-linkedin-android.md +620 -0
- package/dist/data/designs/ios-linkedin-expo.md +469 -0
- package/dist/data/designs/ios-linkedin-swiftui.md +472 -0
- package/dist/data/designs/ios-linkedin.md +444 -0
- package/dist/data/designs/ios-locket-android.md +500 -0
- package/dist/data/designs/ios-locket-expo.md +375 -0
- package/dist/data/designs/ios-locket-swiftui.md +375 -0
- package/dist/data/designs/ios-locket.md +381 -0
- package/dist/data/designs/ios-lyft-android.md +406 -0
- package/dist/data/designs/ios-lyft-expo.md +333 -0
- package/dist/data/designs/ios-lyft-swiftui.md +315 -0
- package/dist/data/designs/ios-lyft.md +337 -0
- package/dist/data/designs/ios-marriott-bonvoy-android.md +488 -0
- package/dist/data/designs/ios-marriott-bonvoy-expo.md +412 -0
- package/dist/data/designs/ios-marriott-bonvoy-swiftui.md +461 -0
- package/dist/data/designs/ios-marriott-bonvoy.md +379 -0
- package/dist/data/designs/ios-mastodon-android.md +476 -0
- package/dist/data/designs/ios-mastodon-expo.md +379 -0
- package/dist/data/designs/ios-mastodon-swiftui.md +349 -0
- package/dist/data/designs/ios-mastodon.md +337 -0
- package/dist/data/designs/ios-match-android.md +496 -0
- package/dist/data/designs/ios-match-expo.md +393 -0
- package/dist/data/designs/ios-match-swiftui.md +450 -0
- package/dist/data/designs/ios-match.md +382 -0
- package/dist/data/designs/ios-max-android.md +454 -0
- package/dist/data/designs/ios-max-expo.md +342 -0
- package/dist/data/designs/ios-max-swiftui.md +332 -0
- package/dist/data/designs/ios-max.md +352 -0
- package/dist/data/designs/ios-mcdonalds-android.md +497 -0
- package/dist/data/designs/ios-mcdonalds-expo.md +382 -0
- package/dist/data/designs/ios-mcdonalds-swiftui.md +394 -0
- package/dist/data/designs/ios-mcdonalds.md +410 -0
- package/dist/data/designs/ios-messenger-android.md +523 -0
- package/dist/data/designs/ios-messenger-expo.md +379 -0
- package/dist/data/designs/ios-messenger-swiftui.md +369 -0
- package/dist/data/designs/ios-messenger.md +361 -0
- package/dist/data/designs/ios-microsoft-teams-android.md +446 -0
- package/dist/data/designs/ios-microsoft-teams-expo.md +362 -0
- package/dist/data/designs/ios-microsoft-teams-swiftui.md +384 -0
- package/dist/data/designs/ios-microsoft-teams.md +359 -0
- package/dist/data/designs/ios-midjourney-android.md +503 -0
- package/dist/data/designs/ios-midjourney-expo.md +406 -0
- package/dist/data/designs/ios-midjourney-swiftui.md +376 -0
- package/dist/data/designs/ios-midjourney.md +407 -0
- package/dist/data/designs/ios-miro-android.md +475 -0
- package/dist/data/designs/ios-miro-expo.md +421 -0
- package/dist/data/designs/ios-miro-swiftui.md +407 -0
- package/dist/data/designs/ios-miro.md +424 -0
- package/dist/data/designs/ios-monday-android.md +426 -0
- package/dist/data/designs/ios-monday-expo.md +382 -0
- package/dist/data/designs/ios-monday-swiftui.md +386 -0
- package/dist/data/designs/ios-monday.md +415 -0
- package/dist/data/designs/ios-monzo-android.md +423 -0
- package/dist/data/designs/ios-monzo-expo.md +391 -0
- package/dist/data/designs/ios-monzo-swiftui.md +371 -0
- package/dist/data/designs/ios-monzo.md +382 -0
- package/dist/data/designs/ios-myfitnesspal-android.md +631 -0
- package/dist/data/designs/ios-myfitnesspal-expo.md +489 -0
- package/dist/data/designs/ios-myfitnesspal-swiftui.md +500 -0
- package/dist/data/designs/ios-myfitnesspal.md +408 -0
- package/dist/data/designs/ios-netflix-android.md +570 -0
- package/dist/data/designs/ios-netflix-expo.md +528 -0
- package/dist/data/designs/ios-netflix-swiftui.md +543 -0
- package/dist/data/designs/ios-netflix.md +476 -0
- package/dist/data/designs/ios-nextdoor-android.md +399 -0
- package/dist/data/designs/ios-nextdoor-expo.md +317 -0
- package/dist/data/designs/ios-nextdoor-swiftui.md +343 -0
- package/dist/data/designs/ios-nextdoor.md +332 -0
- package/dist/data/designs/ios-nike-run-club-android.md +598 -0
- package/dist/data/designs/ios-nike-run-club-expo.md +459 -0
- package/dist/data/designs/ios-nike-run-club-swiftui.md +474 -0
- package/dist/data/designs/ios-nike-run-club.md +400 -0
- package/dist/data/designs/ios-noom-android.md +455 -0
- package/dist/data/designs/ios-noom-expo.md +362 -0
- package/dist/data/designs/ios-noom-swiftui.md +369 -0
- package/dist/data/designs/ios-noom.md +404 -0
- package/dist/data/designs/ios-notion-android.md +575 -0
- package/dist/data/designs/ios-notion-expo.md +543 -0
- package/dist/data/designs/ios-notion-swiftui.md +562 -0
- package/dist/data/designs/ios-notion.md +506 -0
- package/dist/data/designs/ios-nubank-android.md +447 -0
- package/dist/data/designs/ios-nubank-expo.md +391 -0
- package/dist/data/designs/ios-nubank-swiftui.md +391 -0
- package/dist/data/designs/ios-nubank.md +388 -0
- package/dist/data/designs/ios-obsidian-android.md +456 -0
- package/dist/data/designs/ios-obsidian-expo.md +401 -0
- package/dist/data/designs/ios-obsidian-swiftui.md +412 -0
- package/dist/data/designs/ios-obsidian.md +363 -0
- package/dist/data/designs/ios-okcupid-android.md +496 -0
- package/dist/data/designs/ios-okcupid-expo.md +378 -0
- package/dist/data/designs/ios-okcupid-swiftui.md +343 -0
- package/dist/data/designs/ios-okcupid.md +364 -0
- package/dist/data/designs/ios-opentable-android.md +426 -0
- package/dist/data/designs/ios-opentable-expo.md +350 -0
- package/dist/data/designs/ios-opentable-swiftui.md +328 -0
- package/dist/data/designs/ios-opentable.md +411 -0
- package/dist/data/designs/ios-oura-android.md +426 -0
- package/dist/data/designs/ios-oura-expo.md +353 -0
- package/dist/data/designs/ios-oura-swiftui.md +327 -0
- package/dist/data/designs/ios-oura.md +356 -0
- package/dist/data/designs/ios-overcast-android.md +508 -0
- package/dist/data/designs/ios-overcast-expo.md +420 -0
- package/dist/data/designs/ios-overcast-swiftui.md +427 -0
- package/dist/data/designs/ios-overcast.md +414 -0
- package/dist/data/designs/ios-pandora-android.md +477 -0
- package/dist/data/designs/ios-pandora-expo.md +406 -0
- package/dist/data/designs/ios-pandora-swiftui.md +413 -0
- package/dist/data/designs/ios-pandora.md +366 -0
- package/dist/data/designs/ios-panera-android.md +414 -0
- package/dist/data/designs/ios-panera-expo.md +352 -0
- package/dist/data/designs/ios-panera-swiftui.md +369 -0
- package/dist/data/designs/ios-panera.md +412 -0
- package/dist/data/designs/ios-paramount-plus-android.md +415 -0
- package/dist/data/designs/ios-paramount-plus-expo.md +363 -0
- package/dist/data/designs/ios-paramount-plus-swiftui.md +372 -0
- package/dist/data/designs/ios-paramount-plus.md +400 -0
- package/dist/data/designs/ios-paypal-android.md +535 -0
- package/dist/data/designs/ios-paypal-expo.md +429 -0
- package/dist/data/designs/ios-paypal-swiftui.md +466 -0
- package/dist/data/designs/ios-paypal.md +393 -0
- package/dist/data/designs/ios-peacock-android.md +453 -0
- package/dist/data/designs/ios-peacock-expo.md +393 -0
- package/dist/data/designs/ios-peacock-swiftui.md +420 -0
- package/dist/data/designs/ios-peacock.md +411 -0
- package/dist/data/designs/ios-peloton-android.md +470 -0
- package/dist/data/designs/ios-peloton-expo.md +401 -0
- package/dist/data/designs/ios-peloton-swiftui.md +409 -0
- package/dist/data/designs/ios-peloton.md +415 -0
- package/dist/data/designs/ios-perplexity-android.md +553 -0
- package/dist/data/designs/ios-perplexity-expo.md +703 -0
- package/dist/data/designs/ios-perplexity-swiftui.md +602 -0
- package/dist/data/designs/ios-perplexity.md +453 -0
- package/dist/data/designs/ios-pinterest-android.md +551 -0
- package/dist/data/designs/ios-pinterest-expo.md +466 -0
- package/dist/data/designs/ios-pinterest-swiftui.md +464 -0
- package/dist/data/designs/ios-pinterest.md +427 -0
- package/dist/data/designs/ios-plenty-of-fish-android.md +462 -0
- package/dist/data/designs/ios-plenty-of-fish-expo.md +380 -0
- package/dist/data/designs/ios-plenty-of-fish-swiftui.md +429 -0
- package/dist/data/designs/ios-plenty-of-fish.md +387 -0
- package/dist/data/designs/ios-plex-android.md +403 -0
- package/dist/data/designs/ios-plex-expo.md +333 -0
- package/dist/data/designs/ios-plex-swiftui.md +349 -0
- package/dist/data/designs/ios-plex.md +379 -0
- package/dist/data/designs/ios-pluto-tv-android.md +413 -0
- package/dist/data/designs/ios-pluto-tv-expo.md +379 -0
- package/dist/data/designs/ios-pluto-tv-swiftui.md +411 -0
- package/dist/data/designs/ios-pluto-tv.md +362 -0
- package/dist/data/designs/ios-pocket-casts-android.md +492 -0
- package/dist/data/designs/ios-pocket-casts-expo.md +430 -0
- package/dist/data/designs/ios-pocket-casts-swiftui.md +479 -0
- package/dist/data/designs/ios-pocket-casts.md +427 -0
- package/dist/data/designs/ios-postman-android.md +472 -0
- package/dist/data/designs/ios-postman-expo.md +372 -0
- package/dist/data/designs/ios-postman-swiftui.md +377 -0
- package/dist/data/designs/ios-postman.md +405 -0
- package/dist/data/designs/ios-prime-video-android.md +447 -0
- package/dist/data/designs/ios-prime-video-expo.md +365 -0
- package/dist/data/designs/ios-prime-video-swiftui.md +333 -0
- package/dist/data/designs/ios-prime-video.md +351 -0
- package/dist/data/designs/ios-quora-android.md +513 -0
- package/dist/data/designs/ios-quora-expo.md +362 -0
- package/dist/data/designs/ios-quora-swiftui.md +375 -0
- package/dist/data/designs/ios-quora.md +359 -0
- package/dist/data/designs/ios-raya-android.md +401 -0
- package/dist/data/designs/ios-raya-expo.md +366 -0
- package/dist/data/designs/ios-raya-swiftui.md +393 -0
- package/dist/data/designs/ios-raya.md +366 -0
- package/dist/data/designs/ios-reddit-android.md +605 -0
- package/dist/data/designs/ios-reddit-expo.md +553 -0
- package/dist/data/designs/ios-reddit-swiftui.md +514 -0
- package/dist/data/designs/ios-reddit.md +460 -0
- package/dist/data/designs/ios-resy-android.md +430 -0
- package/dist/data/designs/ios-resy-expo.md +344 -0
- package/dist/data/designs/ios-resy-swiftui.md +330 -0
- package/dist/data/designs/ios-resy.md +412 -0
- package/dist/data/designs/ios-revolut-android.md +433 -0
- package/dist/data/designs/ios-revolut-expo.md +379 -0
- package/dist/data/designs/ios-revolut-swiftui.md +372 -0
- package/dist/data/designs/ios-revolut.md +353 -0
- package/dist/data/designs/ios-robinhood-android.md +587 -0
- package/dist/data/designs/ios-robinhood-expo.md +416 -0
- package/dist/data/designs/ios-robinhood-swiftui.md +431 -0
- package/dist/data/designs/ios-robinhood.md +380 -0
- package/dist/data/designs/ios-runna-android.md +485 -0
- package/dist/data/designs/ios-runna-expo.md +388 -0
- package/dist/data/designs/ios-runna-swiftui.md +413 -0
- package/dist/data/designs/ios-runna.md +390 -0
- package/dist/data/designs/ios-shazam-android.md +436 -0
- package/dist/data/designs/ios-shazam-expo.md +348 -0
- package/dist/data/designs/ios-shazam-swiftui.md +394 -0
- package/dist/data/designs/ios-shazam.md +338 -0
- package/dist/data/designs/ios-signal-android.md +462 -0
- package/dist/data/designs/ios-signal-expo.md +361 -0
- package/dist/data/designs/ios-signal-swiftui.md +350 -0
- package/dist/data/designs/ios-signal.md +357 -0
- package/dist/data/designs/ios-skype-android.md +398 -0
- package/dist/data/designs/ios-skype-expo.md +368 -0
- package/dist/data/designs/ios-skype-swiftui.md +369 -0
- package/dist/data/designs/ios-skype.md +406 -0
- package/dist/data/designs/ios-skyscanner-android.md +451 -0
- package/dist/data/designs/ios-skyscanner-expo.md +423 -0
- package/dist/data/designs/ios-skyscanner-swiftui.md +419 -0
- package/dist/data/designs/ios-skyscanner.md +421 -0
- package/dist/data/designs/ios-slack-android.md +695 -0
- package/dist/data/designs/ios-slack-expo.md +601 -0
- package/dist/data/designs/ios-slack-swiftui.md +594 -0
- package/dist/data/designs/ios-slack.md +474 -0
- package/dist/data/designs/ios-sleep-cycle-android.md +436 -0
- package/dist/data/designs/ios-sleep-cycle-expo.md +380 -0
- package/dist/data/designs/ios-sleep-cycle-swiftui.md +409 -0
- package/dist/data/designs/ios-sleep-cycle.md +386 -0
- package/dist/data/designs/ios-snapchat-android.md +671 -0
- package/dist/data/designs/ios-snapchat-expo.md +528 -0
- package/dist/data/designs/ios-snapchat-swiftui.md +557 -0
- package/dist/data/designs/ios-snapchat.md +478 -0
- package/dist/data/designs/ios-sofi-android.md +446 -0
- package/dist/data/designs/ios-sofi-expo.md +387 -0
- package/dist/data/designs/ios-sofi-swiftui.md +379 -0
- package/dist/data/designs/ios-sofi.md +385 -0
- package/dist/data/designs/ios-soundcloud-android.md +488 -0
- package/dist/data/designs/ios-soundcloud-expo.md +364 -0
- package/dist/data/designs/ios-soundcloud-swiftui.md +399 -0
- package/dist/data/designs/ios-soundcloud.md +359 -0
- package/dist/data/designs/ios-southwest-android.md +446 -0
- package/dist/data/designs/ios-southwest-expo.md +389 -0
- package/dist/data/designs/ios-southwest-swiftui.md +405 -0
- package/dist/data/designs/ios-southwest.md +405 -0
- package/dist/data/designs/ios-spotify-android.md +427 -0
- package/dist/data/designs/ios-spotify-expo.md +321 -0
- package/dist/data/designs/ios-spotify-swiftui.md +312 -0
- package/dist/data/designs/ios-spotify.md +366 -0
- package/dist/data/designs/ios-starbucks-android.md +622 -0
- package/dist/data/designs/ios-starbucks-expo.md +497 -0
- package/dist/data/designs/ios-starbucks-swiftui.md +500 -0
- package/dist/data/designs/ios-starbucks.md +440 -0
- package/dist/data/designs/ios-strava-android.md +656 -0
- package/dist/data/designs/ios-strava-expo.md +501 -0
- package/dist/data/designs/ios-strava-swiftui.md +465 -0
- package/dist/data/designs/ios-strava.md +433 -0
- package/dist/data/designs/ios-strong-android.md +479 -0
- package/dist/data/designs/ios-strong-expo.md +396 -0
- package/dist/data/designs/ios-strong-swiftui.md +363 -0
- package/dist/data/designs/ios-strong.md +415 -0
- package/dist/data/designs/ios-substack-android.md +440 -0
- package/dist/data/designs/ios-substack-expo.md +395 -0
- package/dist/data/designs/ios-substack-swiftui.md +371 -0
- package/dist/data/designs/ios-substack.md +372 -0
- package/dist/data/designs/ios-swiggy-android.md +549 -0
- package/dist/data/designs/ios-swiggy-expo.md +443 -0
- package/dist/data/designs/ios-swiggy-swiftui.md +471 -0
- package/dist/data/designs/ios-swiggy.md +432 -0
- package/dist/data/designs/ios-taco-bell-android.md +529 -0
- package/dist/data/designs/ios-taco-bell-expo.md +407 -0
- package/dist/data/designs/ios-taco-bell-swiftui.md +419 -0
- package/dist/data/designs/ios-taco-bell.md +430 -0
- package/dist/data/designs/ios-telegram-android.md +676 -0
- package/dist/data/designs/ios-telegram-expo.md +594 -0
- package/dist/data/designs/ios-telegram-swiftui.md +518 -0
- package/dist/data/designs/ios-telegram.md +458 -0
- package/dist/data/designs/ios-the-league-android.md +454 -0
- package/dist/data/designs/ios-the-league-expo.md +391 -0
- package/dist/data/designs/ios-the-league-swiftui.md +409 -0
- package/dist/data/designs/ios-the-league.md +368 -0
- package/dist/data/designs/ios-things-3-android.md +421 -0
- package/dist/data/designs/ios-things-3-expo.md +351 -0
- package/dist/data/designs/ios-things-3-swiftui.md +359 -0
- package/dist/data/designs/ios-things-3.md +339 -0
- package/dist/data/designs/ios-threads-android.md +588 -0
- package/dist/data/designs/ios-threads-expo.md +468 -0
- package/dist/data/designs/ios-threads-swiftui.md +452 -0
- package/dist/data/designs/ios-threads.md +424 -0
- package/dist/data/designs/ios-threema-android.md +496 -0
- package/dist/data/designs/ios-threema-expo.md +415 -0
- package/dist/data/designs/ios-threema-swiftui.md +446 -0
- package/dist/data/designs/ios-threema.md +397 -0
- package/dist/data/designs/ios-tidal-android.md +398 -0
- package/dist/data/designs/ios-tidal-expo.md +323 -0
- package/dist/data/designs/ios-tidal-swiftui.md +340 -0
- package/dist/data/designs/ios-tidal.md +351 -0
- package/dist/data/designs/ios-tiktok-android.md +654 -0
- package/dist/data/designs/ios-tiktok-expo.md +578 -0
- package/dist/data/designs/ios-tiktok-swiftui.md +595 -0
- package/dist/data/designs/ios-tiktok.md +387 -0
- package/dist/data/designs/ios-tinder-android.md +681 -0
- package/dist/data/designs/ios-tinder-expo.md +512 -0
- package/dist/data/designs/ios-tinder-swiftui.md +497 -0
- package/dist/data/designs/ios-tinder.md +415 -0
- package/dist/data/designs/ios-todoist-android.md +711 -0
- package/dist/data/designs/ios-todoist-expo.md +607 -0
- package/dist/data/designs/ios-todoist-swiftui.md +573 -0
- package/dist/data/designs/ios-todoist.md +418 -0
- package/dist/data/designs/ios-trello-android.md +412 -0
- package/dist/data/designs/ios-trello-expo.md +332 -0
- package/dist/data/designs/ios-trello-swiftui.md +359 -0
- package/dist/data/designs/ios-trello.md +344 -0
- package/dist/data/designs/ios-tripadvisor-android.md +450 -0
- package/dist/data/designs/ios-tripadvisor-expo.md +322 -0
- package/dist/data/designs/ios-tripadvisor-swiftui.md +326 -0
- package/dist/data/designs/ios-tripadvisor.md +356 -0
- package/dist/data/designs/ios-tubi-android.md +453 -0
- package/dist/data/designs/ios-tubi-expo.md +419 -0
- package/dist/data/designs/ios-tubi-swiftui.md +463 -0
- package/dist/data/designs/ios-tubi.md +383 -0
- package/dist/data/designs/ios-tumblr-android.md +462 -0
- package/dist/data/designs/ios-tumblr-expo.md +374 -0
- package/dist/data/designs/ios-tumblr-swiftui.md +380 -0
- package/dist/data/designs/ios-tumblr.md +337 -0
- package/dist/data/designs/ios-turo-android.md +500 -0
- package/dist/data/designs/ios-turo-expo.md +454 -0
- package/dist/data/designs/ios-turo-swiftui.md +447 -0
- package/dist/data/designs/ios-turo.md +392 -0
- package/dist/data/designs/ios-twitch-android.md +412 -0
- package/dist/data/designs/ios-twitch-expo.md +342 -0
- package/dist/data/designs/ios-twitch-swiftui.md +328 -0
- package/dist/data/designs/ios-twitch.md +354 -0
- package/dist/data/designs/ios-uber-android.md +637 -0
- package/dist/data/designs/ios-uber-eats-android.md +502 -0
- package/dist/data/designs/ios-uber-eats-expo.md +407 -0
- package/dist/data/designs/ios-uber-eats-swiftui.md +393 -0
- package/dist/data/designs/ios-uber-eats.md +353 -0
- package/dist/data/designs/ios-uber-expo.md +512 -0
- package/dist/data/designs/ios-uber-swiftui.md +483 -0
- package/dist/data/designs/ios-uber.md +395 -0
- package/dist/data/designs/ios-united-airlines-android.md +494 -0
- package/dist/data/designs/ios-united-airlines-expo.md +408 -0
- package/dist/data/designs/ios-united-airlines-swiftui.md +453 -0
- package/dist/data/designs/ios-united-airlines.md +388 -0
- package/dist/data/designs/ios-venmo-android.md +654 -0
- package/dist/data/designs/ios-venmo-expo.md +458 -0
- package/dist/data/designs/ios-venmo-swiftui.md +469 -0
- package/dist/data/designs/ios-venmo.md +436 -0
- package/dist/data/designs/ios-vercel-android.md +454 -0
- package/dist/data/designs/ios-vercel-expo.md +387 -0
- package/dist/data/designs/ios-vercel-swiftui.md +374 -0
- package/dist/data/designs/ios-vercel.md +399 -0
- package/dist/data/designs/ios-vero-android.md +498 -0
- package/dist/data/designs/ios-vero-expo.md +376 -0
- package/dist/data/designs/ios-vero-swiftui.md +374 -0
- package/dist/data/designs/ios-vero.md +394 -0
- package/dist/data/designs/ios-viber-android.md +377 -0
- package/dist/data/designs/ios-viber-expo.md +375 -0
- package/dist/data/designs/ios-viber-swiftui.md +378 -0
- package/dist/data/designs/ios-viber.md +403 -0
- package/dist/data/designs/ios-vimeo-android.md +465 -0
- package/dist/data/designs/ios-vimeo-expo.md +347 -0
- package/dist/data/designs/ios-vimeo-swiftui.md +383 -0
- package/dist/data/designs/ios-vimeo.md +403 -0
- package/dist/data/designs/ios-vrbo-android.md +488 -0
- package/dist/data/designs/ios-vrbo-expo.md +395 -0
- package/dist/data/designs/ios-vrbo-swiftui.md +421 -0
- package/dist/data/designs/ios-vrbo.md +383 -0
- package/dist/data/designs/ios-vsco-android.md +490 -0
- package/dist/data/designs/ios-vsco-expo.md +413 -0
- package/dist/data/designs/ios-vsco-swiftui.md +449 -0
- package/dist/data/designs/ios-vsco.md +412 -0
- package/dist/data/designs/ios-walmart-android.md +479 -0
- package/dist/data/designs/ios-walmart-expo.md +370 -0
- package/dist/data/designs/ios-walmart-swiftui.md +387 -0
- package/dist/data/designs/ios-walmart.md +366 -0
- package/dist/data/designs/ios-waze-android.md +695 -0
- package/dist/data/designs/ios-waze-expo.md +587 -0
- package/dist/data/designs/ios-waze-swiftui.md +601 -0
- package/dist/data/designs/ios-waze.md +453 -0
- package/dist/data/designs/ios-webull-android.md +429 -0
- package/dist/data/designs/ios-webull-expo.md +384 -0
- package/dist/data/designs/ios-webull-swiftui.md +406 -0
- package/dist/data/designs/ios-webull.md +375 -0
- package/dist/data/designs/ios-wechat-android.md +545 -0
- package/dist/data/designs/ios-wechat-expo.md +398 -0
- package/dist/data/designs/ios-wechat-swiftui.md +394 -0
- package/dist/data/designs/ios-wechat.md +363 -0
- package/dist/data/designs/ios-whatsapp-android.md +568 -0
- package/dist/data/designs/ios-whatsapp-expo.md +502 -0
- package/dist/data/designs/ios-whatsapp-swiftui.md +483 -0
- package/dist/data/designs/ios-whatsapp.md +425 -0
- package/dist/data/designs/ios-whoop-android.md +635 -0
- package/dist/data/designs/ios-whoop-expo.md +562 -0
- package/dist/data/designs/ios-whoop-swiftui.md +553 -0
- package/dist/data/designs/ios-whoop.md +419 -0
- package/dist/data/designs/ios-wise-android.md +428 -0
- package/dist/data/designs/ios-wise-expo.md +357 -0
- package/dist/data/designs/ios-wise-swiftui.md +356 -0
- package/dist/data/designs/ios-wise.md +361 -0
- package/dist/data/designs/ios-x-twitter-android.md +618 -0
- package/dist/data/designs/ios-x-twitter-expo.md +442 -0
- package/dist/data/designs/ios-x-twitter-swiftui.md +429 -0
- package/dist/data/designs/ios-x-twitter.md +432 -0
- package/dist/data/designs/ios-yelp-android.md +455 -0
- package/dist/data/designs/ios-yelp-expo.md +397 -0
- package/dist/data/designs/ios-yelp-swiftui.md +369 -0
- package/dist/data/designs/ios-yelp.md +398 -0
- package/dist/data/designs/ios-youtube-android.md +668 -0
- package/dist/data/designs/ios-youtube-expo.md +435 -0
- package/dist/data/designs/ios-youtube-music-android.md +450 -0
- package/dist/data/designs/ios-youtube-music-expo.md +404 -0
- package/dist/data/designs/ios-youtube-music-swiftui.md +434 -0
- package/dist/data/designs/ios-youtube-music.md +381 -0
- package/dist/data/designs/ios-youtube-swiftui.md +496 -0
- package/dist/data/designs/ios-youtube.md +466 -0
- package/dist/data/designs/ios-zalo-android.md +510 -0
- package/dist/data/designs/ios-zalo-expo.md +389 -0
- package/dist/data/designs/ios-zalo-swiftui.md +431 -0
- package/dist/data/designs/ios-zalo.md +388 -0
- package/dist/data/designs/ios-zomato-android.md +527 -0
- package/dist/data/designs/ios-zomato-expo.md +437 -0
- package/dist/data/designs/ios-zomato-swiftui.md +433 -0
- package/dist/data/designs/ios-zomato.md +439 -0
- package/dist/data/designs/ios-zoom-android.md +423 -0
- package/dist/data/designs/ios-zoom-expo.md +355 -0
- package/dist/data/designs/ios-zoom-swiftui.md +379 -0
- package/dist/data/designs/ios-zoom.md +357 -0
- package/dist/data/designs/ios-zwift-android.md +402 -0
- package/dist/data/designs/ios-zwift-expo.md +402 -0
- package/dist/data/designs/ios-zwift-swiftui.md +378 -0
- package/dist/data/designs/ios-zwift.md +411 -0
- package/dist/data/designs/kraken.md +125 -0
- package/dist/data/designs/lamborghini.md +288 -0
- package/dist/data/designs/linear.app.md +548 -0
- package/dist/data/designs/lovable.md +298 -0
- package/dist/data/designs/mastercard.md +365 -0
- package/dist/data/designs/material-clean.md +289 -0
- package/dist/data/designs/meta.md +683 -0
- package/dist/data/designs/midnight-pro.md +256 -0
- package/dist/data/designs/minimal-brutalist.md +245 -0
- package/dist/data/designs/minimax.md +746 -0
- package/dist/data/designs/mintlify.md +852 -0
- package/dist/data/designs/miro.md +825 -0
- package/dist/data/designs/mistral.ai.md +773 -0
- package/dist/data/designs/mongodb.md +767 -0
- package/dist/data/designs/nike.md +575 -0
- package/dist/data/designs/nintendo-2001.md +649 -0
- package/dist/data/designs/notion.md +821 -0
- package/dist/data/designs/nova-mobile-design-md.md +235 -0
- package/dist/data/designs/nvidia.md +640 -0
- package/dist/data/designs/ollama.md +539 -0
- package/dist/data/designs/opencode.ai.md +521 -0
- package/dist/data/designs/pinterest.md +597 -0
- package/dist/data/designs/playful-color.md +253 -0
- package/dist/data/designs/playstation.md +661 -0
- package/dist/data/designs/posthog.md +690 -0
- package/dist/data/designs/raycast.md +669 -0
- package/dist/data/designs/renault.md +589 -0
- package/dist/data/designs/replicate.md +616 -0
- package/dist/data/designs/resend.md +585 -0
- package/dist/data/designs/revolut.md +636 -0
- package/dist/data/designs/runwayml.md +244 -0
- package/dist/data/designs/sanity.md +357 -0
- package/dist/data/designs/sentry.md +551 -0
- package/dist/data/designs/shopify.md +516 -0
- package/dist/data/designs/slack.md +482 -0
- package/dist/data/designs/soft-glass.md +258 -0
- package/dist/data/designs/spacex.md +363 -0
- package/dist/data/designs/spotify.md +246 -0
- package/dist/data/designs/starbucks.md +580 -0
- package/dist/data/designs/stripe.md +487 -0
- package/dist/data/designs/supabase.md +462 -0
- package/dist/data/designs/superhuman.md +448 -0
- package/dist/data/designs/tesla.md +286 -0
- package/dist/data/designs/theverge.md +339 -0
- package/dist/data/designs/together.ai.md +633 -0
- package/dist/data/designs/uber.md +636 -0
- package/dist/data/designs/vercel.md +736 -0
- package/dist/data/designs/vodafone.md +538 -0
- package/dist/data/designs/voltagent.md +521 -0
- package/dist/data/designs/warp.md +526 -0
- package/dist/data/designs/webflow.md +588 -0
- package/dist/data/designs/wired.md +497 -0
- package/dist/data/designs/wise.md +544 -0
- package/dist/data/designs/x.ai.md +465 -0
- package/dist/data/designs/zapier.md +537 -0
- package/dist/data/index.json +2600 -0
- package/dist/httpServer.js +83 -0
- package/dist/index.js +13 -0
- package/dist/server.js +32 -0
- package/dist/services/designStore.js +59 -0
- package/dist/services/linter.js +87 -0
- package/dist/services/sectionParser.js +154 -0
- package/dist/tools/authoring.js +131 -0
- package/dist/tools/browse.js +232 -0
- package/dist/tools/diff.js +88 -0
- package/dist/tools/getDesign.js +216 -0
- package/dist/tools/guardrails.js +87 -0
- package/dist/tools/lint.js +104 -0
- package/dist/types.js +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,695 @@
|
|
|
1
|
+
# Waze (iOS) — Jetpack Compose Implementation Guide
|
|
2
|
+
|
|
3
|
+
Companion to [DESIGN.md](DESIGN.md) — the framework-neutral spec. This file ports Waze's playful, cartoon-forward visual language to **Android with Jetpack Compose (Material 3)**: a color token object, a `Typography` set, paste-ready `@Composable`s (the cartoon hazard speech bubble, the cyan arrow puck, the next-turn card, the report FAB, the speed-limit tile, the "Go" button), `Modifier`s, motion, and haptics.
|
|
4
|
+
|
|
5
|
+
> Why a Compose guide for an iOS-referenced app? The DESIGN.md tokens are platform-neutral. This file keeps the *visual* identity (the Waze Purple + Cyan electric duo, the **chunky cartoon speech-bubble hazard reports with triangular tails**, the cyan arrow puck, the loud saturated cartography, the tinted purple FAB shadow, Boing's roundness) while making everything idiomatic Android — Google Maps Compose instead of MapKit, SF Pro Rounded's analog (`FontFamily` fallback) for Boing, custom `Shape`s for the tail and arrow, `LocalHapticFeedback` instead of `.sensoryFeedback`, `sp`/`dp` instead of `pt`.
|
|
6
|
+
|
|
7
|
+
Assumes Compose BOM `2024.09+`, Kotlin `2.0+`, `minSdk 24`, Material 3, and `com.google.maps.android:maps-compose` for the loud cartography. No color extraction, so `androidx.palette` is not required.
|
|
8
|
+
|
|
9
|
+
## 1. Color Tokens
|
|
10
|
+
|
|
11
|
+
```kotlin
|
|
12
|
+
// ui/theme/WazeColors.kt
|
|
13
|
+
import androidx.compose.ui.graphics.Color
|
|
14
|
+
|
|
15
|
+
object WazeColors {
|
|
16
|
+
// Brand
|
|
17
|
+
val Purple = Color(0xFF7E55BE) // logo, polyline, FAB, "Go", primary CTAs
|
|
18
|
+
val PurpleDeep = Color(0xFF5B3C9A)
|
|
19
|
+
val PurpleTint = Color(0xFFE8DEF5)
|
|
20
|
+
val Cyan = Color(0xFF33CCFF) // location puck, info glyphs, 2nd logo color
|
|
21
|
+
val CyanDeep = Color(0xFF0099E5)
|
|
22
|
+
|
|
23
|
+
// Hazard colors (the cartoon system)
|
|
24
|
+
val PoliceRed = Color(0xFFEF6A65)
|
|
25
|
+
val TrafficOrng = Color(0xFFF69833)
|
|
26
|
+
val ClosureYel = Color(0xFFF9C42E)
|
|
27
|
+
val ClearedGrn = Color(0xFF75C73E)
|
|
28
|
+
val HazardBrown = Color(0xFF8B6F47)
|
|
29
|
+
val CameraGray = Color(0xFF6B6B6B)
|
|
30
|
+
|
|
31
|
+
// Map cartography (light) — LOUD by design
|
|
32
|
+
val MapCream = Color(0xFFFFFCF2)
|
|
33
|
+
val MapWater = Color(0xFF9BDEEF)
|
|
34
|
+
val MapPark = Color(0xFFC5E89B)
|
|
35
|
+
val MapRoadMajor = Color(0xFFFFFFFF)
|
|
36
|
+
val MapRoadMinor = Color(0xFFF5F0E5)
|
|
37
|
+
val MapHighway = Color(0xFFFFD970)
|
|
38
|
+
val MapBuilding = Color(0xFFE8E2D1)
|
|
39
|
+
val MapLabel = Color(0xFF3D3D3D)
|
|
40
|
+
|
|
41
|
+
// UI chrome
|
|
42
|
+
val CardCanvas = Color(0xFFFFFFFF)
|
|
43
|
+
val SurfaceGray = Color(0xFFF5F5F7)
|
|
44
|
+
val SurfaceGray2 = Color(0xFFEAEAEC)
|
|
45
|
+
val Divider = Color(0xFFD6D6D9)
|
|
46
|
+
|
|
47
|
+
// Text
|
|
48
|
+
val Ink = Color(0xFF1A1A1A) // warm near-black
|
|
49
|
+
val Secondary = Color(0xFF6B6B6B)
|
|
50
|
+
val Tertiary = Color(0xFFA0A0A0)
|
|
51
|
+
|
|
52
|
+
// Semantic
|
|
53
|
+
val Success = Color(0xFF34C759)
|
|
54
|
+
val Warning = Color(0xFFF9C42E)
|
|
55
|
+
val Error = Color(0xFFEF6A65)
|
|
56
|
+
|
|
57
|
+
// Dark (night driving)
|
|
58
|
+
val DarkMapLand = Color(0xFF1E2026)
|
|
59
|
+
val DarkMapWater = Color(0xFF0F3D5E)
|
|
60
|
+
val DarkMapPark = Color(0xFF1F3A1F)
|
|
61
|
+
val DarkCardSurf = Color(0xFF262932)
|
|
62
|
+
val DarkSurface2 = Color(0xFF3A3D47)
|
|
63
|
+
val DarkDivider = Color(0xFF4A4D58)
|
|
64
|
+
val PurpleDark = Color(0xFF9F76DA) // brightened for dark legibility
|
|
65
|
+
val CyanDark = Color(0xFF5DD9FF)
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Waze is a map-first app: a loud light cartography by day, near-black "night driving" by night — but the **Waze Purple + Cyan stay at brand saturation in both**. Wire both Material 3 schemes accordingly.
|
|
70
|
+
|
|
71
|
+
```kotlin
|
|
72
|
+
// ui/theme/Theme.kt
|
|
73
|
+
import androidx.compose.material3.lightColorScheme
|
|
74
|
+
import androidx.compose.material3.darkColorScheme
|
|
75
|
+
import androidx.compose.material3.MaterialTheme
|
|
76
|
+
|
|
77
|
+
private val WazeLight = lightColorScheme(
|
|
78
|
+
primary = WazeColors.Purple,
|
|
79
|
+
onPrimary = Color.White,
|
|
80
|
+
secondary = WazeColors.Cyan,
|
|
81
|
+
background = WazeColors.CardCanvas,
|
|
82
|
+
onBackground = WazeColors.Ink,
|
|
83
|
+
surface = WazeColors.CardCanvas,
|
|
84
|
+
onSurface = WazeColors.Ink,
|
|
85
|
+
surfaceVariant = WazeColors.SurfaceGray,
|
|
86
|
+
outline = WazeColors.Divider,
|
|
87
|
+
error = WazeColors.Error,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
private val WazeDark = darkColorScheme(
|
|
91
|
+
primary = WazeColors.PurpleDark, // brightened, still brand
|
|
92
|
+
onPrimary = Color.White,
|
|
93
|
+
secondary = WazeColors.CyanDark,
|
|
94
|
+
background = WazeColors.DarkMapLand,
|
|
95
|
+
onBackground = Color.White,
|
|
96
|
+
surface = WazeColors.DarkCardSurf,
|
|
97
|
+
onSurface = Color.White,
|
|
98
|
+
surfaceVariant = WazeColors.DarkSurface2,
|
|
99
|
+
outline = WazeColors.DarkDivider,
|
|
100
|
+
error = WazeColors.Error,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
@Composable
|
|
104
|
+
fun WazeTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) =
|
|
105
|
+
MaterialTheme(
|
|
106
|
+
colorScheme = if (darkTheme) WazeDark else WazeLight,
|
|
107
|
+
typography = WazeTypography,
|
|
108
|
+
content = content,
|
|
109
|
+
)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## 2. Typography
|
|
113
|
+
|
|
114
|
+
Waze ships **Boing**, a proprietary rounded sans — roundness IS the brand. The correct Android fallback is the rounded system family. Compose has no built-in `.rounded` design like iOS, so bundle Boing TTFs in `res/font/`; if unavailable, ship a rounded open-source face (Quicksand / Nunito) as the fallback `FontFamily`. **Boing Mono on every numeric** (distance, time, speed, ETA) — variable widths break the at-a-glance driving read.
|
|
115
|
+
|
|
116
|
+
```kotlin
|
|
117
|
+
// ui/theme/WazeType.kt
|
|
118
|
+
import androidx.compose.material3.Typography
|
|
119
|
+
import androidx.compose.ui.text.TextStyle
|
|
120
|
+
import androidx.compose.ui.text.font.Font
|
|
121
|
+
import androidx.compose.ui.text.font.FontFamily
|
|
122
|
+
import androidx.compose.ui.text.font.FontWeight
|
|
123
|
+
import androidx.compose.ui.unit.sp
|
|
124
|
+
|
|
125
|
+
// Boing, with a rounded open-source fallback (Quicksand/Nunito) bundled in res/font/
|
|
126
|
+
val Boing = FontFamily(
|
|
127
|
+
Font(R.font.boing_regular, FontWeight.Normal), // 400
|
|
128
|
+
Font(R.font.boing_bold, FontWeight.Bold), // 700
|
|
129
|
+
Font(R.font.boing_black, FontWeight.Black), // 900 — hero moments only
|
|
130
|
+
)
|
|
131
|
+
val BoingMono = FontFamily(
|
|
132
|
+
Font(R.font.boing_mono_medium, FontWeight.Medium),
|
|
133
|
+
Font(R.font.boing_mono_bold, FontWeight.Bold),
|
|
134
|
+
Font(R.font.boing_mono_black, FontWeight.Black),
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
// Named ramp — mirrors DESIGN.md §3 exactly (pt → sp 1:1). Numerics use BoingMono + tabular figures.
|
|
138
|
+
object WazeText {
|
|
139
|
+
val HeroStreet = TextStyle(Boing, fontWeight = FontWeight.Black, fontSize = 32.sp, lineHeight = 35.sp, letterSpacing = (-0.4).sp)
|
|
140
|
+
val NextTurnDist = TextStyle(BoingMono, fontWeight = FontWeight.Bold, fontSize = 28.sp, lineHeight = 31.sp, fontFeatureSettings = "tnum")
|
|
141
|
+
val StepTitle = TextStyle(Boing, fontWeight = FontWeight.Bold, fontSize = 22.sp, lineHeight = 26.sp, letterSpacing = (-0.2).sp)
|
|
142
|
+
val StepSubtitle = TextStyle(Boing, fontWeight = FontWeight.Normal, fontSize = 17.sp, lineHeight = 22.sp)
|
|
143
|
+
val ETATime = TextStyle(BoingMono, fontWeight = FontWeight.Bold, fontSize = 24.sp, lineHeight = 26.sp, fontFeatureSettings = "tnum")
|
|
144
|
+
val ETADistance = TextStyle(BoingMono, fontWeight = FontWeight.Medium, fontSize = 17.sp, lineHeight = 20.sp, fontFeatureSettings = "tnum")
|
|
145
|
+
val PlaceTitle = TextStyle(Boing, fontWeight = FontWeight.Bold, fontSize = 26.sp, lineHeight = 30.sp, letterSpacing = (-0.3).sp)
|
|
146
|
+
val PlaceSubtitle = TextStyle(Boing, fontWeight = FontWeight.Normal, fontSize = 15.sp, lineHeight = 20.sp)
|
|
147
|
+
val SearchHint = TextStyle(Boing, fontWeight = FontWeight.Normal, fontSize = 17.sp, lineHeight = 22.sp)
|
|
148
|
+
val Section = TextStyle(Boing, fontWeight = FontWeight.Bold, fontSize = 13.sp, lineHeight = 16.sp, letterSpacing = 0.6.sp) // UPPERCASE at call site
|
|
149
|
+
val ListTitle = TextStyle(Boing, fontWeight = FontWeight.Medium, fontSize = 17.sp, lineHeight = 22.sp)
|
|
150
|
+
val ListSubtitle = TextStyle(Boing, fontWeight = FontWeight.Normal, fontSize = 13.sp, lineHeight = 16.sp)
|
|
151
|
+
val SpeedLimitNum = TextStyle(BoingMono, fontWeight = FontWeight.Black, fontSize = 22.sp, lineHeight = 22.sp, fontFeatureSettings = "tnum")
|
|
152
|
+
val CurrentSpeed = TextStyle(BoingMono, fontWeight = FontWeight.Bold, fontSize = 32.sp, lineHeight = 32.sp, fontFeatureSettings = "tnum")
|
|
153
|
+
val SpeedLimitLbl = TextStyle(Boing, fontWeight = FontWeight.Bold, fontSize = 9.sp, lineHeight = 11.sp)
|
|
154
|
+
val MphLabel = TextStyle(Boing, fontWeight = FontWeight.Normal, fontSize = 11.sp, lineHeight = 13.sp)
|
|
155
|
+
val HazardTitle = TextStyle(Boing, fontWeight = FontWeight.Bold, fontSize = 14.sp, lineHeight = 15.sp)
|
|
156
|
+
val HazardTime = TextStyle(Boing, fontWeight = FontWeight.Normal, fontSize = 11.sp, lineHeight = 12.sp)
|
|
157
|
+
val Button = TextStyle(Boing, fontWeight = FontWeight.Bold, fontSize = 17.sp, lineHeight = 17.sp)
|
|
158
|
+
val Caption = TextStyle(Boing, fontWeight = FontWeight.Normal, fontSize = 12.sp, lineHeight = 16.sp)
|
|
159
|
+
val Tab = TextStyle(Boing, fontWeight = FontWeight.Medium, fontSize = 10.sp, lineHeight = 10.sp, letterSpacing = 0.1.sp)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Map onto Material 3 slots so stock components inherit the brand
|
|
163
|
+
val WazeTypography = Typography(
|
|
164
|
+
headlineLarge = WazeText.HeroStreet,
|
|
165
|
+
headlineSmall = WazeText.PlaceTitle,
|
|
166
|
+
titleMedium = WazeText.StepTitle,
|
|
167
|
+
bodyMedium = WazeText.PlaceSubtitle,
|
|
168
|
+
labelLarge = WazeText.Button,
|
|
169
|
+
labelSmall = WazeText.Tab,
|
|
170
|
+
)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## 3. Signature Components
|
|
174
|
+
|
|
175
|
+
### Hazard Speech Bubble (The Signature)
|
|
176
|
+
|
|
177
|
+
The single most recognizable component: a chunky 14.dp-corner rounded rectangle in a full-saturation hazard color with a **triangular tail** pointing down to the location. Implemented with a custom `Shape` for the tail (no SF Symbol / Compose primitive matches it).
|
|
178
|
+
|
|
179
|
+
```kotlin
|
|
180
|
+
import androidx.compose.animation.core.Animatable
|
|
181
|
+
import androidx.compose.animation.core.spring
|
|
182
|
+
import androidx.compose.foundation.background
|
|
183
|
+
import androidx.compose.foundation.layout.*
|
|
184
|
+
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
185
|
+
import androidx.compose.material.icons.Icons
|
|
186
|
+
import androidx.compose.material.icons.filled.*
|
|
187
|
+
import androidx.compose.material3.Icon
|
|
188
|
+
import androidx.compose.material3.Text
|
|
189
|
+
import androidx.compose.runtime.*
|
|
190
|
+
import androidx.compose.ui.Alignment
|
|
191
|
+
import androidx.compose.ui.Modifier
|
|
192
|
+
import androidx.compose.ui.draw.clip
|
|
193
|
+
import androidx.compose.ui.draw.drawBehind
|
|
194
|
+
import androidx.compose.ui.draw.shadow
|
|
195
|
+
import androidx.compose.ui.geometry.Offset
|
|
196
|
+
import androidx.compose.ui.graphics.Color
|
|
197
|
+
import androidx.compose.ui.graphics.Path
|
|
198
|
+
import androidx.compose.ui.graphics.drawscope.Stroke
|
|
199
|
+
import androidx.compose.ui.graphics.vector.ImageVector
|
|
200
|
+
import androidx.compose.ui.unit.dp
|
|
201
|
+
|
|
202
|
+
enum class HazardType { POLICE, TRAFFIC, CLOSURE, CLEARED, POTHOLE, CAMERA }
|
|
203
|
+
|
|
204
|
+
val HazardType.color: Color
|
|
205
|
+
get() = when (this) {
|
|
206
|
+
HazardType.POLICE -> WazeColors.PoliceRed
|
|
207
|
+
HazardType.TRAFFIC -> WazeColors.TrafficOrng
|
|
208
|
+
HazardType.CLOSURE -> WazeColors.ClosureYel
|
|
209
|
+
HazardType.CLEARED -> WazeColors.ClearedGrn
|
|
210
|
+
HazardType.POTHOLE -> WazeColors.HazardBrown
|
|
211
|
+
HazardType.CAMERA -> WazeColors.CameraGray
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
val HazardType.icon: ImageVector
|
|
215
|
+
get() = when (this) {
|
|
216
|
+
HazardType.POLICE -> Icons.Filled.Shield
|
|
217
|
+
HazardType.TRAFFIC -> Icons.Filled.Warning
|
|
218
|
+
HazardType.CLOSURE -> Icons.Filled.Block
|
|
219
|
+
HazardType.CLEARED -> Icons.Filled.CheckCircle
|
|
220
|
+
HazardType.POTHOLE -> Icons.Filled.ReportProblem
|
|
221
|
+
HazardType.CAMERA -> Icons.Filled.CameraAlt
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
val HazardType.title: String
|
|
225
|
+
get() = name.lowercase().replaceFirstChar { it.uppercase() }
|
|
226
|
+
|
|
227
|
+
@Composable
|
|
228
|
+
fun HazardSpeechBubble(
|
|
229
|
+
type: HazardType,
|
|
230
|
+
timeAgo: String?,
|
|
231
|
+
modifier: Modifier = Modifier,
|
|
232
|
+
) {
|
|
233
|
+
val appear = remember { Animatable(0f) }
|
|
234
|
+
LaunchedEffect(Unit) {
|
|
235
|
+
appear.animateTo(1f, spring(dampingRatio = 0.55f, stiffness = 400f)) // pop: 0 → 1.15 → 1.0
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
Column(
|
|
239
|
+
modifier = modifier
|
|
240
|
+
.graphicsLayer { scaleX = appear.value; scaleY = appear.value }
|
|
241
|
+
.shadow(12.dp, RoundedCornerShape(14.dp), spotColor = Color.Black.copy(alpha = 0.2f)),
|
|
242
|
+
horizontalAlignment = Alignment.CenterHorizontally,
|
|
243
|
+
) {
|
|
244
|
+
Row(
|
|
245
|
+
Modifier
|
|
246
|
+
.clip(RoundedCornerShape(14.dp))
|
|
247
|
+
.background(type.color)
|
|
248
|
+
.widthIn(min = 88.dp)
|
|
249
|
+
.padding(horizontal = 12.dp, vertical = 8.dp),
|
|
250
|
+
verticalAlignment = Alignment.CenterVertically,
|
|
251
|
+
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
|
252
|
+
) {
|
|
253
|
+
Icon(type.icon, contentDescription = null, tint = Color.White, modifier = Modifier.size(24.dp))
|
|
254
|
+
Column {
|
|
255
|
+
Text(type.title, style = WazeText.HazardTitle, color = Color.White)
|
|
256
|
+
if (timeAgo != null) Text(timeAgo, style = WazeText.HazardTime, color = Color.White.copy(alpha = 0.8f))
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// Downward triangular tail — custom drawn, same color as the bubble
|
|
260
|
+
Box(
|
|
261
|
+
Modifier
|
|
262
|
+
.size(12.dp, 8.dp)
|
|
263
|
+
.drawBehind {
|
|
264
|
+
val p = Path().apply {
|
|
265
|
+
moveTo(0f, 0f)
|
|
266
|
+
lineTo(size.width, 0f)
|
|
267
|
+
lineTo(size.width / 2f, size.height)
|
|
268
|
+
close()
|
|
269
|
+
}
|
|
270
|
+
drawPath(p, type.color)
|
|
271
|
+
}
|
|
272
|
+
)
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Report FAB (Tinted Purple Shadow — Signature)
|
|
278
|
+
|
|
279
|
+
Bottom-right Waze Purple circle with a **tinted purple shadow** (`spotColor` purple, not black). Opens the report wheel.
|
|
280
|
+
|
|
281
|
+
```kotlin
|
|
282
|
+
import androidx.compose.animation.core.animateFloatAsState
|
|
283
|
+
import androidx.compose.foundation.clickable
|
|
284
|
+
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
285
|
+
import androidx.compose.foundation.interaction.collectIsPressedAsState
|
|
286
|
+
import androidx.compose.foundation.shape.CircleShape
|
|
287
|
+
import androidx.compose.ui.draw.scale
|
|
288
|
+
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
|
289
|
+
import androidx.compose.ui.platform.LocalHapticFeedback
|
|
290
|
+
|
|
291
|
+
@Composable
|
|
292
|
+
fun WazeFAB(onClick: () -> Unit, modifier: Modifier = Modifier) {
|
|
293
|
+
val interaction = remember { MutableInteractionSource() }
|
|
294
|
+
val pressed by interaction.collectIsPressedAsState()
|
|
295
|
+
val scale by animateFloatAsState(if (pressed) 0.94f else 1f, label = "fabScale")
|
|
296
|
+
val haptics = LocalHapticFeedback.current
|
|
297
|
+
|
|
298
|
+
Box(
|
|
299
|
+
modifier = modifier
|
|
300
|
+
.size(56.dp)
|
|
301
|
+
.scale(scale)
|
|
302
|
+
.shadow(16.dp, CircleShape, spotColor = WazeColors.Purple, ambientColor = WazeColors.Purple) // SIGNATURE tinted purple
|
|
303
|
+
.clip(CircleShape)
|
|
304
|
+
.background(if (pressed) WazeColors.PurpleDeep else WazeColors.Purple)
|
|
305
|
+
.clickable(interaction, indication = null) {
|
|
306
|
+
haptics.performHapticFeedback(HapticFeedbackType.LongPress) // ~iOS medium impact
|
|
307
|
+
onClick()
|
|
308
|
+
}
|
|
309
|
+
.semantics { contentDescription = "Report a hazard" },
|
|
310
|
+
contentAlignment = Alignment.Center,
|
|
311
|
+
) {
|
|
312
|
+
Icon(Icons.Filled.Campaign, contentDescription = null, tint = Color.White, modifier = Modifier.size(24.dp))
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
> `spotColor` is honored on API 28+; on older devices draw a soft purple radial glow behind the circle so the signature reads on every device.
|
|
318
|
+
|
|
319
|
+
### Current-Location Puck (Cyan Arrow with Pulse)
|
|
320
|
+
|
|
321
|
+
Waze's puck is a **chunky cyan arrow** (NOT a dot), white-outlined, rotating with heading, with a faint 60.dp pulse ring. Both the arrow and the pulse are custom-drawn.
|
|
322
|
+
|
|
323
|
+
```kotlin
|
|
324
|
+
import androidx.compose.animation.core.*
|
|
325
|
+
import androidx.compose.foundation.Canvas
|
|
326
|
+
import androidx.compose.ui.geometry.Size
|
|
327
|
+
import androidx.compose.ui.graphics.StrokeCap
|
|
328
|
+
import androidx.compose.ui.graphics.drawscope.Stroke as DrawStroke
|
|
329
|
+
|
|
330
|
+
@Composable
|
|
331
|
+
fun WazeLocationPuck(headingDegrees: Float, modifier: Modifier = Modifier) {
|
|
332
|
+
val t = rememberInfiniteTransition(label = "puck")
|
|
333
|
+
val pulse by t.animateFloat(
|
|
334
|
+
0f, 1f, infiniteRepeatable(tween(2000, easing = LinearEasing), RepeatMode.Restart), label = "pulse",
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
Box(modifier, contentAlignment = Alignment.Center) {
|
|
338
|
+
// Outer cyan pulse ring — 0.15 alpha, scale 1.0 → 1.5
|
|
339
|
+
Box(
|
|
340
|
+
Modifier
|
|
341
|
+
.size(60.dp)
|
|
342
|
+
.graphicsLayer { scaleX = 1f + pulse * 0.5f; scaleY = 1f + pulse * 0.5f }
|
|
343
|
+
.background(WazeColors.Cyan.copy(alpha = 0.15f * (1f - pulse)), CircleShape)
|
|
344
|
+
)
|
|
345
|
+
// Chunky cyan arrow, rotates with heading, 3.dp white outline
|
|
346
|
+
Canvas(
|
|
347
|
+
Modifier.size(32.dp, 36.dp).graphicsLayer { rotationZ = headingDegrees }
|
|
348
|
+
) {
|
|
349
|
+
val w = size.width
|
|
350
|
+
val h = size.height
|
|
351
|
+
val arrow = Path().apply {
|
|
352
|
+
moveTo(w * 0.5f, 0f) // tip
|
|
353
|
+
lineTo(w, h * 0.85f) // bottom-right
|
|
354
|
+
lineTo(w * 0.5f, h * 0.70f) // V indent
|
|
355
|
+
lineTo(0f, h * 0.85f) // bottom-left
|
|
356
|
+
close()
|
|
357
|
+
}
|
|
358
|
+
drawPath(arrow, WazeColors.Cyan)
|
|
359
|
+
drawPath(arrow, Color.White, style = DrawStroke(width = 3.dp.toPx()))
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Next-Turn Card (Top of Screen During Navigation)
|
|
366
|
+
|
|
367
|
+
Full-width 100.dp solid Waze Purple card, 16.dp **bottom** corners only (extends into the safe area on top), big direction arrow + Mono distance + street name.
|
|
368
|
+
|
|
369
|
+
```kotlin
|
|
370
|
+
@Composable
|
|
371
|
+
fun NextTurnCard(
|
|
372
|
+
arrowIcon: ImageVector, // e.g. Icons.AutoMirrored.Filled.TurnRight
|
|
373
|
+
arrowRotation: Float,
|
|
374
|
+
distance: String, // "0.4 mi"
|
|
375
|
+
streetName: String, // "Market Street"
|
|
376
|
+
subInstruction: String?, // "then turn left in 0.6 mi"
|
|
377
|
+
modifier: Modifier = Modifier,
|
|
378
|
+
) {
|
|
379
|
+
Row(
|
|
380
|
+
modifier = modifier
|
|
381
|
+
.fillMaxWidth()
|
|
382
|
+
.clip(RoundedCornerShape(bottomStart = 16.dp, bottomEnd = 16.dp)) // top extends into safe area
|
|
383
|
+
.background(WazeColors.Purple)
|
|
384
|
+
.padding(horizontal = 20.dp, vertical = 16.dp),
|
|
385
|
+
verticalAlignment = Alignment.CenterVertically,
|
|
386
|
+
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
|
387
|
+
) {
|
|
388
|
+
Icon(
|
|
389
|
+
arrowIcon, contentDescription = null, tint = Color.White,
|
|
390
|
+
modifier = Modifier.size(64.dp).graphicsLayer { rotationZ = arrowRotation },
|
|
391
|
+
)
|
|
392
|
+
Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
|
393
|
+
Text(distance, style = WazeText.NextTurnDist, color = Color.White)
|
|
394
|
+
Text(streetName, style = WazeText.StepTitle, color = Color.White, maxLines = 2)
|
|
395
|
+
if (subInstruction != null) {
|
|
396
|
+
Text(subInstruction, style = WazeText.Caption.copy(fontSize = 14.sp), color = Color.White.copy(alpha = 0.8f))
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Speed Limit + Current Speed Tile
|
|
404
|
+
|
|
405
|
+
US-style speed-limit signage as an 80×80.dp bottom-left tile; the current-speed number flips red when speeding.
|
|
406
|
+
|
|
407
|
+
```kotlin
|
|
408
|
+
import androidx.compose.foundation.border
|
|
409
|
+
import androidx.compose.material3.HorizontalDivider
|
|
410
|
+
|
|
411
|
+
@Composable
|
|
412
|
+
fun SpeedTile(limit: Int, current: Int, modifier: Modifier = Modifier) {
|
|
413
|
+
val speeding = current > limit
|
|
414
|
+
Column(
|
|
415
|
+
modifier = modifier
|
|
416
|
+
.width(80.dp)
|
|
417
|
+
.shadow(8.dp, RoundedCornerShape(12.dp), spotColor = Color.Black.copy(alpha = 0.10f))
|
|
418
|
+
.clip(RoundedCornerShape(12.dp))
|
|
419
|
+
.background(WazeColors.CardCanvas)
|
|
420
|
+
.padding(8.dp),
|
|
421
|
+
horizontalAlignment = Alignment.CenterHorizontally,
|
|
422
|
+
verticalArrangement = Arrangement.spacedBy(6.dp),
|
|
423
|
+
) {
|
|
424
|
+
Text("SPEED LIMIT", style = WazeText.SpeedLimitLbl, color = WazeColors.Ink)
|
|
425
|
+
Box(
|
|
426
|
+
Modifier.size(40.dp).clip(CircleShape).background(Color.White).border(2.dp, WazeColors.Ink, CircleShape),
|
|
427
|
+
contentAlignment = Alignment.Center,
|
|
428
|
+
) { Text("$limit", style = WazeText.SpeedLimitNum, color = WazeColors.Ink) }
|
|
429
|
+
HorizontalDivider(color = WazeColors.Divider, modifier = Modifier.padding(horizontal = 8.dp))
|
|
430
|
+
Row(verticalAlignment = Alignment.Bottom, horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
|
431
|
+
Text("$current", style = WazeText.CurrentSpeed, color = if (speeding) WazeColors.Error else WazeColors.Ink)
|
|
432
|
+
Text("mph", style = WazeText.MphLabel, color = WazeColors.Secondary)
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### ETA Bottom Bar & "Go" Button
|
|
439
|
+
|
|
440
|
+
```kotlin
|
|
441
|
+
@Composable
|
|
442
|
+
fun WazeETABar(
|
|
443
|
+
duration: String, // "12 min"
|
|
444
|
+
distance: String, // "5.2 mi"
|
|
445
|
+
arrival: String, // "6:14 PM"
|
|
446
|
+
alternativeRouteSaves: String?, // "Save 3 min"
|
|
447
|
+
onEnd: () -> Unit,
|
|
448
|
+
modifier: Modifier = Modifier,
|
|
449
|
+
) {
|
|
450
|
+
Row(
|
|
451
|
+
modifier = modifier.fillMaxWidth().height(80.dp).background(WazeColors.CardCanvas).padding(horizontal = 20.dp),
|
|
452
|
+
verticalAlignment = Alignment.CenterVertically,
|
|
453
|
+
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
|
454
|
+
) {
|
|
455
|
+
Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
|
456
|
+
Text(duration, style = WazeText.ETATime, color = WazeColors.Ink)
|
|
457
|
+
Text("$distance · $arrival", style = WazeText.ETADistance, color = WazeColors.Secondary)
|
|
458
|
+
}
|
|
459
|
+
if (alternativeRouteSaves != null) {
|
|
460
|
+
Box(
|
|
461
|
+
Modifier.clip(CircleShape).background(WazeColors.ClearedGrn).padding(horizontal = 14.dp, vertical = 8.dp)
|
|
462
|
+
) { Text(alternativeRouteSaves, style = WazeText.Button.copy(fontSize = 14.sp), color = Color.White) }
|
|
463
|
+
}
|
|
464
|
+
Box(
|
|
465
|
+
Modifier.clip(CircleShape).background(WazeColors.CardCanvas).border(1.5.dp, WazeColors.Error, CircleShape)
|
|
466
|
+
.clickable(onClick = onEnd).padding(horizontal = 20.dp, vertical = 12.dp)
|
|
467
|
+
) { Text("End", style = WazeText.Button, color = WazeColors.Error) }
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
@Composable
|
|
472
|
+
fun WazeGoButton(onClick: () -> Unit, modifier: Modifier = Modifier) {
|
|
473
|
+
val interaction = remember { MutableInteractionSource() }
|
|
474
|
+
val pressed by interaction.collectIsPressedAsState()
|
|
475
|
+
val scale by animateFloatAsState(if (pressed) 0.97f else 1f, label = "goScale")
|
|
476
|
+
val haptics = LocalHapticFeedback.current
|
|
477
|
+
|
|
478
|
+
Box(
|
|
479
|
+
modifier = modifier
|
|
480
|
+
.fillMaxWidth()
|
|
481
|
+
.height(56.dp)
|
|
482
|
+
.scale(scale)
|
|
483
|
+
.shadow(12.dp, CircleShape, spotColor = WazeColors.Purple, ambientColor = WazeColors.Purple) // tinted purple
|
|
484
|
+
.clip(CircleShape)
|
|
485
|
+
.background(if (pressed) WazeColors.PurpleDeep else WazeColors.Purple)
|
|
486
|
+
.clickable(interaction, indication = null) {
|
|
487
|
+
haptics.performHapticFeedback(HapticFeedbackType.LongPress) // ~iOS heavy impact (see §6 for stronger)
|
|
488
|
+
onClick()
|
|
489
|
+
},
|
|
490
|
+
contentAlignment = Alignment.Center,
|
|
491
|
+
) {
|
|
492
|
+
Text("Go", style = WazeText.Button, color = Color.White)
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
## 4. Loud Cartography + Report Wheel (the distinctive interaction)
|
|
498
|
+
|
|
499
|
+
Waze has no color extraction. Its defining systems are the **loud saturated cartography** and the **cartoon report wheel**. Use Google Maps Compose with a JSON style built from the bright Waze tokens; the polyline is a 6.dp purple "ant trail".
|
|
500
|
+
|
|
501
|
+
```kotlin
|
|
502
|
+
import com.google.maps.android.compose.GoogleMap
|
|
503
|
+
import com.google.maps.android.compose.MapProperties
|
|
504
|
+
import com.google.maps.android.compose.Polyline
|
|
505
|
+
import com.google.maps.android.compose.rememberCameraPositionState
|
|
506
|
+
import com.google.android.gms.maps.model.MapStyleOptions
|
|
507
|
+
import com.google.android.gms.maps.model.LatLng
|
|
508
|
+
import com.google.android.gms.maps.model.RoundCap
|
|
509
|
+
|
|
510
|
+
@Composable
|
|
511
|
+
fun WazeMap(route: List<LatLng>, modifier: Modifier = Modifier, darkTheme: Boolean = isSystemInDarkTheme()) {
|
|
512
|
+
val cameraPositionState = rememberCameraPositionState()
|
|
513
|
+
GoogleMap(
|
|
514
|
+
modifier = modifier.fillMaxSize(),
|
|
515
|
+
cameraPositionState = cameraPositionState,
|
|
516
|
+
properties = MapProperties(
|
|
517
|
+
// JSON style from Waze tokens: water #9BDEEF, parks #C5E89B, land #FFFCF2,
|
|
518
|
+
// highways #FFD970, roads #FFFFFF — LOUD by design (dark: #0F3D5E / #1F3A1F / #1E2026)
|
|
519
|
+
mapStyleOptions = MapStyleOptions(if (darkTheme) WAZE_MAP_STYLE_DARK else WAZE_MAP_STYLE_LIGHT),
|
|
520
|
+
),
|
|
521
|
+
) {
|
|
522
|
+
Polyline(
|
|
523
|
+
points = route,
|
|
524
|
+
color = WazeColors.Purple, // 6.dp purple — thicker than typical
|
|
525
|
+
width = with(androidx.compose.ui.platform.LocalDensity.current) { 6.dp.toPx() },
|
|
526
|
+
startCap = RoundCap(), endCap = RoundCap(),
|
|
527
|
+
)
|
|
528
|
+
// Ant-trail chevron overlay: a second dashed polyline whose pattern offset animates (see §6)
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
const val WAZE_MAP_STYLE_LIGHT = """[ /* water #9BDEEF, parks #C5E89B, land #FFFCF2, highway #FFD970, roads #FFFFFF */ ]"""
|
|
533
|
+
const val WAZE_MAP_STYLE_DARK = """[ /* water #0F3D5E, parks #1F3A1F, land #1E2026, roads #2F2F2F */ ]"""
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### Report Wheel (Cartoon Dial)
|
|
537
|
+
|
|
538
|
+
A literal cartoon dial — embrace it, never tone it down. 8 wedges of hazard icons over a purple scrim.
|
|
539
|
+
|
|
540
|
+
```kotlin
|
|
541
|
+
import androidx.compose.foundation.layout.Box
|
|
542
|
+
import kotlin.math.cos
|
|
543
|
+
import kotlin.math.sin
|
|
544
|
+
|
|
545
|
+
@Composable
|
|
546
|
+
fun ReportWheel(
|
|
547
|
+
onPick: (HazardType) -> Unit,
|
|
548
|
+
onClose: () -> Unit,
|
|
549
|
+
modifier: Modifier = Modifier,
|
|
550
|
+
) {
|
|
551
|
+
val types = listOf(
|
|
552
|
+
HazardType.POLICE, HazardType.TRAFFIC, HazardType.CLOSURE, HazardType.POTHOLE,
|
|
553
|
+
HazardType.CAMERA, HazardType.CLEARED,
|
|
554
|
+
)
|
|
555
|
+
val wheelScale = remember { Animatable(0f) }
|
|
556
|
+
LaunchedEffect(Unit) { wheelScale.animateTo(1f, spring(dampingRatio = 0.7f, stiffness = 300f)) } // spins in
|
|
557
|
+
|
|
558
|
+
Box(
|
|
559
|
+
modifier
|
|
560
|
+
.fillMaxSize()
|
|
561
|
+
.background(WazeColors.Purple.copy(alpha = 0.85f)) // semi-transparent purple scrim
|
|
562
|
+
.clickable(interactionSource = remember { MutableInteractionSource() }, indication = null, onClick = onClose),
|
|
563
|
+
contentAlignment = Alignment.BottomCenter,
|
|
564
|
+
) {
|
|
565
|
+
Box(
|
|
566
|
+
Modifier
|
|
567
|
+
.padding(bottom = 80.dp)
|
|
568
|
+
.size(280.dp)
|
|
569
|
+
.graphicsLayer { scaleX = wheelScale.value; scaleY = wheelScale.value }
|
|
570
|
+
.clip(CircleShape)
|
|
571
|
+
.background(WazeColors.CardCanvas),
|
|
572
|
+
contentAlignment = Alignment.Center,
|
|
573
|
+
) {
|
|
574
|
+
types.forEachIndexed { i, type ->
|
|
575
|
+
val angle = Math.toRadians((i * (360.0 / types.size)) - 90.0)
|
|
576
|
+
val r = 90.dp
|
|
577
|
+
Box(
|
|
578
|
+
Modifier
|
|
579
|
+
.offset(x = (cos(angle) * r.value).dp, y = (sin(angle) * r.value).dp)
|
|
580
|
+
.size(44.dp).clip(CircleShape).background(type.color.copy(alpha = 0.20f))
|
|
581
|
+
.clickable { onPick(type) },
|
|
582
|
+
contentAlignment = Alignment.Center,
|
|
583
|
+
) { Icon(type.icon, contentDescription = type.title, tint = type.color, modifier = Modifier.size(28.dp)) }
|
|
584
|
+
}
|
|
585
|
+
Box(
|
|
586
|
+
Modifier.size(56.dp).clip(CircleShape).background(WazeColors.SurfaceGray).clickable(onClick = onClose),
|
|
587
|
+
contentAlignment = Alignment.Center,
|
|
588
|
+
) { Icon(Icons.Filled.Close, contentDescription = "Close", tint = WazeColors.Ink, modifier = Modifier.size(24.dp)) }
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
## 5. Navigation (search bottom sheet, no tab bar)
|
|
595
|
+
|
|
596
|
+
Waze has no bottom tab bar during driving — the map is full-screen with the next-turn card on top, the ETA bar on the bottom, and a **search bottom sheet** (3 detents: small ≈88.dp, medium ≈50%, full). Android has no live blur; Waze uses a **solid white card** anyway (explicitly unlike Apple's translucent sheet), so a plain opaque `Surface` is the correct choice — no translucency needed.
|
|
597
|
+
|
|
598
|
+
```kotlin
|
|
599
|
+
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
600
|
+
import androidx.compose.material3.ModalBottomSheet
|
|
601
|
+
import androidx.compose.material3.rememberModalBottomSheetState
|
|
602
|
+
import androidx.compose.foundation.text.BasicTextField
|
|
603
|
+
import androidx.compose.ui.graphics.SolidColor
|
|
604
|
+
|
|
605
|
+
@OptIn(ExperimentalMaterial3Api::class)
|
|
606
|
+
@Composable
|
|
607
|
+
fun WazeSearchSheet(onDismiss: () -> Unit, content: @Composable ColumnScope.() -> Unit) {
|
|
608
|
+
ModalBottomSheet(
|
|
609
|
+
onDismissRequest = onDismiss,
|
|
610
|
+
sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = false),
|
|
611
|
+
containerColor = WazeColors.CardCanvas, // solid white — Waze never uses a translucent sheet
|
|
612
|
+
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
|
|
613
|
+
dragHandle = {
|
|
614
|
+
Box(Modifier.fillMaxWidth().padding(top = 8.dp, bottom = 8.dp), contentAlignment = Alignment.Center) {
|
|
615
|
+
Box(Modifier.size(36.dp, 5.dp).clip(RoundedCornerShape(2.5.dp)).background(WazeColors.Divider))
|
|
616
|
+
}
|
|
617
|
+
},
|
|
618
|
+
) {
|
|
619
|
+
Column(Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
|
620
|
+
Row(
|
|
621
|
+
Modifier.fillMaxWidth().height(48.dp).clip(RoundedCornerShape(16.dp)).background(WazeColors.SurfaceGray)
|
|
622
|
+
.padding(horizontal = 16.dp),
|
|
623
|
+
verticalAlignment = Alignment.CenterVertically,
|
|
624
|
+
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
|
625
|
+
) {
|
|
626
|
+
Icon(Icons.Filled.Search, null, tint = WazeColors.Secondary, modifier = Modifier.size(17.dp))
|
|
627
|
+
Text("Where to?", style = WazeText.SearchHint, color = WazeColors.Tertiary)
|
|
628
|
+
}
|
|
629
|
+
content()
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
## 6. Motion
|
|
636
|
+
|
|
637
|
+
| Moment | Compose recipe |
|
|
638
|
+
|--------|----------------|
|
|
639
|
+
| FAB tap | `animateFloatAsState(0.94f)` + shadow tighten; `HapticFeedbackType.LongPress` |
|
|
640
|
+
| Report wheel open | `Animatable.animateTo(1f, spring(dampingRatio = 0.7f, stiffness = 300f))` — wheel spins in (~350ms) |
|
|
641
|
+
| Hazard bubble appear | `Animatable.animateTo(1f, spring(dampingRatio = 0.55f))` — pop 0 → 1.15 → 1.0 over ~400ms |
|
|
642
|
+
| Hazard dismiss (timer) | `animateFloatAsState` alpha 1 → 0 over 1000ms + slight `rotationZ` |
|
|
643
|
+
| Location puck pulse | `rememberInfiniteTransition` scale 1.0 → 1.5, alpha 0.15 → 0, 2000ms `RepeatMode.Restart` |
|
|
644
|
+
| Polyline ant trail | animate a dash-phase `Float` linearly, 2s loop, `RepeatMode.Restart` |
|
|
645
|
+
| Next-turn update | `Crossfade` 250ms + arrow `rotationZ` to the new turn |
|
|
646
|
+
| "Go" tap | `animateFloatAsState(0.97f)` + heavy haptic; 400ms `Crossfade` into navigation mode |
|
|
647
|
+
| Reach destination | confetti/sparkle `Canvas` over the destination pin + success haptic |
|
|
648
|
+
|
|
649
|
+
```kotlin
|
|
650
|
+
// Polyline "ant trail" — animate the dash phase (DESIGN.md §6: 1 chevron / 2 s)
|
|
651
|
+
@Composable
|
|
652
|
+
fun rememberAntTrailPhase(): Float {
|
|
653
|
+
val t = rememberInfiniteTransition(label = "antTrail")
|
|
654
|
+
val phase by t.animateFloat(
|
|
655
|
+
0f, -24f, infiniteRepeatable(tween(2000, easing = LinearEasing), RepeatMode.Restart), label = "phase",
|
|
656
|
+
)
|
|
657
|
+
return phase // feed into a PathEffect dashPathEffect on a Canvas-drawn route overlay
|
|
658
|
+
}
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
Haptics: prefer `LocalHapticFeedback`. For the heavier "Go" / arrival moments use a `Vibrator` `VibrationEffect.createOneShot(25, VibrationEffect.DEFAULT_AMPLITUDE)` to approximate iOS `.impact(.heavy)` / `.success`; the speeding warning maps to a single `VibrationEffect.createOneShot(15, ...)` triggered once when current speed crosses the limit.
|
|
662
|
+
|
|
663
|
+
## 7. Icons
|
|
664
|
+
|
|
665
|
+
Waze ships custom cartoon glyphs (the police hat, the chunky direction arrows); the closest first-party set is `androidx.compose.material:material-icons-extended`. For the playful cartoon feel that makes contributing fun, export Waze's hazard glyphs and the direction arrows as vector drawables and load via `ImageVector.vectorResource(R.drawable.…)`. The triangular speech-bubble tail and the cyan arrow puck are custom `Path`s (above) — no SF Symbol or Compose primitive matches them.
|
|
666
|
+
|
|
667
|
+
| Purpose | SF Symbol (iOS) | Material Icon (Compose) |
|
|
668
|
+
|---------|-----------------|--------------------------|
|
|
669
|
+
| FAB report icon | `exclamationmark.bubble.fill` | `Icons.Filled.Campaign` (or custom speech-bubble drawable) |
|
|
670
|
+
| Police hazard | `shield.fill` (or custom hat) | `Icons.Filled.Shield` |
|
|
671
|
+
| Traffic hazard | `cone.fill` | `Icons.Filled.Warning` |
|
|
672
|
+
| Closure | `xmark.octagon.fill` | `Icons.Filled.Block` |
|
|
673
|
+
| Cleared | `checkmark.circle.fill` | `Icons.Filled.CheckCircle` |
|
|
674
|
+
| Pothole | `exclamationmark.triangle.fill` | `Icons.Filled.ReportProblem` |
|
|
675
|
+
| Camera | `camera.fill` | `Icons.Filled.CameraAlt` |
|
|
676
|
+
| Direction right / left | `arrow.turn.up.right` / `.left` | `Icons.AutoMirrored.Filled.TurnRight` / `TurnLeft` |
|
|
677
|
+
| Search | `magnifyingglass` | `Icons.Filled.Search` |
|
|
678
|
+
| Speed warning | `exclamationmark.octagon.fill` | `Icons.Filled.Report` |
|
|
679
|
+
| Beacon share | `bell.badge.fill` | `Icons.Filled.NotificationsActive` |
|
|
680
|
+
| Gas | `fuelpump.fill` | `Icons.Filled.LocalGasStation` |
|
|
681
|
+
| Home | `house.fill` | `Icons.Filled.Home` |
|
|
682
|
+
| Work | `briefcase.fill` | `Icons.Filled.Work` |
|
|
683
|
+
| Favorite | `star.fill` | `Icons.Filled.Star` |
|
|
684
|
+
| Recent | `clock` | `Icons.Filled.History` |
|
|
685
|
+
|
|
686
|
+
## 8. Minimum SDK & Accessibility Notes
|
|
687
|
+
|
|
688
|
+
- **minSdk 24** (Compose floor is 21; Maps Compose + the tinted shadows are comfortable at 24 — `spotColor` needs API 28+, fall back to a soft purple radial glow behind the FAB/"Go" on older devices). `compileSdk 34+`, Compose BOM `2024.09+`, Kotlin `2.0+`. Add a Maps API key in the manifest.
|
|
689
|
+
- **Edge-to-edge**: call `enableEdgeToEdge()`. The next-turn card intentionally extends into the status-bar area (top corners are square) with 16.dp of content padding from the safe-area top; the ETA bar and FAB respect `WindowInsets.navigationBars` (the FAB sits 16.dp above the ETA bar's inset).
|
|
690
|
+
- **Font scaling**: `sp` honors the user's font scale automatically — keep it on the place card title, body, list rows, and search. **FIX** the glance-critical text — next-turn card, ETA numbers, speed-limit number, hazard speech-bubble text are read at driving speed and must not reflow: derive from `dp` or wrap those subtrees in `CompositionLocalProvider(LocalDensity provides Density(density, fontScale = 1f))`.
|
|
691
|
+
- **TalkBack**: the hazard bubble reads as `"$type, reported $timeAgo, ahead"` via `Modifier.semantics(mergeDescendants = true)`; the location puck announces `"Your current position, heading <direction>"`; the speed tile reads limit + current speed and announces a warning state.
|
|
692
|
+
- **Touch targets**: Material guidance is 48.dp minimum. The 56.dp FAB and 56.dp "Go" button clear it; the full hazard bubble is tappable; report-wheel wedges are 44.dp (pad to a 48.dp hit slop); the Wazer avatar carries a 48.dp hit area on a 24.dp glyph.
|
|
693
|
+
- **Contrast**: Ink `#1A1A1A` on white passes WCAG AAA. White on Waze Purple `#7E55BE` passes AAA at all sizes (next-turn card, "Go"). The hazard speech bubbles use white text on full-saturation hazard colors — Closure Yellow `#F9C42E` with white is a known low-contrast pair; keep the 14sp Bold title weight (it passes AA at that weight) and never go below 14sp for hazard text. The 0.8-alpha white timestamp on hazard colors stays ≥11sp Bold-adjacent.
|
|
694
|
+
- **Reduce motion**: when a reduced-motion preference is set, skip the hazard "pop", freeze the location-puck pulse and the polyline ant trail (static), and replace the "Go" → navigation crossfade with an instant cut.
|
|
695
|
+
- **Dynamic color**: do **not** enable Material You `dynamicColorScheme` — Waze's identity is the fixed electric duo (Waze Purple `#7E55BE` + Cyan `#33CCFF`) and the full-saturation hazard palette. These must stay at brand saturation across light/dark/night modes; wallpaper-derived tints would mute the cartoon system and break the at-a-glance hazard color code.
|