@epic-web/workshop-app 6.69.1 → 6.71.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 (225) hide show
  1. package/build/client/assets/{_-BnmXymJG.js → _-dWSrc4Ox.js} +2 -2
  2. package/build/client/assets/{_-BnmXymJG.js.map → _-dWSrc4Ox.js.map} +1 -1
  3. package/build/client/assets/{_basePickBy-D6pFkWVF.js → _basePickBy-D77BeQbR.js} +2 -2
  4. package/build/client/assets/{_basePickBy-D6pFkWVF.js.map → _basePickBy-D77BeQbR.js.map} +1 -1
  5. package/build/client/assets/{_baseUniq-BbljtzXr.js → _baseUniq-DTO-tFvD.js} +2 -2
  6. package/build/client/assets/{_baseUniq-BbljtzXr.js.map → _baseUniq-DTO-tFvD.js.map} +1 -1
  7. package/build/client/assets/{_exerciseNumber-77g7-L-x.js → _exerciseNumber-DgMb13KP.js} +2 -2
  8. package/build/client/assets/{_exerciseNumber-77g7-L-x.js.map → _exerciseNumber-DgMb13KP.js.map} +1 -1
  9. package/build/client/assets/{_exerciseNumber_._stepNumber.index-DYb7kg06.js → _exerciseNumber_._stepNumber.index-WLW-sVZ0.js} +2 -2
  10. package/build/client/assets/{_exerciseNumber_._stepNumber.index-DYb7kg06.js.map → _exerciseNumber_._stepNumber.index-WLW-sVZ0.js.map} +1 -1
  11. package/build/client/assets/{_exerciseNumber_.finished-CGoPhVVF.js → _exerciseNumber_.finished-DkAs61X_.js} +2 -2
  12. package/build/client/assets/_exerciseNumber_.finished-DkAs61X_.js.map +1 -0
  13. package/build/client/assets/_extra-fwsy2qkP.js +2 -0
  14. package/build/client/assets/_extra-fwsy2qkP.js.map +1 -0
  15. package/build/client/assets/_layout-BQ8VYaze.js +2 -0
  16. package/build/client/assets/_layout-BQ8VYaze.js.map +1 -0
  17. package/build/client/assets/_layout-DR0LQ06M.js +2 -0
  18. package/build/client/assets/_layout-DR0LQ06M.js.map +1 -0
  19. package/build/client/assets/{accordion-CzXT3k43.js → accordion-CQ7oujC6.js} +2 -2
  20. package/build/client/assets/{accordion-CzXT3k43.js.map → accordion-CQ7oujC6.js.map} +1 -1
  21. package/build/client/assets/{account-Cs3Te0is.js → account-C96cpeZR.js} +2 -2
  22. package/build/client/assets/{account-Cs3Te0is.js.map → account-C96cpeZR.js.map} +1 -1
  23. package/build/client/assets/app-CJniokic.js +2 -0
  24. package/build/client/assets/{app-TcFAQB2o.js.map → app-CJniokic.js.map} +1 -1
  25. package/build/client/assets/{arc-BHxP6xxO.js → arc-ChVm3d4e.js} +2 -2
  26. package/build/client/assets/{arc-BHxP6xxO.js.map → arc-ChVm3d4e.js.map} +1 -1
  27. package/build/client/assets/{architectureDiagram-VXUJARFQ-oEJHJt7x.js → architectureDiagram-VXUJARFQ-DkqyKZ50.js} +2 -2
  28. package/build/client/assets/{architectureDiagram-VXUJARFQ-oEJHJt7x.js.map → architectureDiagram-VXUJARFQ-DkqyKZ50.js.map} +1 -1
  29. package/build/client/assets/{blockDiagram-VD42YOAC-7xzSJqoM.js → blockDiagram-VD42YOAC-Cqa8Z0qT.js} +2 -2
  30. package/build/client/assets/{blockDiagram-VD42YOAC-7xzSJqoM.js.map → blockDiagram-VD42YOAC-Cqa8Z0qT.js.map} +1 -1
  31. package/build/client/assets/{button-CIlVtsau.js → button-Cd-ekki5.js} +2 -2
  32. package/build/client/assets/{button-CIlVtsau.js.map → button-Cd-ekki5.js.map} +1 -1
  33. package/build/client/assets/{c4Diagram-YG6GDRKO-BUdT9rCJ.js → c4Diagram-YG6GDRKO-BHQRSJ1P.js} +2 -2
  34. package/build/client/assets/{c4Diagram-YG6GDRKO-BUdT9rCJ.js.map → c4Diagram-YG6GDRKO-BHQRSJ1P.js.map} +1 -1
  35. package/build/client/assets/{cache-MJu_dqFS.js → cache-CAr50MIB.js} +2 -2
  36. package/build/client/assets/{cache-MJu_dqFS.js.map → cache-CAr50MIB.js.map} +1 -1
  37. package/build/client/assets/channel-B7uExpgv.js +2 -0
  38. package/build/client/assets/{channel-BLJkdd1O.js.map → channel-B7uExpgv.js.map} +1 -1
  39. package/build/client/assets/{chunk-4BX2VUAB-qrzenNNi.js → chunk-4BX2VUAB-BOJM4J9w.js} +2 -2
  40. package/build/client/assets/{chunk-4BX2VUAB-qrzenNNi.js.map → chunk-4BX2VUAB-BOJM4J9w.js.map} +1 -1
  41. package/build/client/assets/{chunk-55IACEB6-BOr0rES3.js → chunk-55IACEB6-CO_GT_87.js} +2 -2
  42. package/build/client/assets/{chunk-55IACEB6-BOr0rES3.js.map → chunk-55IACEB6-CO_GT_87.js.map} +1 -1
  43. package/build/client/assets/{chunk-B4BG7PRW-C2qQTBXm.js → chunk-B4BG7PRW-CqfZTumF.js} +2 -2
  44. package/build/client/assets/{chunk-B4BG7PRW-C2qQTBXm.js.map → chunk-B4BG7PRW-CqfZTumF.js.map} +1 -1
  45. package/build/client/assets/{chunk-DI55MBZ5-CSfEUcAq.js → chunk-DI55MBZ5-CxSXOmoK.js} +2 -2
  46. package/build/client/assets/{chunk-DI55MBZ5-CSfEUcAq.js.map → chunk-DI55MBZ5-CxSXOmoK.js.map} +1 -1
  47. package/build/client/assets/{chunk-FMBD7UC4-CyJoWksV.js → chunk-FMBD7UC4-ChHVMdVq.js} +2 -2
  48. package/build/client/assets/{chunk-FMBD7UC4-CyJoWksV.js.map → chunk-FMBD7UC4-ChHVMdVq.js.map} +1 -1
  49. package/build/client/assets/{chunk-QN33PNHL-BpbvTQdp.js → chunk-QN33PNHL-DKEBwj3f.js} +2 -2
  50. package/build/client/assets/{chunk-QN33PNHL-BpbvTQdp.js.map → chunk-QN33PNHL-DKEBwj3f.js.map} +1 -1
  51. package/build/client/assets/{chunk-QZHKN3VN-C2RN0CtQ.js → chunk-QZHKN3VN-Cu5tuE5n.js} +2 -2
  52. package/build/client/assets/{chunk-QZHKN3VN-C2RN0CtQ.js.map → chunk-QZHKN3VN-Cu5tuE5n.js.map} +1 -1
  53. package/build/client/assets/{chunk-TZMSLE5B-0z8lxtDn.js → chunk-TZMSLE5B-BpvH1fVS.js} +2 -2
  54. package/build/client/assets/{chunk-TZMSLE5B-0z8lxtDn.js.map → chunk-TZMSLE5B-BpvH1fVS.js.map} +1 -1
  55. package/build/client/assets/classDiagram-2ON5EDUG-BjjlpwdW.js +2 -0
  56. package/build/client/assets/{classDiagram-2ON5EDUG-_kfNpv_f.js.map → classDiagram-2ON5EDUG-BjjlpwdW.js.map} +1 -1
  57. package/build/client/assets/classDiagram-v2-WZHVMYZB-BjjlpwdW.js +2 -0
  58. package/build/client/assets/{classDiagram-v2-WZHVMYZB-_kfNpv_f.js.map → classDiagram-v2-WZHVMYZB-BjjlpwdW.js.map} +1 -1
  59. package/build/client/assets/clone-DRkw5ylZ.js +2 -0
  60. package/build/client/assets/{clone-CztDUJhf.js.map → clone-DRkw5ylZ.js.map} +1 -1
  61. package/build/client/assets/{cose-bilkent-S5V4N54A-DQM-J4RL.js → cose-bilkent-S5V4N54A-9tAqXXXx.js} +2 -2
  62. package/build/client/assets/{cose-bilkent-S5V4N54A-DQM-J4RL.js.map → cose-bilkent-S5V4N54A-9tAqXXXx.js.map} +1 -1
  63. package/build/client/assets/{dagre-6UL2VRFP-BdfvKPZ9.js → dagre-6UL2VRFP-DdQahM76.js} +2 -2
  64. package/build/client/assets/{dagre-6UL2VRFP-BdfvKPZ9.js.map → dagre-6UL2VRFP-DdQahM76.js.map} +1 -1
  65. package/build/client/assets/{db-x6v-Uxrh.js → db-DAnX-T3_.js} +2 -2
  66. package/build/client/assets/{db-x6v-Uxrh.js.map → db-DAnX-T3_.js.map} +1 -1
  67. package/build/client/assets/{diagram-PSM6KHXK-CgwBEb3G.js → diagram-PSM6KHXK-D2ghOCFR.js} +2 -2
  68. package/build/client/assets/{diagram-PSM6KHXK-CgwBEb3G.js.map → diagram-PSM6KHXK-D2ghOCFR.js.map} +1 -1
  69. package/build/client/assets/{diagram-QEK2KX5R-DEaXdLXz.js → diagram-QEK2KX5R-CVdPnwKa.js} +2 -2
  70. package/build/client/assets/{diagram-QEK2KX5R-DEaXdLXz.js.map → diagram-QEK2KX5R-CVdPnwKa.js.map} +1 -1
  71. package/build/client/assets/{diagram-S2PKOQOG-Dq5QQWqq.js → diagram-S2PKOQOG-ByHcRNai.js} +2 -2
  72. package/build/client/assets/{diagram-S2PKOQOG-Dq5QQWqq.js.map → diagram-S2PKOQOG-ByHcRNai.js.map} +1 -1
  73. package/build/client/assets/{dialog-DnpUg3VT.js → dialog-CzO65Z5w.js} +3 -3
  74. package/build/client/assets/{dialog-DnpUg3VT.js.map → dialog-CzO65Z5w.js.map} +1 -1
  75. package/build/client/assets/{diff-CxEbhF8Q.js → diff-BhWzqoVN.js} +2 -2
  76. package/build/client/assets/{diff-CxEbhF8Q.js.map → diff-BhWzqoVN.js.map} +1 -1
  77. package/build/client/assets/{diff-eAvgXb3f.js → diff-DC-wn6-x.js} +2 -2
  78. package/build/client/assets/{diff-eAvgXb3f.js.map → diff-DC-wn6-x.js.map} +1 -1
  79. package/build/client/assets/{discord-DlU9y5Iz.js → discord-BJkw0IrB.js} +2 -2
  80. package/build/client/assets/{discord-DlU9y5Iz.js.map → discord-BJkw0IrB.js.map} +1 -1
  81. package/build/client/assets/{discord-CuxZiU8E.js → discord-r3m19sUM.js} +2 -2
  82. package/build/client/assets/discord-r3m19sUM.js.map +1 -0
  83. package/build/client/assets/{epic-video-Bx8Ctiez.js → epic-video-8Hv_HMMr.js} +2 -2
  84. package/build/client/assets/{epic-video-Bx8Ctiez.js.map → epic-video-8Hv_HMMr.js.map} +1 -1
  85. package/build/client/assets/{epic-video-BVcJzJzi.js → epic-video-D0drHmgC.js} +2 -2
  86. package/build/client/assets/{epic-video-BVcJzJzi.js.map → epic-video-D0drHmgC.js.map} +1 -1
  87. package/build/client/assets/{erDiagram-Q2GNP2WA-CW73Zw0q.js → erDiagram-Q2GNP2WA-CBRWzQzK.js} +2 -2
  88. package/build/client/assets/{erDiagram-Q2GNP2WA-CW73Zw0q.js.map → erDiagram-Q2GNP2WA-CBRWzQzK.js.map} +1 -1
  89. package/build/client/assets/{error-boundary-DFBd6s0g.js → error-boundary-DVp6wKiz.js} +2 -2
  90. package/build/client/assets/{error-boundary-DFBd6s0g.js.map → error-boundary-DVp6wKiz.js.map} +1 -1
  91. package/build/client/assets/{finished-CmV4aFjA.js → finished-CiVHAeSV.js} +2 -2
  92. package/build/client/assets/{finished-CmV4aFjA.js.map → finished-CiVHAeSV.js.map} +1 -1
  93. package/build/client/assets/{flowDiagram-NV44I4VS-BbxV9VQf.js → flowDiagram-NV44I4VS-L32__tfK.js} +2 -2
  94. package/build/client/assets/{flowDiagram-NV44I4VS-BbxV9VQf.js.map → flowDiagram-NV44I4VS-L32__tfK.js.map} +1 -1
  95. package/build/client/assets/{ganttDiagram-JELNMOA3-CRBJBlE5.js → ganttDiagram-JELNMOA3-Dpp5PKJc.js} +2 -2
  96. package/build/client/assets/{ganttDiagram-JELNMOA3-CRBJBlE5.js.map → ganttDiagram-JELNMOA3-Dpp5PKJc.js.map} +1 -1
  97. package/build/client/assets/{gitGraphDiagram-NY62KEGX-CU0X3hfs.js → gitGraphDiagram-NY62KEGX-zn4IXANG.js} +2 -2
  98. package/build/client/assets/{gitGraphDiagram-NY62KEGX-CU0X3hfs.js.map → gitGraphDiagram-NY62KEGX-zn4IXANG.js.map} +1 -1
  99. package/build/client/assets/{graph-CEUh1UxC.js → graph-Da5nhwRG.js} +2 -2
  100. package/build/client/assets/{graph-CEUh1UxC.js.map → graph-Da5nhwRG.js.map} +1 -1
  101. package/build/client/assets/guide-Cinib8Ji.js +9 -0
  102. package/build/client/assets/guide-Cinib8Ji.js.map +1 -0
  103. package/build/client/assets/{index-D3zOGeBE.js → index-BKAVQvm5.js} +2 -2
  104. package/build/client/assets/{index-D3zOGeBE.js.map → index-BKAVQvm5.js.map} +1 -1
  105. package/build/client/assets/{index-BOhw3wcM.js → index-CJDOQ1bl.js} +2 -2
  106. package/build/client/assets/{index-BOhw3wcM.js.map → index-CJDOQ1bl.js.map} +1 -1
  107. package/build/client/assets/{index-B-9GR1C2.js → index-C_wcF1aP.js} +2 -2
  108. package/build/client/assets/{index-B-9GR1C2.js.map → index-C_wcF1aP.js.map} +1 -1
  109. package/build/client/assets/{index-BW8stNyh.js → index-CdzVFL-Z.js} +3 -3
  110. package/build/client/assets/{index-BW8stNyh.js.map → index-CdzVFL-Z.js.map} +1 -1
  111. package/build/client/assets/index-CmflCPTU.js +2 -0
  112. package/build/client/assets/index-CmflCPTU.js.map +1 -0
  113. package/build/client/assets/index-DuFMeXSm.js +2 -0
  114. package/build/client/assets/index-DuFMeXSm.js.map +1 -0
  115. package/build/client/assets/index-hhQHCvb9.js +2 -0
  116. package/build/client/assets/{index-EdNV8gTk.js.map → index-hhQHCvb9.js.map} +1 -1
  117. package/build/client/assets/{index-C_KjwKVt.js → index-ynYvVAOK.js} +2 -2
  118. package/build/client/assets/{index-C_KjwKVt.js.map → index-ynYvVAOK.js.map} +1 -1
  119. package/build/client/assets/{infoDiagram-WHAUD3N6-BplcSre1.js → infoDiagram-WHAUD3N6-CToPP1ur.js} +2 -2
  120. package/build/client/assets/{infoDiagram-WHAUD3N6-BplcSre1.js.map → infoDiagram-WHAUD3N6-CToPP1ur.js.map} +1 -1
  121. package/build/client/assets/{journeyDiagram-XKPGCS4Q-yxvCkf49.js → journeyDiagram-XKPGCS4Q-BBRpqEuF.js} +2 -2
  122. package/build/client/assets/{journeyDiagram-XKPGCS4Q-yxvCkf49.js.map → journeyDiagram-XKPGCS4Q-BBRpqEuF.js.map} +1 -1
  123. package/build/client/assets/{kanban-definition-3W4ZIXB7-DFEBMrRH.js → kanban-definition-3W4ZIXB7-CyGlZ-MK.js} +2 -2
  124. package/build/client/assets/{kanban-definition-3W4ZIXB7-DFEBMrRH.js.map → kanban-definition-3W4ZIXB7-CyGlZ-MK.js.map} +1 -1
  125. package/build/client/assets/{launch-editor-B2dmpkaO.js → launch-editor-D2exGfVu.js} +2 -2
  126. package/build/client/assets/{launch-editor-B2dmpkaO.js.map → launch-editor-D2exGfVu.js.map} +1 -1
  127. package/build/client/assets/{layout-CiHrgFnf.js → layout-CUEelucj.js} +2 -2
  128. package/build/client/assets/{layout-CiHrgFnf.js.map → layout-CUEelucj.js.map} +1 -1
  129. package/build/client/assets/{linear-C-81cvJP.js → linear-DzZ9bjHs.js} +2 -2
  130. package/build/client/assets/{linear-C-81cvJP.js.map → linear-DzZ9bjHs.js.map} +1 -1
  131. package/build/client/assets/{loading-CUydCGD3.js → loading-CDNzW5oO.js} +2 -2
  132. package/build/client/assets/{loading-CUydCGD3.js.map → loading-CDNzW5oO.js.map} +1 -1
  133. package/build/client/assets/{login-DvBmP_ce.js → login-mWjVXGbJ.js} +2 -2
  134. package/build/client/assets/{login-DvBmP_ce.js.map → login-mWjVXGbJ.js.map} +1 -1
  135. package/build/client/assets/manifest-970c9ad1.js +1 -0
  136. package/build/client/assets/{mdx-vrch0szL.js → mdx-BzyhMqFg.js} +3 -3
  137. package/build/client/assets/{mdx-vrch0szL.js.map → mdx-BzyhMqFg.js.map} +1 -1
  138. package/build/client/assets/{mermaid.core-D3y7PO8B.js → mermaid.core-BdxLLjl2.js} +5 -5
  139. package/build/client/assets/{mermaid.core-D3y7PO8B.js.map → mermaid.core-BdxLLjl2.js.map} +1 -1
  140. package/build/client/assets/{mindmap-definition-VGOIOE7T-VMZ6ZZlW.js → mindmap-definition-VGOIOE7T-DeKD8ncg.js} +2 -2
  141. package/build/client/assets/{mindmap-definition-VGOIOE7T-VMZ6ZZlW.js.map → mindmap-definition-VGOIOE7T-DeKD8ncg.js.map} +1 -1
  142. package/build/client/assets/{misc-DVYuZMjW.js → misc-W4055b-0.js} +2 -2
  143. package/build/client/assets/{misc-DVYuZMjW.js.map → misc-W4055b-0.js.map} +1 -1
  144. package/build/client/assets/{nav-chevrons-DlNUibJV.js → nav-chevrons-Dk4GtZwQ.js} +2 -2
  145. package/build/client/assets/{nav-chevrons-DlNUibJV.js.map → nav-chevrons-Dk4GtZwQ.js.map} +1 -1
  146. package/build/client/assets/{offline-videos-Do9PBh87.js → offline-videos-BP7_xJkO.js} +2 -2
  147. package/build/client/assets/{offline-videos-Do9PBh87.js.map → offline-videos-BP7_xJkO.js.map} +1 -1
  148. package/build/client/assets/{onboarding-indicator-CVwXz3Cn.js → onboarding-indicator-B-XR90_G.js} +2 -2
  149. package/build/client/assets/{onboarding-indicator-CVwXz3Cn.js.map → onboarding-indicator-B-XR90_G.js.map} +1 -1
  150. package/build/client/assets/{pieDiagram-ADFJNKIX-CKbrBdQs.js → pieDiagram-ADFJNKIX-BQ4sFDrB.js} +2 -2
  151. package/build/client/assets/{pieDiagram-ADFJNKIX-CKbrBdQs.js.map → pieDiagram-ADFJNKIX-BQ4sFDrB.js.map} +1 -1
  152. package/build/client/assets/playground-DmEAkxG1.js +2 -0
  153. package/build/client/assets/playground-DmEAkxG1.js.map +1 -0
  154. package/build/client/assets/{playground-window-D9a7P7rH.js → playground-window-x2mQ5o1O.js} +2 -2
  155. package/build/client/assets/{playground-window-D9a7P7rH.js.map → playground-window-x2mQ5o1O.js.map} +1 -1
  156. package/build/client/assets/{preferences-BCvK10k2.js → preferences-D6HQ5bK1.js} +2 -2
  157. package/build/client/assets/{preferences-BCvK10k2.js.map → preferences-D6HQ5bK1.js.map} +1 -1
  158. package/build/client/assets/{preview-CiDtuQCc.js → preview-fhmjENlm.js} +2 -2
  159. package/build/client/assets/{preview-CiDtuQCc.js.map → preview-fhmjENlm.js.map} +1 -1
  160. package/build/client/assets/{product-GLsnY1u3.js → product-CvyMpYD_.js} +2 -2
  161. package/build/client/assets/{product-GLsnY1u3.js.map → product-CvyMpYD_.js.map} +1 -1
  162. package/build/client/assets/{progress-fKsNxmmt.js → progress-ILaVQtOO.js} +2 -2
  163. package/build/client/assets/{progress-fKsNxmmt.js.map → progress-ILaVQtOO.js.map} +1 -1
  164. package/build/client/assets/{progress-bar-B27isaGl.js → progress-bar-DpWhcyhC.js} +2 -2
  165. package/build/client/assets/{progress-bar-B27isaGl.js.map → progress-bar-DpWhcyhC.js.map} +1 -1
  166. package/build/client/assets/{quadrantDiagram-AYHSOK5B-Bb5EtkPw.js → quadrantDiagram-AYHSOK5B-QnjodHfi.js} +2 -2
  167. package/build/client/assets/{quadrantDiagram-AYHSOK5B-Bb5EtkPw.js.map → quadrantDiagram-AYHSOK5B-QnjodHfi.js.map} +1 -1
  168. package/build/client/assets/{requirementDiagram-UZGBJVZJ-BNsXiFG2.js → requirementDiagram-UZGBJVZJ-mL9Oeda0.js} +2 -2
  169. package/build/client/assets/{requirementDiagram-UZGBJVZJ-BNsXiFG2.js.map → requirementDiagram-UZGBJVZJ-mL9Oeda0.js.map} +1 -1
  170. package/build/client/assets/{root-Ch373D3a.js → root-Bktp3RtN.js} +2 -2
  171. package/build/client/assets/{root-Ch373D3a.js.map → root-Bktp3RtN.js.map} +1 -1
  172. package/build/client/assets/{sankeyDiagram-TZEHDZUN-qlPqhk7P.js → sankeyDiagram-TZEHDZUN-B8_zpQVR.js} +2 -2
  173. package/build/client/assets/{sankeyDiagram-TZEHDZUN-qlPqhk7P.js.map → sankeyDiagram-TZEHDZUN-B8_zpQVR.js.map} +1 -1
  174. package/build/client/assets/{sequenceDiagram-WL72ISMW-C3d31B7K.js → sequenceDiagram-WL72ISMW-BDd5tjuk.js} +2 -2
  175. package/build/client/assets/{sequenceDiagram-WL72ISMW-C3d31B7K.js.map → sequenceDiagram-WL72ISMW-BDd5tjuk.js.map} +1 -1
  176. package/build/client/assets/{set-playground-DeMY9i7p.js → set-playground-BSGwH9dH.js} +2 -2
  177. package/build/client/assets/{set-playground-DeMY9i7p.js.map → set-playground-BSGwH9dH.js.map} +1 -1
  178. package/build/client/assets/{stateDiagram-FKZM4ZOC-C1eIQm_7.js → stateDiagram-FKZM4ZOC-DGPNpRbW.js} +2 -2
  179. package/build/client/assets/{stateDiagram-FKZM4ZOC-C1eIQm_7.js.map → stateDiagram-FKZM4ZOC-DGPNpRbW.js.map} +1 -1
  180. package/build/client/assets/stateDiagram-v2-4FDKWEC3-DxaFuKxL.js +2 -0
  181. package/build/client/assets/{stateDiagram-v2-4FDKWEC3-CAmcrDIS.js.map → stateDiagram-v2-4FDKWEC3-DxaFuKxL.js.map} +1 -1
  182. package/build/client/assets/status-indicator-C6DiLYL5.js +2 -0
  183. package/build/client/assets/status-indicator-C6DiLYL5.js.map +1 -0
  184. package/build/client/assets/tailwind-B97VvnKU.css +1 -0
  185. package/build/client/assets/test-DtQCjBBX.js +2 -0
  186. package/build/client/assets/{test-CdEKoDoS.js.map → test-DtQCjBBX.js.map} +1 -1
  187. package/build/client/assets/{tests-xD9PppmM.js → tests-fDISNsE-.js} +2 -2
  188. package/build/client/assets/{tests-xD9PppmM.js.map → tests-fDISNsE-.js.map} +1 -1
  189. package/build/client/assets/{timeline-definition-IT6M3QCI-Di_ZGPjO.js → timeline-definition-IT6M3QCI-BnMOh0dz.js} +2 -2
  190. package/build/client/assets/{timeline-definition-IT6M3QCI-Di_ZGPjO.js.map → timeline-definition-IT6M3QCI-BnMOh0dz.js.map} +1 -1
  191. package/build/client/assets/{tooltip-Chzzs4KB.js → tooltip-Tlsyx2YO.js} +2 -2
  192. package/build/client/assets/{tooltip-Chzzs4KB.js.map → tooltip-Tlsyx2YO.js.map} +1 -1
  193. package/build/client/assets/{treemap-KMMF4GRG-DZrMUxqR.js → treemap-KMMF4GRG-Ds3XkDP-.js} +2 -2
  194. package/build/client/assets/{treemap-KMMF4GRG-DZrMUxqR.js.map → treemap-KMMF4GRG-Ds3XkDP-.js.map} +1 -1
  195. package/build/client/assets/{workspace-structure-i_5Tiikk.js → workspace-structure-B6Rpl-B2.js} +2 -2
  196. package/build/client/assets/{workspace-structure-i_5Tiikk.js.map → workspace-structure-B6Rpl-B2.js.map} +1 -1
  197. package/build/client/assets/{xychartDiagram-PRI3JC2R-BxuKJVc7.js → xychartDiagram-PRI3JC2R-DH_JPNZp.js} +2 -2
  198. package/build/client/assets/{xychartDiagram-PRI3JC2R-BxuKJVc7.js.map → xychartDiagram-PRI3JC2R-DH_JPNZp.js.map} +1 -1
  199. package/build/server/index.js +690 -114
  200. package/build/server/index.js.map +1 -1
  201. package/package.json +3 -3
  202. package/build/client/assets/_exerciseNumber_.finished-CGoPhVVF.js.map +0 -1
  203. package/build/client/assets/_extra-BZPB_nWQ.js +0 -2
  204. package/build/client/assets/_extra-BZPB_nWQ.js.map +0 -1
  205. package/build/client/assets/_layout-BxQPZuW6.js +0 -2
  206. package/build/client/assets/_layout-BxQPZuW6.js.map +0 -1
  207. package/build/client/assets/_layout-yxOoJ6Yg.js +0 -2
  208. package/build/client/assets/_layout-yxOoJ6Yg.js.map +0 -1
  209. package/build/client/assets/app-TcFAQB2o.js +0 -2
  210. package/build/client/assets/channel-BLJkdd1O.js +0 -2
  211. package/build/client/assets/classDiagram-2ON5EDUG-_kfNpv_f.js +0 -2
  212. package/build/client/assets/classDiagram-v2-WZHVMYZB-_kfNpv_f.js +0 -2
  213. package/build/client/assets/clone-CztDUJhf.js +0 -2
  214. package/build/client/assets/discord-CuxZiU8E.js.map +0 -1
  215. package/build/client/assets/guide-B4wAqzq_.js +0 -9
  216. package/build/client/assets/guide-B4wAqzq_.js.map +0 -1
  217. package/build/client/assets/index-C6vQqVxz.js +0 -2
  218. package/build/client/assets/index-C6vQqVxz.js.map +0 -1
  219. package/build/client/assets/index-EdNV8gTk.js +0 -2
  220. package/build/client/assets/manifest-34df6718.js +0 -1
  221. package/build/client/assets/playground-C_aP_pE8.js +0 -2
  222. package/build/client/assets/playground-C_aP_pE8.js.map +0 -1
  223. package/build/client/assets/stateDiagram-v2-4FDKWEC3-CAmcrDIS.js +0 -2
  224. package/build/client/assets/tailwind-D_K12wB7.css +0 -1
  225. package/build/client/assets/test-CdEKoDoS.js +0 -2
