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.
Files changed (907) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +119 -0
  3. package/dist/__tests__/designStore.test.js +41 -0
  4. package/dist/__tests__/linter.test.js +23 -0
  5. package/dist/__tests__/sectionParser.test.js +60 -0
  6. package/dist/__tests__/server.test.js +129 -0
  7. package/dist/constants.js +12 -0
  8. package/dist/data/authoring-guide.md +113 -0
  9. package/dist/data/designs/airbnb.md +545 -0
  10. package/dist/data/designs/airtable.md +554 -0
  11. package/dist/data/designs/apple.md +562 -0
  12. package/dist/data/designs/binance.md +634 -0
  13. package/dist/data/designs/bmw-m.md +503 -0
  14. package/dist/data/designs/bmw.md +544 -0
  15. package/dist/data/designs/bugatti.md +454 -0
  16. package/dist/data/designs/cal.md +542 -0
  17. package/dist/data/designs/card-heavy.md +250 -0
  18. package/dist/data/designs/claude.md +589 -0
  19. package/dist/data/designs/clay.md +541 -0
  20. package/dist/data/designs/clickhouse.md +544 -0
  21. package/dist/data/designs/cohere.md +451 -0
  22. package/dist/data/designs/coinbase.md +570 -0
  23. package/dist/data/designs/composio.md +506 -0
  24. package/dist/data/designs/content-first.md +236 -0
  25. package/dist/data/designs/cursor.md +537 -0
  26. package/dist/data/designs/data-dashboard.md +300 -0
  27. package/dist/data/designs/dell-1996.md +632 -0
  28. package/dist/data/designs/elevenlabs.md +504 -0
  29. package/dist/data/designs/enterprise-neutral.md +252 -0
  30. package/dist/data/designs/expo.md +526 -0
  31. package/dist/data/designs/ferrari.md +531 -0
  32. package/dist/data/designs/figma.md +578 -0
  33. package/dist/data/designs/framer.md +544 -0
  34. package/dist/data/designs/hashicorp.md +575 -0
  35. package/dist/data/designs/hp.md +670 -0
  36. package/dist/data/designs/ibm.md +550 -0
  37. package/dist/data/designs/intercom.md +546 -0
  38. package/dist/data/designs/ios-acorns-android.md +430 -0
  39. package/dist/data/designs/ios-acorns-expo.md +381 -0
  40. package/dist/data/designs/ios-acorns-swiftui.md +378 -0
  41. package/dist/data/designs/ios-acorns.md +384 -0
  42. package/dist/data/designs/ios-airbnb-android.md +658 -0
  43. package/dist/data/designs/ios-airbnb-expo.md +457 -0
  44. package/dist/data/designs/ios-airbnb-swiftui.md +464 -0
  45. package/dist/data/designs/ios-airbnb.md +410 -0
  46. package/dist/data/designs/ios-alltrails-android.md +451 -0
  47. package/dist/data/designs/ios-alltrails-expo.md +400 -0
  48. package/dist/data/designs/ios-alltrails-swiftui.md +343 -0
  49. package/dist/data/designs/ios-alltrails.md +344 -0
  50. package/dist/data/designs/ios-amazon-android.md +686 -0
  51. package/dist/data/designs/ios-amazon-expo.md +433 -0
  52. package/dist/data/designs/ios-amazon-music-android.md +416 -0
  53. package/dist/data/designs/ios-amazon-music-expo.md +368 -0
  54. package/dist/data/designs/ios-amazon-music-swiftui.md +436 -0
  55. package/dist/data/designs/ios-amazon-music.md +389 -0
  56. package/dist/data/designs/ios-amazon-swiftui.md +460 -0
  57. package/dist/data/designs/ios-amazon.md +440 -0
  58. package/dist/data/designs/ios-apple-fitness-android.md +462 -0
  59. package/dist/data/designs/ios-apple-fitness-expo.md +373 -0
  60. package/dist/data/designs/ios-apple-fitness-swiftui.md +373 -0
  61. package/dist/data/designs/ios-apple-fitness.md +399 -0
  62. package/dist/data/designs/ios-apple-maps-android.md +646 -0
  63. package/dist/data/designs/ios-apple-maps-expo.md +557 -0
  64. package/dist/data/designs/ios-apple-maps-swiftui.md +588 -0
  65. package/dist/data/designs/ios-apple-maps.md +447 -0
  66. package/dist/data/designs/ios-apple-music-android.md +737 -0
  67. package/dist/data/designs/ios-apple-music-expo.md +596 -0
  68. package/dist/data/designs/ios-apple-music-swiftui.md +578 -0
  69. package/dist/data/designs/ios-apple-music.md +494 -0
  70. package/dist/data/designs/ios-apple-notes-android.md +675 -0
  71. package/dist/data/designs/ios-apple-notes-expo.md +468 -0
  72. package/dist/data/designs/ios-apple-notes-swiftui.md +489 -0
  73. package/dist/data/designs/ios-apple-notes.md +413 -0
  74. package/dist/data/designs/ios-apple-tv-android.md +405 -0
  75. package/dist/data/designs/ios-apple-tv-expo.md +341 -0
  76. package/dist/data/designs/ios-apple-tv-swiftui.md +348 -0
  77. package/dist/data/designs/ios-apple-tv.md +390 -0
  78. package/dist/data/designs/ios-apple-wallet-android.md +617 -0
  79. package/dist/data/designs/ios-apple-wallet-expo.md +487 -0
  80. package/dist/data/designs/ios-apple-wallet-swiftui.md +425 -0
  81. package/dist/data/designs/ios-apple-wallet.md +360 -0
  82. package/dist/data/designs/ios-asana-android.md +435 -0
  83. package/dist/data/designs/ios-asana-expo.md +411 -0
  84. package/dist/data/designs/ios-asana-swiftui.md +416 -0
  85. package/dist/data/designs/ios-asana.md +433 -0
  86. package/dist/data/designs/ios-audible-android.md +450 -0
  87. package/dist/data/designs/ios-audible-expo.md +328 -0
  88. package/dist/data/designs/ios-audible-swiftui.md +418 -0
  89. package/dist/data/designs/ios-audible.md +364 -0
  90. package/dist/data/designs/ios-bandcamp-android.md +471 -0
  91. package/dist/data/designs/ios-bandcamp-expo.md +378 -0
  92. package/dist/data/designs/ios-bandcamp-swiftui.md +374 -0
  93. package/dist/data/designs/ios-bandcamp.md +372 -0
  94. package/dist/data/designs/ios-bear-android.md +496 -0
  95. package/dist/data/designs/ios-bear-expo.md +449 -0
  96. package/dist/data/designs/ios-bear-swiftui.md +479 -0
  97. package/dist/data/designs/ios-bear.md +412 -0
  98. package/dist/data/designs/ios-bereal-android.md +392 -0
  99. package/dist/data/designs/ios-bereal-expo.md +299 -0
  100. package/dist/data/designs/ios-bereal-swiftui.md +319 -0
  101. package/dist/data/designs/ios-bereal.md +336 -0
  102. package/dist/data/designs/ios-binance-android.md +481 -0
  103. package/dist/data/designs/ios-binance-expo.md +404 -0
  104. package/dist/data/designs/ios-binance-swiftui.md +418 -0
  105. package/dist/data/designs/ios-binance.md +410 -0
  106. package/dist/data/designs/ios-bluesky-android.md +442 -0
  107. package/dist/data/designs/ios-bluesky-expo.md +362 -0
  108. package/dist/data/designs/ios-bluesky-swiftui.md +328 -0
  109. package/dist/data/designs/ios-bluesky.md +338 -0
  110. package/dist/data/designs/ios-booking-android.md +471 -0
  111. package/dist/data/designs/ios-booking-expo.md +364 -0
  112. package/dist/data/designs/ios-booking-swiftui.md +377 -0
  113. package/dist/data/designs/ios-booking.md +346 -0
  114. package/dist/data/designs/ios-bumble-android.md +756 -0
  115. package/dist/data/designs/ios-bumble-expo.md +629 -0
  116. package/dist/data/designs/ios-bumble-swiftui.md +546 -0
  117. package/dist/data/designs/ios-bumble.md +424 -0
  118. package/dist/data/designs/ios-cal-ai-android.md +664 -0
  119. package/dist/data/designs/ios-cal-ai-expo.md +415 -0
  120. package/dist/data/designs/ios-cal-ai-swiftui.md +486 -0
  121. package/dist/data/designs/ios-cal-ai.md +387 -0
  122. package/dist/data/designs/ios-calm-android.md +431 -0
  123. package/dist/data/designs/ios-calm-expo.md +384 -0
  124. package/dist/data/designs/ios-calm-swiftui.md +327 -0
  125. package/dist/data/designs/ios-calm.md +356 -0
  126. package/dist/data/designs/ios-canva-android.md +469 -0
  127. package/dist/data/designs/ios-canva-expo.md +374 -0
  128. package/dist/data/designs/ios-canva-swiftui.md +422 -0
  129. package/dist/data/designs/ios-canva.md +395 -0
  130. package/dist/data/designs/ios-cash-app-android.md +601 -0
  131. package/dist/data/designs/ios-cash-app-expo.md +453 -0
  132. package/dist/data/designs/ios-cash-app-swiftui.md +463 -0
  133. package/dist/data/designs/ios-cash-app.md +365 -0
  134. package/dist/data/designs/ios-character-ai-android.md +489 -0
  135. package/dist/data/designs/ios-character-ai-expo.md +420 -0
  136. package/dist/data/designs/ios-character-ai-swiftui.md +417 -0
  137. package/dist/data/designs/ios-character-ai.md +392 -0
  138. package/dist/data/designs/ios-charles-schwab-android.md +454 -0
  139. package/dist/data/designs/ios-charles-schwab-expo.md +388 -0
  140. package/dist/data/designs/ios-charles-schwab-swiftui.md +394 -0
  141. package/dist/data/designs/ios-charles-schwab.md +380 -0
  142. package/dist/data/designs/ios-chatgpt-android.md +753 -0
  143. package/dist/data/designs/ios-chatgpt-expo.md +644 -0
  144. package/dist/data/designs/ios-chatgpt-swiftui.md +653 -0
  145. package/dist/data/designs/ios-chatgpt.md +466 -0
  146. package/dist/data/designs/ios-chime-android.md +438 -0
  147. package/dist/data/designs/ios-chime-expo.md +419 -0
  148. package/dist/data/designs/ios-chime-swiftui.md +383 -0
  149. package/dist/data/designs/ios-chime.md +389 -0
  150. package/dist/data/designs/ios-chipotle-android.md +397 -0
  151. package/dist/data/designs/ios-chipotle-expo.md +301 -0
  152. package/dist/data/designs/ios-chipotle-swiftui.md +345 -0
  153. package/dist/data/designs/ios-chipotle.md +340 -0
  154. package/dist/data/designs/ios-citymapper-android.md +466 -0
  155. package/dist/data/designs/ios-citymapper-expo.md +420 -0
  156. package/dist/data/designs/ios-citymapper-swiftui.md +424 -0
  157. package/dist/data/designs/ios-citymapper.md +394 -0
  158. package/dist/data/designs/ios-claude-android.md +625 -0
  159. package/dist/data/designs/ios-claude-expo.md +671 -0
  160. package/dist/data/designs/ios-claude-swiftui.md +649 -0
  161. package/dist/data/designs/ios-claude.md +447 -0
  162. package/dist/data/designs/ios-clickup-android.md +484 -0
  163. package/dist/data/designs/ios-clickup-expo.md +423 -0
  164. package/dist/data/designs/ios-clickup-swiftui.md +416 -0
  165. package/dist/data/designs/ios-clickup.md +431 -0
  166. package/dist/data/designs/ios-clubhouse-android.md +524 -0
  167. package/dist/data/designs/ios-clubhouse-expo.md +425 -0
  168. package/dist/data/designs/ios-clubhouse-swiftui.md +447 -0
  169. package/dist/data/designs/ios-clubhouse.md +406 -0
  170. package/dist/data/designs/ios-coffee-meets-bagel-android.md +461 -0
  171. package/dist/data/designs/ios-coffee-meets-bagel-expo.md +372 -0
  172. package/dist/data/designs/ios-coffee-meets-bagel-swiftui.md +368 -0
  173. package/dist/data/designs/ios-coffee-meets-bagel.md +376 -0
  174. package/dist/data/designs/ios-coinbase-android.md +611 -0
  175. package/dist/data/designs/ios-coinbase-expo.md +500 -0
  176. package/dist/data/designs/ios-coinbase-swiftui.md +490 -0
  177. package/dist/data/designs/ios-coinbase.md +409 -0
  178. package/dist/data/designs/ios-copilot-android.md +625 -0
  179. package/dist/data/designs/ios-copilot-expo.md +423 -0
  180. package/dist/data/designs/ios-copilot-swiftui.md +471 -0
  181. package/dist/data/designs/ios-copilot.md +367 -0
  182. package/dist/data/designs/ios-craft-android.md +459 -0
  183. package/dist/data/designs/ios-craft-expo.md +417 -0
  184. package/dist/data/designs/ios-craft-swiftui.md +449 -0
  185. package/dist/data/designs/ios-craft.md +449 -0
  186. package/dist/data/designs/ios-crunchyroll-android.md +432 -0
  187. package/dist/data/designs/ios-crunchyroll-expo.md +388 -0
  188. package/dist/data/designs/ios-crunchyroll-swiftui.md +417 -0
  189. package/dist/data/designs/ios-crunchyroll.md +388 -0
  190. package/dist/data/designs/ios-crypto-com-android.md +461 -0
  191. package/dist/data/designs/ios-crypto-com-expo.md +404 -0
  192. package/dist/data/designs/ios-crypto-com-swiftui.md +419 -0
  193. package/dist/data/designs/ios-crypto-com.md +410 -0
  194. package/dist/data/designs/ios-deepseek-android.md +471 -0
  195. package/dist/data/designs/ios-deepseek-expo.md +391 -0
  196. package/dist/data/designs/ios-deepseek-swiftui.md +354 -0
  197. package/dist/data/designs/ios-deepseek.md +393 -0
  198. package/dist/data/designs/ios-deezer-android.md +475 -0
  199. package/dist/data/designs/ios-deezer-expo.md +400 -0
  200. package/dist/data/designs/ios-deezer-swiftui.md +430 -0
  201. package/dist/data/designs/ios-deezer.md +388 -0
  202. package/dist/data/designs/ios-deliveroo-android.md +493 -0
  203. package/dist/data/designs/ios-deliveroo-expo.md +424 -0
  204. package/dist/data/designs/ios-deliveroo-swiftui.md +398 -0
  205. package/dist/data/designs/ios-deliveroo.md +420 -0
  206. package/dist/data/designs/ios-delta-android.md +439 -0
  207. package/dist/data/designs/ios-delta-expo.md +381 -0
  208. package/dist/data/designs/ios-delta-swiftui.md +400 -0
  209. package/dist/data/designs/ios-delta.md +397 -0
  210. package/dist/data/designs/ios-discord-android.md +611 -0
  211. package/dist/data/designs/ios-discord-expo.md +618 -0
  212. package/dist/data/designs/ios-discord-swiftui.md +630 -0
  213. package/dist/data/designs/ios-discord.md +451 -0
  214. package/dist/data/designs/ios-disney-plus-android.md +464 -0
  215. package/dist/data/designs/ios-disney-plus-expo.md +358 -0
  216. package/dist/data/designs/ios-disney-plus-swiftui.md +412 -0
  217. package/dist/data/designs/ios-disney-plus.md +355 -0
  218. package/dist/data/designs/ios-dominos-android.md +417 -0
  219. package/dist/data/designs/ios-dominos-expo.md +316 -0
  220. package/dist/data/designs/ios-dominos-swiftui.md +340 -0
  221. package/dist/data/designs/ios-dominos.md +347 -0
  222. package/dist/data/designs/ios-doordash-android.md +527 -0
  223. package/dist/data/designs/ios-doordash-expo.md +323 -0
  224. package/dist/data/designs/ios-doordash-swiftui.md +301 -0
  225. package/dist/data/designs/ios-doordash.md +393 -0
  226. package/dist/data/designs/ios-dropbox-android.md +522 -0
  227. package/dist/data/designs/ios-dropbox-expo.md +393 -0
  228. package/dist/data/designs/ios-dropbox-swiftui.md +400 -0
  229. package/dist/data/designs/ios-dropbox.md +374 -0
  230. package/dist/data/designs/ios-duolingo-android.md +641 -0
  231. package/dist/data/designs/ios-duolingo-expo.md +597 -0
  232. package/dist/data/designs/ios-duolingo-swiftui.md +539 -0
  233. package/dist/data/designs/ios-duolingo.md +409 -0
  234. package/dist/data/designs/ios-ebay-android.md +436 -0
  235. package/dist/data/designs/ios-ebay-expo.md +344 -0
  236. package/dist/data/designs/ios-ebay-swiftui.md +308 -0
  237. package/dist/data/designs/ios-ebay.md +355 -0
  238. package/dist/data/designs/ios-espn-android.md +468 -0
  239. package/dist/data/designs/ios-espn-expo.md +387 -0
  240. package/dist/data/designs/ios-espn-swiftui.md +410 -0
  241. package/dist/data/designs/ios-espn.md +384 -0
  242. package/dist/data/designs/ios-etsy-android.md +439 -0
  243. package/dist/data/designs/ios-etsy-expo.md +351 -0
  244. package/dist/data/designs/ios-etsy-swiftui.md +296 -0
  245. package/dist/data/designs/ios-etsy.md +355 -0
  246. package/dist/data/designs/ios-evernote-android.md +419 -0
  247. package/dist/data/designs/ios-evernote-expo.md +379 -0
  248. package/dist/data/designs/ios-evernote-swiftui.md +380 -0
  249. package/dist/data/designs/ios-evernote.md +416 -0
  250. package/dist/data/designs/ios-expedia-android.md +451 -0
  251. package/dist/data/designs/ios-expedia-expo.md +433 -0
  252. package/dist/data/designs/ios-expedia-swiftui.md +399 -0
  253. package/dist/data/designs/ios-expedia.md +431 -0
  254. package/dist/data/designs/ios-facebook-android.md +628 -0
  255. package/dist/data/designs/ios-facebook-expo.md +471 -0
  256. package/dist/data/designs/ios-facebook-swiftui.md +459 -0
  257. package/dist/data/designs/ios-facebook.md +452 -0
  258. package/dist/data/designs/ios-feeld-android.md +431 -0
  259. package/dist/data/designs/ios-feeld-expo.md +379 -0
  260. package/dist/data/designs/ios-feeld-swiftui.md +401 -0
  261. package/dist/data/designs/ios-feeld.md +378 -0
  262. package/dist/data/designs/ios-fidelity-android.md +426 -0
  263. package/dist/data/designs/ios-fidelity-expo.md +396 -0
  264. package/dist/data/designs/ios-fidelity-swiftui.md +398 -0
  265. package/dist/data/designs/ios-fidelity.md +387 -0
  266. package/dist/data/designs/ios-figma-android.md +578 -0
  267. package/dist/data/designs/ios-figma-expo.md +504 -0
  268. package/dist/data/designs/ios-figma-swiftui.md +542 -0
  269. package/dist/data/designs/ios-figma.md +404 -0
  270. package/dist/data/designs/ios-fitbit-android.md +439 -0
  271. package/dist/data/designs/ios-fitbit-expo.md +389 -0
  272. package/dist/data/designs/ios-fitbit-swiftui.md +380 -0
  273. package/dist/data/designs/ios-fitbit.md +396 -0
  274. package/dist/data/designs/ios-flickr-android.md +506 -0
  275. package/dist/data/designs/ios-flickr-expo.md +434 -0
  276. package/dist/data/designs/ios-flickr-swiftui.md +421 -0
  277. package/dist/data/designs/ios-flickr.md +394 -0
  278. package/dist/data/designs/ios-flighty-android.md +418 -0
  279. package/dist/data/designs/ios-flighty-expo.md +353 -0
  280. package/dist/data/designs/ios-flighty-swiftui.md +337 -0
  281. package/dist/data/designs/ios-flighty.md +357 -0
  282. package/dist/data/designs/ios-flo-android.md +447 -0
  283. package/dist/data/designs/ios-flo-expo.md +363 -0
  284. package/dist/data/designs/ios-flo-swiftui.md +355 -0
  285. package/dist/data/designs/ios-flo.md +351 -0
  286. package/dist/data/designs/ios-garmin-connect-android.md +531 -0
  287. package/dist/data/designs/ios-garmin-connect-expo.md +429 -0
  288. package/dist/data/designs/ios-garmin-connect-swiftui.md +459 -0
  289. package/dist/data/designs/ios-garmin-connect.md +419 -0
  290. package/dist/data/designs/ios-gas-android.md +438 -0
  291. package/dist/data/designs/ios-gas-expo.md +350 -0
  292. package/dist/data/designs/ios-gas-swiftui.md +329 -0
  293. package/dist/data/designs/ios-gas.md +387 -0
  294. package/dist/data/designs/ios-gemini-android.md +568 -0
  295. package/dist/data/designs/ios-gemini-expo.md +416 -0
  296. package/dist/data/designs/ios-gemini-swiftui.md +424 -0
  297. package/dist/data/designs/ios-gemini.md +351 -0
  298. package/dist/data/designs/ios-github-android.md +507 -0
  299. package/dist/data/designs/ios-github-expo.md +486 -0
  300. package/dist/data/designs/ios-github-swiftui.md +459 -0
  301. package/dist/data/designs/ios-github.md +394 -0
  302. package/dist/data/designs/ios-gmail-android.md +548 -0
  303. package/dist/data/designs/ios-gmail-expo.md +457 -0
  304. package/dist/data/designs/ios-gmail-swiftui.md +470 -0
  305. package/dist/data/designs/ios-gmail.md +441 -0
  306. package/dist/data/designs/ios-goodreads-android.md +436 -0
  307. package/dist/data/designs/ios-goodreads-expo.md +407 -0
  308. package/dist/data/designs/ios-goodreads-swiftui.md +378 -0
  309. package/dist/data/designs/ios-goodreads.md +385 -0
  310. package/dist/data/designs/ios-google-calendar-android.md +565 -0
  311. package/dist/data/designs/ios-google-calendar-expo.md +616 -0
  312. package/dist/data/designs/ios-google-calendar-swiftui.md +585 -0
  313. package/dist/data/designs/ios-google-calendar.md +431 -0
  314. package/dist/data/designs/ios-google-maps-android.md +614 -0
  315. package/dist/data/designs/ios-google-maps-expo.md +515 -0
  316. package/dist/data/designs/ios-google-maps-swiftui.md +484 -0
  317. package/dist/data/designs/ios-google-maps.md +451 -0
  318. package/dist/data/designs/ios-grammarly-android.md +449 -0
  319. package/dist/data/designs/ios-grammarly-expo.md +383 -0
  320. package/dist/data/designs/ios-grammarly-swiftui.md +381 -0
  321. package/dist/data/designs/ios-grammarly.md +392 -0
  322. package/dist/data/designs/ios-grindr-android.md +494 -0
  323. package/dist/data/designs/ios-grindr-expo.md +358 -0
  324. package/dist/data/designs/ios-grindr-swiftui.md +357 -0
  325. package/dist/data/designs/ios-grindr.md +356 -0
  326. package/dist/data/designs/ios-grok-android.md +471 -0
  327. package/dist/data/designs/ios-grok-expo.md +388 -0
  328. package/dist/data/designs/ios-grok-swiftui.md +397 -0
  329. package/dist/data/designs/ios-grok.md +357 -0
  330. package/dist/data/designs/ios-groupme-android.md +551 -0
  331. package/dist/data/designs/ios-groupme-expo.md +442 -0
  332. package/dist/data/designs/ios-groupme-swiftui.md +439 -0
  333. package/dist/data/designs/ios-groupme.md +424 -0
  334. package/dist/data/designs/ios-grubhub-android.md +506 -0
  335. package/dist/data/designs/ios-grubhub-expo.md +428 -0
  336. package/dist/data/designs/ios-grubhub-swiftui.md +408 -0
  337. package/dist/data/designs/ios-grubhub.md +427 -0
  338. package/dist/data/designs/ios-happn-android.md +464 -0
  339. package/dist/data/designs/ios-happn-expo.md +411 -0
  340. package/dist/data/designs/ios-happn-swiftui.md +401 -0
  341. package/dist/data/designs/ios-happn.md +400 -0
  342. package/dist/data/designs/ios-headspace-android.md +688 -0
  343. package/dist/data/designs/ios-headspace-expo.md +574 -0
  344. package/dist/data/designs/ios-headspace-swiftui.md +498 -0
  345. package/dist/data/designs/ios-headspace.md +430 -0
  346. package/dist/data/designs/ios-hevy-android.md +473 -0
  347. package/dist/data/designs/ios-hevy-expo.md +405 -0
  348. package/dist/data/designs/ios-hevy-swiftui.md +367 -0
  349. package/dist/data/designs/ios-hevy.md +410 -0
  350. package/dist/data/designs/ios-hinge-android.md +743 -0
  351. package/dist/data/designs/ios-hinge-expo.md +580 -0
  352. package/dist/data/designs/ios-hinge-swiftui.md +512 -0
  353. package/dist/data/designs/ios-hinge.md +405 -0
  354. package/dist/data/designs/ios-hopper-android.md +440 -0
  355. package/dist/data/designs/ios-hopper-expo.md +353 -0
  356. package/dist/data/designs/ios-hopper-swiftui.md +340 -0
  357. package/dist/data/designs/ios-hopper.md +354 -0
  358. package/dist/data/designs/ios-hulu-android.md +435 -0
  359. package/dist/data/designs/ios-hulu-expo.md +331 -0
  360. package/dist/data/designs/ios-hulu-swiftui.md +374 -0
  361. package/dist/data/designs/ios-hulu.md +353 -0
  362. package/dist/data/designs/ios-iheartradio-android.md +481 -0
  363. package/dist/data/designs/ios-iheartradio-expo.md +417 -0
  364. package/dist/data/designs/ios-iheartradio-swiftui.md +423 -0
  365. package/dist/data/designs/ios-iheartradio.md +381 -0
  366. package/dist/data/designs/ios-imessage-android.md +426 -0
  367. package/dist/data/designs/ios-imessage-expo.md +384 -0
  368. package/dist/data/designs/ios-imessage-swiftui.md +378 -0
  369. package/dist/data/designs/ios-imessage.md +394 -0
  370. package/dist/data/designs/ios-instacart-android.md +471 -0
  371. package/dist/data/designs/ios-instacart-expo.md +349 -0
  372. package/dist/data/designs/ios-instacart-swiftui.md +378 -0
  373. package/dist/data/designs/ios-instacart.md +360 -0
  374. package/dist/data/designs/ios-instagram-android.md +646 -0
  375. package/dist/data/designs/ios-instagram-expo.md +310 -0
  376. package/dist/data/designs/ios-instagram-swiftui.md +333 -0
  377. package/dist/data/designs/ios-instagram.md +376 -0
  378. package/dist/data/designs/ios-jira-android.md +432 -0
  379. package/dist/data/designs/ios-jira-expo.md +375 -0
  380. package/dist/data/designs/ios-jira-swiftui.md +433 -0
  381. package/dist/data/designs/ios-jira.md +424 -0
  382. package/dist/data/designs/ios-kakaotalk-android.md +491 -0
  383. package/dist/data/designs/ios-kakaotalk-expo.md +418 -0
  384. package/dist/data/designs/ios-kakaotalk-swiftui.md +406 -0
  385. package/dist/data/designs/ios-kakaotalk.md +414 -0
  386. package/dist/data/designs/ios-kayak-android.md +466 -0
  387. package/dist/data/designs/ios-kayak-expo.md +407 -0
  388. package/dist/data/designs/ios-kayak-swiftui.md +426 -0
  389. package/dist/data/designs/ios-kayak.md +392 -0
  390. package/dist/data/designs/ios-kick-android.md +487 -0
  391. package/dist/data/designs/ios-kick-expo.md +434 -0
  392. package/dist/data/designs/ios-kick-swiftui.md +429 -0
  393. package/dist/data/designs/ios-kick.md +389 -0
  394. package/dist/data/designs/ios-kik-android.md +433 -0
  395. package/dist/data/designs/ios-kik-expo.md +363 -0
  396. package/dist/data/designs/ios-kik-swiftui.md +363 -0
  397. package/dist/data/designs/ios-kik.md +392 -0
  398. package/dist/data/designs/ios-kindle-android.md +439 -0
  399. package/dist/data/designs/ios-kindle-expo.md +356 -0
  400. package/dist/data/designs/ios-kindle-swiftui.md +372 -0
  401. package/dist/data/designs/ios-kindle.md +369 -0
  402. package/dist/data/designs/ios-klarna-android.md +420 -0
  403. package/dist/data/designs/ios-klarna-expo.md +349 -0
  404. package/dist/data/designs/ios-klarna-swiftui.md +360 -0
  405. package/dist/data/designs/ios-klarna.md +356 -0
  406. package/dist/data/designs/ios-lemon8-android.md +492 -0
  407. package/dist/data/designs/ios-lemon8-expo.md +413 -0
  408. package/dist/data/designs/ios-lemon8-swiftui.md +428 -0
  409. package/dist/data/designs/ios-lemon8.md +378 -0
  410. package/dist/data/designs/ios-life360-android.md +474 -0
  411. package/dist/data/designs/ios-life360-expo.md +375 -0
  412. package/dist/data/designs/ios-life360-swiftui.md +390 -0
  413. package/dist/data/designs/ios-life360.md +402 -0
  414. package/dist/data/designs/ios-line-android.md +517 -0
  415. package/dist/data/designs/ios-line-expo.md +402 -0
  416. package/dist/data/designs/ios-line-swiftui.md +361 -0
  417. package/dist/data/designs/ios-line.md +362 -0
  418. package/dist/data/designs/ios-linear-android.md +457 -0
  419. package/dist/data/designs/ios-linear-expo.md +367 -0
  420. package/dist/data/designs/ios-linear-swiftui.md +401 -0
  421. package/dist/data/designs/ios-linear.md +368 -0
  422. package/dist/data/designs/ios-linkedin-android.md +620 -0
  423. package/dist/data/designs/ios-linkedin-expo.md +469 -0
  424. package/dist/data/designs/ios-linkedin-swiftui.md +472 -0
  425. package/dist/data/designs/ios-linkedin.md +444 -0
  426. package/dist/data/designs/ios-locket-android.md +500 -0
  427. package/dist/data/designs/ios-locket-expo.md +375 -0
  428. package/dist/data/designs/ios-locket-swiftui.md +375 -0
  429. package/dist/data/designs/ios-locket.md +381 -0
  430. package/dist/data/designs/ios-lyft-android.md +406 -0
  431. package/dist/data/designs/ios-lyft-expo.md +333 -0
  432. package/dist/data/designs/ios-lyft-swiftui.md +315 -0
  433. package/dist/data/designs/ios-lyft.md +337 -0
  434. package/dist/data/designs/ios-marriott-bonvoy-android.md +488 -0
  435. package/dist/data/designs/ios-marriott-bonvoy-expo.md +412 -0
  436. package/dist/data/designs/ios-marriott-bonvoy-swiftui.md +461 -0
  437. package/dist/data/designs/ios-marriott-bonvoy.md +379 -0
  438. package/dist/data/designs/ios-mastodon-android.md +476 -0
  439. package/dist/data/designs/ios-mastodon-expo.md +379 -0
  440. package/dist/data/designs/ios-mastodon-swiftui.md +349 -0
  441. package/dist/data/designs/ios-mastodon.md +337 -0
  442. package/dist/data/designs/ios-match-android.md +496 -0
  443. package/dist/data/designs/ios-match-expo.md +393 -0
  444. package/dist/data/designs/ios-match-swiftui.md +450 -0
  445. package/dist/data/designs/ios-match.md +382 -0
  446. package/dist/data/designs/ios-max-android.md +454 -0
  447. package/dist/data/designs/ios-max-expo.md +342 -0
  448. package/dist/data/designs/ios-max-swiftui.md +332 -0
  449. package/dist/data/designs/ios-max.md +352 -0
  450. package/dist/data/designs/ios-mcdonalds-android.md +497 -0
  451. package/dist/data/designs/ios-mcdonalds-expo.md +382 -0
  452. package/dist/data/designs/ios-mcdonalds-swiftui.md +394 -0
  453. package/dist/data/designs/ios-mcdonalds.md +410 -0
  454. package/dist/data/designs/ios-messenger-android.md +523 -0
  455. package/dist/data/designs/ios-messenger-expo.md +379 -0
  456. package/dist/data/designs/ios-messenger-swiftui.md +369 -0
  457. package/dist/data/designs/ios-messenger.md +361 -0
  458. package/dist/data/designs/ios-microsoft-teams-android.md +446 -0
  459. package/dist/data/designs/ios-microsoft-teams-expo.md +362 -0
  460. package/dist/data/designs/ios-microsoft-teams-swiftui.md +384 -0
  461. package/dist/data/designs/ios-microsoft-teams.md +359 -0
  462. package/dist/data/designs/ios-midjourney-android.md +503 -0
  463. package/dist/data/designs/ios-midjourney-expo.md +406 -0
  464. package/dist/data/designs/ios-midjourney-swiftui.md +376 -0
  465. package/dist/data/designs/ios-midjourney.md +407 -0
  466. package/dist/data/designs/ios-miro-android.md +475 -0
  467. package/dist/data/designs/ios-miro-expo.md +421 -0
  468. package/dist/data/designs/ios-miro-swiftui.md +407 -0
  469. package/dist/data/designs/ios-miro.md +424 -0
  470. package/dist/data/designs/ios-monday-android.md +426 -0
  471. package/dist/data/designs/ios-monday-expo.md +382 -0
  472. package/dist/data/designs/ios-monday-swiftui.md +386 -0
  473. package/dist/data/designs/ios-monday.md +415 -0
  474. package/dist/data/designs/ios-monzo-android.md +423 -0
  475. package/dist/data/designs/ios-monzo-expo.md +391 -0
  476. package/dist/data/designs/ios-monzo-swiftui.md +371 -0
  477. package/dist/data/designs/ios-monzo.md +382 -0
  478. package/dist/data/designs/ios-myfitnesspal-android.md +631 -0
  479. package/dist/data/designs/ios-myfitnesspal-expo.md +489 -0
  480. package/dist/data/designs/ios-myfitnesspal-swiftui.md +500 -0
  481. package/dist/data/designs/ios-myfitnesspal.md +408 -0
  482. package/dist/data/designs/ios-netflix-android.md +570 -0
  483. package/dist/data/designs/ios-netflix-expo.md +528 -0
  484. package/dist/data/designs/ios-netflix-swiftui.md +543 -0
  485. package/dist/data/designs/ios-netflix.md +476 -0
  486. package/dist/data/designs/ios-nextdoor-android.md +399 -0
  487. package/dist/data/designs/ios-nextdoor-expo.md +317 -0
  488. package/dist/data/designs/ios-nextdoor-swiftui.md +343 -0
  489. package/dist/data/designs/ios-nextdoor.md +332 -0
  490. package/dist/data/designs/ios-nike-run-club-android.md +598 -0
  491. package/dist/data/designs/ios-nike-run-club-expo.md +459 -0
  492. package/dist/data/designs/ios-nike-run-club-swiftui.md +474 -0
  493. package/dist/data/designs/ios-nike-run-club.md +400 -0
  494. package/dist/data/designs/ios-noom-android.md +455 -0
  495. package/dist/data/designs/ios-noom-expo.md +362 -0
  496. package/dist/data/designs/ios-noom-swiftui.md +369 -0
  497. package/dist/data/designs/ios-noom.md +404 -0
  498. package/dist/data/designs/ios-notion-android.md +575 -0
  499. package/dist/data/designs/ios-notion-expo.md +543 -0
  500. package/dist/data/designs/ios-notion-swiftui.md +562 -0
  501. package/dist/data/designs/ios-notion.md +506 -0
  502. package/dist/data/designs/ios-nubank-android.md +447 -0
  503. package/dist/data/designs/ios-nubank-expo.md +391 -0
  504. package/dist/data/designs/ios-nubank-swiftui.md +391 -0
  505. package/dist/data/designs/ios-nubank.md +388 -0
  506. package/dist/data/designs/ios-obsidian-android.md +456 -0
  507. package/dist/data/designs/ios-obsidian-expo.md +401 -0
  508. package/dist/data/designs/ios-obsidian-swiftui.md +412 -0
  509. package/dist/data/designs/ios-obsidian.md +363 -0
  510. package/dist/data/designs/ios-okcupid-android.md +496 -0
  511. package/dist/data/designs/ios-okcupid-expo.md +378 -0
  512. package/dist/data/designs/ios-okcupid-swiftui.md +343 -0
  513. package/dist/data/designs/ios-okcupid.md +364 -0
  514. package/dist/data/designs/ios-opentable-android.md +426 -0
  515. package/dist/data/designs/ios-opentable-expo.md +350 -0
  516. package/dist/data/designs/ios-opentable-swiftui.md +328 -0
  517. package/dist/data/designs/ios-opentable.md +411 -0
  518. package/dist/data/designs/ios-oura-android.md +426 -0
  519. package/dist/data/designs/ios-oura-expo.md +353 -0
  520. package/dist/data/designs/ios-oura-swiftui.md +327 -0
  521. package/dist/data/designs/ios-oura.md +356 -0
  522. package/dist/data/designs/ios-overcast-android.md +508 -0
  523. package/dist/data/designs/ios-overcast-expo.md +420 -0
  524. package/dist/data/designs/ios-overcast-swiftui.md +427 -0
  525. package/dist/data/designs/ios-overcast.md +414 -0
  526. package/dist/data/designs/ios-pandora-android.md +477 -0
  527. package/dist/data/designs/ios-pandora-expo.md +406 -0
  528. package/dist/data/designs/ios-pandora-swiftui.md +413 -0
  529. package/dist/data/designs/ios-pandora.md +366 -0
  530. package/dist/data/designs/ios-panera-android.md +414 -0
  531. package/dist/data/designs/ios-panera-expo.md +352 -0
  532. package/dist/data/designs/ios-panera-swiftui.md +369 -0
  533. package/dist/data/designs/ios-panera.md +412 -0
  534. package/dist/data/designs/ios-paramount-plus-android.md +415 -0
  535. package/dist/data/designs/ios-paramount-plus-expo.md +363 -0
  536. package/dist/data/designs/ios-paramount-plus-swiftui.md +372 -0
  537. package/dist/data/designs/ios-paramount-plus.md +400 -0
  538. package/dist/data/designs/ios-paypal-android.md +535 -0
  539. package/dist/data/designs/ios-paypal-expo.md +429 -0
  540. package/dist/data/designs/ios-paypal-swiftui.md +466 -0
  541. package/dist/data/designs/ios-paypal.md +393 -0
  542. package/dist/data/designs/ios-peacock-android.md +453 -0
  543. package/dist/data/designs/ios-peacock-expo.md +393 -0
  544. package/dist/data/designs/ios-peacock-swiftui.md +420 -0
  545. package/dist/data/designs/ios-peacock.md +411 -0
  546. package/dist/data/designs/ios-peloton-android.md +470 -0
  547. package/dist/data/designs/ios-peloton-expo.md +401 -0
  548. package/dist/data/designs/ios-peloton-swiftui.md +409 -0
  549. package/dist/data/designs/ios-peloton.md +415 -0
  550. package/dist/data/designs/ios-perplexity-android.md +553 -0
  551. package/dist/data/designs/ios-perplexity-expo.md +703 -0
  552. package/dist/data/designs/ios-perplexity-swiftui.md +602 -0
  553. package/dist/data/designs/ios-perplexity.md +453 -0
  554. package/dist/data/designs/ios-pinterest-android.md +551 -0
  555. package/dist/data/designs/ios-pinterest-expo.md +466 -0
  556. package/dist/data/designs/ios-pinterest-swiftui.md +464 -0
  557. package/dist/data/designs/ios-pinterest.md +427 -0
  558. package/dist/data/designs/ios-plenty-of-fish-android.md +462 -0
  559. package/dist/data/designs/ios-plenty-of-fish-expo.md +380 -0
  560. package/dist/data/designs/ios-plenty-of-fish-swiftui.md +429 -0
  561. package/dist/data/designs/ios-plenty-of-fish.md +387 -0
  562. package/dist/data/designs/ios-plex-android.md +403 -0
  563. package/dist/data/designs/ios-plex-expo.md +333 -0
  564. package/dist/data/designs/ios-plex-swiftui.md +349 -0
  565. package/dist/data/designs/ios-plex.md +379 -0
  566. package/dist/data/designs/ios-pluto-tv-android.md +413 -0
  567. package/dist/data/designs/ios-pluto-tv-expo.md +379 -0
  568. package/dist/data/designs/ios-pluto-tv-swiftui.md +411 -0
  569. package/dist/data/designs/ios-pluto-tv.md +362 -0
  570. package/dist/data/designs/ios-pocket-casts-android.md +492 -0
  571. package/dist/data/designs/ios-pocket-casts-expo.md +430 -0
  572. package/dist/data/designs/ios-pocket-casts-swiftui.md +479 -0
  573. package/dist/data/designs/ios-pocket-casts.md +427 -0
  574. package/dist/data/designs/ios-postman-android.md +472 -0
  575. package/dist/data/designs/ios-postman-expo.md +372 -0
  576. package/dist/data/designs/ios-postman-swiftui.md +377 -0
  577. package/dist/data/designs/ios-postman.md +405 -0
  578. package/dist/data/designs/ios-prime-video-android.md +447 -0
  579. package/dist/data/designs/ios-prime-video-expo.md +365 -0
  580. package/dist/data/designs/ios-prime-video-swiftui.md +333 -0
  581. package/dist/data/designs/ios-prime-video.md +351 -0
  582. package/dist/data/designs/ios-quora-android.md +513 -0
  583. package/dist/data/designs/ios-quora-expo.md +362 -0
  584. package/dist/data/designs/ios-quora-swiftui.md +375 -0
  585. package/dist/data/designs/ios-quora.md +359 -0
  586. package/dist/data/designs/ios-raya-android.md +401 -0
  587. package/dist/data/designs/ios-raya-expo.md +366 -0
  588. package/dist/data/designs/ios-raya-swiftui.md +393 -0
  589. package/dist/data/designs/ios-raya.md +366 -0
  590. package/dist/data/designs/ios-reddit-android.md +605 -0
  591. package/dist/data/designs/ios-reddit-expo.md +553 -0
  592. package/dist/data/designs/ios-reddit-swiftui.md +514 -0
  593. package/dist/data/designs/ios-reddit.md +460 -0
  594. package/dist/data/designs/ios-resy-android.md +430 -0
  595. package/dist/data/designs/ios-resy-expo.md +344 -0
  596. package/dist/data/designs/ios-resy-swiftui.md +330 -0
  597. package/dist/data/designs/ios-resy.md +412 -0
  598. package/dist/data/designs/ios-revolut-android.md +433 -0
  599. package/dist/data/designs/ios-revolut-expo.md +379 -0
  600. package/dist/data/designs/ios-revolut-swiftui.md +372 -0
  601. package/dist/data/designs/ios-revolut.md +353 -0
  602. package/dist/data/designs/ios-robinhood-android.md +587 -0
  603. package/dist/data/designs/ios-robinhood-expo.md +416 -0
  604. package/dist/data/designs/ios-robinhood-swiftui.md +431 -0
  605. package/dist/data/designs/ios-robinhood.md +380 -0
  606. package/dist/data/designs/ios-runna-android.md +485 -0
  607. package/dist/data/designs/ios-runna-expo.md +388 -0
  608. package/dist/data/designs/ios-runna-swiftui.md +413 -0
  609. package/dist/data/designs/ios-runna.md +390 -0
  610. package/dist/data/designs/ios-shazam-android.md +436 -0
  611. package/dist/data/designs/ios-shazam-expo.md +348 -0
  612. package/dist/data/designs/ios-shazam-swiftui.md +394 -0
  613. package/dist/data/designs/ios-shazam.md +338 -0
  614. package/dist/data/designs/ios-signal-android.md +462 -0
  615. package/dist/data/designs/ios-signal-expo.md +361 -0
  616. package/dist/data/designs/ios-signal-swiftui.md +350 -0
  617. package/dist/data/designs/ios-signal.md +357 -0
  618. package/dist/data/designs/ios-skype-android.md +398 -0
  619. package/dist/data/designs/ios-skype-expo.md +368 -0
  620. package/dist/data/designs/ios-skype-swiftui.md +369 -0
  621. package/dist/data/designs/ios-skype.md +406 -0
  622. package/dist/data/designs/ios-skyscanner-android.md +451 -0
  623. package/dist/data/designs/ios-skyscanner-expo.md +423 -0
  624. package/dist/data/designs/ios-skyscanner-swiftui.md +419 -0
  625. package/dist/data/designs/ios-skyscanner.md +421 -0
  626. package/dist/data/designs/ios-slack-android.md +695 -0
  627. package/dist/data/designs/ios-slack-expo.md +601 -0
  628. package/dist/data/designs/ios-slack-swiftui.md +594 -0
  629. package/dist/data/designs/ios-slack.md +474 -0
  630. package/dist/data/designs/ios-sleep-cycle-android.md +436 -0
  631. package/dist/data/designs/ios-sleep-cycle-expo.md +380 -0
  632. package/dist/data/designs/ios-sleep-cycle-swiftui.md +409 -0
  633. package/dist/data/designs/ios-sleep-cycle.md +386 -0
  634. package/dist/data/designs/ios-snapchat-android.md +671 -0
  635. package/dist/data/designs/ios-snapchat-expo.md +528 -0
  636. package/dist/data/designs/ios-snapchat-swiftui.md +557 -0
  637. package/dist/data/designs/ios-snapchat.md +478 -0
  638. package/dist/data/designs/ios-sofi-android.md +446 -0
  639. package/dist/data/designs/ios-sofi-expo.md +387 -0
  640. package/dist/data/designs/ios-sofi-swiftui.md +379 -0
  641. package/dist/data/designs/ios-sofi.md +385 -0
  642. package/dist/data/designs/ios-soundcloud-android.md +488 -0
  643. package/dist/data/designs/ios-soundcloud-expo.md +364 -0
  644. package/dist/data/designs/ios-soundcloud-swiftui.md +399 -0
  645. package/dist/data/designs/ios-soundcloud.md +359 -0
  646. package/dist/data/designs/ios-southwest-android.md +446 -0
  647. package/dist/data/designs/ios-southwest-expo.md +389 -0
  648. package/dist/data/designs/ios-southwest-swiftui.md +405 -0
  649. package/dist/data/designs/ios-southwest.md +405 -0
  650. package/dist/data/designs/ios-spotify-android.md +427 -0
  651. package/dist/data/designs/ios-spotify-expo.md +321 -0
  652. package/dist/data/designs/ios-spotify-swiftui.md +312 -0
  653. package/dist/data/designs/ios-spotify.md +366 -0
  654. package/dist/data/designs/ios-starbucks-android.md +622 -0
  655. package/dist/data/designs/ios-starbucks-expo.md +497 -0
  656. package/dist/data/designs/ios-starbucks-swiftui.md +500 -0
  657. package/dist/data/designs/ios-starbucks.md +440 -0
  658. package/dist/data/designs/ios-strava-android.md +656 -0
  659. package/dist/data/designs/ios-strava-expo.md +501 -0
  660. package/dist/data/designs/ios-strava-swiftui.md +465 -0
  661. package/dist/data/designs/ios-strava.md +433 -0
  662. package/dist/data/designs/ios-strong-android.md +479 -0
  663. package/dist/data/designs/ios-strong-expo.md +396 -0
  664. package/dist/data/designs/ios-strong-swiftui.md +363 -0
  665. package/dist/data/designs/ios-strong.md +415 -0
  666. package/dist/data/designs/ios-substack-android.md +440 -0
  667. package/dist/data/designs/ios-substack-expo.md +395 -0
  668. package/dist/data/designs/ios-substack-swiftui.md +371 -0
  669. package/dist/data/designs/ios-substack.md +372 -0
  670. package/dist/data/designs/ios-swiggy-android.md +549 -0
  671. package/dist/data/designs/ios-swiggy-expo.md +443 -0
  672. package/dist/data/designs/ios-swiggy-swiftui.md +471 -0
  673. package/dist/data/designs/ios-swiggy.md +432 -0
  674. package/dist/data/designs/ios-taco-bell-android.md +529 -0
  675. package/dist/data/designs/ios-taco-bell-expo.md +407 -0
  676. package/dist/data/designs/ios-taco-bell-swiftui.md +419 -0
  677. package/dist/data/designs/ios-taco-bell.md +430 -0
  678. package/dist/data/designs/ios-telegram-android.md +676 -0
  679. package/dist/data/designs/ios-telegram-expo.md +594 -0
  680. package/dist/data/designs/ios-telegram-swiftui.md +518 -0
  681. package/dist/data/designs/ios-telegram.md +458 -0
  682. package/dist/data/designs/ios-the-league-android.md +454 -0
  683. package/dist/data/designs/ios-the-league-expo.md +391 -0
  684. package/dist/data/designs/ios-the-league-swiftui.md +409 -0
  685. package/dist/data/designs/ios-the-league.md +368 -0
  686. package/dist/data/designs/ios-things-3-android.md +421 -0
  687. package/dist/data/designs/ios-things-3-expo.md +351 -0
  688. package/dist/data/designs/ios-things-3-swiftui.md +359 -0
  689. package/dist/data/designs/ios-things-3.md +339 -0
  690. package/dist/data/designs/ios-threads-android.md +588 -0
  691. package/dist/data/designs/ios-threads-expo.md +468 -0
  692. package/dist/data/designs/ios-threads-swiftui.md +452 -0
  693. package/dist/data/designs/ios-threads.md +424 -0
  694. package/dist/data/designs/ios-threema-android.md +496 -0
  695. package/dist/data/designs/ios-threema-expo.md +415 -0
  696. package/dist/data/designs/ios-threema-swiftui.md +446 -0
  697. package/dist/data/designs/ios-threema.md +397 -0
  698. package/dist/data/designs/ios-tidal-android.md +398 -0
  699. package/dist/data/designs/ios-tidal-expo.md +323 -0
  700. package/dist/data/designs/ios-tidal-swiftui.md +340 -0
  701. package/dist/data/designs/ios-tidal.md +351 -0
  702. package/dist/data/designs/ios-tiktok-android.md +654 -0
  703. package/dist/data/designs/ios-tiktok-expo.md +578 -0
  704. package/dist/data/designs/ios-tiktok-swiftui.md +595 -0
  705. package/dist/data/designs/ios-tiktok.md +387 -0
  706. package/dist/data/designs/ios-tinder-android.md +681 -0
  707. package/dist/data/designs/ios-tinder-expo.md +512 -0
  708. package/dist/data/designs/ios-tinder-swiftui.md +497 -0
  709. package/dist/data/designs/ios-tinder.md +415 -0
  710. package/dist/data/designs/ios-todoist-android.md +711 -0
  711. package/dist/data/designs/ios-todoist-expo.md +607 -0
  712. package/dist/data/designs/ios-todoist-swiftui.md +573 -0
  713. package/dist/data/designs/ios-todoist.md +418 -0
  714. package/dist/data/designs/ios-trello-android.md +412 -0
  715. package/dist/data/designs/ios-trello-expo.md +332 -0
  716. package/dist/data/designs/ios-trello-swiftui.md +359 -0
  717. package/dist/data/designs/ios-trello.md +344 -0
  718. package/dist/data/designs/ios-tripadvisor-android.md +450 -0
  719. package/dist/data/designs/ios-tripadvisor-expo.md +322 -0
  720. package/dist/data/designs/ios-tripadvisor-swiftui.md +326 -0
  721. package/dist/data/designs/ios-tripadvisor.md +356 -0
  722. package/dist/data/designs/ios-tubi-android.md +453 -0
  723. package/dist/data/designs/ios-tubi-expo.md +419 -0
  724. package/dist/data/designs/ios-tubi-swiftui.md +463 -0
  725. package/dist/data/designs/ios-tubi.md +383 -0
  726. package/dist/data/designs/ios-tumblr-android.md +462 -0
  727. package/dist/data/designs/ios-tumblr-expo.md +374 -0
  728. package/dist/data/designs/ios-tumblr-swiftui.md +380 -0
  729. package/dist/data/designs/ios-tumblr.md +337 -0
  730. package/dist/data/designs/ios-turo-android.md +500 -0
  731. package/dist/data/designs/ios-turo-expo.md +454 -0
  732. package/dist/data/designs/ios-turo-swiftui.md +447 -0
  733. package/dist/data/designs/ios-turo.md +392 -0
  734. package/dist/data/designs/ios-twitch-android.md +412 -0
  735. package/dist/data/designs/ios-twitch-expo.md +342 -0
  736. package/dist/data/designs/ios-twitch-swiftui.md +328 -0
  737. package/dist/data/designs/ios-twitch.md +354 -0
  738. package/dist/data/designs/ios-uber-android.md +637 -0
  739. package/dist/data/designs/ios-uber-eats-android.md +502 -0
  740. package/dist/data/designs/ios-uber-eats-expo.md +407 -0
  741. package/dist/data/designs/ios-uber-eats-swiftui.md +393 -0
  742. package/dist/data/designs/ios-uber-eats.md +353 -0
  743. package/dist/data/designs/ios-uber-expo.md +512 -0
  744. package/dist/data/designs/ios-uber-swiftui.md +483 -0
  745. package/dist/data/designs/ios-uber.md +395 -0
  746. package/dist/data/designs/ios-united-airlines-android.md +494 -0
  747. package/dist/data/designs/ios-united-airlines-expo.md +408 -0
  748. package/dist/data/designs/ios-united-airlines-swiftui.md +453 -0
  749. package/dist/data/designs/ios-united-airlines.md +388 -0
  750. package/dist/data/designs/ios-venmo-android.md +654 -0
  751. package/dist/data/designs/ios-venmo-expo.md +458 -0
  752. package/dist/data/designs/ios-venmo-swiftui.md +469 -0
  753. package/dist/data/designs/ios-venmo.md +436 -0
  754. package/dist/data/designs/ios-vercel-android.md +454 -0
  755. package/dist/data/designs/ios-vercel-expo.md +387 -0
  756. package/dist/data/designs/ios-vercel-swiftui.md +374 -0
  757. package/dist/data/designs/ios-vercel.md +399 -0
  758. package/dist/data/designs/ios-vero-android.md +498 -0
  759. package/dist/data/designs/ios-vero-expo.md +376 -0
  760. package/dist/data/designs/ios-vero-swiftui.md +374 -0
  761. package/dist/data/designs/ios-vero.md +394 -0
  762. package/dist/data/designs/ios-viber-android.md +377 -0
  763. package/dist/data/designs/ios-viber-expo.md +375 -0
  764. package/dist/data/designs/ios-viber-swiftui.md +378 -0
  765. package/dist/data/designs/ios-viber.md +403 -0
  766. package/dist/data/designs/ios-vimeo-android.md +465 -0
  767. package/dist/data/designs/ios-vimeo-expo.md +347 -0
  768. package/dist/data/designs/ios-vimeo-swiftui.md +383 -0
  769. package/dist/data/designs/ios-vimeo.md +403 -0
  770. package/dist/data/designs/ios-vrbo-android.md +488 -0
  771. package/dist/data/designs/ios-vrbo-expo.md +395 -0
  772. package/dist/data/designs/ios-vrbo-swiftui.md +421 -0
  773. package/dist/data/designs/ios-vrbo.md +383 -0
  774. package/dist/data/designs/ios-vsco-android.md +490 -0
  775. package/dist/data/designs/ios-vsco-expo.md +413 -0
  776. package/dist/data/designs/ios-vsco-swiftui.md +449 -0
  777. package/dist/data/designs/ios-vsco.md +412 -0
  778. package/dist/data/designs/ios-walmart-android.md +479 -0
  779. package/dist/data/designs/ios-walmart-expo.md +370 -0
  780. package/dist/data/designs/ios-walmart-swiftui.md +387 -0
  781. package/dist/data/designs/ios-walmart.md +366 -0
  782. package/dist/data/designs/ios-waze-android.md +695 -0
  783. package/dist/data/designs/ios-waze-expo.md +587 -0
  784. package/dist/data/designs/ios-waze-swiftui.md +601 -0
  785. package/dist/data/designs/ios-waze.md +453 -0
  786. package/dist/data/designs/ios-webull-android.md +429 -0
  787. package/dist/data/designs/ios-webull-expo.md +384 -0
  788. package/dist/data/designs/ios-webull-swiftui.md +406 -0
  789. package/dist/data/designs/ios-webull.md +375 -0
  790. package/dist/data/designs/ios-wechat-android.md +545 -0
  791. package/dist/data/designs/ios-wechat-expo.md +398 -0
  792. package/dist/data/designs/ios-wechat-swiftui.md +394 -0
  793. package/dist/data/designs/ios-wechat.md +363 -0
  794. package/dist/data/designs/ios-whatsapp-android.md +568 -0
  795. package/dist/data/designs/ios-whatsapp-expo.md +502 -0
  796. package/dist/data/designs/ios-whatsapp-swiftui.md +483 -0
  797. package/dist/data/designs/ios-whatsapp.md +425 -0
  798. package/dist/data/designs/ios-whoop-android.md +635 -0
  799. package/dist/data/designs/ios-whoop-expo.md +562 -0
  800. package/dist/data/designs/ios-whoop-swiftui.md +553 -0
  801. package/dist/data/designs/ios-whoop.md +419 -0
  802. package/dist/data/designs/ios-wise-android.md +428 -0
  803. package/dist/data/designs/ios-wise-expo.md +357 -0
  804. package/dist/data/designs/ios-wise-swiftui.md +356 -0
  805. package/dist/data/designs/ios-wise.md +361 -0
  806. package/dist/data/designs/ios-x-twitter-android.md +618 -0
  807. package/dist/data/designs/ios-x-twitter-expo.md +442 -0
  808. package/dist/data/designs/ios-x-twitter-swiftui.md +429 -0
  809. package/dist/data/designs/ios-x-twitter.md +432 -0
  810. package/dist/data/designs/ios-yelp-android.md +455 -0
  811. package/dist/data/designs/ios-yelp-expo.md +397 -0
  812. package/dist/data/designs/ios-yelp-swiftui.md +369 -0
  813. package/dist/data/designs/ios-yelp.md +398 -0
  814. package/dist/data/designs/ios-youtube-android.md +668 -0
  815. package/dist/data/designs/ios-youtube-expo.md +435 -0
  816. package/dist/data/designs/ios-youtube-music-android.md +450 -0
  817. package/dist/data/designs/ios-youtube-music-expo.md +404 -0
  818. package/dist/data/designs/ios-youtube-music-swiftui.md +434 -0
  819. package/dist/data/designs/ios-youtube-music.md +381 -0
  820. package/dist/data/designs/ios-youtube-swiftui.md +496 -0
  821. package/dist/data/designs/ios-youtube.md +466 -0
  822. package/dist/data/designs/ios-zalo-android.md +510 -0
  823. package/dist/data/designs/ios-zalo-expo.md +389 -0
  824. package/dist/data/designs/ios-zalo-swiftui.md +431 -0
  825. package/dist/data/designs/ios-zalo.md +388 -0
  826. package/dist/data/designs/ios-zomato-android.md +527 -0
  827. package/dist/data/designs/ios-zomato-expo.md +437 -0
  828. package/dist/data/designs/ios-zomato-swiftui.md +433 -0
  829. package/dist/data/designs/ios-zomato.md +439 -0
  830. package/dist/data/designs/ios-zoom-android.md +423 -0
  831. package/dist/data/designs/ios-zoom-expo.md +355 -0
  832. package/dist/data/designs/ios-zoom-swiftui.md +379 -0
  833. package/dist/data/designs/ios-zoom.md +357 -0
  834. package/dist/data/designs/ios-zwift-android.md +402 -0
  835. package/dist/data/designs/ios-zwift-expo.md +402 -0
  836. package/dist/data/designs/ios-zwift-swiftui.md +378 -0
  837. package/dist/data/designs/ios-zwift.md +411 -0
  838. package/dist/data/designs/kraken.md +125 -0
  839. package/dist/data/designs/lamborghini.md +288 -0
  840. package/dist/data/designs/linear.app.md +548 -0
  841. package/dist/data/designs/lovable.md +298 -0
  842. package/dist/data/designs/mastercard.md +365 -0
  843. package/dist/data/designs/material-clean.md +289 -0
  844. package/dist/data/designs/meta.md +683 -0
  845. package/dist/data/designs/midnight-pro.md +256 -0
  846. package/dist/data/designs/minimal-brutalist.md +245 -0
  847. package/dist/data/designs/minimax.md +746 -0
  848. package/dist/data/designs/mintlify.md +852 -0
  849. package/dist/data/designs/miro.md +825 -0
  850. package/dist/data/designs/mistral.ai.md +773 -0
  851. package/dist/data/designs/mongodb.md +767 -0
  852. package/dist/data/designs/nike.md +575 -0
  853. package/dist/data/designs/nintendo-2001.md +649 -0
  854. package/dist/data/designs/notion.md +821 -0
  855. package/dist/data/designs/nova-mobile-design-md.md +235 -0
  856. package/dist/data/designs/nvidia.md +640 -0
  857. package/dist/data/designs/ollama.md +539 -0
  858. package/dist/data/designs/opencode.ai.md +521 -0
  859. package/dist/data/designs/pinterest.md +597 -0
  860. package/dist/data/designs/playful-color.md +253 -0
  861. package/dist/data/designs/playstation.md +661 -0
  862. package/dist/data/designs/posthog.md +690 -0
  863. package/dist/data/designs/raycast.md +669 -0
  864. package/dist/data/designs/renault.md +589 -0
  865. package/dist/data/designs/replicate.md +616 -0
  866. package/dist/data/designs/resend.md +585 -0
  867. package/dist/data/designs/revolut.md +636 -0
  868. package/dist/data/designs/runwayml.md +244 -0
  869. package/dist/data/designs/sanity.md +357 -0
  870. package/dist/data/designs/sentry.md +551 -0
  871. package/dist/data/designs/shopify.md +516 -0
  872. package/dist/data/designs/slack.md +482 -0
  873. package/dist/data/designs/soft-glass.md +258 -0
  874. package/dist/data/designs/spacex.md +363 -0
  875. package/dist/data/designs/spotify.md +246 -0
  876. package/dist/data/designs/starbucks.md +580 -0
  877. package/dist/data/designs/stripe.md +487 -0
  878. package/dist/data/designs/supabase.md +462 -0
  879. package/dist/data/designs/superhuman.md +448 -0
  880. package/dist/data/designs/tesla.md +286 -0
  881. package/dist/data/designs/theverge.md +339 -0
  882. package/dist/data/designs/together.ai.md +633 -0
  883. package/dist/data/designs/uber.md +636 -0
  884. package/dist/data/designs/vercel.md +736 -0
  885. package/dist/data/designs/vodafone.md +538 -0
  886. package/dist/data/designs/voltagent.md +521 -0
  887. package/dist/data/designs/warp.md +526 -0
  888. package/dist/data/designs/webflow.md +588 -0
  889. package/dist/data/designs/wired.md +497 -0
  890. package/dist/data/designs/wise.md +544 -0
  891. package/dist/data/designs/x.ai.md +465 -0
  892. package/dist/data/designs/zapier.md +537 -0
  893. package/dist/data/index.json +2600 -0
  894. package/dist/httpServer.js +83 -0
  895. package/dist/index.js +13 -0
  896. package/dist/server.js +32 -0
  897. package/dist/services/designStore.js +59 -0
  898. package/dist/services/linter.js +87 -0
  899. package/dist/services/sectionParser.js +154 -0
  900. package/dist/tools/authoring.js +131 -0
  901. package/dist/tools/browse.js +232 -0
  902. package/dist/tools/diff.js +88 -0
  903. package/dist/tools/getDesign.js +216 -0
  904. package/dist/tools/guardrails.js +87 -0
  905. package/dist/tools/lint.js +104 -0
  906. package/dist/types.js +1 -0
  907. package/package.json +65 -0