@@ -1 +1 @@
1
- {"version":3,"file":"preferences-BCvK10k2.js","sources":["../../../app/routes/_app+/preferences.tsx"],"sourcesContent":["import {\n\tgetPreferences,\n\tsetPreferences,\n} from '@epic-web/workshop-utils/db.server'\nimport {\n\tgetOfflineVideoSummary,\n\tstartOfflineVideoDownload,\n\tdeleteOfflineVideosForWorkshop,\n} from '@epic-web/workshop-utils/offline-videos.server'\nimport {\n\tForm,\n\tLink,\n\tuseFetcher,\n\tuseLoaderData,\n\tuseNavigation,\n} from 'react-router'\nimport { Button } from '#app/components/button.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { ensureUndeployed, useInterval } from '#app/utils/misc.tsx'\nimport { useRootLoaderData } from '#app/utils/root-loader.ts'\nimport { redirectWithToast } from '#app/utils/toast.server.ts'\nimport { type Route } from './+types/preferences.tsx'\n\nconst downloadResolutionOptions = [\n\t{ value: 'best', label: 'Best available' },\n\t{ value: 'high', label: 'High' },\n\t{ value: 'medium', label: 'Medium' },\n\t{ value: 'low', label: 'Low' },\n] as const\ntype DownloadResolutionOption =\n\t(typeof downloadResolutionOptions)[number]['value']\n\nfunction isDownloadResolutionOption(\n\tvalue: FormDataEntryValue | null,\n): value is DownloadResolutionOption {\n\treturn (\n\t\ttypeof value === 'string' &&\n\t\tdownloadResolutionOptions.some((option) => option.value === value)\n\t)\n}\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tensureUndeployed()\n\tconst [preferences, offlineVideos] = await Promise.all([\n\t\tgetPreferences(),\n\t\tgetOfflineVideoSummary({ request }),\n\t])\n\treturn { preferences, offlineVideos }\n}\n\nexport async function action({ request }: Route.ActionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\n\tif (intent === 'download-offline-videos') {\n\t\tconst result = await startOfflineVideoDownload({ request })\n\t\tif (result.queued === 0) {\n\t\t\tconst description =\n\t\t\t\tresult.available === 0\n\t\t\t\t\t? 'No downloadable videos were found for this workshop.'\n\t\t\t\t\t: result.unavailable > 0\n\t\t\t\t\t\t? 'All available videos are already downloaded. Some videos require access to download.'\n\t\t\t\t\t\t: 'All available videos are already downloaded.'\n\t\t\treturn redirectWithToast('/preferences', {\n\t\t\t\ttitle: 'Offline videos are ready',\n\t\t\t\tdescription,\n\t\t\t\ttype: 'success',\n\t\t\t})\n\t\t}\n\n\t\treturn redirectWithToast('/preferences', {\n\t\t\ttitle: 'Offline downloads started',\n\t\t\tdescription: `Queued ${result.queued} video${result.queued === 1 ? '' : 's'} for download.`,\n\t\t\ttype: 'success',\n\t\t})\n\t}\n\n\tif (intent === 'delete-offline-videos') {\n\t\tconst result = await deleteOfflineVideosForWorkshop()\n\t\tconst description =\n\t\t\tresult.deletedFiles === 0\n\t\t\t\t? 'No offline videos were removed.'\n\t\t\t\t: `Removed ${result.deletedFiles} offline video${\n\t\t\t\t\t\tresult.deletedFiles === 1 ? '' : 's'\n\t\t\t\t\t}.`\n\t\treturn redirectWithToast('/preferences', {\n\t\t\ttitle: 'Offline videos cleared',\n\t\t\tdescription,\n\t\t\ttype: 'success',\n\t\t})\n\t}\n\n\tconst minResolution = formData.get('minResolution')\n\tconst maxResolution = formData.get('maxResolution')\n\tconst downloadResolution = formData.get('downloadResolution')\n\tconst fontSize = formData.get('fontSize')\n\tconst optOutPresence = formData.get('optOutPresence') === 'on'\n\tconst persistPlayground = formData.get('persistPlayground') === 'on'\n\tconst dismissExerciseWarning = formData.get('dismissExerciseWarning') === 'on'\n\tconst downloadResolutionValue = isDownloadResolutionOption(downloadResolution)\n\t\t? downloadResolution\n\t\t: undefined\n\n\tawait setPreferences({\n\t\tplayer: {\n\t\t\tminResolution: minResolution ? Number(minResolution) : undefined,\n\t\t\tmaxResolution: maxResolution ? Number(maxResolution) : undefined,\n\t\t},\n\t\tofflineVideo: {\n\t\t\tdownloadResolution: downloadResolutionValue,\n\t\t},\n\t\tfontSize: fontSize ? Number(fontSize) : undefined,\n\t\tpresence: { optOut: optOutPresence },\n\t\tplayground: { persist: persistPlayground },\n\t\texerciseWarning: { dismissed: dismissExerciseWarning },\n\t})\n\n\treturn redirectWithToast('/preferences', {\n\t\ttitle: 'Preferences updated',\n\t\tdescription: 'Your preferences have been updated.',\n\t\ttype: 'success',\n\t})\n}\n\nexport default function AccountSettings() {\n\tconst loaderData = useLoaderData<typeof loader>()\n\tconst rootData = useRootLoaderData()\n\tconst playerPreferences = rootData.preferences?.player\n\tconst offlineVideoPreferences = rootData.preferences?.offlineVideo\n\tconst fontSizePreference = rootData.preferences?.fontSize\n\tconst presencePreferences = rootData.preferences?.presence\n\tconst playgroundPreferences = rootData.preferences?.playground\n\tconst exerciseWarningPreferences = rootData.preferences?.exerciseWarning\n\tconst navigation = useNavigation()\n\tconst offlineVideosFetcher = useFetcher<typeof loader>()\n\tconst offlineVideos =\n\t\tofflineVideosFetcher.data?.offlineVideos ?? loaderData.offlineVideos\n\tconst isDownloading = offlineVideos.downloadState.status === 'running'\n\n\tconst isSubmitting = navigation.state === 'submitting'\n\n\tuseInterval(\n\t\t() => {\n\t\t\tif (offlineVideosFetcher.state === 'idle') {\n\t\t\t\tvoid offlineVideosFetcher.load('/resources/offline-videos')\n\t\t\t}\n\t\t},\n\t\tisDownloading ? 2000 : null,\n\t)\n\n\treturn (\n\t\t<div className=\"h-full w-full overflow-y-auto\">\n\t\t\t<main className=\"container mt-12 flex w-full max-w-3xl grow flex-col gap-4 pb-24\">\n\t\t\t\t<h1 className=\"text-h1 mb-4\">Preferences</h1>\n\t\t\t\t<Form method=\"post\" className=\"flex w-full max-w-sm flex-col gap-4\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h2 className=\"text-body-xl mb-2\">Video Player Preferences</h2>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<label htmlFor=\"minResolution\">Minimum Resolution:</label>\n\t\t\t\t\t\t\t<select\n\t\t\t\t\t\t\t\tid=\"minResolution\"\n\t\t\t\t\t\t\t\tname=\"minResolution\"\n\t\t\t\t\t\t\t\tdefaultValue={playerPreferences?.minResolution}\n\t\t\t\t\t\t\t\tclassName=\"border-border bg-background text-foreground rounded-md border px-2 py-1\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<option value=\"\">Auto</option>\n\t\t\t\t\t\t\t\t<option value=\"480\">480p</option>\n\t\t\t\t\t\t\t\t<option value=\"720\">720p</option>\n\t\t\t\t\t\t\t\t<option value=\"1080\">1080p</option>\n\t\t\t\t\t\t\t\t<option value=\"1440\">1440p</option>\n\t\t\t\t\t\t\t\t<option value=\"2160\">2160p (4K)</option>\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<label htmlFor=\"maxResolution\">Maximum Resolution:</label>\n\t\t\t\t\t\t\t<select\n\t\t\t\t\t\t\t\tid=\"maxResolution\"\n\t\t\t\t\t\t\t\tname=\"maxResolution\"\n\t\t\t\t\t\t\t\tdefaultValue={playerPreferences?.maxResolution}\n\t\t\t\t\t\t\t\tclassName=\"border-border bg-background text-foreground rounded-md border px-2 py-1\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<option value=\"\">Auto</option>\n\t\t\t\t\t\t\t\t<option value=\"720\">720p</option>\n\t\t\t\t\t\t\t\t<option value=\"1080\">1080p</option>\n\t\t\t\t\t\t\t\t<option value=\"1440\">1440p</option>\n\t\t\t\t\t\t\t\t<option value=\"2160\">2160p (4K)</option>\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h2 className=\"text-body-xl mb-2\">Offline Video Downloads</h2>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<label htmlFor=\"downloadResolution\">Download Resolution:</label>\n\t\t\t\t\t\t\t<select\n\t\t\t\t\t\t\t\tid=\"downloadResolution\"\n\t\t\t\t\t\t\t\tname=\"downloadResolution\"\n\t\t\t\t\t\t\t\tdefaultValue={\n\t\t\t\t\t\t\t\t\tofflineVideoPreferences?.downloadResolution ?? 'best'\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tclassName=\"border-border bg-background text-foreground rounded-md border px-2 py-1\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{downloadResolutionOptions.map((option) => (\n\t\t\t\t\t\t\t\t\t<option key={option.value} value={option.value}>\n\t\t\t\t\t\t\t\t\t\t{option.label}\n\t\t\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\tDefaults to the best available resolution.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t\t\t\t<h2 className=\"text-body-xl\">Font Size Preference</h2>\n\t\t\t\t\t\t\t<SimpleTooltip content=\"Defaults to 16px\">\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<label htmlFor=\"fontSize\">Font Size</label>\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\t\tid=\"fontSize\"\n\t\t\t\t\t\t\t\tname=\"fontSize\"\n\t\t\t\t\t\t\t\tdefaultValue={fontSizePreference ?? 16}\n\t\t\t\t\t\t\t\tstep=\"1\"\n\t\t\t\t\t\t\t\tmin=\"12\"\n\t\t\t\t\t\t\t\tmax=\"26\"\n\t\t\t\t\t\t\t\tclassName=\"border-border bg-background text-foreground rounded-md border px-2 py-1\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t\t\t\t<h2 className=\"text-body-xl\">Presence Preference</h2>\n\n\t\t\t\t\t\t\t<SimpleTooltip content=\"This controls whether your name and avatar are displayed in the pile of faces in navigation\">\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t\tid=\"optOutPresence\"\n\t\t\t\t\t\t\t\tname=\"optOutPresence\"\n\t\t\t\t\t\t\t\tdefaultChecked={presencePreferences?.optOut}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<label htmlFor=\"optOutPresence\">\n\t\t\t\t\t\t\t\tOpt out of presence features\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t\t\t\t<h2 className=\"text-body-xl\">Persist Playground</h2>\n\n\t\t\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\t\t\tcontent={`When enabled, clicking \"Set to Playground\" will save the current playground in the \"saved-playgrounds\" directory.`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t\tid=\"persistPlayground\"\n\t\t\t\t\t\t\t\tname=\"persistPlayground\"\n\t\t\t\t\t\t\t\tdefaultChecked={playgroundPreferences?.persist}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<label htmlFor=\"persistPlayground\">\n\t\t\t\t\t\t\t\tEnable saving playground\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t\t\t\t<h2 className=\"text-body-xl\">Exercise Directory Warning</h2>\n\n\t\t\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\t\t\tcontent={`When enabled, you'll see a warning banner when you have changes in the exercises directory. This helps remind you to work in the playground directory instead.`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t\tid=\"dismissExerciseWarning\"\n\t\t\t\t\t\t\t\tname=\"dismissExerciseWarning\"\n\t\t\t\t\t\t\t\tdefaultChecked={exerciseWarningPreferences?.dismissed}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<label htmlFor=\"dismissExerciseWarning\">\n\t\t\t\t\t\t\t\tDismiss exercise directory warnings\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div className=\"h-4\" />\n\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvarient=\"primary\"\n\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\tname=\"intent\"\n\t\t\t\t\t\tvalue=\"update-preferences\"\n\t\t\t\t\t\tdisabled={isSubmitting}\n\t\t\t\t\t>\n\t\t\t\t\t\t{isSubmitting ? 'Updating...' : 'Update Preferences'}\n\t\t\t\t\t</Button>\n\t\t\t\t</Form>\n\n\t\t\t\t<section className=\"border-border mt-6 flex w-full max-w-xl flex-col gap-3 border-t pt-6\">\n\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t<h2 className=\"text-body-xl\">Offline videos</h2>\n\t\t\t\t\t\t<SimpleTooltip content=\"Keep videos ready to watch when you're offline.\">\n\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t</div>\n\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\tDownload all workshop videos so you can watch them when offline.\n\t\t\t\t\t</p>\n\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\tAdmins can manage all downloaded videos on the{' '}\n\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\tclassName=\"text-foreground underline\"\n\t\t\t\t\t\t\tto=\"/admin/offline-videos\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tOffline videos admin page\n\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t.\n\t\t\t\t\t</p>\n\t\t\t\t\t<div className=\"flex flex-wrap items-center gap-3\">\n\t\t\t\t\t\t<Form method=\"post\">\n\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\tvarient=\"primary\"\n\t\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\t\tname=\"intent\"\n\t\t\t\t\t\t\t\tvalue=\"download-offline-videos\"\n\t\t\t\t\t\t\t\tdisabled={\n\t\t\t\t\t\t\t\t\tisDownloading ||\n\t\t\t\t\t\t\t\t\tisSubmitting ||\n\t\t\t\t\t\t\t\t\tofflineVideos.totalVideos === 0\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{isDownloading ? 'Downloading...' : 'Download all videos'}\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t<Form method=\"post\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\t\tname=\"intent\"\n\t\t\t\t\t\t\t\tvalue=\"delete-offline-videos\"\n\t\t\t\t\t\t\t\tdisabled={isSubmitting || offlineVideos.downloadedVideos === 0}\n\t\t\t\t\t\t\t\tclassName=\"border-border text-foreground hover:bg-muted inline-flex items-center gap-2 rounded border px-3 py-2 text-sm disabled:cursor-not-allowed disabled:opacity-50\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tDelete offline videos\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t<span className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t{offlineVideos.downloadedVideos} of {offlineVideos.totalVideos}{' '}\n\t\t\t\t\t\t\tdownloaded\n\t\t\t\t\t\t\t{offlineVideos.unavailableVideos > 0\n\t\t\t\t\t\t\t\t? ` (${offlineVideos.unavailableVideos} unavailable)`\n\t\t\t\t\t\t\t\t: null}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t{isDownloading ? (\n\t\t\t\t\t\t<div className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t\tDownloading {offlineVideos.downloadState.completed} of{' '}\n\t\t\t\t\t\t\t\t{offlineVideos.downloadState.total} videos\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t{offlineVideos.downloadState.current ? (\n\t\t\t\t\t\t\t\t<p className=\"truncate\">\n\t\t\t\t\t\t\t\t\tCurrent: {offlineVideos.downloadState.current.title}\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : null}\n\t\t\t\t</section>\n\t\t\t</main>\n\t\t</div>\n\t)\n}\n"],"names":["downloadResolutionOptions","value","label","preferences","_UNSAFE_withComponentProps","loaderData","useLoaderData","rootData","useRootLoaderData","playerPreferences","player","offlineVideoPreferences","offlineVideo","fontSizePreference","fontSize","presencePreferences","presence","playgroundPreferences","playground","exerciseWarningPreferences","exerciseWarning","navigation","useNavigation","offlineVideosFetcher","useFetcher","offlineVideos","data","isDownloading","downloadState","status","isSubmitting","state","useInterval","load","className","children","jsxs","jsx","Form","method","htmlFor","id","name","defaultValue","minResolution","maxResolution","downloadResolution","map","option","SimpleTooltip","content","Icon","tabIndex","type","step","min","max","defaultChecked","optOut","persist","dismissed","Button","varient","disabled","Link","to","totalVideos","downloadedVideos","unavailableVideos","completed","total","current","title"],"mappings":"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"}
1
+ {"version":3,"file":"preferences-D6HQ5bK1.js","sources":["../../../app/routes/_app+/preferences.tsx"],"sourcesContent":["import {\n\tgetPreferences,\n\tsetPreferences,\n} from '@epic-web/workshop-utils/db.server'\nimport {\n\tgetOfflineVideoSummary,\n\tstartOfflineVideoDownload,\n\tdeleteOfflineVideosForWorkshop,\n} from '@epic-web/workshop-utils/offline-videos.server'\nimport {\n\tForm,\n\tLink,\n\tuseFetcher,\n\tuseLoaderData,\n\tuseNavigation,\n} from 'react-router'\nimport { Button } from '#app/components/button.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { ensureUndeployed, useInterval } from '#app/utils/misc.tsx'\nimport { useRootLoaderData } from '#app/utils/root-loader.ts'\nimport { redirectWithToast } from '#app/utils/toast.server.ts'\nimport { type Route } from './+types/preferences.tsx'\n\nconst downloadResolutionOptions = [\n\t{ value: 'best', label: 'Best available' },\n\t{ value: 'high', label: 'High' },\n\t{ value: 'medium', label: 'Medium' },\n\t{ value: 'low', label: 'Low' },\n] as const\ntype DownloadResolutionOption =\n\t(typeof downloadResolutionOptions)[number]['value']\n\nfunction isDownloadResolutionOption(\n\tvalue: FormDataEntryValue | null,\n): value is DownloadResolutionOption {\n\treturn (\n\t\ttypeof value === 'string' &&\n\t\tdownloadResolutionOptions.some((option) => option.value === value)\n\t)\n}\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tensureUndeployed()\n\tconst [preferences, offlineVideos] = await Promise.all([\n\t\tgetPreferences(),\n\t\tgetOfflineVideoSummary({ request }),\n\t])\n\treturn { preferences, offlineVideos }\n}\n\nexport async function action({ request }: Route.ActionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\n\tif (intent === 'download-offline-videos') {\n\t\tconst result = await startOfflineVideoDownload({ request })\n\t\tif (result.queued === 0) {\n\t\t\tconst description =\n\t\t\t\tresult.available === 0\n\t\t\t\t\t? 'No downloadable videos were found for this workshop.'\n\t\t\t\t\t: result.unavailable > 0\n\t\t\t\t\t\t? 'All available videos are already downloaded. Some videos require access to download.'\n\t\t\t\t\t\t: 'All available videos are already downloaded.'\n\t\t\treturn redirectWithToast('/preferences', {\n\t\t\t\ttitle: 'Offline videos are ready',\n\t\t\t\tdescription,\n\t\t\t\ttype: 'success',\n\t\t\t})\n\t\t}\n\n\t\treturn redirectWithToast('/preferences', {\n\t\t\ttitle: 'Offline downloads started',\n\t\t\tdescription: `Queued ${result.queued} video${result.queued === 1 ? '' : 's'} for download.`,\n\t\t\ttype: 'success',\n\t\t})\n\t}\n\n\tif (intent === 'delete-offline-videos') {\n\t\tconst result = await deleteOfflineVideosForWorkshop()\n\t\tconst description =\n\t\t\tresult.deletedFiles === 0\n\t\t\t\t? 'No offline videos were removed.'\n\t\t\t\t: `Removed ${result.deletedFiles} offline video${\n\t\t\t\t\t\tresult.deletedFiles === 1 ? '' : 's'\n\t\t\t\t\t}.`\n\t\treturn redirectWithToast('/preferences', {\n\t\t\ttitle: 'Offline videos cleared',\n\t\t\tdescription,\n\t\t\ttype: 'success',\n\t\t})\n\t}\n\n\tconst minResolution = formData.get('minResolution')\n\tconst maxResolution = formData.get('maxResolution')\n\tconst downloadResolution = formData.get('downloadResolution')\n\tconst fontSize = formData.get('fontSize')\n\tconst optOutPresence = formData.get('optOutPresence') === 'on'\n\tconst persistPlayground = formData.get('persistPlayground') === 'on'\n\tconst dismissExerciseWarning = formData.get('dismissExerciseWarning') === 'on'\n\tconst downloadResolutionValue = isDownloadResolutionOption(downloadResolution)\n\t\t? downloadResolution\n\t\t: undefined\n\n\tawait setPreferences({\n\t\tplayer: {\n\t\t\tminResolution: minResolution ? Number(minResolution) : undefined,\n\t\t\tmaxResolution: maxResolution ? Number(maxResolution) : undefined,\n\t\t},\n\t\tofflineVideo: {\n\t\t\tdownloadResolution: downloadResolutionValue,\n\t\t},\n\t\tfontSize: fontSize ? Number(fontSize) : undefined,\n\t\tpresence: { optOut: optOutPresence },\n\t\tplayground: { persist: persistPlayground },\n\t\texerciseWarning: { dismissed: dismissExerciseWarning },\n\t})\n\n\treturn redirectWithToast('/preferences', {\n\t\ttitle: 'Preferences updated',\n\t\tdescription: 'Your preferences have been updated.',\n\t\ttype: 'success',\n\t})\n}\n\nexport default function AccountSettings() {\n\tconst loaderData = useLoaderData<typeof loader>()\n\tconst rootData = useRootLoaderData()\n\tconst playerPreferences = rootData.preferences?.player\n\tconst offlineVideoPreferences = rootData.preferences?.offlineVideo\n\tconst fontSizePreference = rootData.preferences?.fontSize\n\tconst presencePreferences = rootData.preferences?.presence\n\tconst playgroundPreferences = rootData.preferences?.playground\n\tconst exerciseWarningPreferences = rootData.preferences?.exerciseWarning\n\tconst navigation = useNavigation()\n\tconst offlineVideosFetcher = useFetcher<typeof loader>()\n\tconst offlineVideos =\n\t\tofflineVideosFetcher.data?.offlineVideos ?? loaderData.offlineVideos\n\tconst isDownloading = offlineVideos.downloadState.status === 'running'\n\n\tconst isSubmitting = navigation.state === 'submitting'\n\n\tuseInterval(\n\t\t() => {\n\t\t\tif (offlineVideosFetcher.state === 'idle') {\n\t\t\t\tvoid offlineVideosFetcher.load('/resources/offline-videos')\n\t\t\t}\n\t\t},\n\t\tisDownloading ? 2000 : null,\n\t)\n\n\treturn (\n\t\t<div className=\"h-full w-full overflow-y-auto\">\n\t\t\t<main className=\"container mt-12 flex w-full max-w-3xl grow flex-col gap-4 pb-24\">\n\t\t\t\t<h1 className=\"text-h1 mb-4\">Preferences</h1>\n\t\t\t\t<Form method=\"post\" className=\"flex w-full max-w-sm flex-col gap-4\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h2 className=\"text-body-xl mb-2\">Video Player Preferences</h2>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<label htmlFor=\"minResolution\">Minimum Resolution:</label>\n\t\t\t\t\t\t\t<select\n\t\t\t\t\t\t\t\tid=\"minResolution\"\n\t\t\t\t\t\t\t\tname=\"minResolution\"\n\t\t\t\t\t\t\t\tdefaultValue={playerPreferences?.minResolution}\n\t\t\t\t\t\t\t\tclassName=\"border-border bg-background text-foreground rounded-md border px-2 py-1\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<option value=\"\">Auto</option>\n\t\t\t\t\t\t\t\t<option value=\"480\">480p</option>\n\t\t\t\t\t\t\t\t<option value=\"720\">720p</option>\n\t\t\t\t\t\t\t\t<option value=\"1080\">1080p</option>\n\t\t\t\t\t\t\t\t<option value=\"1440\">1440p</option>\n\t\t\t\t\t\t\t\t<option value=\"2160\">2160p (4K)</option>\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<label htmlFor=\"maxResolution\">Maximum Resolution:</label>\n\t\t\t\t\t\t\t<select\n\t\t\t\t\t\t\t\tid=\"maxResolution\"\n\t\t\t\t\t\t\t\tname=\"maxResolution\"\n\t\t\t\t\t\t\t\tdefaultValue={playerPreferences?.maxResolution}\n\t\t\t\t\t\t\t\tclassName=\"border-border bg-background text-foreground rounded-md border px-2 py-1\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<option value=\"\">Auto</option>\n\t\t\t\t\t\t\t\t<option value=\"720\">720p</option>\n\t\t\t\t\t\t\t\t<option value=\"1080\">1080p</option>\n\t\t\t\t\t\t\t\t<option value=\"1440\">1440p</option>\n\t\t\t\t\t\t\t\t<option value=\"2160\">2160p (4K)</option>\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h2 className=\"text-body-xl mb-2\">Offline Video Downloads</h2>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<label htmlFor=\"downloadResolution\">Download Resolution:</label>\n\t\t\t\t\t\t\t<select\n\t\t\t\t\t\t\t\tid=\"downloadResolution\"\n\t\t\t\t\t\t\t\tname=\"downloadResolution\"\n\t\t\t\t\t\t\t\tdefaultValue={\n\t\t\t\t\t\t\t\t\tofflineVideoPreferences?.downloadResolution ?? 'best'\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tclassName=\"border-border bg-background text-foreground rounded-md border px-2 py-1\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{downloadResolutionOptions.map((option) => (\n\t\t\t\t\t\t\t\t\t<option key={option.value} value={option.value}>\n\t\t\t\t\t\t\t\t\t\t{option.label}\n\t\t\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\tDefaults to the best available resolution.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t\t\t\t<h2 className=\"text-body-xl\">Font Size Preference</h2>\n\t\t\t\t\t\t\t<SimpleTooltip content=\"Defaults to 16px\">\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<label htmlFor=\"fontSize\">Font Size</label>\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\t\tid=\"fontSize\"\n\t\t\t\t\t\t\t\tname=\"fontSize\"\n\t\t\t\t\t\t\t\tdefaultValue={fontSizePreference ?? 16}\n\t\t\t\t\t\t\t\tstep=\"1\"\n\t\t\t\t\t\t\t\tmin=\"12\"\n\t\t\t\t\t\t\t\tmax=\"26\"\n\t\t\t\t\t\t\t\tclassName=\"border-border bg-background text-foreground rounded-md border px-2 py-1\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t\t\t\t<h2 className=\"text-body-xl\">Presence Preference</h2>\n\n\t\t\t\t\t\t\t<SimpleTooltip content=\"This controls whether your name and avatar are displayed in the pile of faces in navigation\">\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t\tid=\"optOutPresence\"\n\t\t\t\t\t\t\t\tname=\"optOutPresence\"\n\t\t\t\t\t\t\t\tdefaultChecked={presencePreferences?.optOut}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<label htmlFor=\"optOutPresence\">\n\t\t\t\t\t\t\t\tOpt out of presence features\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t\t\t\t<h2 className=\"text-body-xl\">Persist Playground</h2>\n\n\t\t\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\t\t\tcontent={`When enabled, clicking \"Set to Playground\" will save the current playground in the \"saved-playgrounds\" directory.`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t\tid=\"persistPlayground\"\n\t\t\t\t\t\t\t\tname=\"persistPlayground\"\n\t\t\t\t\t\t\t\tdefaultChecked={playgroundPreferences?.persist}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<label htmlFor=\"persistPlayground\">\n\t\t\t\t\t\t\t\tEnable saving playground\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t\t\t\t<h2 className=\"text-body-xl\">Exercise Directory Warning</h2>\n\n\t\t\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\t\t\tcontent={`When enabled, you'll see a warning banner when you have changes in the exercises directory. This helps remind you to work in the playground directory instead.`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t\tid=\"dismissExerciseWarning\"\n\t\t\t\t\t\t\t\tname=\"dismissExerciseWarning\"\n\t\t\t\t\t\t\t\tdefaultChecked={exerciseWarningPreferences?.dismissed}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<label htmlFor=\"dismissExerciseWarning\">\n\t\t\t\t\t\t\t\tDismiss exercise directory warnings\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div className=\"h-4\" />\n\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvarient=\"primary\"\n\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\tname=\"intent\"\n\t\t\t\t\t\tvalue=\"update-preferences\"\n\t\t\t\t\t\tdisabled={isSubmitting}\n\t\t\t\t\t>\n\t\t\t\t\t\t{isSubmitting ? 'Updating...' : 'Update Preferences'}\n\t\t\t\t\t</Button>\n\t\t\t\t</Form>\n\n\t\t\t\t<section className=\"border-border mt-6 flex w-full max-w-xl flex-col gap-3 border-t pt-6\">\n\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t<h2 className=\"text-body-xl\">Offline videos</h2>\n\t\t\t\t\t\t<SimpleTooltip content=\"Keep videos ready to watch when you're offline.\">\n\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t</div>\n\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\tDownload all workshop videos so you can watch them when offline.\n\t\t\t\t\t</p>\n\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\tAdmins can manage all downloaded videos on the{' '}\n\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\tclassName=\"text-foreground underline\"\n\t\t\t\t\t\t\tto=\"/admin/offline-videos\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tOffline videos admin page\n\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t.\n\t\t\t\t\t</p>\n\t\t\t\t\t<div className=\"flex flex-wrap items-center gap-3\">\n\t\t\t\t\t\t<Form method=\"post\">\n\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\tvarient=\"primary\"\n\t\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\t\tname=\"intent\"\n\t\t\t\t\t\t\t\tvalue=\"download-offline-videos\"\n\t\t\t\t\t\t\t\tdisabled={\n\t\t\t\t\t\t\t\t\tisDownloading ||\n\t\t\t\t\t\t\t\t\tisSubmitting ||\n\t\t\t\t\t\t\t\t\tofflineVideos.totalVideos === 0\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{isDownloading ? 'Downloading...' : 'Download all videos'}\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t<Form method=\"post\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\t\tname=\"intent\"\n\t\t\t\t\t\t\t\tvalue=\"delete-offline-videos\"\n\t\t\t\t\t\t\t\tdisabled={isSubmitting || offlineVideos.downloadedVideos === 0}\n\t\t\t\t\t\t\t\tclassName=\"border-border text-foreground hover:bg-muted inline-flex items-center gap-2 rounded border px-3 py-2 text-sm disabled:cursor-not-allowed disabled:opacity-50\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tDelete offline videos\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t<span className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t{offlineVideos.downloadedVideos} of {offlineVideos.totalVideos}{' '}\n\t\t\t\t\t\t\tdownloaded\n\t\t\t\t\t\t\t{offlineVideos.unavailableVideos > 0\n\t\t\t\t\t\t\t\t? ` (${offlineVideos.unavailableVideos} unavailable)`\n\t\t\t\t\t\t\t\t: null}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t{isDownloading ? (\n\t\t\t\t\t\t<div className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t\tDownloading {offlineVideos.downloadState.completed} of{' '}\n\t\t\t\t\t\t\t\t{offlineVideos.downloadState.total} videos\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t{offlineVideos.downloadState.current ? (\n\t\t\t\t\t\t\t\t<p className=\"truncate\">\n\t\t\t\t\t\t\t\t\tCurrent: {offlineVideos.downloadState.current.title}\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : null}\n\t\t\t\t</section>\n\t\t\t</main>\n\t\t</div>\n\t)\n}\n"],"names":["downloadResolutionOptions","value","label","preferences","_UNSAFE_withComponentProps","loaderData","useLoaderData","rootData","useRootLoaderData","playerPreferences","player","offlineVideoPreferences","offlineVideo","fontSizePreference","fontSize","presencePreferences","presence","playgroundPreferences","playground","exerciseWarningPreferences","exerciseWarning","navigation","useNavigation","offlineVideosFetcher","useFetcher","offlineVideos","data","isDownloading","downloadState","status","isSubmitting","state","useInterval","load","className","children","jsxs","jsx","Form","method","htmlFor","id","name","defaultValue","minResolution","maxResolution","downloadResolution","map","option","SimpleTooltip","content","Icon","tabIndex","type","step","min","max","defaultChecked","optOut","persist","dismissed","Button","varient","disabled","Link","to","totalVideos","downloadedVideos","unavailableVideos","completed","total","current","title"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{j as e}from"./jsx-runtime-C5WNSv3b.js";import{r as u}from"./index-CqIc3cxq.js";import{f as x,d as A}from"./chunk-EPOLDU6W-BCLmut3y.js";import{u as F,l as k,I as h,a as C,c as R}from"./misc-DVYuZMjW.js";import{B as P,L as O}from"./button-CIlVtsau.js";import{L as I}from"./loading-CUydCGD3.js";import{s as j}from"./progress-bar-B27isaGl.js";import{u as g}from"./pe-CIZUOJMr.js";import{u as b}from"./index-BW8stNyh.js";import{a as L}from"./root-loader-BOzEMapJ.js";import{k as z,T as v,a as S,b as N}from"./tooltip-Chzzs4KB.js";function q({name:r}){const t=x(),n=g(),o=t.formData?.get("intent"),l=o==="stop"?"Stopping App":o==="restart"?"Restarting App":null,a=F();return e.jsxs(t.Form,{method:"POST",action:"/start",children:[n,j,e.jsx("input",{type:"hidden",name:"name",value:r}),e.jsx("button",{type:"submit",name:"intent",value:a?"restart":"stop",className:"h-full border-r px-3 py-4 font-mono text-xs leading-none uppercase",children:l||(a?"Restart App":"Stop App")})]})}function B({port:r}){const t=x(),n=g();return e.jsxs(t.Form,{method:"POST",action:"/start",children:[n,j,e.jsx("input",{type:"hidden",name:"port",value:r}),e.jsx(P,{varient:"mono",type:"submit",name:"intent",value:"stop-port",children:t.state==="idle"?"Stop Port":"Stopping Port"})]})}function D({name:r}){const t=x(),n=g();return t.data?.status==="app-not-started"?t.data.error==="port-unavailable"?e.jsxs("div",{children:["The port is unavailable. Would you like to stop whatever is running on that port and try again?",e.jsx(B,{port:t.data.port})]}):e.jsx("div",{children:"An unknown error has happened."}):e.jsxs(t.Form,{method:"POST",action:"/start",children:[n,j,e.jsx("input",{type:"hidden",name:"name",value:r}),t.state==="idle"?e.jsx(P,{type:"submit",name:"intent",value:"start",varient:"mono",children:"Start App"}):e.jsx("div",{children:e.jsx(I,{children:"Starting App"})})]})}function _({name:r,port:t,portIsAvailable:n,isRunning:o,baseUrl:l,id:a,initialRoute:p,ref:s}){const d=L(),[m,c]=u.useState(!1);return o||m?e.jsx(K,{baseUrl:l,id:a,name:r,ref:s,initialRoute:p}):n===!1?e.jsxs("div",{className:"flex flex-col items-center justify-center",children:[e.jsxs("p",{className:"max-w-xs pb-5 text-center",role:"status",children:["The port for this app is unavailable. It could be that you're running it ",e.jsx("a",{href:k({domain:d.domain,port:t}),className:"underline",target:"_blank",rel:"noreferrer",children:"elsewhere"}),". ",e.jsx(O,{onClick:()=>c(!0),children:"Show here anyway"})]}),e.jsx(B,{port:t})]}):e.jsx("div",{className:"flex h-full flex-col items-center justify-center",children:e.jsx(D,{name:r})})}function K({baseUrl:r,id:t,name:n,initialRoute:o,ref:l}){const a=b(),[p,s]=u.useState(0),d=t+p,m=u.useRef(null),c=new URL(o,r),[i,w]=u.useState(c),y=u.useRef(t);y.current!==t&&(y.current=t,w(c));function U(f){if(f){const E=new URL(f,r);w(E),s(T=>T+1)}}return u.useImperativeHandle(l,()=>({handleExtrnalNavigation:U})),e.jsx(z,{children:e.jsxs("div",{className:"flex h-full grow flex-col",children:[e.jsxs("div",{className:"flex items-center justify-between border-b pl-1.5",children:[e.jsx("div",{className:"mr-2 flex items-center justify-center gap-2 px-1",children:e.jsxs(v,{children:[e.jsx(S,{asChild:!0,children:e.jsx("button",{type:"button",className:"flex aspect-square h-full w-full items-center justify-center p-1 transition disabled:opacity-40",onClick:()=>{s(f=>f+1)},children:e.jsx(h,{name:"Refresh","aria-hidden":"true"})})}),e.jsx(N,{children:"Refresh"})]})}),e.jsx("div",{className:"bg-background text-foreground flex flex-1 items-center border-x p-3 leading-none",children:e.jsx("a",{href:i.toString(),target:"_blank",rel:"noreferrer",children:i.toString()})}),e.jsx(q,{name:n}),e.jsxs(v,{children:[e.jsx(S,{asChild:!0,children:e.jsx("a",{href:i.toString(),target:"_blank",rel:"noreferrer",className:C("flex aspect-square items-center justify-center px-3.5"),children:e.jsx(h,{name:"ExternalLink"})})}),e.jsx(N,{children:"Open in new tab"})]})]}),e.jsx("div",{className:"bg-background flex h-full w-full grow",children:e.jsx("iframe",{title:n,ref:m,src:i.toString(),className:"bg-background h-full w-full grow",style:{colorScheme:a},allow:"clipboard-write"},d)})]})})}function te({id:r,appInfo:t,inBrowserBrowserRef:n}){const o=L(),[l]=A(),a=b();if(!t)return e.jsx("p",{children:"No app here. Sorry."});const{isRunning:p,dev:s,name:d,portIsAvailable:m,title:c}=t;if(!s)return e.jsx("div",{className:"flex h-full items-center justify-center text-lg",children:e.jsx("p",{children:"No preview available for this app."})});if(ENV.EPICSHOP_DEPLOYED&&t.stackBlitzUrl){const i=new URL(t.stackBlitzUrl);return i.searchParams.set("embed","1"),i.searchParams.set("theme",a),e.jsx(H,{title:c,url:i.toString(),loadingContent:e.jsx(I,{children:e.jsxs("span",{children:["Loading"," ",e.jsxs("a",{className:"underline",href:t.stackBlitzUrl,children:['"',c,'"']})]})})})}if(s.type==="script"){const i=k({domain:o.domain,port:s.portNumber});return e.jsx(_,{ref:n,isRunning:p,id:r??d,name:d,portIsAvailable:m,port:s.portNumber,baseUrl:i,initialRoute:l.get("pathname")??s.initialRoute})}else return s.type==="browser"||s.type==="export"?e.jsxs("div",{className:"scrollbar-thin scrollbar-thumb-scrollbar relative h-full grow overflow-y-auto",children:[e.jsxs("a",{href:s.pathname,target:"_blank",rel:"noreferrer",className:R("bg-muted text-foreground hover:bg-muted/80 absolute right-5 bottom-5 flex items-center justify-center rounded-full p-2.5 transition"),children:[e.jsx(h,{name:"ExternalLink","aria-hidden":"true"}),e.jsx("span",{className:"sr-only",children:"Open in New Window"})]}),e.jsx("iframe",{title:c,src:s.pathname,className:"bg-background h-full w-full grow",style:{colorScheme:a},allow:"clipboard-write"})]}):e.jsx("div",{className:"flex h-full items-center justify-center text-lg",children:e.jsxs("p",{children:["Preview for dev type of ",e.jsx("code",{children:s.type})," not supported."]})})}function H({url:r,title:t,loadingContent:n}){const o=b(),[l,a]=u.useState(!1);return e.jsxs("div",{className:"h-full w-full grow",children:[l?null:e.jsx("div",{className:"absolute inset-0 z-10 flex items-center justify-center",children:n}),e.jsx("iframe",{onLoad:()=>a(!0),onError:()=>a(!0),src:r,className:R("h-full w-full grow transition-opacity duration-300",l?"opacity-100":"opacity-0"),title:t,sandbox:"allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox",allow:"clipboard-write",style:{colorScheme:o}})]})}export{te as P};
2
- //# sourceMappingURL=preview-CiDtuQCc.js.map
1
+ import{j as e}from"./jsx-runtime-C5WNSv3b.js";import{r as u}from"./index-CqIc3cxq.js";import{f as x,d as A}from"./chunk-EPOLDU6W-BCLmut3y.js";import{u as F,l as k,I as h,a as C,c as R}from"./misc-W4055b-0.js";import{B as P,L as O}from"./button-Cd-ekki5.js";import{L as I}from"./loading-CDNzW5oO.js";import{s as j}from"./progress-bar-DpWhcyhC.js";import{u as g}from"./pe-CIZUOJMr.js";import{u as b}from"./index-CdzVFL-Z.js";import{a as L}from"./root-loader-BOzEMapJ.js";import{m as z,T as v,j as S,k as N}from"./tooltip-Tlsyx2YO.js";function q({name:r}){const t=x(),n=g(),o=t.formData?.get("intent"),l=o==="stop"?"Stopping App":o==="restart"?"Restarting App":null,a=F();return e.jsxs(t.Form,{method:"POST",action:"/start",children:[n,j,e.jsx("input",{type:"hidden",name:"name",value:r}),e.jsx("button",{type:"submit",name:"intent",value:a?"restart":"stop",className:"h-full border-r px-3 py-4 font-mono text-xs leading-none uppercase",children:l||(a?"Restart App":"Stop App")})]})}function B({port:r}){const t=x(),n=g();return e.jsxs(t.Form,{method:"POST",action:"/start",children:[n,j,e.jsx("input",{type:"hidden",name:"port",value:r}),e.jsx(P,{varient:"mono",type:"submit",name:"intent",value:"stop-port",children:t.state==="idle"?"Stop Port":"Stopping Port"})]})}function D({name:r}){const t=x(),n=g();return t.data?.status==="app-not-started"?t.data.error==="port-unavailable"?e.jsxs("div",{children:["The port is unavailable. Would you like to stop whatever is running on that port and try again?",e.jsx(B,{port:t.data.port})]}):e.jsx("div",{children:"An unknown error has happened."}):e.jsxs(t.Form,{method:"POST",action:"/start",children:[n,j,e.jsx("input",{type:"hidden",name:"name",value:r}),t.state==="idle"?e.jsx(P,{type:"submit",name:"intent",value:"start",varient:"mono",children:"Start App"}):e.jsx("div",{children:e.jsx(I,{children:"Starting App"})})]})}function _({name:r,port:t,portIsAvailable:n,isRunning:o,baseUrl:l,id:a,initialRoute:p,ref:s}){const d=L(),[m,c]=u.useState(!1);return o||m?e.jsx(K,{baseUrl:l,id:a,name:r,ref:s,initialRoute:p}):n===!1?e.jsxs("div",{className:"flex flex-col items-center justify-center",children:[e.jsxs("p",{className:"max-w-xs pb-5 text-center",role:"status",children:["The port for this app is unavailable. It could be that you're running it ",e.jsx("a",{href:k({domain:d.domain,port:t}),className:"underline",target:"_blank",rel:"noreferrer",children:"elsewhere"}),". ",e.jsx(O,{onClick:()=>c(!0),children:"Show here anyway"})]}),e.jsx(B,{port:t})]}):e.jsx("div",{className:"flex h-full flex-col items-center justify-center",children:e.jsx(D,{name:r})})}function K({baseUrl:r,id:t,name:n,initialRoute:o,ref:l}){const a=b(),[p,s]=u.useState(0),d=t+p,m=u.useRef(null),c=new URL(o,r),[i,w]=u.useState(c),y=u.useRef(t);y.current!==t&&(y.current=t,w(c));function U(f){if(f){const E=new URL(f,r);w(E),s(T=>T+1)}}return u.useImperativeHandle(l,()=>({handleExtrnalNavigation:U})),e.jsx(z,{children:e.jsxs("div",{className:"flex h-full grow flex-col",children:[e.jsxs("div",{className:"flex items-center justify-between border-b pl-1.5",children:[e.jsx("div",{className:"mr-2 flex items-center justify-center gap-2 px-1",children:e.jsxs(v,{children:[e.jsx(S,{asChild:!0,children:e.jsx("button",{type:"button",className:"flex aspect-square h-full w-full items-center justify-center p-1 transition disabled:opacity-40",onClick:()=>{s(f=>f+1)},children:e.jsx(h,{name:"Refresh","aria-hidden":"true"})})}),e.jsx(N,{children:"Refresh"})]})}),e.jsx("div",{className:"bg-background text-foreground flex flex-1 items-center border-x p-3 leading-none",children:e.jsx("a",{href:i.toString(),target:"_blank",rel:"noreferrer",children:i.toString()})}),e.jsx(q,{name:n}),e.jsxs(v,{children:[e.jsx(S,{asChild:!0,children:e.jsx("a",{href:i.toString(),target:"_blank",rel:"noreferrer",className:C("flex aspect-square items-center justify-center px-3.5"),children:e.jsx(h,{name:"ExternalLink"})})}),e.jsx(N,{children:"Open in new tab"})]})]}),e.jsx("div",{className:"bg-background flex h-full w-full grow",children:e.jsx("iframe",{title:n,ref:m,src:i.toString(),className:"bg-background h-full w-full grow",style:{colorScheme:a},allow:"clipboard-write"},d)})]})})}function te({id:r,appInfo:t,inBrowserBrowserRef:n}){const o=L(),[l]=A(),a=b();if(!t)return e.jsx("p",{children:"No app here. Sorry."});const{isRunning:p,dev:s,name:d,portIsAvailable:m,title:c}=t;if(!s)return e.jsx("div",{className:"flex h-full items-center justify-center text-lg",children:e.jsx("p",{children:"No preview available for this app."})});if(ENV.EPICSHOP_DEPLOYED&&t.stackBlitzUrl){const i=new URL(t.stackBlitzUrl);return i.searchParams.set("embed","1"),i.searchParams.set("theme",a),e.jsx(H,{title:c,url:i.toString(),loadingContent:e.jsx(I,{children:e.jsxs("span",{children:["Loading"," ",e.jsxs("a",{className:"underline",href:t.stackBlitzUrl,children:['"',c,'"']})]})})})}if(s.type==="script"){const i=k({domain:o.domain,port:s.portNumber});return e.jsx(_,{ref:n,isRunning:p,id:r??d,name:d,portIsAvailable:m,port:s.portNumber,baseUrl:i,initialRoute:l.get("pathname")??s.initialRoute})}else return s.type==="browser"||s.type==="export"?e.jsxs("div",{className:"scrollbar-thin scrollbar-thumb-scrollbar relative h-full grow overflow-y-auto",children:[e.jsxs("a",{href:s.pathname,target:"_blank",rel:"noreferrer",className:R("bg-muted text-foreground hover:bg-muted/80 absolute right-5 bottom-5 flex items-center justify-center rounded-full p-2.5 transition"),children:[e.jsx(h,{name:"ExternalLink","aria-hidden":"true"}),e.jsx("span",{className:"sr-only",children:"Open in New Window"})]}),e.jsx("iframe",{title:c,src:s.pathname,className:"bg-background h-full w-full grow",style:{colorScheme:a},allow:"clipboard-write"})]}):e.jsx("div",{className:"flex h-full items-center justify-center text-lg",children:e.jsxs("p",{children:["Preview for dev type of ",e.jsx("code",{children:s.type})," not supported."]})})}function H({url:r,title:t,loadingContent:n}){const o=b(),[l,a]=u.useState(!1);return e.jsxs("div",{className:"h-full w-full grow",children:[l?null:e.jsx("div",{className:"absolute inset-0 z-10 flex items-center justify-center",children:n}),e.jsx("iframe",{onLoad:()=>a(!0),onError:()=>a(!0),src:r,className:R("h-full w-full grow transition-opacity duration-300",l?"opacity-100":"opacity-0"),title:t,sandbox:"allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox",allow:"clipboard-write",style:{colorScheme:o}})]})}export{te as P};
2
+ //# sourceMappingURL=preview-fhmjENlm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"preview-CiDtuQCc.js","sources":["../../../app/routes/start.tsx","../../../app/components/in-browser-browser.tsx","../../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/preview.tsx"],"sourcesContent":["import { invariant, invariantResponse } from '@epic-web/invariant'\nimport { getAppByName } from '@epic-web/workshop-utils/apps.server'\nimport {\n\tcloseProcess,\n\trunAppDev,\n\tstopPort,\n\twaitOnApp,\n} from '@epic-web/workshop-utils/process-manager.server'\nimport { data, type ActionFunctionArgs, useFetcher } from 'react-router'\nimport { Button } from '#app/components/button.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { showProgressBarField } from '#app/components/progress-bar.tsx'\nimport { ensureUndeployed, useAltDown } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.tsx'\nimport { createToastHeaders } from '#app/utils/toast.server'\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\tinvariantResponse(typeof intent === 'string', 'intent is required')\n\n\tif (intent === 'start' || intent === 'stop' || intent === 'restart') {\n\t\tconst name = formData.get('name')\n\t\tinvariantResponse(typeof name === 'string', 'name is required')\n\t\tconst app = await getAppByName(name)\n\t\tif (!app) {\n\t\t\tthrow new Response('Not found', { status: 404 })\n\t\t}\n\t\tif (app.dev.type !== 'script') {\n\t\t\tthrow new Response(`App \"${name}\" does not have a server`, {\n\t\t\t\tstatus: 400,\n\t\t\t})\n\t\t}\n\n\t\tasync function startApp() {\n\t\t\tinvariant(app, 'app must be defined')\n\t\t\tconst result = await runAppDev(app)\n\t\t\tif (result.running) {\n\t\t\t\tconst appRunningResult = await waitOnApp(app)\n\t\t\t\tif (appRunningResult?.status === 'success') {\n\t\t\t\t\t// wait another 200ms just in case the build output for assets isn't finished\n\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 200))\n\t\t\t\t\treturn dataWithPE(request, formData, {\n\t\t\t\t\t\tstatus: 'app-started',\n\t\t\t\t\t} as const)\n\t\t\t\t} else if (app.dev.type === 'script') {\n\t\t\t\t\tconst errorMessage = appRunningResult\n\t\t\t\t\t\t? appRunningResult.error\n\t\t\t\t\t\t: 'Unknown error'\n\t\t\t\t\treturn data(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstatus: 'app-not-started',\n\t\t\t\t\t\t\terror: errorMessage,\n\t\t\t\t\t\t\tport: app.dev.portNumber,\n\t\t\t\t\t\t} as const,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t\tstatusText: 'App did not start',\n\t\t\t\t\t\t\theaders: await createToastHeaders({\n\t\t\t\t\t\t\t\tdescription: errorMessage,\n\t\t\t\t\t\t\t\ttitle: 'App did not start',\n\t\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t} else if (result.portNumber) {\n\t\t\t\treturn dataWithPE(request, formData, {\n\t\t\t\t\tstatus: 'app-not-started',\n\t\t\t\t\terror: result.status,\n\t\t\t\t\tport: result.portNumber,\n\t\t\t\t} as const)\n\t\t\t} else {\n\t\t\t\tthrow new Response(\n\t\t\t\t\t'Tried starting a server for an app that does not have one',\n\t\t\t\t\t{ status: 400 },\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tasync function stopApp() {\n\t\t\tinvariant(app, 'app must be defined')\n\t\t\tawait closeProcess(app.name)\n\t\t\treturn dataWithPE(request, formData, { status: 'app-stopped' } as const)\n\t\t}\n\n\t\tswitch (intent) {\n\t\t\tcase 'start': {\n\t\t\t\treturn startApp()\n\t\t\t}\n\t\t\tcase 'stop': {\n\t\t\t\treturn stopApp()\n\t\t\t}\n\t\t\tcase 'restart': {\n\t\t\t\tawait stopApp()\n\t\t\t\treturn startApp()\n\t\t\t}\n\t\t}\n\t}\n\n\tif (intent === 'stop-port') {\n\t\tconst port = formData.get('port')\n\t\tinvariantResponse(typeof port === 'string', 'port is required')\n\t\tawait stopPort(port)\n\t\treturn dataWithPE(request, formData, { status: 'port-stopped' } as const)\n\t}\n\tthrow new Error(`Unknown intent: ${intent}`)\n}\n\nexport function AppStopper({ name }: { name: string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tconst inFlightIntent = fetcher.formData?.get('intent')\n\tconst inFlightState =\n\t\tinFlightIntent === 'stop'\n\t\t\t? 'Stopping App'\n\t\t\t: inFlightIntent === 'restart'\n\t\t\t\t? 'Restarting App'\n\t\t\t\t: null\n\tconst altDown = useAltDown()\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t<button\n\t\t\t\ttype=\"submit\"\n\t\t\t\tname=\"intent\"\n\t\t\t\tvalue={altDown ? 'restart' : 'stop'}\n\t\t\t\tclassName=\"h-full border-r px-3 py-4 font-mono text-xs leading-none uppercase\"\n\t\t\t>\n\t\t\t\t{inFlightState ? inFlightState : altDown ? 'Restart App' : 'Stop App'}\n\t\t\t</button>\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function PortStopper({ port }: { port: number | string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"port\" value={port} />\n\t\t\t<Button varient=\"mono\" type=\"submit\" name=\"intent\" value=\"stop-port\">\n\t\t\t\t{fetcher.state === 'idle' ? 'Stop Port' : 'Stopping Port'}\n\t\t\t</Button>\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function AppStarter({ name }: { name: string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tif (fetcher.data?.status === 'app-not-started') {\n\t\tif (fetcher.data.error === 'port-unavailable') {\n\t\t\treturn (\n\t\t\t\t<div>\n\t\t\t\t\tThe port is unavailable. Would you like to stop whatever is running on\n\t\t\t\t\tthat port and try again?\n\t\t\t\t\t<PortStopper port={fetcher.data.port} />\n\t\t\t\t</div>\n\t\t\t)\n\t\t} else {\n\t\t\treturn <div>An unknown error has happened.</div>\n\t\t}\n\t}\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t{fetcher.state === 'idle' ? (\n\t\t\t\t<Button type=\"submit\" name=\"intent\" value=\"start\" varient=\"mono\">\n\t\t\t\t\tStart App\n\t\t\t\t</Button>\n\t\t\t) : (\n\t\t\t\t<div>\n\t\t\t\t\t<Loading>Starting App</Loading>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</fetcher.Form>\n\t)\n}\n","import { clsx } from 'clsx'\nimport * as React from 'react'\nimport { useImperativeHandle, useRef, useState } from 'react'\nimport { Icon } from '#app/components/icons.tsx'\nimport { AppStarter, AppStopper, PortStopper } from '#app/routes/start.tsx'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { getBaseUrl } from '#app/utils/misc.tsx'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\nimport { LinkButton } from './button.tsx'\nimport {\n\tTooltip,\n\tTooltipContent,\n\tTooltipProvider,\n\tTooltipTrigger,\n} from './ui/tooltip.tsx'\n\nexport type InBrowserBrowserRef = {\n\thandleExtrnalNavigation: (pathname?: string) => void\n}\n\ntype Props = {\n\tid: string\n\tname: string\n\tport: number\n\tportIsAvailable: boolean | null\n\tisRunning: boolean\n\tbaseUrl: string\n\tinitialRoute: string\n\tref?: React.Ref<InBrowserBrowserRef>\n}\n\nexport function InBrowserBrowser({\n\tname,\n\tport,\n\tportIsAvailable,\n\tisRunning,\n\tbaseUrl,\n\tid,\n\tinitialRoute,\n\tref,\n}: Props) {\n\tconst requestInfo = useRequestInfo()\n\tconst [showUnmanaged, setShowUnmanaged] = useState(false)\n\tif (isRunning || showUnmanaged) {\n\t\treturn (\n\t\t\t<InBrowserBrowserForRealz\n\t\t\t\tbaseUrl={baseUrl}\n\t\t\t\tid={id}\n\t\t\t\tname={name}\n\t\t\t\tref={ref}\n\t\t\t\tinitialRoute={initialRoute}\n\t\t\t/>\n\t\t)\n\t} else if (portIsAvailable === false) {\n\t\treturn (\n\t\t\t<div className=\"flex flex-col items-center justify-center\">\n\t\t\t\t<p className=\"max-w-xs pb-5 text-center\" role=\"status\">\n\t\t\t\t\t{`The port for this app is unavailable. It could be that you're running it `}\n\t\t\t\t\t<a\n\t\t\t\t\t\thref={getBaseUrl({ domain: requestInfo.domain, port })}\n\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t>\n\t\t\t\t\t\telsewhere\n\t\t\t\t\t</a>\n\t\t\t\t\t{'. '}\n\t\t\t\t\t<LinkButton onClick={() => setShowUnmanaged(true)}>\n\t\t\t\t\t\tShow here anyway\n\t\t\t\t\t</LinkButton>\n\t\t\t\t</p>\n\t\t\t\t<PortStopper port={port} />\n\t\t\t</div>\n\t\t)\n\t} else {\n\t\treturn (\n\t\t\t<div className=\"flex h-full flex-col items-center justify-center\">\n\t\t\t\t<AppStarter name={name} />\n\t\t\t</div>\n\t\t)\n\t}\n}\ntype RealBrowserProps = {\n\tbaseUrl: string\n\tid: string\n\tname: string\n\tinitialRoute: string\n\tref?: React.Ref<InBrowserBrowserRef>\n}\n\nfunction InBrowserBrowserForRealz({\n\tbaseUrl,\n\tid,\n\tname,\n\tinitialRoute,\n\tref,\n}: RealBrowserProps) {\n\tconst theme = useTheme()\n\tconst [iframeKeyNumber, setIframeKeyNumber] = useState(0)\n\tconst iframeKey = id + iframeKeyNumber\n\tconst iframeRef = useRef<HTMLIFrameElement>(null)\n\n\tconst appUrl = new URL(initialRoute, baseUrl)\n\tconst [iframeSrcUrl, setIframeSrcUrl] = useState(appUrl)\n\n\tconst currentId = useRef(id)\n\tif (currentId.current !== id) {\n\t\tcurrentId.current = id\n\t\tsetIframeSrcUrl(appUrl)\n\t}\n\n\tfunction handleExtrnalNavigation(pathname?: string) {\n\t\tif (pathname) {\n\t\t\tconst newUrl = new URL(pathname, baseUrl)\n\t\t\tsetIframeSrcUrl(newUrl)\n\t\t\tsetIframeKeyNumber((prev) => prev + 1)\n\t\t}\n\t}\n\n\tuseImperativeHandle(ref, () => ({ handleExtrnalNavigation }))\n\n\treturn (\n\t\t<TooltipProvider>\n\t\t\t<div className=\"flex h-full grow flex-col\">\n\t\t\t\t<div className=\"flex items-center justify-between border-b pl-1.5\">\n\t\t\t\t\t<div className=\"mr-2 flex items-center justify-center gap-2 px-1\">\n\t\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclassName=\"flex aspect-square h-full w-full items-center justify-center p-1 transition disabled:opacity-40\"\n\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\tsetIframeKeyNumber((prev) => prev + 1)\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon name=\"Refresh\" aria-hidden=\"true\" />\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t<TooltipContent>Refresh</TooltipContent>\n\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"bg-background text-foreground flex flex-1 items-center border-x p-3 leading-none\">\n\t\t\t\t\t\t<a href={iframeSrcUrl.toString()} target=\"_blank\" rel=\"noreferrer\">\n\t\t\t\t\t\t\t{iframeSrcUrl.toString()}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</div>\n\t\t\t\t\t<AppStopper name={name} />\n\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref={iframeSrcUrl.toString()}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t'flex aspect-square items-center justify-center px-3.5',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"ExternalLink\" />\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t<TooltipContent>Open in new tab</TooltipContent>\n\t\t\t\t\t</Tooltip>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"bg-background flex h-full w-full grow\">\n\t\t\t\t\t<iframe\n\t\t\t\t\t\ttitle={name}\n\t\t\t\t\t\tkey={iframeKey}\n\t\t\t\t\t\tref={iframeRef}\n\t\t\t\t\t\tsrc={iframeSrcUrl.toString()}\n\t\t\t\t\t\tclassName=\"bg-background h-full w-full grow\"\n\t\t\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</TooltipProvider>\n\t)\n}\n","import { type BaseExerciseStepApp } from '@epic-web/workshop-utils/apps.server'\nimport { useState } from 'react'\nimport { useSearchParams } from 'react-router'\nimport { Icon } from '#app/components/icons'\nimport {\n\tInBrowserBrowser,\n\ttype InBrowserBrowserRef,\n} from '#app/components/in-browser-browser.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { cn, getBaseUrl } from '#app/utils/misc.tsx'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\n\nexport function Preview({\n\tid,\n\tappInfo,\n\tinBrowserBrowserRef,\n}: {\n\tid?: string\n\tappInfo: {\n\t\tisRunning: boolean\n\t\tappName?: string\n\t\tname: string\n\t\ttitle: string\n\t\tportIsAvailable: boolean | null\n\t\ttype: string\n\t\tfullPath: string\n\t\tdev: BaseExerciseStepApp['dev']\n\t\ttest: BaseExerciseStepApp['test']\n\t\tstackBlitzUrl: BaseExerciseStepApp['stackBlitzUrl']\n\t} | null\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}) {\n\tconst requestInfo = useRequestInfo()\n\tconst [searchParams] = useSearchParams()\n\tconst theme = useTheme()\n\tif (!appInfo) return <p>No app here. Sorry.</p>\n\tconst { isRunning, dev, name, portIsAvailable, title } = appInfo\n\n\tif (!dev) {\n\t\treturn (\n\t\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t\t<p>No preview available for this app.</p>\n\t\t\t</div>\n\t\t)\n\t}\n\n\tif (ENV.EPICSHOP_DEPLOYED && appInfo.stackBlitzUrl) {\n\t\tconst url = new URL(appInfo.stackBlitzUrl)\n\t\turl.searchParams.set('embed', '1')\n\t\turl.searchParams.set('theme', theme)\n\n\t\treturn (\n\t\t\t<StackBlitzEmbed\n\t\t\t\ttitle={title}\n\t\t\t\turl={url.toString()}\n\t\t\t\tloadingContent={\n\t\t\t\t\t<Loading>\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\tLoading{' '}\n\t\t\t\t\t\t\t<a className=\"underline\" href={appInfo.stackBlitzUrl}>\n\t\t\t\t\t\t\t\t\"{title}\"\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</Loading>\n\t\t\t\t}\n\t\t\t/>\n\t\t)\n\t}\n\n\tif (dev.type === 'script') {\n\t\tconst baseUrl = getBaseUrl({\n\t\t\tdomain: requestInfo.domain,\n\t\t\tport: dev.portNumber,\n\t\t})\n\t\treturn (\n\t\t\t<InBrowserBrowser\n\t\t\t\tref={inBrowserBrowserRef}\n\t\t\t\tisRunning={isRunning}\n\t\t\t\tid={id ?? name}\n\t\t\t\tname={name}\n\t\t\t\tportIsAvailable={portIsAvailable}\n\t\t\t\tport={dev.portNumber}\n\t\t\t\tbaseUrl={baseUrl}\n\t\t\t\tinitialRoute={searchParams.get('pathname') ?? dev.initialRoute}\n\t\t\t/>\n\t\t)\n\t} else if (dev.type === 'browser' || dev.type === 'export') {\n\t\treturn (\n\t\t\t<div className=\"scrollbar-thin scrollbar-thumb-scrollbar relative h-full grow overflow-y-auto\">\n\t\t\t\t<a\n\t\t\t\t\thref={dev.pathname}\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'bg-muted text-foreground hover:bg-muted/80 absolute right-5 bottom-5 flex items-center justify-center rounded-full p-2.5 transition',\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<Icon name=\"ExternalLink\" aria-hidden=\"true\" />\n\t\t\t\t\t<span className=\"sr-only\">Open in New Window</span>\n\t\t\t\t</a>\n\t\t\t\t<iframe\n\t\t\t\t\ttitle={title}\n\t\t\t\t\tsrc={dev.pathname}\n\t\t\t\t\tclassName=\"bg-background h-full w-full grow\"\n\t\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t)\n\t} else {\n\t\treturn (\n\t\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t\t<p>\n\t\t\t\t\tPreview for dev type of <code>{dev.type}</code> not supported.\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t)\n\t}\n}\n\nexport function StackBlitzEmbed({\n\turl,\n\ttitle,\n\tloadingContent,\n}: {\n\turl: string\n\ttitle?: string\n\tloadingContent: React.ReactNode\n}) {\n\tconst theme = useTheme()\n\tconst [iframeLoaded, setIframeLoaded] = useState(false)\n\n\treturn (\n\t\t<div className=\"h-full w-full grow\">\n\t\t\t{iframeLoaded ? null : (\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t{loadingContent}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<iframe\n\t\t\t\tonLoad={() => setIframeLoaded(true)}\n\t\t\t\t// show what would have shown if there is an error\n\t\t\t\tonError={() => setIframeLoaded(true)}\n\t\t\t\tsrc={url}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'h-full w-full grow transition-opacity duration-300',\n\t\t\t\t\tiframeLoaded ? 'opacity-100' : 'opacity-0',\n\t\t\t\t)}\n\t\t\t\ttitle={title}\n\t\t\t\tsandbox=\"allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox\"\n\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n"],"names":["AppStopper","name","fetcher","useFetcher","peRedirectInput","usePERedirectInput","inFlightIntent","formData","get","inFlightState","altDown","useAltDown","Form","method","action","children","showProgressBarField","type","value","jsx","className","PortStopper","port","Button","varient","state","AppStarter","data","status","error","Loading","InBrowserBrowser","portIsAvailable","isRunning","baseUrl","id","initialRoute","ref","requestInfo","useRequestInfo","showUnmanaged","setShowUnmanaged","useState","InBrowserBrowserForRealz","jsxs","getBaseUrl","LinkButton","theme","useTheme","iframeKeyNumber","setIframeKeyNumber","iframeKey","iframeRef","useRef","appUrl","iframeSrcUrl","setIframeSrcUrl","currentId","handleExtrnalNavigation","pathname","newUrl","prev","useImperativeHandle","TooltipProvider","Tooltip","TooltipTrigger","Icon","TooltipContent","clsx","Preview","appInfo","inBrowserBrowserRef","searchParams","useSearchParams","dev","title","url","StackBlitzEmbed","cn","loadingContent","iframeLoaded","setIframeLoaded"],"mappings":"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"}
1
+ {"version":3,"file":"preview-fhmjENlm.js","sources":["../../../app/routes/start.tsx","../../../app/components/in-browser-browser.tsx","../../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/preview.tsx"],"sourcesContent":["import { invariant, invariantResponse } from '@epic-web/invariant'\nimport { getAppByName } from '@epic-web/workshop-utils/apps.server'\nimport {\n\tcloseProcess,\n\trunAppDev,\n\tstopPort,\n\twaitOnApp,\n} from '@epic-web/workshop-utils/process-manager.server'\nimport { data, type ActionFunctionArgs, useFetcher } from 'react-router'\nimport { Button } from '#app/components/button.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { showProgressBarField } from '#app/components/progress-bar.tsx'\nimport { ensureUndeployed, useAltDown } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.tsx'\nimport { createToastHeaders } from '#app/utils/toast.server'\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\tinvariantResponse(typeof intent === 'string', 'intent is required')\n\n\tif (intent === 'start' || intent === 'stop' || intent === 'restart') {\n\t\tconst name = formData.get('name')\n\t\tinvariantResponse(typeof name === 'string', 'name is required')\n\t\tconst app = await getAppByName(name)\n\t\tif (!app) {\n\t\t\tthrow new Response('Not found', { status: 404 })\n\t\t}\n\t\tif (app.dev.type !== 'script') {\n\t\t\tthrow new Response(`App \"${name}\" does not have a server`, {\n\t\t\t\tstatus: 400,\n\t\t\t})\n\t\t}\n\n\t\tasync function startApp() {\n\t\t\tinvariant(app, 'app must be defined')\n\t\t\tconst result = await runAppDev(app)\n\t\t\tif (result.running) {\n\t\t\t\tconst appRunningResult = await waitOnApp(app)\n\t\t\t\tif (appRunningResult?.status === 'success') {\n\t\t\t\t\t// wait another 200ms just in case the build output for assets isn't finished\n\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 200))\n\t\t\t\t\treturn dataWithPE(request, formData, {\n\t\t\t\t\t\tstatus: 'app-started',\n\t\t\t\t\t} as const)\n\t\t\t\t} else if (app.dev.type === 'script') {\n\t\t\t\t\tconst errorMessage = appRunningResult\n\t\t\t\t\t\t? appRunningResult.error\n\t\t\t\t\t\t: 'Unknown error'\n\t\t\t\t\treturn data(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstatus: 'app-not-started',\n\t\t\t\t\t\t\terror: errorMessage,\n\t\t\t\t\t\t\tport: app.dev.portNumber,\n\t\t\t\t\t\t} as const,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t\tstatusText: 'App did not start',\n\t\t\t\t\t\t\theaders: await createToastHeaders({\n\t\t\t\t\t\t\t\tdescription: errorMessage,\n\t\t\t\t\t\t\t\ttitle: 'App did not start',\n\t\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t} else if (result.portNumber) {\n\t\t\t\treturn dataWithPE(request, formData, {\n\t\t\t\t\tstatus: 'app-not-started',\n\t\t\t\t\terror: result.status,\n\t\t\t\t\tport: result.portNumber,\n\t\t\t\t} as const)\n\t\t\t} else {\n\t\t\t\tthrow new Response(\n\t\t\t\t\t'Tried starting a server for an app that does not have one',\n\t\t\t\t\t{ status: 400 },\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tasync function stopApp() {\n\t\t\tinvariant(app, 'app must be defined')\n\t\t\tawait closeProcess(app.name)\n\t\t\treturn dataWithPE(request, formData, { status: 'app-stopped' } as const)\n\t\t}\n\n\t\tswitch (intent) {\n\t\t\tcase 'start': {\n\t\t\t\treturn startApp()\n\t\t\t}\n\t\t\tcase 'stop': {\n\t\t\t\treturn stopApp()\n\t\t\t}\n\t\t\tcase 'restart': {\n\t\t\t\tawait stopApp()\n\t\t\t\treturn startApp()\n\t\t\t}\n\t\t}\n\t}\n\n\tif (intent === 'stop-port') {\n\t\tconst port = formData.get('port')\n\t\tinvariantResponse(typeof port === 'string', 'port is required')\n\t\tawait stopPort(port)\n\t\treturn dataWithPE(request, formData, { status: 'port-stopped' } as const)\n\t}\n\tthrow new Error(`Unknown intent: ${intent}`)\n}\n\nexport function AppStopper({ name }: { name: string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tconst inFlightIntent = fetcher.formData?.get('intent')\n\tconst inFlightState =\n\t\tinFlightIntent === 'stop'\n\t\t\t? 'Stopping App'\n\t\t\t: inFlightIntent === 'restart'\n\t\t\t\t? 'Restarting App'\n\t\t\t\t: null\n\tconst altDown = useAltDown()\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t<button\n\t\t\t\ttype=\"submit\"\n\t\t\t\tname=\"intent\"\n\t\t\t\tvalue={altDown ? 'restart' : 'stop'}\n\t\t\t\tclassName=\"h-full border-r px-3 py-4 font-mono text-xs leading-none uppercase\"\n\t\t\t>\n\t\t\t\t{inFlightState ? inFlightState : altDown ? 'Restart App' : 'Stop App'}\n\t\t\t</button>\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function PortStopper({ port }: { port: number | string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"port\" value={port} />\n\t\t\t<Button varient=\"mono\" type=\"submit\" name=\"intent\" value=\"stop-port\">\n\t\t\t\t{fetcher.state === 'idle' ? 'Stop Port' : 'Stopping Port'}\n\t\t\t</Button>\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function AppStarter({ name }: { name: string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tif (fetcher.data?.status === 'app-not-started') {\n\t\tif (fetcher.data.error === 'port-unavailable') {\n\t\t\treturn (\n\t\t\t\t<div>\n\t\t\t\t\tThe port is unavailable. Would you like to stop whatever is running on\n\t\t\t\t\tthat port and try again?\n\t\t\t\t\t<PortStopper port={fetcher.data.port} />\n\t\t\t\t</div>\n\t\t\t)\n\t\t} else {\n\t\t\treturn <div>An unknown error has happened.</div>\n\t\t}\n\t}\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t{fetcher.state === 'idle' ? (\n\t\t\t\t<Button type=\"submit\" name=\"intent\" value=\"start\" varient=\"mono\">\n\t\t\t\t\tStart App\n\t\t\t\t</Button>\n\t\t\t) : (\n\t\t\t\t<div>\n\t\t\t\t\t<Loading>Starting App</Loading>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</fetcher.Form>\n\t)\n}\n","import { clsx } from 'clsx'\nimport * as React from 'react'\nimport { useImperativeHandle, useRef, useState } from 'react'\nimport { Icon } from '#app/components/icons.tsx'\nimport { AppStarter, AppStopper, PortStopper } from '#app/routes/start.tsx'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { getBaseUrl } from '#app/utils/misc.tsx'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\nimport { LinkButton } from './button.tsx'\nimport {\n\tTooltip,\n\tTooltipContent,\n\tTooltipProvider,\n\tTooltipTrigger,\n} from './ui/tooltip.tsx'\n\nexport type InBrowserBrowserRef = {\n\thandleExtrnalNavigation: (pathname?: string) => void\n}\n\ntype Props = {\n\tid: string\n\tname: string\n\tport: number\n\tportIsAvailable: boolean | null\n\tisRunning: boolean\n\tbaseUrl: string\n\tinitialRoute: string\n\tref?: React.Ref<InBrowserBrowserRef>\n}\n\nexport function InBrowserBrowser({\n\tname,\n\tport,\n\tportIsAvailable,\n\tisRunning,\n\tbaseUrl,\n\tid,\n\tinitialRoute,\n\tref,\n}: Props) {\n\tconst requestInfo = useRequestInfo()\n\tconst [showUnmanaged, setShowUnmanaged] = useState(false)\n\tif (isRunning || showUnmanaged) {\n\t\treturn (\n\t\t\t<InBrowserBrowserForRealz\n\t\t\t\tbaseUrl={baseUrl}\n\t\t\t\tid={id}\n\t\t\t\tname={name}\n\t\t\t\tref={ref}\n\t\t\t\tinitialRoute={initialRoute}\n\t\t\t/>\n\t\t)\n\t} else if (portIsAvailable === false) {\n\t\treturn (\n\t\t\t<div className=\"flex flex-col items-center justify-center\">\n\t\t\t\t<p className=\"max-w-xs pb-5 text-center\" role=\"status\">\n\t\t\t\t\t{`The port for this app is unavailable. It could be that you're running it `}\n\t\t\t\t\t<a\n\t\t\t\t\t\thref={getBaseUrl({ domain: requestInfo.domain, port })}\n\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t>\n\t\t\t\t\t\telsewhere\n\t\t\t\t\t</a>\n\t\t\t\t\t{'. '}\n\t\t\t\t\t<LinkButton onClick={() => setShowUnmanaged(true)}>\n\t\t\t\t\t\tShow here anyway\n\t\t\t\t\t</LinkButton>\n\t\t\t\t</p>\n\t\t\t\t<PortStopper port={port} />\n\t\t\t</div>\n\t\t)\n\t} else {\n\t\treturn (\n\t\t\t<div className=\"flex h-full flex-col items-center justify-center\">\n\t\t\t\t<AppStarter name={name} />\n\t\t\t</div>\n\t\t)\n\t}\n}\ntype RealBrowserProps = {\n\tbaseUrl: string\n\tid: string\n\tname: string\n\tinitialRoute: string\n\tref?: React.Ref<InBrowserBrowserRef>\n}\n\nfunction InBrowserBrowserForRealz({\n\tbaseUrl,\n\tid,\n\tname,\n\tinitialRoute,\n\tref,\n}: RealBrowserProps) {\n\tconst theme = useTheme()\n\tconst [iframeKeyNumber, setIframeKeyNumber] = useState(0)\n\tconst iframeKey = id + iframeKeyNumber\n\tconst iframeRef = useRef<HTMLIFrameElement>(null)\n\n\tconst appUrl = new URL(initialRoute, baseUrl)\n\tconst [iframeSrcUrl, setIframeSrcUrl] = useState(appUrl)\n\n\tconst currentId = useRef(id)\n\tif (currentId.current !== id) {\n\t\tcurrentId.current = id\n\t\tsetIframeSrcUrl(appUrl)\n\t}\n\n\tfunction handleExtrnalNavigation(pathname?: string) {\n\t\tif (pathname) {\n\t\t\tconst newUrl = new URL(pathname, baseUrl)\n\t\t\tsetIframeSrcUrl(newUrl)\n\t\t\tsetIframeKeyNumber((prev) => prev + 1)\n\t\t}\n\t}\n\n\tuseImperativeHandle(ref, () => ({ handleExtrnalNavigation }))\n\n\treturn (\n\t\t<TooltipProvider>\n\t\t\t<div className=\"flex h-full grow flex-col\">\n\t\t\t\t<div className=\"flex items-center justify-between border-b pl-1.5\">\n\t\t\t\t\t<div className=\"mr-2 flex items-center justify-center gap-2 px-1\">\n\t\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclassName=\"flex aspect-square h-full w-full items-center justify-center p-1 transition disabled:opacity-40\"\n\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\tsetIframeKeyNumber((prev) => prev + 1)\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon name=\"Refresh\" aria-hidden=\"true\" />\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t<TooltipContent>Refresh</TooltipContent>\n\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"bg-background text-foreground flex flex-1 items-center border-x p-3 leading-none\">\n\t\t\t\t\t\t<a href={iframeSrcUrl.toString()} target=\"_blank\" rel=\"noreferrer\">\n\t\t\t\t\t\t\t{iframeSrcUrl.toString()}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</div>\n\t\t\t\t\t<AppStopper name={name} />\n\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref={iframeSrcUrl.toString()}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t'flex aspect-square items-center justify-center px-3.5',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"ExternalLink\" />\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t<TooltipContent>Open in new tab</TooltipContent>\n\t\t\t\t\t</Tooltip>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"bg-background flex h-full w-full grow\">\n\t\t\t\t\t<iframe\n\t\t\t\t\t\ttitle={name}\n\t\t\t\t\t\tkey={iframeKey}\n\t\t\t\t\t\tref={iframeRef}\n\t\t\t\t\t\tsrc={iframeSrcUrl.toString()}\n\t\t\t\t\t\tclassName=\"bg-background h-full w-full grow\"\n\t\t\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</TooltipProvider>\n\t)\n}\n","import { type BaseExerciseStepApp } from '@epic-web/workshop-utils/apps.server'\nimport { useState } from 'react'\nimport { useSearchParams } from 'react-router'\nimport { Icon } from '#app/components/icons'\nimport {\n\tInBrowserBrowser,\n\ttype InBrowserBrowserRef,\n} from '#app/components/in-browser-browser.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { cn, getBaseUrl } from '#app/utils/misc.tsx'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\n\nexport function Preview({\n\tid,\n\tappInfo,\n\tinBrowserBrowserRef,\n}: {\n\tid?: string\n\tappInfo: {\n\t\tisRunning: boolean\n\t\tappName?: string\n\t\tname: string\n\t\ttitle: string\n\t\tportIsAvailable: boolean | null\n\t\ttype: string\n\t\tfullPath: string\n\t\tdev: BaseExerciseStepApp['dev']\n\t\ttest: BaseExerciseStepApp['test']\n\t\tstackBlitzUrl: BaseExerciseStepApp['stackBlitzUrl']\n\t} | null\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}) {\n\tconst requestInfo = useRequestInfo()\n\tconst [searchParams] = useSearchParams()\n\tconst theme = useTheme()\n\tif (!appInfo) return <p>No app here. Sorry.</p>\n\tconst { isRunning, dev, name, portIsAvailable, title } = appInfo\n\n\tif (!dev) {\n\t\treturn (\n\t\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t\t<p>No preview available for this app.</p>\n\t\t\t</div>\n\t\t)\n\t}\n\n\tif (ENV.EPICSHOP_DEPLOYED && appInfo.stackBlitzUrl) {\n\t\tconst url = new URL(appInfo.stackBlitzUrl)\n\t\turl.searchParams.set('embed', '1')\n\t\turl.searchParams.set('theme', theme)\n\n\t\treturn (\n\t\t\t<StackBlitzEmbed\n\t\t\t\ttitle={title}\n\t\t\t\turl={url.toString()}\n\t\t\t\tloadingContent={\n\t\t\t\t\t<Loading>\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\tLoading{' '}\n\t\t\t\t\t\t\t<a className=\"underline\" href={appInfo.stackBlitzUrl}>\n\t\t\t\t\t\t\t\t\"{title}\"\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</Loading>\n\t\t\t\t}\n\t\t\t/>\n\t\t)\n\t}\n\n\tif (dev.type === 'script') {\n\t\tconst baseUrl = getBaseUrl({\n\t\t\tdomain: requestInfo.domain,\n\t\t\tport: dev.portNumber,\n\t\t})\n\t\treturn (\n\t\t\t<InBrowserBrowser\n\t\t\t\tref={inBrowserBrowserRef}\n\t\t\t\tisRunning={isRunning}\n\t\t\t\tid={id ?? name}\n\t\t\t\tname={name}\n\t\t\t\tportIsAvailable={portIsAvailable}\n\t\t\t\tport={dev.portNumber}\n\t\t\t\tbaseUrl={baseUrl}\n\t\t\t\tinitialRoute={searchParams.get('pathname') ?? dev.initialRoute}\n\t\t\t/>\n\t\t)\n\t} else if (dev.type === 'browser' || dev.type === 'export') {\n\t\treturn (\n\t\t\t<div className=\"scrollbar-thin scrollbar-thumb-scrollbar relative h-full grow overflow-y-auto\">\n\t\t\t\t<a\n\t\t\t\t\thref={dev.pathname}\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'bg-muted text-foreground hover:bg-muted/80 absolute right-5 bottom-5 flex items-center justify-center rounded-full p-2.5 transition',\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<Icon name=\"ExternalLink\" aria-hidden=\"true\" />\n\t\t\t\t\t<span className=\"sr-only\">Open in New Window</span>\n\t\t\t\t</a>\n\t\t\t\t<iframe\n\t\t\t\t\ttitle={title}\n\t\t\t\t\tsrc={dev.pathname}\n\t\t\t\t\tclassName=\"bg-background h-full w-full grow\"\n\t\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t)\n\t} else {\n\t\treturn (\n\t\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t\t<p>\n\t\t\t\t\tPreview for dev type of <code>{dev.type}</code> not supported.\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t)\n\t}\n}\n\nexport function StackBlitzEmbed({\n\turl,\n\ttitle,\n\tloadingContent,\n}: {\n\turl: string\n\ttitle?: string\n\tloadingContent: React.ReactNode\n}) {\n\tconst theme = useTheme()\n\tconst [iframeLoaded, setIframeLoaded] = useState(false)\n\n\treturn (\n\t\t<div className=\"h-full w-full grow\">\n\t\t\t{iframeLoaded ? null : (\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t{loadingContent}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<iframe\n\t\t\t\tonLoad={() => setIframeLoaded(true)}\n\t\t\t\t// show what would have shown if there is an error\n\t\t\t\tonError={() => setIframeLoaded(true)}\n\t\t\t\tsrc={url}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'h-full w-full grow transition-opacity duration-300',\n\t\t\t\t\tiframeLoaded ? 'opacity-100' : 'opacity-0',\n\t\t\t\t)}\n\t\t\t\ttitle={title}\n\t\t\t\tsandbox=\"allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox\"\n\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n"],"names":["AppStopper","name","fetcher","useFetcher","peRedirectInput","usePERedirectInput","inFlightIntent","formData","get","inFlightState","altDown","useAltDown","Form","method","action","children","showProgressBarField","type","value","jsx","className","PortStopper","port","Button","varient","state","AppStarter","data","status","error","Loading","InBrowserBrowser","portIsAvailable","isRunning","baseUrl","id","initialRoute","ref","requestInfo","useRequestInfo","showUnmanaged","setShowUnmanaged","useState","InBrowserBrowserForRealz","jsxs","getBaseUrl","LinkButton","theme","useTheme","iframeKeyNumber","setIframeKeyNumber","iframeKey","iframeRef","useRef","appUrl","iframeSrcUrl","setIframeSrcUrl","currentId","handleExtrnalNavigation","pathname","newUrl","prev","useImperativeHandle","TooltipProvider","Tooltip","TooltipTrigger","Icon","TooltipContent","clsx","Preview","appInfo","inBrowserBrowserRef","searchParams","useSearchParams","dev","title","url","StackBlitzEmbed","cn","loadingContent","iframeLoaded","setIframeLoaded"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{j as e}from"./jsx-runtime-C5WNSv3b.js";import{u as g}from"./index-BW8stNyh.js";import{c as r}from"./misc-DVYuZMjW.js";import{u as p}from"./workshop-config-Zfc8zU0x.js";const i={font:"w-[1em] h-[1em]",xs:"w-3 h-3",sm:"w-4 h-4",md:"w-5 h-5",lg:"w-6 h-6",xl:"w-7 h-7","2xl":"w-8 h-8"},x={font:"gap-1.5",xs:"gap-1.5",sm:"gap-1.5",md:"gap-2",lg:"gap-2",xl:"gap-3","2xl":"gap-4"};function w({size:s="font",style:c="themed",className:o,children:t,...m}){const{product:{logo:n,displayName:l}}=p(),h=g(),a=n.includes(".svg")?e.jsxs("svg",{...m,className:r(i[s],"inline self-center",o),children:[e.jsx("title",{children:l}),e.jsx("use",{href:`${n}#${c==="themed"?h:"monochrome"}`})]}):e.jsx("img",{src:n,alt:l,...m,className:r(i[s],"inline self-center",o)});return t?e.jsxs("span",{className:`inline-flex items-center ${x[s]}`,children:[a,t]}):a}export{w as L};
2
- //# sourceMappingURL=product-GLsnY1u3.js.map
1
+ import{j as e}from"./jsx-runtime-C5WNSv3b.js";import{u as g}from"./index-CdzVFL-Z.js";import{c as r}from"./misc-W4055b-0.js";import{u as p}from"./workshop-config-Zfc8zU0x.js";const i={font:"w-[1em] h-[1em]",xs:"w-3 h-3",sm:"w-4 h-4",md:"w-5 h-5",lg:"w-6 h-6",xl:"w-7 h-7","2xl":"w-8 h-8"},x={font:"gap-1.5",xs:"gap-1.5",sm:"gap-1.5",md:"gap-2",lg:"gap-2",xl:"gap-3","2xl":"gap-4"};function w({size:s="font",style:c="themed",className:o,children:t,...m}){const{product:{logo:n,displayName:l}}=p(),h=g(),a=n.includes(".svg")?e.jsxs("svg",{...m,className:r(i[s],"inline self-center",o),children:[e.jsx("title",{children:l}),e.jsx("use",{href:`${n}#${c==="themed"?h:"monochrome"}`})]}):e.jsx("img",{src:n,alt:l,...m,className:r(i[s],"inline self-center",o)});return t?e.jsxs("span",{className:`inline-flex items-center ${x[s]}`,children:[a,t]}):a}export{w as L};
2
+ //# sourceMappingURL=product-CvyMpYD_.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"product-GLsnY1u3.js","sources":["../../../app/components/product.tsx"],"sourcesContent":["import { useTheme } from '#app/routes/theme/index.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useWorkshopConfig } from './workshop-config.tsx'\n\ntype Sizes = 'font' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'\n\nconst sizeClassName = {\n\tfont: 'w-[1em] h-[1em]',\n\txs: 'w-3 h-3',\n\tsm: 'w-4 h-4',\n\tmd: 'w-5 h-5',\n\tlg: 'w-6 h-6',\n\txl: 'w-7 h-7',\n\t'2xl': 'w-8 h-8',\n} as const\n\nconst childrenSizeClassName = {\n\tfont: 'gap-1.5',\n\txs: 'gap-1.5',\n\tsm: 'gap-1.5',\n\tmd: 'gap-2',\n\tlg: 'gap-2',\n\txl: 'gap-3',\n\t'2xl': 'gap-4',\n} satisfies Record<Sizes, string>\n\nexport function ProductName(props: React.HTMLAttributes<HTMLSpanElement>) {\n\tconst {\n\t\tproduct: { displayName },\n\t} = useWorkshopConfig()\n\treturn <span {...props}>{displayName}</span>\n}\n\nexport function Logo({\n\tsize = 'font',\n\tstyle = 'themed',\n\tclassName,\n\tchildren,\n\t...props\n}: React.SVGProps<SVGSVGElement> & {\n\tsize?: Sizes\n\tstyle?: 'themed' | 'monochrome'\n\tclassName?: string\n\tchildren?: React.ReactNode\n}) {\n\tconst {\n\t\tproduct: { logo, displayName },\n\t} = useWorkshopConfig()\n\tconst theme = useTheme()\n\n\tconst logoElement = logo.includes('.svg') ? (\n\t\t<svg\n\t\t\t{...props}\n\t\t\tclassName={cn(sizeClassName[size], 'inline self-center', className)}\n\t\t>\n\t\t\t<title>{displayName}</title>\n\t\t\t<use href={`${logo}#${style === 'themed' ? theme : 'monochrome'}`} />\n\t\t</svg>\n\t) : (\n\t\t// @ts-expect-error - svg props can't all be applied to img... meh, probably won't ever be a real issue...\n\t\t<img\n\t\t\tsrc={logo}\n\t\t\talt={displayName}\n\t\t\t{...props}\n\t\t\tclassName={cn(sizeClassName[size], 'inline self-center', className)}\n\t\t/>\n\t)\n\n\tif (children) {\n\t\treturn (\n\t\t\t<span\n\t\t\t\tclassName={`inline-flex items-center ${childrenSizeClassName[size]}`}\n\t\t\t>\n\t\t\t\t{logoElement}\n\t\t\t\t{children}\n\t\t\t</span>\n\t\t)\n\t}\n\n\treturn logoElement\n}\n"],"names":["sizeClassName","childrenSizeClassName","Logo","size","style","className","children","props","logo","displayName","useWorkshopConfig","theme","useTheme","logoElement","jsxs","cn","jsx"],"mappings":"+KAMA,MAAMA,EAAgB,CACrB,KAAM,kBACN,GAAI,UACJ,GAAI,UACJ,GAAI,UACJ,GAAI,UACJ,GAAI,UACJ,MAAO,SACR,EAEMC,EAAwB,CAC7B,KAAM,UACN,GAAI,UACJ,GAAI,UACJ,GAAI,QACJ,GAAI,QACJ,GAAI,QACJ,MAAO,OACR,EASO,SAASC,EAAK,CACpB,KAAAC,EAAO,OACP,MAAAC,EAAQ,SACR,UAAAC,EACA,SAAAC,EACA,GAAGC,CACJ,EAKG,CACF,KAAM,CACL,QAAS,CAAE,KAAAC,EAAM,YAAAC,CAAA,CAAY,EAC1BC,EAAA,EACEC,EAAQC,EAAA,EAERC,EAAcL,EAAK,SAAS,MAAM,EACvCM,EAAAA,KAAC,MAAA,CACC,GAAGP,EACJ,UAAWQ,EAAGf,EAAcG,CAAI,EAAG,qBAAsBE,CAAS,EAElE,SAAA,CAAAW,EAAAA,IAAC,SAAO,SAAAP,CAAA,CAAY,EACpBO,EAAAA,IAAC,MAAA,CAAI,KAAM,GAAGR,CAAI,IAAIJ,IAAU,SAAWO,EAAQ,YAAY,EAAA,CAAI,CAAA,CAAA,CAAA,EAIpEK,EAAAA,IAAC,MAAA,CACA,IAAKR,EACL,IAAKC,EACJ,GAAGF,EACJ,UAAWQ,EAAGf,EAAcG,CAAI,EAAG,qBAAsBE,CAAS,CAAA,CAAA,EAIpE,OAAIC,EAEFQ,EAAAA,KAAC,OAAA,CACA,UAAW,4BAA4Bb,EAAsBE,CAAI,CAAC,GAEjE,SAAA,CAAAU,EACAP,CAAA,CAAA,CAAA,EAKGO,CACR"}
1
+ {"version":3,"file":"product-CvyMpYD_.js","sources":["../../../app/components/product.tsx"],"sourcesContent":["import { useTheme } from '#app/routes/theme/index.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useWorkshopConfig } from './workshop-config.tsx'\n\ntype Sizes = 'font' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'\n\nconst sizeClassName = {\n\tfont: 'w-[1em] h-[1em]',\n\txs: 'w-3 h-3',\n\tsm: 'w-4 h-4',\n\tmd: 'w-5 h-5',\n\tlg: 'w-6 h-6',\n\txl: 'w-7 h-7',\n\t'2xl': 'w-8 h-8',\n} as const\n\nconst childrenSizeClassName = {\n\tfont: 'gap-1.5',\n\txs: 'gap-1.5',\n\tsm: 'gap-1.5',\n\tmd: 'gap-2',\n\tlg: 'gap-2',\n\txl: 'gap-3',\n\t'2xl': 'gap-4',\n} satisfies Record<Sizes, string>\n\nexport function ProductName(props: React.HTMLAttributes<HTMLSpanElement>) {\n\tconst {\n\t\tproduct: { displayName },\n\t} = useWorkshopConfig()\n\treturn <span {...props}>{displayName}</span>\n}\n\nexport function Logo({\n\tsize = 'font',\n\tstyle = 'themed',\n\tclassName,\n\tchildren,\n\t...props\n}: React.SVGProps<SVGSVGElement> & {\n\tsize?: Sizes\n\tstyle?: 'themed' | 'monochrome'\n\tclassName?: string\n\tchildren?: React.ReactNode\n}) {\n\tconst {\n\t\tproduct: { logo, displayName },\n\t} = useWorkshopConfig()\n\tconst theme = useTheme()\n\n\tconst logoElement = logo.includes('.svg') ? (\n\t\t<svg\n\t\t\t{...props}\n\t\t\tclassName={cn(sizeClassName[size], 'inline self-center', className)}\n\t\t>\n\t\t\t<title>{displayName}</title>\n\t\t\t<use href={`${logo}#${style === 'themed' ? theme : 'monochrome'}`} />\n\t\t</svg>\n\t) : (\n\t\t// @ts-expect-error - svg props can't all be applied to img... meh, probably won't ever be a real issue...\n\t\t<img\n\t\t\tsrc={logo}\n\t\t\talt={displayName}\n\t\t\t{...props}\n\t\t\tclassName={cn(sizeClassName[size], 'inline self-center', className)}\n\t\t/>\n\t)\n\n\tif (children) {\n\t\treturn (\n\t\t\t<span\n\t\t\t\tclassName={`inline-flex items-center ${childrenSizeClassName[size]}`}\n\t\t\t>\n\t\t\t\t{logoElement}\n\t\t\t\t{children}\n\t\t\t</span>\n\t\t)\n\t}\n\n\treturn logoElement\n}\n"],"names":["sizeClassName","childrenSizeClassName","Logo","size","style","className","children","props","logo","displayName","useWorkshopConfig","theme","useTheme","logoElement","jsxs","cn","jsx"],"mappings":"+KAMA,MAAMA,EAAgB,CACrB,KAAM,kBACN,GAAI,UACJ,GAAI,UACJ,GAAI,UACJ,GAAI,UACJ,GAAI,UACJ,MAAO,SACR,EAEMC,EAAwB,CAC7B,KAAM,UACN,GAAI,UACJ,GAAI,UACJ,GAAI,QACJ,GAAI,QACJ,GAAI,QACJ,MAAO,OACR,EASO,SAASC,EAAK,CACpB,KAAAC,EAAO,OACP,MAAAC,EAAQ,SACR,UAAAC,EACA,SAAAC,EACA,GAAGC,CACJ,EAKG,CACF,KAAM,CACL,QAAS,CAAE,KAAAC,EAAM,YAAAC,CAAA,CAAY,EAC1BC,EAAA,EACEC,EAAQC,EAAA,EAERC,EAAcL,EAAK,SAAS,MAAM,EACvCM,EAAAA,KAAC,MAAA,CACC,GAAGP,EACJ,UAAWQ,EAAGf,EAAcG,CAAI,EAAG,qBAAsBE,CAAS,EAElE,SAAA,CAAAW,EAAAA,IAAC,SAAO,SAAAP,CAAA,CAAY,EACpBO,EAAAA,IAAC,MAAA,CAAI,KAAM,GAAGR,CAAI,IAAIJ,IAAU,SAAWO,EAAQ,YAAY,EAAA,CAAI,CAAA,CAAA,CAAA,EAIpEK,EAAAA,IAAC,MAAA,CACA,IAAKR,EACL,IAAKC,EACJ,GAAGF,EACJ,UAAWQ,EAAGf,EAAcG,CAAI,EAAG,qBAAsBE,CAAS,CAAA,CAAA,EAIpE,OAAIC,EAEFQ,EAAAA,KAAC,OAAA,CACA,UAAW,4BAA4Bb,EAAsBE,CAAI,CAAC,GAEjE,SAAA,CAAAU,EACAP,CAAA,CAAA,CAAA,EAKGO,CACR"}