@@ -0,0 +1,611 @@
1
+ # Discord (iOS) — Jetpack Compose Implementation Guide
2
+
3
+ Companion to [DESIGN.md](DESIGN.md) — the framework-neutral spec. This file ports Discord's visual language to **Android with Jetpack Compose (Material 3)**: a color token object, a `Typography` set, paste-ready `@Composable`s, `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 (Discord's three-gray surface system, single Blurple accent, the rounded-square server rail, role-colored usernames, presence dots) while making everything idiomatic Android — a gesture-driven drawer instead of UIKit swipe panes, `FontFamily(Font(R.font.…))` instead of `Font.custom`, `sp`/`dp` instead of `pt`.
6
+
7
+ Assumes Compose BOM `2024.09+`, Kotlin `2.0+`, `minSdk 24`, Material 3, and [Coil](https://coil-kt.github.io/coil/) `2.6+` for server icons and avatars.
8
+
9
+ ## 1. Color Tokens
10
+
11
+ ```kotlin
12
+ // ui/theme/DiscordColors.kt
13
+ import androidx.compose.ui.graphics.Brush
14
+ import androidx.compose.ui.graphics.Color
15
+
16
+ object DiscordColors {
17
+ // Brand
18
+ val Blurple = Color(0xFF5865F2)
19
+ val BlurplePressed = Color(0xFF4752C4)
20
+ val BlurpleLegacy = Color(0xFF7289DA)
21
+
22
+ // Three-gray surface system (Dark — the default; the adjacency IS the brand)
23
+ val ServerRail = Color(0xFF1E1F22) // leftmost, darkest
24
+ val ChannelList = Color(0xFF2B2D31) // middle pane / modals
25
+ val ChatCanvas = Color(0xFF313338) // the "document"
26
+ val Surface2 = Color(0xFF383A40) // compose bar — one step lighter than chat
27
+ val Divider = Color(0xFF3F4147)
28
+ val RowHover = Color(0xFF2E3035)
29
+ val ActiveChannelBg = Color(0xFF404249)
30
+
31
+ // Three-gray surface system (Light — rarely used, ~80% stay on dark)
32
+ val LightCanvas = Color(0xFFFFFFFF)
33
+ val LightSurface1 = Color(0xFFF2F3F5)
34
+ val LightSurface2 = Color(0xFFEBEDEF)
35
+ val LightDivider = Color(0xFFE3E5E8)
36
+
37
+ // Text
38
+ val TextPrimary = Color(0xFFF2F3F5)
39
+ val TextSecondary = Color(0xFFB5BAC1)
40
+ val TextMuted = Color(0xFF949BA4)
41
+ val TextLink = Color(0xFF00A8FC) // distinct blue from Blurple
42
+ val TextDisabled = Color(0xFF5D6069)
43
+
44
+ // Status (presence dots)
45
+ val OnlineGreen = Color(0xFF23A55A)
46
+ val IdleYellow = Color(0xFFF0B232)
47
+ val DNDRed = Color(0xFFF23F43)
48
+ val OfflineGray = Color(0xFF80848E)
49
+ val StreamingPurple = Color(0xFF593695)
50
+
51
+ // Destructive / brand variants
52
+ val DestructiveRed = Color(0xFFDA373C)
53
+ val BoostPink = Color(0xFFEB459E)
54
+
55
+ // Common default role colors (server owners set arbitrary hex)
56
+ val RoleAdmin = Color(0xFFED4245)
57
+ val RoleMod = Color(0xFF57F287)
58
+ val RoleVIPGold = Color(0xFFFEE75C)
59
+ val RoleBotAqua = Color(0xFF23C1D2)
60
+ }
61
+
62
+ // Nitro / Boost gradient
63
+ val NitroGradient = Brush.linearGradient(listOf(DiscordColors.Blurple, DiscordColors.BoostPink))
64
+ ```
65
+
66
+ Discord is dark-first; wire a `darkColorScheme` and keep the three grays unexaggerated. A light scheme exists but is a straightforward inversion.
67
+
68
+ ```kotlin
69
+ // ui/theme/Theme.kt
70
+ import androidx.compose.material3.MaterialTheme
71
+ import androidx.compose.material3.darkColorScheme
72
+ import androidx.compose.runtime.Composable
73
+
74
+ private val DiscordScheme = darkColorScheme(
75
+ primary = DiscordColors.Blurple,
76
+ onPrimary = DiscordColors.TextPrimary,
77
+ background = DiscordColors.ChatCanvas,
78
+ onBackground = DiscordColors.TextPrimary,
79
+ surface = DiscordColors.ChannelList,
80
+ onSurface = DiscordColors.TextPrimary,
81
+ surfaceVariant = DiscordColors.Surface2,
82
+ outline = DiscordColors.Divider,
83
+ error = DiscordColors.DNDRed,
84
+ )
85
+
86
+ @Composable
87
+ fun DiscordTheme(content: @Composable () -> Unit) =
88
+ MaterialTheme(colorScheme = DiscordScheme, typography = DiscordTypography, content = content)
89
+ ```
90
+
91
+ ## 2. Typography
92
+
93
+ `gg sans` (proprietary, replaced Whitney in 2023) and `gg mono` are proprietary. Drop the TTFs in `res/font/` (lowercase, snake_case). Fall back to the system sans (Roboto) and system monospace — closest free pairing. Discord's working range is compact: 14–20sp.
94
+
95
+ ```kotlin
96
+ // ui/theme/DiscordType.kt
97
+ import androidx.compose.material3.Typography
98
+ import androidx.compose.ui.text.TextStyle
99
+ import androidx.compose.ui.text.font.Font
100
+ import androidx.compose.ui.text.font.FontFamily
101
+ import androidx.compose.ui.text.font.FontWeight
102
+ import androidx.compose.ui.unit.sp
103
+
104
+ val GgSans = FontFamily(
105
+ Font(R.font.gg_sans_regular, FontWeight.Normal),
106
+ Font(R.font.gg_sans_medium, FontWeight.Medium),
107
+ Font(R.font.gg_sans_semibold, FontWeight.SemiBold),
108
+ Font(R.font.gg_sans_bold, FontWeight.Bold),
109
+ )
110
+ val GgMono = FontFamily(Font(R.font.gg_mono_regular, FontWeight.Normal))
111
+
112
+ // Named ramp — mirrors DESIGN.md §3 exactly (pt → sp 1:1)
113
+ object DiscordText {
114
+ val ScreenTitle = TextStyle(GgSans, fontWeight = FontWeight.Bold, fontSize = 20.sp, lineHeight = 24.sp, letterSpacing = (-0.2).sp)
115
+ val ChannelActive = TextStyle(GgSans, fontWeight = FontWeight.SemiBold, fontSize = 16.sp, lineHeight = 20.sp, letterSpacing = (-0.1).sp)
116
+ val ChannelInactive = TextStyle(GgSans, fontWeight = FontWeight.Medium, fontSize = 16.sp, lineHeight = 20.sp, letterSpacing = (-0.1).sp)
117
+ val Username = TextStyle(GgSans, fontWeight = FontWeight.SemiBold, fontSize = 16.sp, lineHeight = 19.sp, letterSpacing = (-0.1).sp)
118
+ val MessageBody = TextStyle(GgSans, fontWeight = FontWeight.Normal, fontSize = 16.sp, lineHeight = 22.sp, letterSpacing = (-0.1).sp)
119
+ val Timestamp = TextStyle(GgSans, fontWeight = FontWeight.Medium, fontSize = 12.sp, lineHeight = 14.sp)
120
+ val ReplyContext = TextStyle(GgSans, fontWeight = FontWeight.Normal, fontSize = 14.sp, lineHeight = 18.sp, letterSpacing = (-0.1).sp)
121
+ val SystemMessage = TextStyle(GgSans, fontWeight = FontWeight.Medium, fontSize = 14.sp, lineHeight = 18.sp)
122
+ val SectionLabel = TextStyle(GgSans, fontWeight = FontWeight.Bold, fontSize = 12.sp, lineHeight = 14.sp, letterSpacing = 0.5.sp)
123
+ val MemberName = TextStyle(GgSans, fontWeight = FontWeight.Medium, fontSize = 14.sp, lineHeight = 17.sp, letterSpacing = (-0.1).sp)
124
+ val Button = TextStyle(GgSans, fontWeight = FontWeight.Medium, fontSize = 14.sp, lineHeight = 14.sp)
125
+ val Tab = TextStyle(GgSans, fontWeight = FontWeight.SemiBold, fontSize = 10.sp, lineHeight = 10.sp, letterSpacing = 0.1.sp)
126
+ val Code = TextStyle(GgMono, fontWeight = FontWeight.Normal, fontSize = 14.sp, lineHeight = 20.sp)
127
+ val Blockquote = TextStyle(GgSans, fontWeight = FontWeight.Normal, fontSize = 16.sp, lineHeight = 22.sp, letterSpacing = (-0.1).sp)
128
+ }
129
+
130
+ val DiscordTypography = Typography(
131
+ headlineSmall = DiscordText.ScreenTitle,
132
+ titleMedium = DiscordText.Username,
133
+ bodyMedium = DiscordText.MessageBody,
134
+ labelSmall = DiscordText.Tab,
135
+ )
136
+ ```
137
+
138
+ ## 3. Signature Components
139
+
140
+ ### Server Rail (the defining Discord component)
141
+
142
+ 48dp rounded **squares** — corner radius morphs 16dp → 12dp on active (the "squircle-er" effect) with a 4dp × 40dp white leading indicator bar.
143
+
144
+ ```kotlin
145
+ import androidx.compose.animation.core.*
146
+ import androidx.compose.foundation.background
147
+ import androidx.compose.foundation.clickable
148
+ import androidx.compose.foundation.layout.*
149
+ import androidx.compose.foundation.rememberScrollState
150
+ import androidx.compose.foundation.shape.CircleShape
151
+ import androidx.compose.foundation.shape.RoundedCornerShape
152
+ import androidx.compose.foundation.verticalScroll
153
+ import androidx.compose.material.icons.Icons
154
+ import androidx.compose.material.icons.filled.Add
155
+ import androidx.compose.material.icons.filled.Explore
156
+ import androidx.compose.material.icons.filled.Home
157
+ import androidx.compose.material3.Icon
158
+ import androidx.compose.material3.Text
159
+ import androidx.compose.runtime.*
160
+ import androidx.compose.ui.Alignment
161
+ import androidx.compose.ui.Modifier
162
+ import androidx.compose.ui.draw.clip
163
+ import androidx.compose.ui.graphics.Color
164
+ import androidx.compose.ui.unit.dp
165
+ import coil.compose.AsyncImage
166
+
167
+ data class Server(
168
+ val id: String, val name: String, val imageUrl: String?,
169
+ val initials: String, val unreadCount: Int, val mentionCount: Int,
170
+ )
171
+
172
+ @Composable
173
+ fun DCServerRail(servers: List<Server>, activeId: String?, onSelect: (String) -> Unit, modifier: Modifier = Modifier) {
174
+ Column(
175
+ modifier
176
+ .width(72.dp)
177
+ .fillMaxHeight()
178
+ .background(DiscordColors.ServerRail)
179
+ .verticalScroll(rememberScrollState())
180
+ .padding(vertical = 8.dp),
181
+ horizontalAlignment = Alignment.CenterHorizontally,
182
+ verticalArrangement = Arrangement.spacedBy(8.dp),
183
+ ) {
184
+ Box(Modifier.size(48.dp).clip(RoundedCornerShape(16.dp)).background(NitroGradient), contentAlignment = Alignment.Center) {
185
+ Icon(Icons.Filled.Home, "Home", tint = Color.White, modifier = Modifier.size(22.dp))
186
+ }
187
+ Box(Modifier.width(32.dp).height(2.dp).background(DiscordColors.Divider))
188
+ servers.forEach { s -> DCServerIcon(s, s.id == activeId) { onSelect(s.id) } }
189
+ Box(Modifier.size(48.dp).clip(CircleShape).background(DiscordColors.ChannelList), contentAlignment = Alignment.Center) {
190
+ Icon(Icons.Filled.Add, "Add a server", tint = DiscordColors.OnlineGreen, modifier = Modifier.size(22.dp))
191
+ }
192
+ Box(Modifier.size(48.dp).clip(CircleShape).background(DiscordColors.ChannelList), contentAlignment = Alignment.Center) {
193
+ Icon(Icons.Filled.Explore, "Explore servers", tint = DiscordColors.OnlineGreen, modifier = Modifier.size(22.dp))
194
+ }
195
+ }
196
+ }
197
+
198
+ @Composable
199
+ fun DCServerIcon(server: Server, isActive: Boolean, onClick: () -> Unit) {
200
+ val corner by animateDpAsState(if (isActive) 12.dp else 16.dp, spring(dampingRatio = 0.7f, stiffness = 380f), label = "corner")
201
+ val barHeight by animateDpAsState(
202
+ if (isActive) 40.dp else if (server.unreadCount > 0) 8.dp else 0.dp,
203
+ spring(dampingRatio = 0.7f, stiffness = 520f), label = "bar",
204
+ )
205
+ Row(verticalAlignment = Alignment.CenterVertically) {
206
+ Box(Modifier.width(4.dp).height(barHeight).clip(RoundedCornerShape(2.dp)).background(DiscordColors.TextPrimary))
207
+ Spacer(Modifier.width(8.dp))
208
+ Box(contentAlignment = Alignment.BottomEnd) {
209
+ Box(
210
+ Modifier.size(48.dp).clip(RoundedCornerShape(corner)).background(DiscordColors.Blurple).clickable(onClick = onClick),
211
+ contentAlignment = Alignment.Center,
212
+ ) {
213
+ if (server.imageUrl != null) {
214
+ AsyncImage(server.imageUrl, server.name, Modifier.matchParentSize())
215
+ } else {
216
+ Text(server.initials, style = DiscordText.Button, color = Color.White)
217
+ }
218
+ }
219
+ if (server.mentionCount > 0) {
220
+ Box(
221
+ Modifier
222
+ .offset(x = 6.dp, y = 6.dp)
223
+ .defaultMinSize(18.dp, 18.dp)
224
+ .clip(CircleShape)
225
+ .background(DiscordColors.DNDRed)
226
+ .padding(horizontal = 5.dp),
227
+ contentAlignment = Alignment.Center,
228
+ ) {
229
+ Text("${minOf(server.mentionCount, 99)}", style = DiscordText.Timestamp, color = Color.White)
230
+ }
231
+ }
232
+ }
233
+ Spacer(Modifier.width(12.dp))
234
+ }
235
+ }
236
+ ```
237
+
238
+ ### Message Row (role color + presence dot)
239
+
240
+ ```kotlin
241
+ import androidx.compose.ui.text.style.TextOverflow
242
+ import androidx.compose.foundation.layout.Box
243
+
244
+ enum class Presence { Online, Idle, DND, Offline, Streaming }
245
+
246
+ @Composable
247
+ fun DCMessageRow(
248
+ avatarUrl: String,
249
+ username: String,
250
+ roleColor: Color, // user's highest-priority role; fallback TextPrimary
251
+ timestamp: String,
252
+ message: String,
253
+ presence: Presence,
254
+ isGrouped: Boolean,
255
+ modifier: Modifier = Modifier,
256
+ ) {
257
+ Row(
258
+ modifier
259
+ .fillMaxWidth()
260
+ .padding(horizontal = 16.dp, vertical = if (isGrouped) 2.dp else 8.dp),
261
+ horizontalArrangement = Arrangement.spacedBy(12.dp),
262
+ ) {
263
+ if (isGrouped) {
264
+ Spacer(Modifier.width(40.dp)) // align to the 52dp avatar gutter
265
+ } else {
266
+ Box(contentAlignment = Alignment.BottomEnd) {
267
+ AsyncImage(avatarUrl, null, Modifier.size(40.dp).clip(CircleShape))
268
+ val dot = when (presence) {
269
+ Presence.Online -> DiscordColors.OnlineGreen
270
+ Presence.Idle -> DiscordColors.IdleYellow
271
+ Presence.DND -> DiscordColors.DNDRed
272
+ Presence.Offline -> DiscordColors.OfflineGray
273
+ Presence.Streaming -> DiscordColors.StreamingPurple
274
+ }
275
+ Box(
276
+ Modifier
277
+ .size(12.dp)
278
+ .clip(CircleShape)
279
+ .background(DiscordColors.ChatCanvas) // 2dp canvas-colored ring punches through
280
+ .padding(2.dp)
281
+ .clip(CircleShape)
282
+ .background(dot),
283
+ )
284
+ }
285
+ }
286
+ Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(2.dp)) {
287
+ if (!isGrouped) {
288
+ Row(horizontalArrangement = Arrangement.spacedBy(6.dp), verticalAlignment = Alignment.CenterVertically) {
289
+ Text(username, style = DiscordText.Username, color = roleColor)
290
+ Text(timestamp, style = DiscordText.Timestamp, color = DiscordColors.TextMuted)
291
+ }
292
+ }
293
+ Text(message, style = DiscordText.MessageBody, color = DiscordColors.TextPrimary, overflow = TextOverflow.Clip)
294
+ }
295
+ }
296
+ }
297
+ ```
298
+
299
+ ### Compose Bar
300
+
301
+ ```kotlin
302
+ import androidx.compose.foundation.border
303
+ import androidx.compose.foundation.text.BasicTextField
304
+ import androidx.compose.material.icons.filled.AddCircle
305
+ import androidx.compose.material.icons.filled.CardGiftcard
306
+ import androidx.compose.material.icons.filled.EmojiEmotions
307
+ import androidx.compose.material.icons.filled.Gif
308
+ import androidx.compose.material.icons.filled.Send
309
+ import androidx.compose.ui.focus.onFocusChanged
310
+ import androidx.compose.ui.graphics.SolidColor
311
+ import androidx.compose.ui.hapticfeedback.HapticFeedbackType
312
+ import androidx.compose.ui.platform.LocalHapticFeedback
313
+
314
+ @Composable
315
+ fun DCComposeBar(channelName: String, modifier: Modifier = Modifier) {
316
+ var text by remember { mutableStateOf("") }
317
+ var focused by remember { mutableStateOf(false) }
318
+ val haptics = LocalHapticFeedback.current
319
+
320
+ Row(
321
+ modifier
322
+ .fillMaxWidth()
323
+ .padding(horizontal = 12.dp, vertical = 8.dp)
324
+ .clip(RoundedCornerShape(8.dp))
325
+ .background(DiscordColors.Surface2) // intentionally one step lighter than chat canvas
326
+ .border(2.dp, if (focused) DiscordColors.Blurple else Color.Transparent, RoundedCornerShape(8.dp))
327
+ .padding(horizontal = 12.dp, vertical = 10.dp),
328
+ verticalAlignment = Alignment.CenterVertically,
329
+ horizontalArrangement = Arrangement.spacedBy(10.dp),
330
+ ) {
331
+ Icon(Icons.Filled.AddCircle, "Attach", tint = DiscordColors.TextSecondary, modifier = Modifier.size(22.dp))
332
+ BasicTextField(
333
+ value = text,
334
+ onValueChange = { text = it },
335
+ textStyle = DiscordText.MessageBody.copy(color = DiscordColors.TextPrimary),
336
+ cursorBrush = SolidColor(DiscordColors.Blurple),
337
+ maxLines = 6,
338
+ modifier = Modifier.weight(1f).onFocusChanged { focused = it.isFocused },
339
+ decorationBox = { inner ->
340
+ if (text.isEmpty()) Text("Message $channelName", style = DiscordText.MessageBody, color = DiscordColors.TextMuted)
341
+ inner()
342
+ },
343
+ )
344
+ if (text.isEmpty()) {
345
+ Icon(Icons.Filled.CardGiftcard, "Gift", tint = DiscordColors.TextSecondary, modifier = Modifier.size(20.dp))
346
+ Icon(Icons.Filled.Gif, "GIF", tint = DiscordColors.TextSecondary, modifier = Modifier.size(20.dp))
347
+ Icon(Icons.Filled.EmojiEmotions, "Emoji", tint = DiscordColors.TextSecondary, modifier = Modifier.size(20.dp))
348
+ } else {
349
+ Box(
350
+ Modifier.size(32.dp).clip(CircleShape).background(DiscordColors.Blurple).clickable {
351
+ haptics.performHapticFeedback(HapticFeedbackType.TextHandleMove) // ~iOS soft impact
352
+ text = ""
353
+ },
354
+ contentAlignment = Alignment.Center,
355
+ ) { Icon(Icons.Filled.Send, "Send", tint = Color.White, modifier = Modifier.size(18.dp)) }
356
+ }
357
+ }
358
+ }
359
+ ```
360
+
361
+ ### Channel List Row
362
+
363
+ ```kotlin
364
+ import androidx.compose.material.icons.filled.Campaign
365
+ import androidx.compose.material.icons.filled.Tag
366
+ import androidx.compose.material.icons.filled.VolumeUp
367
+
368
+ enum class ChannelType { Text, Voice, Announcement }
369
+
370
+ @Composable
371
+ fun DCChannelRow(name: String, type: ChannelType, isActive: Boolean, unread: Boolean, mentionCount: Int, modifier: Modifier = Modifier) {
372
+ val icon = when (type) {
373
+ ChannelType.Text -> Icons.Filled.Tag
374
+ ChannelType.Voice -> Icons.Filled.VolumeUp
375
+ ChannelType.Announcement -> Icons.Filled.Campaign
376
+ }
377
+ val textColor = if (isActive || unread || mentionCount > 0) DiscordColors.TextPrimary else DiscordColors.TextMuted
378
+ Box(modifier.fillMaxWidth().height(36.dp)) {
379
+ if (isActive) Box(Modifier.width(3.dp).fillMaxHeight().background(DiscordColors.Blurple))
380
+ Row(
381
+ Modifier
382
+ .fillMaxSize()
383
+ .padding(horizontal = 8.dp)
384
+ .clip(RoundedCornerShape(4.dp))
385
+ .background(if (isActive) DiscordColors.ActiveChannelBg else Color.Transparent)
386
+ .padding(horizontal = 8.dp),
387
+ verticalAlignment = Alignment.CenterVertically,
388
+ horizontalArrangement = Arrangement.spacedBy(6.dp),
389
+ ) {
390
+ Icon(icon, null, tint = DiscordColors.TextMuted, modifier = Modifier.size(16.dp))
391
+ Text(name, style = if (isActive) DiscordText.ChannelActive else DiscordText.ChannelInactive, color = textColor)
392
+ Spacer(Modifier.weight(1f))
393
+ if (mentionCount > 0) {
394
+ Box(
395
+ Modifier.defaultMinSize(18.dp, 16.dp).clip(RoundedCornerShape(8.dp)).background(DiscordColors.DNDRed).padding(horizontal = 6.dp),
396
+ contentAlignment = Alignment.Center,
397
+ ) { Text("$mentionCount", style = DiscordText.Timestamp, color = Color.White) }
398
+ }
399
+ }
400
+ }
401
+ }
402
+ ```
403
+
404
+ ### Voice Channel Speaking Ring
405
+
406
+ ```kotlin
407
+ @Composable
408
+ fun DCSpeakingRing(isActiveSpeaker: Boolean, modifier: Modifier = Modifier, avatar: @Composable () -> Unit) {
409
+ val pulse by if (isActiveSpeaker) {
410
+ rememberInfiniteTransition(label = "speak").animateFloat(
411
+ 1f, 1.12f, infiniteRepeatable(tween(300, easing = FastOutSlowInEasing), RepeatMode.Reverse), label = "ring",
412
+ )
413
+ } else remember { mutableStateOf(1f) }
414
+ Box(modifier, contentAlignment = Alignment.Center) {
415
+ avatar()
416
+ if (isActiveSpeaker) {
417
+ Box(
418
+ Modifier
419
+ .matchParentSize()
420
+ .scale(pulse)
421
+ .clip(CircleShape)
422
+ .border(2.5.dp, DiscordColors.OnlineGreen, CircleShape),
423
+ )
424
+ }
425
+ }
426
+ }
427
+ ```
428
+
429
+ ### Emoji Reaction Chip
430
+
431
+ ```kotlin
432
+ @Composable
433
+ fun DCReactionChip(emoji: String, count: Int, didReact: Boolean, onTap: () -> Unit, modifier: Modifier = Modifier) {
434
+ val haptics = LocalHapticFeedback.current
435
+ Row(
436
+ modifier
437
+ .clip(RoundedCornerShape(8.dp))
438
+ .background(if (didReact) DiscordColors.Blurple.copy(alpha = 0.3f) else DiscordColors.ChannelList)
439
+ .border(1.dp, if (didReact) DiscordColors.Blurple else DiscordColors.Divider, RoundedCornerShape(8.dp))
440
+ .clickable { haptics.performHapticFeedback(HapticFeedbackType.TextHandleMove); onTap() }
441
+ .padding(horizontal = 8.dp, vertical = 4.dp),
442
+ verticalAlignment = Alignment.CenterVertically,
443
+ horizontalArrangement = Arrangement.spacedBy(4.dp),
444
+ ) {
445
+ Text(emoji, style = DiscordText.MessageBody)
446
+ Text("$count", style = DiscordText.Timestamp.copy(fontSize = 13.sp), color = DiscordColors.TextPrimary)
447
+ }
448
+ }
449
+ ```
450
+
451
+ ## 4. Three-Pane Swipe Navigation (the signature dynamic)
452
+
453
+ Discord has no color extraction — its distinctive dynamic system is the **three-pane horizontal-swipe architecture**: on mobile the server rail + channel list is a left drawer; swipe right to open, swipe left to close. Build it with a gesture-driven offset rather than `ModalNavigationDrawer` so the rail + channel list animate together as a unit.
454
+
455
+ ```kotlin
456
+ import androidx.compose.foundation.gestures.detectHorizontalDragGestures
457
+ import androidx.compose.ui.input.pointer.pointerInput
458
+ import androidx.compose.ui.platform.LocalDensity
459
+ import androidx.compose.ui.unit.IntOffset
460
+ import kotlin.math.roundToInt
461
+
462
+ @Composable
463
+ fun DCMobileShell(
464
+ servers: List<Server>,
465
+ chat: @Composable () -> Unit,
466
+ channelList: @Composable () -> Unit,
467
+ ) {
468
+ BoxWithConstraints(Modifier.fillMaxSize()) {
469
+ val density = LocalDensity.current
470
+ val drawerWidthPx = with(density) { (maxWidth * 0.85f).toPx() }
471
+ var open by remember { mutableStateOf(true) }
472
+ val offsetPx by animateFloatAsState(
473
+ targetValue = if (open) 0f else -drawerWidthPx,
474
+ animationSpec = spring(dampingRatio = 0.85f, stiffness = 380f),
475
+ label = "drawer",
476
+ )
477
+ // Chat canvas — pushed right when drawer is open
478
+ Box(
479
+ Modifier
480
+ .fillMaxSize()
481
+ .offset { IntOffset((drawerWidthPx + offsetPx).roundToInt(), 0) }
482
+ .background(DiscordColors.ChatCanvas)
483
+ .pointerInput(Unit) {
484
+ detectHorizontalDragGestures(onDragEnd = { /* settle handled below */ }) { _, drag ->
485
+ if (drag > 8) open = true else if (drag < -8) open = false
486
+ }
487
+ },
488
+ ) { chat() }
489
+ // Rail + channel list, animating as one unit
490
+ Row(
491
+ Modifier
492
+ .width(maxWidth * 0.85f)
493
+ .fillMaxHeight()
494
+ .offset { IntOffset(offsetPx.roundToInt(), 0) },
495
+ ) {
496
+ DCServerRail(servers, activeId = servers.firstOrNull()?.id, onSelect = {})
497
+ Box(Modifier.weight(1f).fillMaxHeight().background(DiscordColors.ChannelList)) { channelList() }
498
+ }
499
+ }
500
+ }
501
+ ```
502
+
503
+ ## 5. Navigation
504
+
505
+ Discord's mobile root is a **4-tab bottom bar** (Servers / Messages / Notifications / You) — *not* a tab bar for channels (channels live in the swipe drawer above). The bar sits on `ServerRail` gray. Active tint is white (Blurple is structural, not for chrome). Discord is aggressively flat — Android has no live blur, so use an opaque rail-colored surface, no elevation.
506
+
507
+ ```kotlin
508
+ import androidx.compose.material.icons.filled.GridView
509
+ import androidx.compose.material.icons.filled.Notifications
510
+ import androidx.compose.material.icons.filled.Forum
511
+ import androidx.compose.material.icons.filled.AccountCircle
512
+ import androidx.compose.material3.NavigationBar
513
+ import androidx.compose.material3.NavigationBarItem
514
+ import androidx.compose.material3.NavigationBarItemDefaults
515
+
516
+ @Composable
517
+ fun DCBottomBar(selected: Int, mentionCount: Int, onSelect: (Int) -> Unit) {
518
+ NavigationBar(containerColor = DiscordColors.ServerRail, tonalElevation = 0.dp) {
519
+ val items = listOf(
520
+ "Servers" to Icons.Filled.GridView,
521
+ "Messages" to Icons.Filled.Forum,
522
+ "Notifications" to Icons.Filled.Notifications,
523
+ "You" to Icons.Filled.AccountCircle,
524
+ )
525
+ items.forEachIndexed { i, (label, icon) ->
526
+ NavigationBarItem(
527
+ selected = selected == i,
528
+ onClick = { onSelect(i) },
529
+ icon = {
530
+ Box(contentAlignment = Alignment.TopEnd) {
531
+ Icon(icon, contentDescription = label, modifier = Modifier.size(22.dp))
532
+ if (label == "Notifications" && mentionCount > 0) {
533
+ Box(
534
+ Modifier.offset(x = 8.dp, y = (-4).dp).defaultMinSize(16.dp, 16.dp)
535
+ .clip(CircleShape).background(DiscordColors.DNDRed).padding(horizontal = 4.dp),
536
+ contentAlignment = Alignment.Center,
537
+ ) { Text("$mentionCount", style = DiscordText.Tab, color = Color.White) }
538
+ }
539
+ }
540
+ },
541
+ label = { Text(label, style = DiscordText.Tab) },
542
+ colors = NavigationBarItemDefaults.colors(
543
+ selectedIconColor = DiscordColors.TextPrimary, // white, not Blurple
544
+ selectedTextColor = DiscordColors.TextPrimary,
545
+ unselectedIconColor = DiscordColors.TextMuted,
546
+ unselectedTextColor = DiscordColors.TextMuted,
547
+ indicatorColor = Color.Transparent, // Discord has no Material pill
548
+ ),
549
+ )
550
+ }
551
+ }
552
+ }
553
+ ```
554
+
555
+ ## 6. Motion
556
+
557
+ | Moment | Compose recipe |
558
+ |--------|----------------|
559
+ | Server icon active | `animateDpAsState` corner 16 → 12 with `spring(dampingRatio = 0.7f)` (squircle morph) |
560
+ | Active indicator bar | `animateDpAsState` height 0/8 → 40 with `spring` |
561
+ | Speaking ring pulse | `rememberInfiniteTransition` `scale` 1.0 → 1.12 over 300ms `RepeatMode.Reverse` |
562
+ | Message arrival | `AnimatedVisibility` + `slideInVertically { it / 6 }` + `fadeIn` (≈150ms) |
563
+ | Reaction add | chip `scale` 1.0 → 1.2 → 1.0; `HapticFeedbackType.TextHandleMove` (soft) |
564
+ | Drawer open/close | gesture-driven `offset { IntOffset(...) }` + settle `spring(dampingRatio = 0.85f)` |
565
+ | Typing indicator | three `Circle`s with staggered `alpha` via `rememberInfiniteTransition` (300ms cycle each) |
566
+ | Spoiler reveal | `Crossfade` blur → clear over 200ms |
567
+
568
+ ```kotlin
569
+ // Server-icon squircle morph (already in DCServerIcon §3)
570
+ val corner by animateDpAsState(if (isActive) 12.dp else 16.dp, spring(dampingRatio = 0.7f, stiffness = 380f), label = "corner")
571
+ ```
572
+
573
+ Haptics: prefer `LocalHapticFeedback`. For richer control use `LocalView.current.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)` (API 30+) or a `Vibrator` `VibrationEffect.createOneShot(10, ...)` to approximate iOS's soft `.impact` on send/react.
574
+
575
+ ## 7. Icons
576
+
577
+ Discord ships many proprietary glyphs (Discord logo, Nitro star, Wumpus, channel-type icons). Use `androidx.compose.material:material-icons-extended` for the closest semantic match; bundle brand glyphs as vector drawables and load via `ImageVector.vectorResource(R.drawable.…)`.
578
+
579
+ | Component | SF Symbol (iOS) | Material Icon (Compose) |
580
+ |-----------|-----------------|--------------------------|
581
+ | Text channel | `number` | `Icons.Filled.Tag` |
582
+ | Voice channel | `speaker.wave.2.fill` | `Icons.Filled.VolumeUp` |
583
+ | Announcement channel | `megaphone.fill` | `Icons.Filled.Campaign` |
584
+ | Home / Discover | `house.fill` | `Icons.Filled.Home` (or custom logo) |
585
+ | Add server | `plus` | `Icons.Filled.Add` (green) |
586
+ | Explore servers | `safari.fill` | `Icons.Filled.Explore` |
587
+ | Compose attach | `plus.circle.fill` | `Icons.Filled.AddCircle` |
588
+ | Gift | `gift` | `Icons.Filled.CardGiftcard` |
589
+ | GIF picker | `photo.stack` | `Icons.Filled.Gif` |
590
+ | Emoji | `face.smiling` | `Icons.Filled.EmojiEmotions` |
591
+ | Send | `paperplane.fill` | `Icons.Filled.Send` |
592
+ | Pin | `pin.fill` | `Icons.Filled.PushPin` |
593
+ | Member list | `person.2.fill` | `Icons.Filled.People` |
594
+ | Search | `magnifyingglass` | `Icons.Filled.Search` |
595
+ | Servers tab | (custom grid) | `Icons.Filled.GridView` |
596
+ | Messages tab | `bubble.left.and.bubble.right.fill` | `Icons.Filled.Forum` |
597
+ | Notifications tab | `bell.fill` | `Icons.Filled.Notifications` |
598
+ | Profile tab | `person.crop.circle.fill` | `Icons.Filled.AccountCircle` |
599
+ | Mic | `mic.fill` / `mic.slash.fill` | `Icons.Filled.Mic` / `Icons.Filled.MicOff` |
600
+ | Nitro / Boost | (custom gradient glyph) | Vector drawable + `NitroGradient` brush |
601
+
602
+ ## 8. Minimum SDK & Accessibility Notes
603
+
604
+ - **minSdk 24** (Compose floor is 21; modern motion is comfortable at 24). `compileSdk 34+`, Compose BOM `2024.09+`, Kotlin `2.0+`.
605
+ - **Edge-to-edge**: call `enableEdgeToEdge()` in the `Activity`. The dark canvas wants light-content system bars; the Dynamic Island analog (status bar) sits over the `ServerRail` gray. Apply `Scaffold`/`windowInsetsPadding` so the compose bar and tab bar clear gesture nav.
606
+ - **Font scaling**: `sp` honors the user's font scale — keep it on message body, username, channel names. Pin layout-sensitive text (timestamps, tab labels) and the presence-dot size by deriving from `dp`. Cap code blocks at 18sp.
607
+ - **TalkBack**: merge username + role + message into one node with `Modifier.semantics(mergeDescendants = true)`; announce presence separately ("Online", "Do Not Disturb") — never rely on the dot color alone. Server icons get `contentDescription = server.name`.
608
+ - **Touch targets**: Material guidance is 48dp minimum. Server icons are 48dp (clear); the 36dp channel row and 32dp send circle need 48dp hit area via padding; avatar tap gets +8dp hitSlop.
609
+ - **Contrast**: the three-gray system with `#F2F3F5` text passes WCAG AA at 16sp. The real low-contrast pairs are **`#949BA4` TextMuted on `#313338`** (timestamps) and **`#5D6069` TextDisabled** — validate at 12sp and strengthen toward `#B5BAC1` where needed. If a server's arbitrary role color fails contrast against the chat canvas, fall back to `#F2F3F5`.
610
+ - **Reduce motion**: when `Settings.Global.ANIMATOR_DURATION_SCALE == 0f`, disable the server-icon squircle morph and the speaking-ring pulse.
611
+ - **Dynamic color**: do **not** enable Material You `dynamicDarkColorScheme()` — Discord's three-gray surface system and the single Blurple accent are brand-load-bearing and must not shift with wallpaper. Strong-brand app: keep the curated scheme.