@shapio/cms 0.5.8 → 0.5.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/assets/{AssetTile-BrMzsUZD.js → AssetTile-DecaDqjj.js} +2 -2
- package/dist/admin/assets/{AssetTile-BrMzsUZD.js.map → AssetTile-DecaDqjj.js.map} +1 -1
- package/dist/admin/assets/AssistError-rslPtgWB.js +2 -0
- package/dist/admin/assets/{AssistError-Cs-r9Ssc.js.map → AssistError-rslPtgWB.js.map} +1 -1
- package/dist/admin/assets/{BlockMenuItems-DsccXMc_.js → BlockMenuItems-JHFue7Qt.js} +2 -2
- package/dist/admin/assets/{BlockMenuItems-DsccXMc_.js.map → BlockMenuItems-JHFue7Qt.js.map} +1 -1
- package/dist/admin/assets/Body-7NgJl9Pi.js +2 -0
- package/dist/admin/assets/Body-7NgJl9Pi.js.map +1 -0
- package/dist/admin/assets/Builder-DmlYcgiP.js +2 -0
- package/dist/admin/assets/Builder-DmlYcgiP.js.map +1 -0
- package/dist/admin/assets/{CodeEditor-CBCR73Wd.js → CodeEditor-Dv1FtkvI.js} +2 -2
- package/dist/admin/assets/{CodeEditor-CBCR73Wd.js.map → CodeEditor-Dv1FtkvI.js.map} +1 -1
- package/dist/admin/assets/{CopyButton-CxFsBHfF.js → CopyButton-Brnpfqe0.js} +2 -2
- package/dist/admin/assets/{CopyButton-CxFsBHfF.js.map → CopyButton-Brnpfqe0.js.map} +1 -1
- package/dist/admin/assets/{CursorPager-BW2U3v6l.js → CursorPager-C7cAK5Qe.js} +2 -2
- package/dist/admin/assets/{CursorPager-BW2U3v6l.js.map → CursorPager-C7cAK5Qe.js.map} +1 -1
- package/dist/admin/assets/{ExternalLink-BITMgS1K.js → ExternalLink-D80sb5Jj.js} +2 -2
- package/dist/admin/assets/{ExternalLink-BITMgS1K.js.map → ExternalLink-D80sb5Jj.js.map} +1 -1
- package/dist/admin/assets/{FocalPoint-CpZTve1E.js → FocalPoint-Bhtb1gUa.js} +2 -2
- package/dist/admin/assets/{FocalPoint-CpZTve1E.js.map → FocalPoint-Bhtb1gUa.js.map} +1 -1
- package/dist/admin/assets/Form-Cf1ephPH.js +2 -0
- package/dist/admin/assets/Form-Cf1ephPH.js.map +1 -0
- package/dist/admin/assets/FormCheckboxGroup-BzVZFR3W.js +2 -0
- package/dist/admin/assets/FormCheckboxGroup-BzVZFR3W.js.map +1 -0
- package/dist/admin/assets/{FormRadioGroup-Cfx5pvzU.js → FormRadioGroup-BzmLzRnI.js} +2 -2
- package/dist/admin/assets/{FormRadioGroup-Cfx5pvzU.js.map → FormRadioGroup-BzmLzRnI.js.map} +1 -1
- package/dist/admin/assets/FormSelectField-Cl7EjXc3.js +2 -0
- package/dist/admin/assets/FormSelectField-Cl7EjXc3.js.map +1 -0
- package/dist/admin/assets/FormSheet-CLZpd_7B.js +2 -0
- package/dist/admin/assets/FormSheet-CLZpd_7B.js.map +1 -0
- package/dist/admin/assets/{FormSwitchField-BLOh7qei.js → FormSwitchField-BbqQ3tx_.js} +2 -2
- package/dist/admin/assets/{FormSwitchField-BLOh7qei.js.map → FormSwitchField-BbqQ3tx_.js.map} +1 -1
- package/dist/admin/assets/{FormTextareaField-CO115n_u.js → FormTextareaField-9RN5Pt3B.js} +2 -2
- package/dist/admin/assets/{FormTextareaField-CO115n_u.js.map → FormTextareaField-9RN5Pt3B.js.map} +1 -1
- package/dist/admin/assets/{HintedLabel-DzHnEdIK.js → HintedLabel-D9IVF0EE.js} +2 -2
- package/dist/admin/assets/{HintedLabel-DzHnEdIK.js.map → HintedLabel-D9IVF0EE.js.map} +1 -1
- package/dist/admin/assets/{InfoHint-CSEtcHjL.js → InfoHint-tlSeZB9U.js} +2 -2
- package/dist/admin/assets/{InfoHint-CSEtcHjL.js.map → InfoHint-tlSeZB9U.js.map} +1 -1
- package/dist/admin/assets/{InlineConfirm-yW-iUKFC.js → InlineConfirm-Kj9AOIFO.js} +2 -2
- package/dist/admin/assets/{InlineConfirm-yW-iUKFC.js.map → InlineConfirm-Kj9AOIFO.js.map} +1 -1
- package/dist/admin/assets/{InsertMenuItem-CCr9e0qY.js → InsertMenuItem-CHAp2tH7.js} +2 -2
- package/dist/admin/assets/{InsertMenuItem-CCr9e0qY.js.map → InsertMenuItem-CHAp2tH7.js.map} +1 -1
- package/dist/admin/assets/{LinkTabs-8SmS1vCd.js → LinkTabs-oQXsy1I3.js} +2 -2
- package/dist/admin/assets/{LinkTabs-8SmS1vCd.js.map → LinkTabs-oQXsy1I3.js.map} +1 -1
- package/dist/admin/assets/{Match-CcD9KxHH.js → Match-BfNRwPfR.js} +2 -2
- package/dist/admin/assets/{Match-CcD9KxHH.js.map → Match-BfNRwPfR.js.map} +1 -1
- package/dist/admin/assets/{NoAccess-C8RLPN0I.js → NoAccess-DnEpYj9l.js} +2 -2
- package/dist/admin/assets/{NoAccess-C8RLPN0I.js.map → NoAccess-DnEpYj9l.js.map} +1 -1
- package/dist/admin/assets/Panel-Bcl09TtM.js.map +1 -1
- package/dist/admin/assets/{QueryView-xMP_uJ_t.js → QueryView-B86NcRt5.js} +2 -2
- package/dist/admin/assets/{QueryView-xMP_uJ_t.js.map → QueryView-B86NcRt5.js.map} +1 -1
- package/dist/admin/assets/{RadioTile-DQFmni5A.js → RadioTile-Bwd2Pmlk.js} +2 -2
- package/dist/admin/assets/RadioTile-Bwd2Pmlk.js.map +1 -0
- package/dist/admin/assets/{RichTextField-CVHRIbnu.js → RichTextField-Dou79MHF.js} +4 -4
- package/dist/admin/assets/RichTextField-Dou79MHF.js.map +1 -0
- package/dist/admin/assets/{RowTitle-Bqt6evG9.js → RowTitle-DH9OZs3g.js} +2 -2
- package/dist/admin/assets/{RowTitle-Bqt6evG9.js.map → RowTitle-DH9OZs3g.js.map} +1 -1
- package/dist/admin/assets/{SecretReveal-Bm6nYg5J.js → SecretReveal-D95oACLj.js} +2 -2
- package/dist/admin/assets/{SecretReveal-Bm6nYg5J.js.map → SecretReveal-D95oACLj.js.map} +1 -1
- package/dist/admin/assets/{SharedGlyph-cUmTh0_C.js → SharedGlyph-Chwb1EIS.js} +2 -2
- package/dist/admin/assets/{SharedGlyph-cUmTh0_C.js.map → SharedGlyph-Chwb1EIS.js.map} +1 -1
- package/dist/admin/assets/StepList-D9iHsUZJ.js +2 -0
- package/dist/admin/assets/StepList-D9iHsUZJ.js.map +1 -0
- package/dist/admin/assets/Structure-CewJL1b3.js +2 -0
- package/dist/admin/assets/{Structure-D8csgrIt.js.map → Structure-CewJL1b3.js.map} +1 -1
- package/dist/admin/assets/{SubNavLink-CiCaVV8U.js → SubNavLink-7Cs1LqMv.js} +2 -2
- package/dist/admin/assets/SubNavLink-7Cs1LqMv.js.map +1 -0
- package/dist/admin/assets/{SuggestAltButton-CvIoirnz.js → SuggestAltButton-BK1uo4yC.js} +2 -2
- package/dist/admin/assets/{SuggestAltButton-CvIoirnz.js.map → SuggestAltButton-BK1uo4yC.js.map} +1 -1
- package/dist/admin/assets/{TextLink-HRn66VL1.js → TextLink-Dfs5wsc5.js} +2 -2
- package/dist/admin/assets/{TextLink-HRn66VL1.js.map → TextLink-Dfs5wsc5.js.map} +1 -1
- package/dist/admin/assets/{Thumbnail-DNj5TRBI.js → Thumbnail-C2A_Ub77.js} +2 -2
- package/dist/admin/assets/{Thumbnail-DNj5TRBI.js.map → Thumbnail-C2A_Ub77.js.map} +1 -1
- package/dist/admin/assets/Trans-CPoNNUK1.js +2 -0
- package/dist/admin/assets/Trans-CPoNNUK1.js.map +1 -0
- package/dist/admin/assets/{UnsavedChangesGuard-CUiuMklN.js → UnsavedChangesGuard-BsEyn9oH.js} +2 -2
- package/dist/admin/assets/{UnsavedChangesGuard-CUiuMklN.js.map → UnsavedChangesGuard-BsEyn9oH.js.map} +1 -1
- package/dist/admin/assets/{UserAvatar-p-jV-LoD.js → UserAvatar-CgGKOFfP.js} +2 -2
- package/dist/admin/assets/{UserAvatar-p-jV-LoD.js.map → UserAvatar-CgGKOFfP.js.map} +1 -1
- package/dist/admin/assets/auth-BFSvtV59.js +2 -0
- package/dist/admin/assets/{auth-CQO4MBUj.js.map → auth-BFSvtV59.js.map} +1 -1
- package/dist/admin/assets/{badge-CqKF1pwz.js → badge-DGqA_yr_.js} +2 -2
- package/dist/admin/assets/{badge-CqKF1pwz.js.map → badge-DGqA_yr_.js.map} +1 -1
- package/dist/admin/assets/baseExtensions-TVKN1UwW.js.map +1 -1
- package/dist/admin/assets/{boxes-CAygw8zF.js → boxes-_5klpWNM.js} +2 -2
- package/dist/admin/assets/{boxes-CAygw8zF.js.map → boxes-_5klpWNM.js.map} +1 -1
- package/dist/admin/assets/{calendar-clock-BZGtAvWR.js → calendar-clock-VXok22Xj.js} +2 -2
- package/dist/admin/assets/{calendar-clock-BZGtAvWR.js.map → calendar-clock-VXok22Xj.js.map} +1 -1
- package/dist/admin/assets/changeSets-B6HxCJ4A.js +2 -0
- package/dist/admin/assets/{changeSets-8EburmT0.js.map → changeSets-B6HxCJ4A.js.map} +1 -1
- package/dist/admin/assets/chevron-left-CkRxDtvO.js +2 -0
- package/dist/admin/assets/{chevron-left-DGU3HGYG.js.map → chevron-left-CkRxDtvO.js.map} +1 -1
- package/dist/admin/assets/{circle-check-C37MSJqX.js → circle-check-DtDq7QMo.js} +2 -2
- package/dist/admin/assets/{circle-check-C37MSJqX.js.map → circle-check-DtDq7QMo.js.map} +1 -1
- package/dist/admin/assets/{clock-2arjsgZ4.js → clock-BtvZR9KD.js} +2 -2
- package/dist/admin/assets/{clock-2arjsgZ4.js.map → clock-BtvZR9KD.js.map} +1 -1
- package/dist/admin/assets/cn-DVhJ55Mo.js.map +1 -1
- package/dist/admin/assets/{constants-a_15vqOh.js → constants-DY3YJAKH.js} +2 -2
- package/dist/admin/assets/{constants-a_15vqOh.js.map → constants-DY3YJAKH.js.map} +1 -1
- package/dist/admin/assets/content-BNZF26Ve.js +3 -0
- package/dist/admin/assets/content-BNZF26Ve.js.map +1 -0
- package/dist/admin/assets/{contentCounts-DP7YYeZZ.js → contentCounts-BzC7IQqP.js} +2 -2
- package/dist/admin/assets/{contentCounts-DP7YYeZZ.js.map → contentCounts-BzC7IQqP.js.map} +1 -1
- package/dist/admin/assets/{contentTypes-84uc0bjR.js → contentTypes-Bz2xpqGf.js} +2 -2
- package/dist/admin/assets/{contentTypes-84uc0bjR.js.map → contentTypes-Bz2xpqGf.js.map} +1 -1
- package/dist/admin/assets/{context-IKYdzQJ-.js → context-CEVKblBl.js} +2 -2
- package/dist/admin/assets/{context-IKYdzQJ-.js.map → context-CEVKblBl.js.map} +1 -1
- package/dist/admin/assets/{copy-CsSRHgKZ.js → copy-B7vIq8DS.js} +2 -2
- package/dist/admin/assets/{copy-CsSRHgKZ.js.map → copy-B7vIq8DS.js.map} +1 -1
- package/dist/admin/assets/createLucideIcon-BOsNKleB.js +2 -0
- package/dist/admin/assets/createLucideIcon-BOsNKleB.js.map +1 -0
- package/dist/admin/assets/develop-D6CtwuYj.js +11 -0
- package/dist/admin/assets/develop-D6CtwuYj.js.map +1 -0
- package/dist/admin/assets/{dropdown-menu-_xfaEp5C.js → dropdown-menu-Bz7CLcRK.js} +2 -2
- package/dist/admin/assets/{dropdown-menu-_xfaEp5C.js.map → dropdown-menu-Bz7CLcRK.js.map} +1 -1
- package/dist/admin/assets/{ellipsis-F91991on.js → ellipsis-Ci0rsbCJ.js} +2 -2
- package/dist/admin/assets/{ellipsis-F91991on.js.map → ellipsis-Ci0rsbCJ.js.map} +1 -1
- package/dist/admin/assets/{entryLink-CVB-TdIn.js → entryLink-B0hSb_dN.js} +2 -2
- package/dist/admin/assets/{entryLink-CVB-TdIn.js.map → entryLink-B0hSb_dN.js.map} +1 -1
- package/dist/admin/assets/es2015-Cv57ynE1.js +42 -0
- package/dist/admin/assets/es2015-Cv57ynE1.js.map +1 -0
- package/dist/admin/assets/{external-link-CdG6kHfA.js → external-link-Bs9YRzvY.js} +2 -2
- package/dist/admin/assets/{external-link-CdG6kHfA.js.map → external-link-Bs9YRzvY.js.map} +1 -1
- package/dist/admin/assets/{field-COOzRptX.js → field-D-xWW2E7.js} +2 -2
- package/dist/admin/assets/{field-COOzRptX.js.map → field-D-xWW2E7.js.map} +1 -1
- package/dist/admin/assets/{file-stack-28ZtO1xW.js → file-stack-X4OGmkLA.js} +2 -2
- package/dist/admin/assets/{file-stack-28ZtO1xW.js.map → file-stack-X4OGmkLA.js.map} +1 -1
- package/dist/admin/assets/{fileRoute-s7mCMYUJ.js → fileRoute-DMal-zYL.js} +2 -2
- package/dist/admin/assets/{fileRoute-s7mCMYUJ.js.map → fileRoute-DMal-zYL.js.map} +1 -1
- package/dist/admin/assets/{folder-plus-DIk0pWkP.js → folder-plus-De2GNvry.js} +2 -2
- package/dist/admin/assets/{folder-plus-DIk0pWkP.js.map → folder-plus-De2GNvry.js.map} +1 -1
- package/dist/admin/assets/followPlural-CsgeALTW.js +2 -0
- package/dist/admin/assets/followPlural-CsgeALTW.js.map +1 -0
- package/dist/admin/assets/{globe-DFr3Gd2w.js → globe-DBw84s8Z.js} +2 -2
- package/dist/admin/assets/{globe-DFr3Gd2w.js.map → globe-DBw84s8Z.js.map} +1 -1
- package/dist/admin/assets/{image-DT79QFa_.js → image-CX4mT-_R.js} +2 -2
- package/dist/admin/assets/{image-DT79QFa_.js.map → image-CX4mT-_R.js.map} +1 -1
- package/dist/admin/assets/{image-off-DFs5upyX.js → image-off-CVaH_qKf.js} +2 -2
- package/dist/admin/assets/{image-off-DFs5upyX.js.map → image-off-CVaH_qKf.js.map} +1 -1
- package/dist/admin/assets/inbox-C0PVc6UI.js +2 -0
- package/dist/admin/assets/inbox-C0PVc6UI.js.map +1 -0
- package/dist/admin/assets/{inbox-CySnQydm.js → inbox-D9SmWt5L.js} +2 -2
- package/dist/admin/assets/{inbox-CySnQydm.js.map → inbox-D9SmWt5L.js.map} +1 -1
- package/dist/admin/assets/index-BqtCXB0u.js +4 -0
- package/dist/admin/assets/index-BqtCXB0u.js.map +1 -0
- package/dist/admin/assets/index-DZsQq6fY.css +2 -0
- package/dist/admin/assets/{key-round-D36CePnN.js → key-round-C8sd9CLN.js} +2 -2
- package/dist/admin/assets/{key-round-D36CePnN.js.map → key-round-C8sd9CLN.js.map} +1 -1
- package/dist/admin/assets/{labels-DQckbLGW.js → labels-BtktCNGw.js} +2 -2
- package/dist/admin/assets/{labels-DQckbLGW.js.map → labels-BtktCNGw.js.map} +1 -1
- package/dist/admin/assets/{languages-CzbTaQv9.js → languages-DLjdz6gb.js} +2 -2
- package/dist/admin/assets/{languages-CzbTaQv9.js.map → languages-DLjdz6gb.js.map} +1 -1
- package/dist/admin/assets/{layers-BmcodiaH.js → layers-swLuw-3a.js} +2 -2
- package/dist/admin/assets/{layers-BmcodiaH.js.map → layers-swLuw-3a.js.map} +1 -1
- package/dist/admin/assets/{link-2-off-CoJNwrxm.js → link-2-off-CEsI5T8h.js} +2 -2
- package/dist/admin/assets/{link-2-off-CoJNwrxm.js.map → link-2-off-CEsI5T8h.js.map} +1 -1
- package/dist/admin/assets/{link-Pyr2Y35S.js → link-C98FG_p5.js} +2 -2
- package/dist/admin/assets/{link-Pyr2Y35S.js.map → link-C98FG_p5.js.map} +1 -1
- package/dist/admin/assets/locales-CkuC7TJ1.js +2 -0
- package/dist/admin/assets/{locales-Bg3htKo8.js.map → locales-CkuC7TJ1.js.map} +1 -1
- package/dist/admin/assets/media-CbGSd_Mw.js +2 -0
- package/dist/admin/assets/{media-BCnVhaDH.js.map → media-CbGSd_Mw.js.map} +1 -1
- package/dist/admin/assets/{media-CURizGns.js → media-CeZGDGh7.js} +2 -2
- package/dist/admin/assets/{media-CURizGns.js.map → media-CeZGDGh7.js.map} +1 -1
- package/dist/admin/assets/network-BflLSKFO.js +2 -0
- package/dist/admin/assets/network-BflLSKFO.js.map +1 -0
- package/dist/admin/assets/{plus-BoDtdLCo.js → plus-cr9ZfO6j.js} +2 -2
- package/dist/admin/assets/{plus-BoDtdLCo.js.map → plus-cr9ZfO6j.js.map} +1 -1
- package/dist/admin/assets/publishing-BkxBplUZ.js +2 -0
- package/dist/admin/assets/publishing-BkxBplUZ.js.map +1 -0
- package/dist/admin/assets/{radio-group-4ok5evXq.js → radio-group-CRuWQnuV.js} +2 -2
- package/dist/admin/assets/{radio-group-4ok5evXq.js.map → radio-group-CRuWQnuV.js.map} +1 -1
- package/dist/admin/assets/{rotate-ccw-DL6TzcZh.js → rotate-ccw-BP8Ba-mY.js} +2 -2
- package/dist/admin/assets/{rotate-ccw-DL6TzcZh.js.map → rotate-ccw-BP8Ba-mY.js.map} +1 -1
- package/dist/admin/assets/schedules-BIyBlsYZ.js +2 -0
- package/dist/admin/assets/{schedules-BmB9Y73z.js.map → schedules-BIyBlsYZ.js.map} +1 -1
- package/dist/admin/assets/schema-6eUoC8fJ.js +2 -0
- package/dist/admin/assets/schema-6eUoC8fJ.js.map +1 -0
- package/dist/admin/assets/{scroll-text-PqeZm472.js → scroll-text-B5vfi9fD.js} +2 -2
- package/dist/admin/assets/{scroll-text-PqeZm472.js.map → scroll-text-B5vfi9fD.js.map} +1 -1
- package/dist/admin/assets/{search-BdwIwOzC.js → search-wj7zbkx1.js} +2 -2
- package/dist/admin/assets/{search-BdwIwOzC.js.map → search-wj7zbkx1.js.map} +1 -1
- package/dist/admin/assets/{searchSchemas-CSScloG8.js → searchSchemas-DAnwh3I3.js} +2 -2
- package/dist/admin/assets/{searchSchemas-CSScloG8.js.map → searchSchemas-DAnwh3I3.js.map} +1 -1
- package/dist/admin/assets/{sections-DqBzSKMP.js → sections-CWL-XD6m.js} +2 -2
- package/dist/admin/assets/sections-CWL-XD6m.js.map +1 -0
- package/dist/admin/assets/{sections-BTS683ur.js → sections-DBQpB0uv.js} +2 -2
- package/dist/admin/assets/{sections-BTS683ur.js.map → sections-DBQpB0uv.js.map} +1 -1
- package/dist/admin/assets/{select-C0USI-Ox.js → select-DVrPV1b3.js} +2 -2
- package/dist/admin/assets/{select-C0USI-Ox.js.map → select-DVrPV1b3.js.map} +1 -1
- package/dist/admin/assets/{send-XPWo3m4u.js → send-CzFdgUc_.js} +2 -2
- package/dist/admin/assets/{send-XPWo3m4u.js.map → send-CzFdgUc_.js.map} +1 -1
- package/dist/admin/assets/seo-Bd0sWQMo.js +2 -0
- package/dist/admin/assets/{seo-CceGYTIX.js.map → seo-Bd0sWQMo.js.map} +1 -1
- package/dist/admin/assets/settings-CqnrPmzR.js +2 -0
- package/dist/admin/assets/{settings-B60vHpZd.js.map → settings-CqnrPmzR.js.map} +1 -1
- package/dist/admin/assets/shapes-ZAkMBB-Z.js +6 -0
- package/dist/admin/assets/shapes-ZAkMBB-Z.js.map +1 -0
- package/dist/admin/assets/{skeleton-B5MP72Kw.js → skeleton-CiX26LnL.js} +2 -2
- package/dist/admin/assets/{skeleton-B5MP72Kw.js.map → skeleton-CiX26LnL.js.map} +1 -1
- package/dist/admin/assets/{snapshots-DUI2t-qF.js → snapshots-DbFQNJgN.js} +2 -2
- package/dist/admin/assets/{snapshots-DUI2t-qF.js.map → snapshots-DbFQNJgN.js.map} +1 -1
- package/dist/admin/assets/{sparkles-CvT-jxrW.js → sparkles-D_kmZJVd.js} +2 -2
- package/dist/admin/assets/{sparkles-CvT-jxrW.js.map → sparkles-D_kmZJVd.js.map} +1 -1
- package/dist/admin/assets/src-CMor9izq.js +7 -0
- package/dist/admin/assets/src-CMor9izq.js.map +1 -0
- package/dist/admin/assets/{stableId-BrtQedPy.js → stableId-g1uxJGSz.js} +2 -2
- package/dist/admin/assets/{stableId-BrtQedPy.js.map → stableId-g1uxJGSz.js.map} +1 -1
- package/dist/admin/assets/{store-CdIFG90N.js → store-CznhNKEi.js} +2 -2
- package/dist/admin/assets/{store-CdIFG90N.js.map → store-CznhNKEi.js.map} +1 -1
- package/dist/admin/assets/{switch-Dp6WYNam.js → switch-CiVf05NF.js} +2 -2
- package/dist/admin/assets/{switch-Dp6WYNam.js.map → switch-CiVf05NF.js.map} +1 -1
- package/dist/admin/assets/{theme-65PB8uAu.js → theme-Cv-MfOv8.js} +2 -2
- package/dist/admin/assets/theme-Cv-MfOv8.js.map +1 -0
- package/dist/admin/assets/titles-DrQhW8z3.js +2 -0
- package/dist/admin/assets/titles-DrQhW8z3.js.map +1 -0
- package/dist/admin/assets/tokens-B1S81Epe.js +2 -0
- package/dist/admin/assets/{tokens-ixHjAkDK.js.map → tokens-B1S81Epe.js.map} +1 -1
- package/dist/admin/assets/{tooltip-BGP1DVBt.js → tooltip-Bqf3oyqC.js} +2 -2
- package/dist/admin/assets/{tooltip-BGP1DVBt.js.map → tooltip-Bqf3oyqC.js.map} +1 -1
- package/dist/admin/assets/{undo-2-BiTANHFz.js → undo-2-DpwwRQTf.js} +2 -2
- package/dist/admin/assets/{undo-2-BiTANHFz.js.map → undo-2-DpwwRQTf.js.map} +1 -1
- package/dist/admin/assets/useContentSchema-B_q1rMrG.js +2 -0
- package/dist/admin/assets/useContentSchema-B_q1rMrG.js.map +1 -0
- package/dist/admin/assets/useCursorPager-BHYqHb3M.js +2 -0
- package/dist/admin/assets/{useCursorPager-0zHjlm-7.js.map → useCursorPager-BHYqHb3M.js.map} +1 -1
- package/dist/admin/assets/{useDiscardGuard-BskWSlbT.js → useDiscardGuard-C4QTfiU4.js} +2 -2
- package/dist/admin/assets/{useDiscardGuard-BskWSlbT.js.map → useDiscardGuard-C4QTfiU4.js.map} +1 -1
- package/dist/admin/assets/{useMediaPickerDialog-CU-ekPqX.js → useMediaPickerDialog-BLrVV1Kn.js} +2 -2
- package/dist/admin/assets/{useMediaPickerDialog-CU-ekPqX.js.map → useMediaPickerDialog-BLrVV1Kn.js.map} +1 -1
- package/dist/admin/assets/{useMediaUploader-CBcq1ICg.js → useMediaUploader-CFy6lasO.js} +2 -2
- package/dist/admin/assets/useMediaUploader-CFy6lasO.js.map +1 -0
- package/dist/admin/assets/useModelIndex-NU-WlHQY.js +2 -0
- package/dist/admin/assets/useModelIndex-NU-WlHQY.js.map +1 -0
- package/dist/admin/assets/useNetworkPermission-DehDln-U.js +2 -0
- package/dist/admin/assets/{useNetworkPermission-Cts98h9d.js.map → useNetworkPermission-DehDln-U.js.map} +1 -1
- package/dist/admin/assets/{usePaletteItems-DtReWmkd.js → usePaletteItems-CFpNlSOs.js} +2 -2
- package/dist/admin/assets/{usePaletteItems-DtReWmkd.js.map → usePaletteItems-CFpNlSOs.js.map} +1 -1
- package/dist/admin/assets/usePlaces-BA4x6503.js +2 -0
- package/dist/admin/assets/usePlaces-BA4x6503.js.map +1 -0
- package/dist/admin/assets/useResolvedDefinitions-30lnwFQ1.js +2 -0
- package/dist/admin/assets/useResolvedDefinitions-30lnwFQ1.js.map +1 -0
- package/dist/admin/assets/{useResolvedScheme-C8vcQVko.js → useResolvedScheme-BVM4qLct.js} +2 -2
- package/dist/admin/assets/{useResolvedScheme-C8vcQVko.js.map → useResolvedScheme-BVM4qLct.js.map} +1 -1
- package/dist/admin/assets/useSaveShortcut-DQuNL1uJ.js +2 -0
- package/dist/admin/assets/useSaveShortcut-DQuNL1uJ.js.map +1 -0
- package/dist/admin/assets/{useSchemaScopeAccess-ByrxIdKM.js → useSchemaScopeAccess-JXOMx51q.js} +2 -2
- package/dist/admin/assets/{useSchemaScopeAccess-ByrxIdKM.js.map → useSchemaScopeAccess-JXOMx51q.js.map} +1 -1
- package/dist/admin/assets/users-38jLQ7zr.js +2 -0
- package/dist/admin/assets/users-38jLQ7zr.js.map +1 -0
- package/dist/admin/assets/{users-DM7CXUBJ.js → users-DYwcVDqp.js} +2 -2
- package/dist/admin/assets/{users-DM7CXUBJ.js.map → users-DYwcVDqp.js.map} +1 -1
- package/dist/admin/assets/{zod-Cry7YvLY.js → zod-ZaQjjiAq.js} +2 -2
- package/dist/admin/assets/{zod-Cry7YvLY.js.map → zod-ZaQjjiAq.js.map} +1 -1
- package/dist/admin/index.html +60 -58
- package/dist/cli.js +1 -1
- package/dist/{cliMain-papyXJDd.js → cliMain-CTntiVc2.js} +107 -30
- package/dist/cliMain-CTntiVc2.js.map +1 -0
- package/dist/config.d.ts +2 -2
- package/dist/config.js +1 -1
- package/dist/{contentDisposition-DOL2Xt0l.js → contentDisposition-DzhPhncr.js} +2 -2
- package/dist/{contentDisposition-DOL2Xt0l.js.map → contentDisposition-DzhPhncr.js.map} +1 -1
- package/dist/index.d.ts +43 -6
- package/dist/index.js +2 -2
- package/dist/{public-COKbHR-N.d.ts → public-CMFaGDyf.d.ts} +50 -8
- package/dist/{public-B57h4F7Y.js → public-sJCQaNaP.js} +2 -2
- package/dist/public-sJCQaNaP.js.map +1 -0
- package/dist/{s3Adapter-U01iEAcK.js → s3Adapter-CZcCl0sy.js} +2 -2
- package/dist/{s3Adapter-U01iEAcK.js.map → s3Adapter-CZcCl0sy.js.map} +1 -1
- package/dist/{worker-B-sC-eY2.js → worker-DHm2JwMZ.js} +3140 -1292
- package/dist/worker-DHm2JwMZ.js.map +1 -0
- package/package.json +5 -5
- package/dist/admin/assets/AssistError-Cs-r9Ssc.js +0 -2
- package/dist/admin/assets/Body-BzZD-TZT.js +0 -2
- package/dist/admin/assets/Body-BzZD-TZT.js.map +0 -1
- package/dist/admin/assets/Builder-DW-GJA_q.js +0 -2
- package/dist/admin/assets/Builder-DW-GJA_q.js.map +0 -1
- package/dist/admin/assets/Form-lNrRHc0I.js +0 -2
- package/dist/admin/assets/Form-lNrRHc0I.js.map +0 -1
- package/dist/admin/assets/FormCheckboxGroup-DeeaYnzB.js +0 -2
- package/dist/admin/assets/FormCheckboxGroup-DeeaYnzB.js.map +0 -1
- package/dist/admin/assets/FormSelectField-BzE9Lq9i.js +0 -2
- package/dist/admin/assets/FormSelectField-BzE9Lq9i.js.map +0 -1
- package/dist/admin/assets/RadioTile-DQFmni5A.js.map +0 -1
- package/dist/admin/assets/RichTextField-CVHRIbnu.js.map +0 -1
- package/dist/admin/assets/StepList-BXGYD9eJ.js +0 -2
- package/dist/admin/assets/StepList-BXGYD9eJ.js.map +0 -1
- package/dist/admin/assets/Structure-D8csgrIt.js +0 -2
- package/dist/admin/assets/SubNavLink-CiCaVV8U.js.map +0 -1
- package/dist/admin/assets/auth-CQO4MBUj.js +0 -2
- package/dist/admin/assets/changeSets-8EburmT0.js +0 -2
- package/dist/admin/assets/chevron-left-DGU3HGYG.js +0 -2
- package/dist/admin/assets/content-CAjkbZEY.js +0 -3
- package/dist/admin/assets/content-CAjkbZEY.js.map +0 -1
- package/dist/admin/assets/createLucideIcon-CLmh7Go-.js +0 -2
- package/dist/admin/assets/createLucideIcon-CLmh7Go-.js.map +0 -1
- package/dist/admin/assets/develop-BOqvnlgt.js +0 -11
- package/dist/admin/assets/develop-BOqvnlgt.js.map +0 -1
- package/dist/admin/assets/es2015-BHmI7wjK.js +0 -42
- package/dist/admin/assets/es2015-BHmI7wjK.js.map +0 -1
- package/dist/admin/assets/followPlural-Cm7v_Udv.js +0 -2
- package/dist/admin/assets/followPlural-Cm7v_Udv.js.map +0 -1
- package/dist/admin/assets/inbox-DGO2D8fa.js +0 -2
- package/dist/admin/assets/inbox-DGO2D8fa.js.map +0 -1
- package/dist/admin/assets/index-BIIU9ZI6.js +0 -4
- package/dist/admin/assets/index-BIIU9ZI6.js.map +0 -1
- package/dist/admin/assets/index-lxe7WimO.css +0 -2
- package/dist/admin/assets/locales-Bg3htKo8.js +0 -2
- package/dist/admin/assets/media-BCnVhaDH.js +0 -2
- package/dist/admin/assets/network-BixABr0o.js +0 -2
- package/dist/admin/assets/network-BixABr0o.js.map +0 -1
- package/dist/admin/assets/publishing-Dke9bSKp.js +0 -2
- package/dist/admin/assets/publishing-Dke9bSKp.js.map +0 -1
- package/dist/admin/assets/schedules-BmB9Y73z.js +0 -2
- package/dist/admin/assets/schema-D-qo7XSF.js +0 -2
- package/dist/admin/assets/schema-D-qo7XSF.js.map +0 -1
- package/dist/admin/assets/sections-DqBzSKMP.js.map +0 -1
- package/dist/admin/assets/seo-CceGYTIX.js +0 -2
- package/dist/admin/assets/settings-B60vHpZd.js +0 -2
- package/dist/admin/assets/shapes-B5twqZcp.js +0 -6
- package/dist/admin/assets/shapes-B5twqZcp.js.map +0 -1
- package/dist/admin/assets/src-ndgTSYLX.js +0 -7
- package/dist/admin/assets/src-ndgTSYLX.js.map +0 -1
- package/dist/admin/assets/theme-65PB8uAu.js.map +0 -1
- package/dist/admin/assets/titles-CQiqqDw-.js +0 -2
- package/dist/admin/assets/titles-CQiqqDw-.js.map +0 -1
- package/dist/admin/assets/tokens-ixHjAkDK.js +0 -2
- package/dist/admin/assets/useContentSchema-DtYfhsd2.js +0 -2
- package/dist/admin/assets/useContentSchema-DtYfhsd2.js.map +0 -1
- package/dist/admin/assets/useCursorPager-0zHjlm-7.js +0 -2
- package/dist/admin/assets/useMediaUploader-CBcq1ICg.js.map +0 -1
- package/dist/admin/assets/useNetworkPermission-Cts98h9d.js +0 -2
- package/dist/admin/assets/usePlaces-DC47wVeU.js +0 -2
- package/dist/admin/assets/usePlaces-DC47wVeU.js.map +0 -1
- package/dist/admin/assets/useQueries-CirW3Mvp.js +0 -2
- package/dist/admin/assets/useQueries-CirW3Mvp.js.map +0 -1
- package/dist/admin/assets/useSaveShortcut-rKtp1qK7.js +0 -2
- package/dist/admin/assets/useSaveShortcut-rKtp1qK7.js.map +0 -1
- package/dist/admin/assets/users-2iJYwlJb.js +0 -2
- package/dist/admin/assets/users-2iJYwlJb.js.map +0 -1
- package/dist/cliMain-papyXJDd.js.map +0 -1
- package/dist/public-B57h4F7Y.js.map +0 -1
- package/dist/worker-B-sC-eY2.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media-CURizGns.js","names":["__iconData","__iconData","z.object","z.string","z.number","zodResolver","i18next","useState","i18next","_Fragment","Trash2","_Fragment","useState","_Fragment","AlertTriangle","useState","useRef","z.object","zodResolver","i18next","useId","Loader2","useRef","MoreHorizontal","_Fragment","Trash2","useMemo","useState","useCallback","useState","i18next","useState","i18next","Loader2","useId","useState","useMemo","_Fragment","__toESM","require_jsx_runtime","LoaderCircle","useMoveMediaAssets","useMediaAsset","useUpdateMediaAsset","useDeleteMediaAsset","useMediaFolders","useDeleteMediaFolder","useMediaUsage","useCreateMediaFolder","useUpdateMediaFolder","useNavigate","Link","hasErrorCode","Lock","X","SubmitButton","Page","Sheet","SheetDescription","SheetFooter","PageHeader","TriangleAlert","SheetBody","SheetTitle","StatusChip","SheetHeader","ErrorState","Badge","SheetContent","LoadingState","ShapioApiError","useTranslation","createLucideIcon","useSearch","RowTitle","createLazyRoute","toast","PopoverTrigger","PopoverContent","Popover","instance","describeError","Check","Button","Input","Skeleton","FormError","Alert","ConfirmDialog","AlertDescription","InlineConfirm","ExternalLink","Trash","FieldGroup","FieldContent","FieldLabel","FieldDescription","Field","FocalPoint","Ellipsis","Variants","useMediaPermissions","FileIcon","Pencil","fileKindLabel","MEDIA_STATUS_DISPLAY","isImage","formatBytes","FolderPlus","Globe","Library","Images","Toolbar","UploadQueue","Upload","UploadButton","useMediaUploader","Inbox","DropdownMenuItem","DropdownMenuSeparator","DropdownMenuTrigger","DropdownMenuContent","DropdownMenu","cn","Switch","useController","FormTextField","requiredText","FormFieldError","u","useForm","settle","object","number","string","useDiscardGuard","ROOT_FOLDER","MIME_FILTER_BY_TYPE","SuggestAltButton","Panel","useContentSchema","CopyButton","FormTextareaField","entryLink","__iconData$2","FolderInput","__iconData$1","FolderOpen","__iconData","Folder","import_react","require_react","detailsSchema","valuesFor","asset","changesFrom","values","useAssetDetailsForm","update","form","reset","result","usageCountOf","details","error","useDeleteAssetFlow","remove","blocked","setBlocked","forceOpen","setForceOpen","forceUsageCount","setForceUsageCount","deleted","target","onDeleted","usageCount","isOwner","import_jsx_runtime","DeleteAction","deletion","t","MetadataForm","focal","image","event","onSubmit","readOnly","alt","value","previewImageUrl","variant","Preview","Section","title","children","Row","model","usage","Usage","assetId","item","schema","Visibility","confirming","setConfirming","isPrivate","next","consequence","canManage","Details","query","open","onClose","status","requestOpenChange","canWrite","file","onReplace","discardPrompt","hasFiles","Dropzone","dragging","setDragging","depth","enabled","className","files","onFiles","buildFolderTree","byParent","folders","folder","candidate","build","parentId","a","b","flattenFolderTree","nodes","node","folderSchema","useFolderForm","createFolder","updateFolder","initialName","edit","trimmed","name","onDone","mutation","EditRow","errorId","setFocus","message","creating","pending","FOLDER_ROW_CLASSES","Menu","handingOff","handOff","action","actions","Item","current","currentId","Icon","renameEdit","editing","childEdit","onEditDone","onSelect","child","ScopeButton","icon","label","FolderTree","tree","topLevelEdit","useAssetSelection","selected","setSelected","checked","id","openerOf","selector","useFolderActions","setEditing","deletingId","setDeletingId","deleteFolder","returnFocus","useMediaSearch","search","navigate","previous","changes","moveFocusWithArrows","buttons","index","button","last","useMoveToFolder","move","setTarget","folderId","assetIds","onMoved","Choice","MovePopover","titleId","setOpen","choices","SelectionBar","onClear","mediaLazyRoute","uploader","selection","folderActions","setSearch","uploadFolder","upload","assetQuery"],"sources":["../../../../node_modules/.pnpm/lucide-react@1.49.0_@types+react@19.3.0_react@19.3.0/node_modules/lucide-react/dist/esm/icons/folder-input.mjs","../../../../node_modules/.pnpm/lucide-react@1.49.0_@types+react@19.3.0_react@19.3.0/node_modules/lucide-react/dist/esm/icons/folder-open.mjs","../../../../node_modules/.pnpm/lucide-react@1.49.0_@types+react@19.3.0_react@19.3.0/node_modules/lucide-react/dist/esm/icons/folder.mjs","../../src/features/Media/hooks/useAssetDetailsForm.ts","../../src/features/Media/hooks/useDeleteAssetFlow.ts","../../src/features/Media/Details/DeleteAction/index.tsx","../../src/features/Media/Details/MetadataForm/index.tsx","../../src/features/Media/Details/Preview/index.tsx","../../src/features/Media/Details/Section/index.tsx","../../src/features/Media/Details/Usage/Row/index.tsx","../../src/features/Media/Details/Usage/index.tsx","../../src/features/Media/Details/Visibility/index.tsx","../../src/features/Media/Details/index.tsx","../../src/features/Media/Dropzone/index.tsx","../../src/features/Media/helpers/folderTree.ts","../../src/features/Media/hooks/useFolderForm.ts","../../src/features/Media/FolderTree/EditRow/index.tsx","../../src/features/Media/FolderTree/constants.ts","../../src/features/Media/FolderTree/Menu/index.tsx","../../src/features/Media/FolderTree/Item/index.tsx","../../src/features/Media/FolderTree/ScopeButton/index.tsx","../../src/features/Media/FolderTree/index.tsx","../../src/features/Media/hooks/useAssetSelection.ts","../../src/features/Media/hooks/useFolderActions.ts","../../src/features/Media/hooks/useMediaSearch.ts","../../src/features/Media/helpers/arrowFocus.ts","../../src/features/Media/hooks/useMoveToFolder.ts","../../src/features/Media/MovePopover/Choice/index.tsx","../../src/features/Media/MovePopover/index.tsx","../../src/features/Media/SelectionBar/index.tsx","../../src/features/Media/index.tsx","../../src/app/lazyRoutes/media.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.49.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"folder-input\",\n size: 24,\n node: [\n [\n \"path\",\n {\n d: \"M2 9V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H20a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-1\",\n key: \"fm4g5t\"\n }\n ],\n [\"path\", { d: \"M2 13h10\", key: \"pgb2dq\" }],\n [\"path\", { d: \"m9 16 3-3-3-3\", key: \"6m91ic\" }]\n ]\n};\n__iconData.node;\nconst FolderInput = createLucideIcon(__iconData);\n\nexport { __iconData, FolderInput as default };\n//# sourceMappingURL=folder-input.mjs.map\n","/**\n * @license lucide-react v1.49.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"folder-open\",\n size: 24,\n node: [\n [\n \"path\",\n {\n d: \"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2\",\n key: \"usdka0\"\n }\n ]\n ]\n};\n__iconData.node;\nconst FolderOpen = createLucideIcon(__iconData);\n\nexport { __iconData, FolderOpen as default };\n//# sourceMappingURL=folder-open.mjs.map\n","/**\n * @license lucide-react v1.49.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"folder\",\n size: 24,\n node: [\n [\n \"path\",\n {\n d: \"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\",\n key: \"1kt360\"\n }\n ]\n ]\n};\n__iconData.node;\nconst Folder = createLucideIcon(__iconData);\n\nexport { __iconData, Folder as default };\n//# sourceMappingURL=folder.mjs.map\n","import { zodResolver } from '@hookform/resolvers/zod';\nimport type { MediaAsset, UpdateMediaAssetInput } from '@shapio/client';\nimport { useEffect } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { toast } from 'sonner';\nimport { z } from 'zod';\nimport { useUpdateMediaAsset } from '@/api/media';\nimport { i18next } from '@/app/i18n';\nimport { settle } from '@/helpers/settle';\nimport { requiredText } from '@/helpers/validation';\n\nconst MAX_FILENAME = 255;\nconst MAX_ALT = 1000;\nconst MAX_CAPTION = 4000;\n\nconst detailsSchema = z.object({\n filename: requiredText().max(MAX_FILENAME, 'validation.tooLong'),\n alt: z.string().max(MAX_ALT, 'validation.tooLong'),\n caption: z.string().max(MAX_CAPTION, 'validation.tooLong'),\n focalPoint: z.object({ x: z.number().min(0).max(1), y: z.number().min(0).max(1) }).nullable(),\n});\n\nexport type AssetDetailsValues = z.infer<typeof detailsSchema>;\n\nconst valuesFor = (asset: MediaAsset | undefined): AssetDetailsValues => ({\n filename: asset?.filename ?? '',\n alt: asset?.alt ?? '',\n caption: asset?.caption ?? '',\n focalPoint: asset?.focalPoint ?? null,\n});\n\n/** Only what changed is sent, with the version the editor saw (409 VERSION_CONFLICT if it moved). */\nconst changesFrom = (asset: MediaAsset, values: AssetDetailsValues): UpdateMediaAssetInput => ({\n expectedVersion: asset.version,\n ...(values.filename !== asset.filename ? { filename: values.filename.trim() } : {}),\n ...(values.alt !== asset.alt ? { alt: values.alt } : {}),\n ...(values.caption !== asset.caption ? { caption: values.caption } : {}),\n ...(JSON.stringify(values.focalPoint) !== JSON.stringify(asset.focalPoint)\n ? { focalPoint: values.focalPoint }\n : {}),\n});\n\n/** File name, alt text, caption and focal point of one asset. */\nexport const useAssetDetailsForm = (asset: MediaAsset | undefined) => {\n const update = useUpdateMediaAsset();\n const form = useForm<AssetDetailsValues>({\n resolver: zodResolver(detailsSchema),\n defaultValues: valuesFor(asset),\n });\n const { reset } = form;\n // A different asset (or a fresh load of this one) starts from what the server has.\n useEffect(() => {\n reset(valuesFor(asset));\n update.reset();\n // The mutation object changes identity on every render.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [asset?.id, reset]);\n const onSubmit = form.handleSubmit(async (values) => {\n if (!asset) {\n return;\n }\n const result = await settle(update.mutateAsync({ id: asset.id, input: changesFrom(asset, values) }));\n if (result.ok) {\n reset(valuesFor(result.value));\n toast.success(i18next.t('media.details.saved'));\n }\n });\n return { form, onSubmit, pending: update.isPending, error: update.error };\n};\n","import { ShapioApiError, type MediaAsset } from '@shapio/client';\nimport { useState } from 'react';\nimport { toast } from 'sonner';\nimport { hasErrorCode } from '@/api/errors';\nimport { useDeleteMediaAsset } from '@/api/media';\nimport { i18next } from '@/app/i18n';\n\nconst usageCountOf = (error: unknown): number => {\n const details =\n error instanceof ShapioApiError ? (error.details as { usageCount?: unknown } | undefined) : undefined;\n return typeof details?.usageCount === 'number' ? details.usageCount : 0;\n};\n\n/**\n * Delete, with the server's protection surfaced: a referenced asset answers 409 MEDIA_IN_USE. For an owner\n * the inline confirmation then hands over to a blocking \"Delete anyway\" dialog (which sends `force`); for\n * anyone else the inline confirmation stays open and explains why it can't be deleted.\n */\nexport const useDeleteAssetFlow = (\n asset: MediaAsset | undefined,\n isOwner: boolean,\n onDeleted: () => void,\n) => {\n const remove = useDeleteMediaAsset();\n const [blocked, setBlocked] = useState<{ assetId: string; usageCount: number } | undefined>(undefined);\n const [forceOpen, setForceOpen] = useState(false);\n // Kept while the dialog animates out, so its text doesn't change.\n const [forceUsageCount, setForceUsageCount] = useState(0);\n const deleted = (target: MediaAsset) => {\n toast.success(i18next.t('media.delete.done', { name: target.filename }));\n onDeleted();\n };\n return {\n /** Set once a non-owner's delete was refused because content uses the file. */\n blockedUsageCount: blocked && blocked.assetId === asset?.id ? blocked.usageCount : undefined,\n /** The inline confirmation's action: rejects (and the popover shows why) unless it was handed over. */\n confirm: async () => {\n if (!asset) {\n return;\n }\n try {\n await remove.mutateAsync({ id: asset.id, force: false });\n } catch (error) {\n if (!hasErrorCode(error, 'MEDIA_IN_USE')) {\n throw error;\n }\n const usageCount = usageCountOf(error);\n if (!isOwner) {\n setBlocked({ assetId: asset.id, usageCount });\n throw error;\n }\n remove.reset();\n setForceUsageCount(usageCount);\n setForceOpen(true);\n return;\n }\n deleted(asset);\n },\n force: {\n open: forceOpen,\n usageCount: forceUsageCount,\n pending: remove.isPending,\n error: remove.error,\n onOpenChange: setForceOpen,\n confirm: () => {\n if (asset) {\n remove.mutate(\n { id: asset.id, force: true },\n {\n onSuccess: () => {\n setForceOpen(false);\n deleted(asset);\n },\n },\n );\n }\n },\n },\n };\n};\n","import type { MediaAsset } from '@shapio/client';\nimport { Trash2 } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { ConfirmDialog } from '@/components/ConfirmDialog';\nimport { InlineConfirm } from '@/components/InlineConfirm';\nimport { Button } from '@/components/ui/button';\nimport { useMediaPermissions } from '@/hooks/useMediaPermissions';\nimport { useDeleteAssetFlow } from '../../hooks/useDeleteAssetFlow';\n\ntype DeleteActionProps = { asset: MediaAsset; onDeleted: () => void };\n\n/**\n * \"Delete file\", confirmed inline. If content still uses the file, the confirmation says so; only an owner\n * can then delete it anyway, through a blocking dialog (it leaves that content pointing at a missing file).\n */\nexport const DeleteAction = ({ asset, onDeleted }: DeleteActionProps) => {\n const { t } = useTranslation();\n const { isOwner } = useMediaPermissions();\n const deletion = useDeleteAssetFlow(asset, isOwner, onDeleted);\n const blocked = deletion.blockedUsageCount;\n return (\n <>\n <InlineConfirm\n tone=\"danger\"\n align=\"start\"\n side=\"top\"\n title={t('media.delete.title', { name: asset.filename })}\n description={\n blocked === undefined\n ? t('media.delete.description')\n : `${t('media.delete.inUseDescription', { count: blocked })} ${t('media.delete.onlyOwners')}`\n }\n confirmLabel={t('common.delete')}\n onConfirm={deletion.confirm}\n trigger={\n <Button variant=\"destructive-ghost\">\n <Trash2 aria-hidden=\"true\" />\n {t('media.delete.action')}\n </Button>\n }\n />\n <ConfirmDialog\n open={deletion.force.open}\n onOpenChange={deletion.force.onOpenChange}\n title={t('media.delete.inUseTitle')}\n description={`${t('media.delete.inUseDescription', { count: deletion.force.usageCount })} ${t(\n 'media.delete.ownerMayForce',\n )}`}\n confirmLabel={t('media.delete.force')}\n destructive\n pending={deletion.force.pending}\n error={deletion.force.error}\n onConfirm={deletion.force.confirm}\n />\n </>\n );\n};\n","import type { MediaAsset } from '@shapio/client';\nimport { useController, type UseFormReturn } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport { FocalPoint } from '@/components/FocalPoint';\nimport { FormError } from '@/components/FormError';\nimport { FormTextareaField } from '@/components/FormTextareaField';\nimport { FormTextField } from '@/components/FormTextField';\nimport { SubmitButton } from '@/components/SubmitButton';\nimport { SuggestAltButton } from '@/components/SuggestAltButton';\nimport { FieldGroup } from '@/components/ui/field';\nimport { isImage } from '../../helpers/fileKind';\nimport type { AssetDetailsValues } from '../../hooks/useAssetDetailsForm';\n\ntype MetadataFormProps = {\n asset: MediaAsset;\n form: UseFormReturn<AssetDetailsValues>;\n onSubmit: () => void;\n pending: boolean;\n error: unknown;\n readOnly: boolean;\n};\n\n/** File name, alt text, caption and (images) focal point; saved together. */\nexport const MetadataForm = ({ asset, form, onSubmit, pending, error, readOnly }: MetadataFormProps) => {\n const { t } = useTranslation();\n const focal = useController({ control: form.control, name: 'focalPoint' });\n const image = isImage(asset.mimeType);\n return (\n <form\n noValidate\n aria-label={t('media.details.formLabel')}\n onSubmit={(event) => {\n event.preventDefault();\n onSubmit();\n }}\n >\n <fieldset disabled={readOnly} className=\"contents\">\n <FieldGroup>\n <FormTextField\n control={form.control}\n name=\"filename\"\n label={t('media.fields.filename')}\n autoComplete=\"off\"\n />\n {image ? (\n <FormTextareaField\n control={form.control}\n name=\"alt\"\n label={t('media.fields.alt')}\n rows={2}\n placeholder={t('media.details.altHint')}\n />\n ) : null}\n {image && !readOnly ? (\n <SuggestAltButton\n assetId={asset.id}\n mimeType={asset.mimeType}\n onSuggest={(alt) => form.setValue('alt', alt, { shouldDirty: true, shouldValidate: true })}\n />\n ) : null}\n <FormTextareaField\n control={form.control}\n name=\"caption\"\n label={t('media.fields.caption')}\n rows={2}\n />\n {image && !readOnly ? (\n <FocalPoint\n imageUrl={asset.url}\n value={focal.field.value}\n onChange={(value) => focal.field.onChange(value)}\n />\n ) : null}\n <FormError error={error} />\n {readOnly ? null : (\n <div className=\"flex justify-end\">\n <SubmitButton\n pending={pending}\n pendingLabel={t('common.saving')}\n disabled={!form.formState.isDirty}\n >\n {t('common.saveChanges')}\n </SubmitButton>\n </div>\n )}\n </FieldGroup>\n </fieldset>\n </form>\n );\n};\n","import type { MediaAsset } from '@shapio/client';\nimport { ExternalLink } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { Button } from '@/components/ui/button';\nimport { FileIcon } from '../../FileIcon';\nimport { isImage } from '../../helpers/fileKind';\n\ntype PreviewProps = { asset: MediaAsset };\n\n/** The widest ready variant up to 1280 px, else the original. */\nconst previewImageUrl = (asset: MediaAsset): string =>\n asset.variants.find((variant) => variant.name === 'w1280' && variant.url)?.url ??\n asset.variants.find((variant) => variant.name === 'w640' && variant.url)?.url ??\n asset.url;\n\n/** Images, video and audio play inline; other files show their type and an Open link. */\nexport const Preview = ({ asset }: PreviewProps) => {\n const { t } = useTranslation();\n if (isImage(asset.mimeType)) {\n return (\n <img\n src={previewImageUrl(asset)}\n alt={asset.alt || t('media.details.previewOf', { name: asset.filename })}\n className=\"max-h-72 w-full rounded-lg border bg-muted object-contain\"\n />\n );\n }\n if (asset.mimeType.startsWith('video/')) {\n return (\n <video\n src={asset.url}\n controls\n preload=\"metadata\"\n className=\"max-h-72 w-full rounded-lg border bg-muted\"\n />\n );\n }\n if (asset.mimeType.startsWith('audio/')) {\n return <audio src={asset.url} controls preload=\"metadata\" className=\"w-full\" />;\n }\n return (\n <div className=\"flex flex-col items-center gap-3 rounded-lg border bg-muted px-4 py-8\">\n <FileIcon mimeType={asset.mimeType} className=\"size-10 text-muted-foreground\" />\n <Button asChild variant=\"outline\" size=\"sm\">\n <a href={asset.url} target=\"_blank\" rel=\"noopener noreferrer\">\n <ExternalLink aria-hidden=\"true\" />\n {t('media.details.openFile')}\n </a>\n </Button>\n </div>\n );\n};\n","import type { ReactNode } from 'react';\n\ntype SectionProps = { title: string; children: ReactNode };\n\n/** A titled block of the details sheet. */\nexport const Section = ({ title, children }: SectionProps) => (\n <section className=\"space-y-3\">\n <h3 className=\"text-sm font-semibold\">{title}</h3>\n {children}\n </section>\n);\n","import type { MediaUsage } from '@shapio/client';\nimport type { ModelDefinition } from '@shapio/schema';\nimport { Link } from '@tanstack/react-router';\nimport { useTranslation } from 'react-i18next';\nimport { RowTitle } from '@/components/RowTitle';\nimport { StatusChip } from '@/components/StatusChip';\nimport { Badge } from '@/components/ui/badge';\nimport { entryLink } from '@/features/Inbox/helpers/entryLink';\n\ntype RowProps = {\n usage: MediaUsage;\n /** The entry's model, when the admin may read it; without it the entry is named but not linked. */\n model: ModelDefinition | undefined;\n};\n\n/** One entry version using the asset: its title linking to the entry in that locale, the type, locale and state. */\nexport const Row = ({ usage, model }: RowProps) => {\n const { t } = useTranslation();\n return (\n <li className=\"flex min-w-0 items-center gap-2 px-3 py-2\">\n <div className=\"min-w-0 flex-1 space-y-0.5\">\n {model ? (\n <>\n <RowTitle asChild className=\"block truncate text-sm\">\n <Link {...entryLink(model.apiKey, usage.entryId, model.kind, { locale: usage.locale })}>\n {usage.title ?? t('content.untitled')}\n </Link>\n </RowTitle>\n <p className=\"truncate text-meta text-muted-foreground\">{model.label}</p>\n </>\n ) : (\n <p className=\"truncate text-sm text-muted-foreground\">{t('media.usage.hidden')}</p>\n )}\n </div>\n <Badge variant=\"outline\" className=\"font-mono\">\n {usage.locale}\n </Badge>\n <StatusChip\n size=\"sm\"\n tone={usage.state === 'published' ? 'success' : 'neutral'}\n label={usage.state === 'published' ? t('media.usage.published') : t('media.usage.draft')}\n />\n </li>\n );\n};\n","import { useTranslation } from 'react-i18next';\nimport { useMediaUsage } from '@/api/media';\nimport { ErrorState } from '@/components/ErrorState';\nimport { Skeleton } from '@/components/ui/skeleton';\nimport { useContentSchema } from '@/features/Content/hooks/useContentSchema';\nimport { Row } from './Row';\n\ntype UsageProps = { assetId: string };\n\n/** \"Used in\": the entries whose draft or published version references the asset, by title and type. */\nexport const Usage = ({ assetId }: UsageProps) => {\n const { t } = useTranslation();\n const usage = useMediaUsage(assetId);\n const { schema } = useContentSchema();\n if (usage.isPending) {\n return <Skeleton className=\"h-8 w-full\" />;\n }\n if (usage.isError) {\n return <ErrorState error={usage.error} onRetry={() => void usage.refetch()} />;\n }\n if (usage.data.total === 0) {\n return <p className=\"text-sm text-muted-foreground\">{t('media.usage.none')}</p>;\n }\n return (\n <div className=\"space-y-2\">\n <p className=\"text-sm\">{t('media.usage.count', { count: usage.data.total })}</p>\n <ul className=\"divide-y rounded-lg border\">\n {usage.data.items.map((item) => (\n <Row\n key={`${item.entryId}:${item.fieldId}:${item.locale}:${item.state}`}\n usage={item}\n model={schema?.models.get(item.modelId)}\n />\n ))}\n </ul>\n </div>\n );\n};\n","import type { MediaAsset } from '@shapio/client';\nimport { Globe, Lock } from 'lucide-react';\nimport { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { toast } from 'sonner';\nimport { useUpdateMediaAsset } from '@/api/media';\nimport { InlineConfirm } from '@/components/InlineConfirm';\nimport { Field, FieldContent, FieldDescription, FieldLabel } from '@/components/ui/field';\nimport { Switch } from '@/components/ui/switch';\n\ntype VisibilityProps = { asset: MediaAsset; canManage: boolean };\n\n/**\n * Public files have a stable URL anyone can open; private files only open through signed links that\n * expire. One line says what the current setting means. Changing it needs `media.manage` and is confirmed\n * beside the switch, because it changes who can see the file.\n */\nexport const Visibility = ({ asset, canManage }: VisibilityProps) => {\n const { t } = useTranslation();\n const update = useUpdateMediaAsset();\n const [confirming, setConfirming] = useState(false);\n const isPrivate = asset.visibility === 'private';\n const next = isPrivate ? 'public' : 'private';\n const consequence = isPrivate\n ? t('media.visibility.privateExplanation')\n : t('media.visibility.publicExplanation');\n return (\n <Field orientation=\"horizontal\">\n <FieldContent>\n <div className=\"flex items-center gap-1.5\">\n {isPrivate ? (\n <Lock aria-hidden=\"true\" className=\"size-4 text-muted-foreground\" />\n ) : (\n <Globe aria-hidden=\"true\" className=\"size-4 text-muted-foreground\" />\n )}\n <FieldLabel htmlFor=\"asset-private\">{t('media.visibility.privateLabel')}</FieldLabel>\n </div>\n <FieldDescription id=\"asset-private-description\">\n {canManage ? consequence : `${consequence} ${t('media.visibility.needsManage')}`}\n </FieldDescription>\n </FieldContent>\n <InlineConfirm\n tone={next === 'public' ? 'danger' : 'default'}\n open={confirming}\n onOpenChange={setConfirming}\n title={\n next === 'private' ? t('media.visibility.makePrivateTitle') : t('media.visibility.makePublicTitle')\n }\n description={\n next === 'private'\n ? t('media.visibility.makePrivateDescription')\n : t('media.visibility.makePublicDescription')\n }\n confirmLabel={\n next === 'private' ? t('media.visibility.makePrivate') : t('media.visibility.makePublic')\n }\n onConfirm={() =>\n update\n .mutateAsync({ id: asset.id, input: { expectedVersion: asset.version, visibility: next } })\n .then(() => toast.success(t('media.visibility.changed')))\n }\n >\n <Switch\n id=\"asset-private\"\n checked={isPrivate}\n disabled={!canManage || update.isPending}\n aria-describedby=\"asset-private-description\"\n onCheckedChange={() => setConfirming(true)}\n />\n </InlineConfirm>\n </Field>\n );\n};\n","import { AlertTriangle } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { useMediaAsset } from '@/api/media';\nimport { CopyButton } from '@/components/CopyButton';\nimport { ErrorState } from '@/components/ErrorState';\nimport { LoadingState } from '@/components/LoadingState';\nimport { StatusChip } from '@/components/StatusChip';\nimport { Alert, AlertDescription } from '@/components/ui/alert';\nimport {\n Sheet,\n SheetBody,\n SheetContent,\n SheetDescription,\n SheetFooter,\n SheetHeader,\n SheetTitle,\n} from '@/components/ui/sheet';\nimport { useDiscardGuard } from '@/hooks/useDiscardGuard';\nimport { useMediaPermissions } from '@/hooks/useMediaPermissions';\nimport { fileKindLabel } from '../helpers/fileKind';\nimport { formatBytes } from '../helpers/formatBytes';\nimport { MEDIA_STATUS_DISPLAY } from '../helpers/statusDisplay';\nimport { useAssetDetailsForm } from '../hooks/useAssetDetailsForm';\nimport { UploadButton } from '../UploadButton';\nimport { DeleteAction } from './DeleteAction';\nimport { MetadataForm } from './MetadataForm';\nimport { Preview } from './Preview';\nimport { Section } from './Section';\nimport { Usage } from './Usage';\nimport { Variants } from './Variants';\nimport { Visibility } from './Visibility';\n\ntype DetailsProps = {\n assetId: string | undefined;\n onClose: () => void;\n onReplace: (assetId: string, file: File) => void;\n};\n\n/** One asset: preview, metadata, focal point, visibility, variants, \"used in\", replace and delete. */\nexport const Details = ({ assetId, onClose, onReplace }: DetailsProps) => {\n const { t } = useTranslation();\n const query = useMediaAsset(assetId);\n const asset = query.data;\n const { canWrite, canManage } = useMediaPermissions();\n const details = useAssetDetailsForm(asset);\n const { requestOpenChange, discardPrompt } = useDiscardGuard({\n dirty: details.form.formState.isDirty,\n pending: details.pending,\n onOpenChange: (open) => {\n if (!open) {\n details.form.reset();\n onClose();\n }\n },\n });\n const status = asset ? MEDIA_STATUS_DISPLAY[asset.status] : undefined;\n return (\n <>\n <Sheet open={assetId !== undefined} onOpenChange={requestOpenChange}>\n <SheetContent size=\"sm\">\n <SheetHeader>\n <SheetTitle className=\"pr-8 break-all\">{asset?.filename ?? t('media.details.title')}</SheetTitle>\n <SheetDescription className=\"text-meta\">\n {asset\n ? [\n fileKindLabel(asset.filename, asset.mimeType),\n formatBytes(asset.sizeBytes),\n asset.width && asset.height\n ? t('media.dimensions', { width: asset.width, height: asset.height })\n : '',\n ]\n .filter(Boolean)\n .join(' · ')\n : t('common.loading')}\n </SheetDescription>\n {asset && status ? (\n // In the fixed header, not the scrolling body: the focus trap wraps here without scrolling.\n <div className=\"flex flex-wrap items-center gap-2 pt-1\">\n <StatusChip tone={status.tone} label={t(status.labelKey)} />\n {asset.visibility === 'private' ? (\n <StatusChip tone=\"muted\" label={t('media.visibility.private')} />\n ) : null}\n <span className=\"ml-auto\">\n <CopyButton value={asset.url} />\n </span>\n </div>\n ) : null}\n </SheetHeader>\n <SheetBody className=\"space-y-6\">\n {query.isPending ? <LoadingState rows={3} /> : null}\n {query.isError ? <ErrorState error={query.error} onRetry={() => void query.refetch()} /> : null}\n {asset && status ? (\n <>\n <div className=\"space-y-3\">\n <Preview asset={asset} />\n {asset.urlExpiresAt ? (\n <p className=\"text-meta text-muted-foreground\">{t('media.details.signedLinkNote')}</p>\n ) : null}\n {asset.processingError ? (\n <Alert variant=\"destructive\">\n <AlertTriangle aria-hidden=\"true\" />\n <AlertDescription>{asset.processingError}</AlertDescription>\n </Alert>\n ) : null}\n </div>\n <Section title={t('media.details.metadata')}>\n <MetadataForm\n asset={asset}\n form={details.form}\n onSubmit={() => void details.onSubmit()}\n pending={details.pending}\n error={details.error}\n readOnly={!canWrite}\n />\n </Section>\n <Section title={t('media.usage.title')}>\n <Usage assetId={asset.id} />\n </Section>\n <Section title={t('media.visibility.title')}>\n <Visibility asset={asset} canManage={canManage} />\n </Section>\n <Section title={t('media.variants.title')}>\n <Variants asset={asset} />\n </Section>\n </>\n ) : null}\n </SheetBody>\n {asset && (canWrite || canManage) ? (\n <SheetFooter className=\"flex-row flex-wrap justify-between\">\n {canManage ? <DeleteAction asset={asset} onDeleted={onClose} /> : null}\n {canWrite ? (\n <UploadButton\n variant=\"outline\"\n multiple={false}\n label={t('media.details.replace')}\n onFiles={([file]) => (file ? onReplace(asset.id, file) : undefined)}\n className=\"ml-auto\"\n />\n ) : null}\n </SheetFooter>\n ) : null}\n </SheetContent>\n </Sheet>\n {discardPrompt}\n </>\n );\n};\n","import { Upload } from 'lucide-react';\nimport { useRef, useState, type DragEvent, type ReactNode } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { cn } from '@/helpers/cn';\n\ntype DropzoneProps = {\n enabled: boolean;\n onFiles: (files: File[]) => void;\n children: ReactNode;\n className?: string;\n};\n\nconst hasFiles = (event: DragEvent) => event.dataTransfer.types.includes('Files');\n\n/**\n * Drop files anywhere over the library to upload them. A pointer shortcut only: the Upload button is the\n * keyboard and screen-reader path, so the overlay is hidden from assistive technology.\n */\nexport const Dropzone = ({ enabled, onFiles, children, className }: DropzoneProps) => {\n const { t } = useTranslation();\n const [dragging, setDragging] = useState(false);\n const depth = useRef(0);\n if (!enabled) {\n return <div className={className}>{children}</div>;\n }\n return (\n <div\n className={cn('relative', className)}\n onDragEnter={(event) => {\n if (hasFiles(event)) {\n depth.current += 1;\n setDragging(true);\n }\n }}\n onDragLeave={() => {\n depth.current = Math.max(0, depth.current - 1);\n if (depth.current === 0) {\n setDragging(false);\n }\n }}\n onDragOver={(event) => {\n if (hasFiles(event)) {\n event.preventDefault();\n event.dataTransfer.dropEffect = 'copy';\n }\n }}\n onDrop={(event) => {\n event.preventDefault();\n depth.current = 0;\n setDragging(false);\n const files = [...event.dataTransfer.files];\n if (files.length > 0) {\n onFiles(files);\n }\n }}\n >\n {children}\n {dragging ? (\n <div\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-0 z-20 flex flex-col items-center justify-center gap-2 rounded-xl border-2 border-dashed border-primary bg-background/90 text-primary\"\n >\n <Upload className=\"size-8\" />\n <p className=\"font-semibold\">{t('media.upload.dropHere')}</p>\n </div>\n ) : null}\n </div>\n );\n};\n","import type { MediaFolder } from '@shapio/client';\n\nexport type FolderNode = MediaFolder & { children: FolderNode[]; depth: number };\n\n/** Builds the folder tree from the flat list, siblings sorted by name. Orphans (parent missing) go to the root. */\nexport const buildFolderTree = (folders: readonly MediaFolder[]): FolderNode[] => {\n const byParent = Map.groupBy(folders, (folder) =>\n folder.parentId && folders.some((candidate) => candidate.id === folder.parentId) ? folder.parentId : null,\n );\n const build = (parentId: string | null, depth: number): FolderNode[] =>\n [...(byParent.get(parentId) ?? [])]\n .sort((a, b) => a.name.localeCompare(b.name))\n .map((folder) => ({ ...folder, depth, children: build(folder.id, depth + 1) }));\n return build(null, 0);\n};\n\n/** Depth-first: every folder with its depth, for pickers that show the tree as an indented list. */\nexport const flattenFolderTree = (nodes: readonly FolderNode[]): FolderNode[] =>\n nodes.flatMap((node) => [node, ...flattenFolderTree(node.children)]);\n\n/** The folder and everything under it (a folder cannot move into these). */\nexport const descendantIds = (folders: readonly MediaFolder[], id: string): Set<string> => {\n const result = new Set([id]);\n let grew = true;\n while (grew) {\n grew = false;\n for (const folder of folders) {\n if (folder.parentId && result.has(folder.parentId) && !result.has(folder.id)) {\n result.add(folder.id);\n grew = true;\n }\n }\n }\n return result;\n};\n","import { zodResolver } from '@hookform/resolvers/zod';\nimport type { MediaFolder } from '@shapio/client';\nimport { useForm } from 'react-hook-form';\nimport { toast } from 'sonner';\nimport { z } from 'zod';\nimport { useCreateMediaFolder, useUpdateMediaFolder } from '@/api/media';\nimport { i18next } from '@/app/i18n';\nimport { settle } from '@/helpers/settle';\nimport { requiredText } from '@/helpers/validation';\n\nconst MAX_NAME_LENGTH = 255;\n\nconst folderSchema = z.object({ name: requiredText().max(MAX_NAME_LENGTH, 'validation.tooLong') });\n\nexport type FolderValues = z.infer<typeof folderSchema>;\n\n/** What the inline folder row edits: a new folder (under `parentId`) or the name of `folder`. */\nexport type FolderEdit =\n { mode: 'create'; parentId: string | null } | { mode: 'rename'; folder: MediaFolder };\n\n/** The inline folder row's form: creates a folder or renames one, then calls `onDone`. */\nexport const useFolderForm = (edit: FolderEdit, onDone: () => void) => {\n const createFolder = useCreateMediaFolder();\n const updateFolder = useUpdateMediaFolder();\n const initialName = edit.mode === 'rename' ? edit.folder.name : '';\n const form = useForm<FolderValues>({\n resolver: zodResolver(folderSchema),\n defaultValues: { name: initialName },\n });\n const onSubmit = form.handleSubmit(async ({ name }) => {\n const trimmed = name.trim();\n if (edit.mode === 'rename' && trimmed === edit.folder.name) {\n onDone();\n return;\n }\n const result = await settle(\n edit.mode === 'rename'\n ? updateFolder.mutateAsync({\n id: edit.folder.id,\n input: { expectedVersion: edit.folder.version, name: trimmed },\n })\n : createFolder.mutateAsync({ name: trimmed, parentId: edit.parentId }),\n );\n if (result.ok) {\n toast.success(\n i18next.t(edit.mode === 'rename' ? 'media.folders.renamed' : 'media.folders.created', {\n name: trimmed,\n }),\n );\n onDone();\n }\n });\n const mutation = edit.mode === 'rename' ? updateFolder : createFolder;\n return { form, onSubmit, initialName, pending: mutation.isPending, error: mutation.error };\n};\n","import { Check, FolderPlus, Loader2, Pencil, X } from 'lucide-react';\nimport { useEffect, useId, type FocusEvent, type KeyboardEvent } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { FormFieldError } from '@/components/FormFieldError';\nimport { Button } from '@/components/ui/button';\nimport { Input } from '@/components/ui/input';\nimport { describeError } from '@/helpers/describeError';\nimport { useFolderForm, type FolderEdit } from '../../hooks/useFolderForm';\n\ntype EditRowProps = {\n edit: FolderEdit;\n /** `returnFocus`: false when focus already left the row (a click elsewhere), so it isn't pulled back. */\n onDone: (returnFocus: boolean) => void;\n};\n\n/**\n * A folder name being typed in place, in the tree (the caller's list item): a new folder or a rename. Enter saves, Escape cancels;\n * leaving the row without changing anything cancels too.\n */\nexport const EditRow = ({ edit, onDone }: EditRowProps) => {\n const { t } = useTranslation();\n const errorId = useId();\n const { form, onSubmit, initialName, pending, error } = useFolderForm(edit, () => onDone(true));\n const { setFocus } = form;\n useEffect(() => {\n setFocus('name', { shouldSelect: true });\n }, [setFocus]);\n const fieldError = form.formState.errors.name?.message;\n const message = fieldError ?? (error ? describeError(error) : undefined);\n const creating = edit.mode === 'create';\n const cancelOnEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && !pending) {\n event.preventDefault();\n event.stopPropagation();\n onDone(true);\n }\n };\n const cancelWhenLeftUnchanged = (event: FocusEvent<HTMLFormElement>) => {\n const next = event.relatedTarget;\n if (next instanceof Node && event.currentTarget.contains(next)) {\n return;\n }\n if (!pending && form.getValues('name').trim() === initialName) {\n onDone(false);\n }\n };\n return (\n <div>\n <form\n noValidate\n onSubmit={(event) => void onSubmit(event)}\n onKeyDown={cancelOnEscape}\n onBlur={cancelWhenLeftUnchanged}\n className=\"flex items-center gap-1 py-0.5 pl-1\"\n >\n {creating ? (\n <FolderPlus aria-hidden=\"true\" className=\"size-4 shrink-0 text-muted-foreground\" />\n ) : (\n <Pencil aria-hidden=\"true\" className=\"size-4 shrink-0 text-muted-foreground\" />\n )}\n <Input\n {...form.register('name')}\n inputSize=\"sm\"\n autoComplete=\"off\"\n spellCheck={false}\n readOnly={pending}\n aria-label={\n creating ? t('media.folders.newName') : t('media.folders.renameLabel', { name: edit.folder.name })\n }\n aria-invalid={message ? true : undefined}\n aria-describedby={message ? errorId : undefined}\n className=\"h-8 px-2\"\n />\n <Button\n type=\"submit\"\n variant=\"ghost\"\n size=\"icon-xs\"\n disabled={pending}\n aria-label={creating ? t('media.folders.create') : t('media.folders.saveName')}\n >\n {pending ? <Loader2 aria-hidden=\"true\" className=\"animate-spin\" /> : <Check aria-hidden=\"true\" />}\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n disabled={pending}\n aria-label={t('common.cancel')}\n onClick={() => onDone(true)}\n >\n <X aria-hidden=\"true\" />\n </Button>\n </form>\n <div className=\"pl-6\">\n <FormFieldError id={errorId} message={message} />\n </div>\n </div>\n );\n};\n","/** A 36px folder-rail row: muted until hovered, accent pill while it is the current scope. */\nexport const FOLDER_ROW_CLASSES =\n 'flex h-9 min-w-0 items-center gap-2.5 rounded-lg text-left text-sm font-medium text-muted-foreground outline-none hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-[current=true]:bg-accent aria-[current=true]:font-semibold aria-[current=true]:text-accent-foreground [&_svg]:size-4 [&_svg]:shrink-0';\n","import type { MediaFolder } from '@shapio/client';\nimport { FolderPlus, MoreHorizontal, Pencil, Trash2 } from 'lucide-react';\nimport { useRef } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { InlineConfirm } from '@/components/InlineConfirm';\nimport { Button } from '@/components/ui/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu';\n\nexport type FolderActions = {\n onCreate: (parentId: string | null) => void;\n onRename: (folder: MediaFolder) => void;\n /** The folder whose delete confirmation is open. */\n deletingId: string | undefined;\n onDeleteOpenChange: (folder: MediaFolder, open: boolean) => void;\n onDelete: (folder: MediaFolder) => Promise<unknown>;\n};\n\ntype MenuProps = { folder: MediaFolder; canManage: boolean; actions: FolderActions };\n\n/**\n * A folder's \"…\" menu: new subfolder and rename (an inline row takes focus), delete (confirmed in a popover\n * anchored to this button).\n */\nexport const Menu = ({ folder, canManage, actions }: MenuProps) => {\n const { t } = useTranslation();\n // A menu item hands focus to the inline row or the delete confirmation instead of the menu button.\n const handingOff = useRef(false);\n const handOff = (action: () => void) => () => {\n handingOff.current = true;\n action();\n };\n return (\n <DropdownMenu>\n <InlineConfirm\n tone=\"danger\"\n open={actions.deletingId === folder.id}\n onOpenChange={(open) => actions.onDeleteOpenChange(folder, open)}\n title={t('media.folders.deleteTitle', { name: folder.name })}\n description={t('media.folders.deleteDescription')}\n confirmLabel={t('common.delete')}\n onConfirm={() => actions.onDelete(folder)}\n >\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon-xs\"\n aria-label={t('media.folders.actions', { name: folder.name })}\n className=\"absolute right-1.5\"\n data-folder-menu={folder.id}\n >\n <MoreHorizontal aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n </InlineConfirm>\n <DropdownMenuContent\n align=\"end\"\n onCloseAutoFocus={(event) => {\n if (handingOff.current) {\n handingOff.current = false;\n event.preventDefault();\n }\n }}\n >\n <DropdownMenuItem onSelect={handOff(() => actions.onCreate(folder.id))}>\n <FolderPlus aria-hidden=\"true\" />\n {t('media.folders.newSubfolder')}\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={handOff(() => actions.onRename(folder))}>\n <Pencil aria-hidden=\"true\" />\n {t('media.folders.rename')}\n </DropdownMenuItem>\n {canManage ? (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n variant=\"destructive\"\n onSelect={handOff(() => actions.onDeleteOpenChange(folder, true))}\n >\n <Trash2 aria-hidden=\"true\" />\n {t('common.delete')}\n </DropdownMenuItem>\n </>\n ) : null}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n};\n","import { Folder, FolderOpen } from 'lucide-react';\nimport { cn } from '@/helpers/cn';\nimport type { FolderNode } from '../../helpers/folderTree';\nimport type { FolderEdit } from '../../hooks/useFolderForm';\nimport { FOLDER_ROW_CLASSES } from '../constants';\nimport { EditRow } from '../EditRow';\nimport { Menu, type FolderActions } from '../Menu';\n\ntype ItemProps = {\n node: FolderNode;\n currentId: string | undefined;\n canWrite: boolean;\n canManage: boolean;\n actions: FolderActions;\n /** The inline row being edited anywhere in the tree. */\n editing: FolderEdit | undefined;\n onEditDone: (returnFocus: boolean) => void;\n onSelect: (id: string) => void;\n};\n\n/** A folder (button + actions menu, or its name being edited) and its subfolders, as a nested list. */\nexport const Item = ({\n node,\n currentId,\n canWrite,\n canManage,\n actions,\n editing,\n onEditDone,\n onSelect,\n}: ItemProps) => {\n const current = node.id === currentId;\n const Icon = current ? FolderOpen : Folder;\n const renameEdit = editing?.mode === 'rename' && editing.folder.id === node.id ? editing : undefined;\n const childEdit = editing?.mode === 'create' && editing.parentId === node.id ? editing : undefined;\n return (\n <li>\n {renameEdit ? (\n <EditRow edit={renameEdit} onDone={onEditDone} />\n ) : (\n <div className=\"relative flex items-center\">\n <button\n type=\"button\"\n aria-current={current ? 'true' : undefined}\n onClick={() => onSelect(node.id)}\n className={cn(FOLDER_ROW_CLASSES, 'flex-1 pl-2.5', canWrite ? 'pr-9' : 'pr-2.5')}\n >\n <Icon aria-hidden=\"true\" />\n <span className=\"truncate\">{node.name}</span>\n <span className=\"ml-auto text-xs font-medium text-muted-foreground tabular-nums\">\n {node.assetCount}\n </span>\n </button>\n {canWrite ? <Menu folder={node} canManage={canManage} actions={actions} /> : null}\n </div>\n )}\n {node.children.length > 0 || childEdit ? (\n <ul className=\"mt-0.5 ml-4 space-y-0.5 border-l pl-1.5\">\n {childEdit ? (\n <li>\n <EditRow edit={childEdit} onDone={onEditDone} />\n </li>\n ) : null}\n {node.children.map((child) => (\n <Item\n key={child.id}\n node={child}\n currentId={currentId}\n canWrite={canWrite}\n canManage={canManage}\n actions={actions}\n editing={editing}\n onEditDone={onEditDone}\n onSelect={onSelect}\n />\n ))}\n </ul>\n ) : null}\n </li>\n );\n};\n","import type { ReactNode } from 'react';\nimport { cn } from '@/helpers/cn';\nimport { FOLDER_ROW_CLASSES } from '../constants';\n\ntype ScopeButtonProps = { current: boolean; icon: ReactNode; label: string; onClick: () => void };\n\n/** \"All media\" and \"Not in a folder\": scopes above the folder list. */\nexport const ScopeButton = ({ current, icon, label, onClick }: ScopeButtonProps) => (\n <button\n type=\"button\"\n aria-current={current ? 'true' : undefined}\n onClick={onClick}\n className={cn(FOLDER_ROW_CLASSES, 'w-full px-2.5')}\n >\n {icon}\n <span className=\"truncate\">{label}</span>\n </button>\n);\n","import type { MediaFolder } from '@shapio/client';\nimport { Images, Inbox } from 'lucide-react';\nimport { useMemo } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Panel } from '@/components/Panel';\nimport { Skeleton } from '@/components/ui/skeleton';\nimport { ROOT_FOLDER } from '../constants';\nimport { buildFolderTree } from '../helpers/folderTree';\nimport type { FolderEdit } from '../hooks/useFolderForm';\nimport { EditRow } from './EditRow';\nimport { Item } from './Item';\nimport type { FolderActions } from './Menu';\nimport { ScopeButton } from './ScopeButton';\n\ntype FolderTreeProps = {\n folders: readonly MediaFolder[] | undefined;\n /** A folder ID, `root`, or undefined for every folder. */\n current: string | undefined;\n canWrite: boolean;\n canManage: boolean;\n actions: FolderActions;\n /** The folder name being typed in place (a new folder or a rename), if any. */\n editing: FolderEdit | undefined;\n onEditDone: (returnFocus: boolean) => void;\n onSelect: (folder: string | undefined) => void;\n className?: string;\n};\n\n/**\n * The folder rail: \"All media\", \"Not in a folder\", then every folder with rename / new subfolder / delete.\n * New top-level folders come from the page header; new and renamed folders are named in place.\n */\nexport const FolderTree = ({\n folders,\n current,\n canWrite,\n canManage,\n actions,\n editing,\n onEditDone,\n onSelect,\n className,\n}: FolderTreeProps) => {\n const { t } = useTranslation();\n const tree = useMemo(() => buildFolderTree(folders ?? []), [folders]);\n const topLevelEdit = editing?.mode === 'create' && editing.parentId === null ? editing : undefined;\n return (\n <Panel title={t('media.folders.title')} flush className={className} bodyClassName=\"p-2\">\n <nav aria-label={t('media.folders.title')} className=\"space-y-1\">\n <ul className=\"space-y-0.5\">\n <li>\n <ScopeButton\n current={current === undefined}\n icon={<Images aria-hidden=\"true\" />}\n label={t('media.folders.all')}\n onClick={() => onSelect(undefined)}\n />\n </li>\n <li>\n <ScopeButton\n current={current === ROOT_FOLDER}\n icon={<Inbox aria-hidden=\"true\" />}\n label={t('media.folders.unfiled')}\n onClick={() => onSelect(ROOT_FOLDER)}\n />\n </li>\n </ul>\n {folders === undefined ? (\n <Skeleton className=\"h-8 w-full\" />\n ) : tree.length > 0 || topLevelEdit ? (\n <ul className=\"space-y-0.5 border-t pt-1\">\n {topLevelEdit ? (\n <li>\n <EditRow edit={topLevelEdit} onDone={onEditDone} />\n </li>\n ) : null}\n {tree.map((node) => (\n <Item\n key={node.id}\n node={node}\n currentId={current}\n canWrite={canWrite}\n canManage={canManage}\n actions={actions}\n editing={editing}\n onEditDone={onEditDone}\n onSelect={onSelect}\n />\n ))}\n </ul>\n ) : null}\n </nav>\n </Panel>\n );\n};\n","import { useCallback, useState } from 'react';\n\n/** The assets ticked for bulk actions. */\nexport const useAssetSelection = () => {\n const [selected, setSelected] = useState<ReadonlySet<string>>(new Set());\n const toggle = useCallback(\n (id: string, checked: boolean) =>\n setSelected((current) => {\n const next = new Set(current);\n if (checked) {\n next.add(id);\n } else {\n next.delete(id);\n }\n return next;\n }),\n [],\n );\n const clear = useCallback(() => setSelected(new Set()), []);\n return { selected, toggle, clear };\n};\n","import type { MediaFolder } from '@shapio/client';\nimport { useState } from 'react';\nimport { toast } from 'sonner';\nimport { useDeleteMediaFolder } from '@/api/media';\nimport { i18next } from '@/app/i18n';\nimport type { FolderActions } from '../FolderTree/Menu';\nimport type { FolderEdit } from './useFolderForm';\n\n/**\n * Where focus returns after an inline folder row: the page header's \"New folder\" button (`data-new-folder`)\n * for a top-level folder, otherwise the folder's actions button (`data-folder-menu` = its ID).\n */\nconst openerOf = (edit: FolderEdit): HTMLElement | null => {\n const id = edit.mode === 'rename' ? edit.folder.id : edit.parentId;\n const selector = id === null ? '[data-new-folder]' : `[data-folder-menu=\"${CSS.escape(id)}\"]`;\n return document.querySelector<HTMLElement>(selector);\n};\n\n/**\n * Create, rename and delete folders: the inline row being edited (create/rename happen in the tree, not a\n * dialog) and the folder whose delete confirmation is open.\n */\nexport const useFolderActions = (onDeleted: (folder: MediaFolder) => void) => {\n const [editing, setEditing] = useState<FolderEdit | undefined>(undefined);\n const [deletingId, setDeletingId] = useState<string | undefined>(undefined);\n const deleteFolder = useDeleteMediaFolder();\n const actions: FolderActions = {\n onCreate: (parentId) => setEditing({ mode: 'create', parentId }),\n onRename: (folder) => setEditing({ mode: 'rename', folder }),\n deletingId,\n onDeleteOpenChange: (folder, open) => setDeletingId(open ? folder.id : undefined),\n onDelete: (folder) =>\n deleteFolder.mutateAsync(folder.id).then(() => {\n toast.success(i18next.t('media.folders.deleted', { name: folder.name }));\n onDeleted(folder);\n }),\n };\n return {\n actions,\n editing,\n /**\n * Closes the inline row. With `returnFocus`, focus goes back to what opened it (the header button or\n * the folder's actions button) once the tree has re-rendered; not when focus already moved elsewhere.\n */\n stopEditing: (returnFocus: boolean) => {\n const edit = editing;\n setEditing(undefined);\n if (edit && returnFocus) {\n requestAnimationFrame(() => openerOf(edit)?.focus());\n }\n },\n };\n};\n","import { useNavigate, useSearch } from '@tanstack/react-router';\nimport type { MediaSearch } from '@/app/searchSchemas';\nimport { MIME_FILTER_BY_TYPE } from '../constants';\n\n/** Folder, filters, view and the open asset live in the URL (bookmarkable, back-button friendly). */\nexport const useMediaSearch = () => {\n const search = useSearch({ from: '/app/media' });\n const navigate = useNavigate({ from: '/media' });\n const setSearch = (changes: Partial<MediaSearch>, replace = false) =>\n void navigate({ search: (previous) => ({ ...previous, ...changes }), replace });\n return {\n search,\n setSearch,\n /** The API query for the current folder and filters. */\n assetQuery: {\n ...(search.folder ? { folder: search.folder } : {}),\n ...(search.q ? { search: search.q } : {}),\n ...(search.type ? { mimeType: MIME_FILTER_BY_TYPE[search.type] } : {}),\n },\n };\n};\n","import type { KeyboardEvent } from 'react';\n\n/**\n * Up/Down (and Home/End) move focus between the enabled buttons inside `event.currentTarget`, for short\n * pick lists where Tab alone would be slow.\n */\nexport const moveFocusWithArrows = (event: KeyboardEvent<HTMLElement>) => {\n const keys = ['ArrowDown', 'ArrowUp', 'Home', 'End'];\n if (!keys.includes(event.key)) {\n return;\n }\n const buttons = [...event.currentTarget.querySelectorAll<HTMLButtonElement>('button:not(:disabled)')];\n if (buttons.length === 0) {\n return;\n }\n event.preventDefault();\n const index = buttons.findIndex((button) => button === document.activeElement);\n const last = buttons.length - 1;\n const next =\n event.key === 'Home'\n ? 0\n : event.key === 'End'\n ? last\n : event.key === 'ArrowDown'\n ? Math.min(index + 1, last)\n : Math.max(index - 1, 0);\n buttons[next]?.focus();\n};\n","import { useState } from 'react';\nimport { toast } from 'sonner';\nimport { useMoveMediaAssets } from '@/api/media';\nimport { i18next } from '@/app/i18n';\nimport { settle } from '@/helpers/settle';\n\n/** The move target while a move runs: a folder ID, or null for \"no folder\". */\ntype MoveTarget = string | null;\n\n/** Moves assets into a folder (or out of every folder) and reports it; `onMoved` runs on success. */\nexport const useMoveToFolder = (assetIds: readonly string[], onMoved: () => void) => {\n const move = useMoveMediaAssets();\n const [target, setTarget] = useState<MoveTarget | undefined>(undefined);\n return {\n /** The folder being moved into while the request runs. */\n target: move.isPending ? target : undefined,\n pending: move.isPending,\n error: move.error,\n reset: move.reset,\n moveTo: async (folderId: MoveTarget) => {\n setTarget(folderId);\n const result = await settle(move.mutateAsync({ assetIds: [...assetIds], folderId }));\n if (result.ok) {\n toast.success(i18next.t('media.move.done', { count: result.value.moved.length }));\n onMoved();\n }\n },\n };\n};\n","import { Loader2 } from 'lucide-react';\nimport type { CSSProperties, ReactNode } from 'react';\nimport { cn } from '@/helpers/cn';\nimport { FOLDER_ROW_CLASSES } from '../../FolderTree/constants';\n\ntype ChoiceProps = {\n icon: ReactNode;\n label: string;\n /** Nesting level, indents the row (a runtime value, passed as a CSS variable). */\n depth: number;\n pending: boolean;\n disabled: boolean;\n onClick: () => void;\n};\n\n/** One folder in the move popover, indented by its depth; a spinner while the move into it runs. */\nexport const Choice = ({ icon, label, depth, pending, disabled, onClick }: ChoiceProps) => (\n <li>\n <button\n type=\"button\"\n disabled={disabled}\n aria-busy={pending || undefined}\n onClick={onClick}\n style={{ '--depth': depth } as CSSProperties}\n className={cn(\n FOLDER_ROW_CLASSES,\n 'w-full pr-2.5 pl-[calc(0.625rem+var(--depth)*1rem)] disabled:opacity-50',\n )}\n >\n {pending ? <Loader2 aria-hidden=\"true\" className=\"animate-spin\" /> : icon}\n <span className=\"truncate\">{label}</span>\n </button>\n </li>\n);\n","import { Folder, FolderInput, Inbox } from 'lucide-react';\nimport { useId, useMemo, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useMediaFolders } from '@/api/media';\nimport { FormError } from '@/components/FormError';\nimport { Button } from '@/components/ui/button';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';\nimport { Skeleton } from '@/components/ui/skeleton';\nimport { moveFocusWithArrows } from '../helpers/arrowFocus';\nimport { buildFolderTree, flattenFolderTree } from '../helpers/folderTree';\nimport { useMoveToFolder } from '../hooks/useMoveToFolder';\nimport { Choice } from './Choice';\n\ntype MovePopoverProps = { assetIds: readonly string[]; onMoved: () => void };\n\n/**\n * \"Move to…\" for the selected files: a popover with the folder tree; choosing a folder moves them at once.\n * Up and Down move through the folders.\n */\nexport const MovePopover = ({ assetIds, onMoved }: MovePopoverProps) => {\n const { t } = useTranslation();\n const titleId = useId();\n const [open, setOpen] = useState(false);\n const folders = useMediaFolders();\n const choices = useMemo(() => flattenFolderTree(buildFolderTree(folders.data ?? [])), [folders.data]);\n const move = useMoveToFolder(assetIds, () => {\n setOpen(false);\n onMoved();\n });\n const changeOpen = (next: boolean) => {\n if (move.pending) {\n return;\n }\n if (next) {\n move.reset();\n }\n setOpen(next);\n };\n return (\n <Popover open={open} onOpenChange={changeOpen} modal>\n <PopoverTrigger asChild>\n <Button size=\"sm\" variant=\"outline\">\n <FolderInput aria-hidden=\"true\" />\n {t('media.move.action')}\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" aria-labelledby={titleId} className=\"w-72 space-y-2 p-2\">\n <p id={titleId} className=\"px-2.5 pt-1 text-sm font-semibold\">\n {t('media.move.title', { count: assetIds.length })}\n </p>\n <ul className=\"max-h-72 space-y-0.5 overflow-y-auto\" onKeyDown={moveFocusWithArrows}>\n <Choice\n icon={<Inbox aria-hidden=\"true\" />}\n label={t('media.folders.none')}\n depth={0}\n pending={move.target === null}\n disabled={move.pending}\n onClick={() => void move.moveTo(null)}\n />\n {choices.map((folder) => (\n <Choice\n key={folder.id}\n icon={<Folder aria-hidden=\"true\" />}\n label={folder.name}\n depth={folder.depth}\n pending={move.target === folder.id}\n disabled={move.pending}\n onClick={() => void move.moveTo(folder.id)}\n />\n ))}\n </ul>\n {folders.isPending ? <Skeleton className=\"h-8 w-full\" /> : null}\n <FormError error={move.error} />\n </PopoverContent>\n </Popover>\n );\n};\n","import { X } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { Button } from '@/components/ui/button';\nimport { MovePopover } from '../MovePopover';\n\ntype SelectionBarProps = { selected: ReadonlySet<string>; onClear: () => void };\n\n/** Bulk actions for the ticked assets. Announced when the selection changes. */\nexport const SelectionBar = ({ selected, onClear }: SelectionBarProps) => {\n const { t } = useTranslation();\n return (\n <div className=\"flex flex-wrap items-center gap-2 rounded-xl border bg-accent py-1.5 pr-1.5 pl-4 text-accent-foreground\">\n <span role=\"status\" aria-live=\"polite\" className=\"mr-auto text-sm font-medium\">\n {t('media.selectedCount', { count: selected.size })}\n </span>\n <MovePopover assetIds={[...selected]} onMoved={onClear} />\n <Button size=\"sm\" variant=\"ghost\" onClick={onClear}>\n <X aria-hidden=\"true\" />\n {t('media.clearSelection')}\n </Button>\n </div>\n );\n};\n","import { FolderPlus } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { useMediaFolders } from '@/api/media';\nimport { Page } from '@/components/Page';\nimport { PageHeader } from '@/components/PageHeader';\nimport { Button } from '@/components/ui/button';\nimport { useMediaPermissions } from '@/hooks/useMediaPermissions';\nimport { useMediaUploader } from '@/hooks/useMediaUploader';\nimport { ROOT_FOLDER } from './constants';\nimport { Details } from './Details';\nimport { Dropzone } from './Dropzone';\nimport { FolderTree } from './FolderTree';\nimport { useAssetSelection } from './hooks/useAssetSelection';\nimport { useFolderActions } from './hooks/useFolderActions';\nimport { useMediaSearch } from './hooks/useMediaSearch';\nimport { Library } from './Library';\nimport { SelectionBar } from './SelectionBar';\nimport { Toolbar } from './Toolbar';\nimport { UploadButton } from './UploadButton';\nimport { UploadQueue } from './UploadQueue';\n\n/** The media library: folders, search and filters, uploads (drop or pick), bulk move and asset details. Folders are created and renamed in place. */\nexport const Media = () => {\n const { t } = useTranslation();\n const { search, setSearch, assetQuery } = useMediaSearch();\n const folders = useMediaFolders();\n const { canWrite, canManage } = useMediaPermissions();\n const uploader = useMediaUploader();\n const selection = useAssetSelection();\n const folderActions = useFolderActions((folder) => {\n if (search.folder === folder.id) {\n setSearch({ folder: undefined });\n }\n });\n const uploadFolder = search.folder && search.folder !== ROOT_FOLDER ? search.folder : null;\n const upload = (files: File[]) => uploader.enqueue(files, { folderId: uploadFolder, visibility: 'public' });\n return (\n <Page width=\"full\">\n <PageHeader\n title={t('media.title')}\n actions={\n canWrite ? (\n <>\n <Button variant=\"outline\" data-new-folder onClick={() => folderActions.actions.onCreate(null)}>\n <FolderPlus aria-hidden=\"true\" />\n {t('media.folders.new')}\n </Button>\n <UploadButton label={t('media.upload.action')} onFiles={upload} />\n </>\n ) : null\n }\n />\n <div className=\"grid gap-6 lg:grid-cols-[13.75rem_minmax(0,1fr)]\">\n <FolderTree\n folders={folders.data}\n current={search.folder}\n canWrite={canWrite}\n canManage={canManage}\n actions={folderActions.actions}\n editing={folderActions.editing}\n onEditDone={folderActions.stopEditing}\n onSelect={(folder) => {\n selection.clear();\n setSearch({ folder });\n }}\n className=\"lg:self-start\"\n />\n <Dropzone enabled={canWrite} onFiles={upload} className=\"min-h-96 min-w-0 space-y-4\">\n <UploadQueue onRetry={uploader.retry} onDismiss={uploader.dismiss} />\n <Toolbar\n query={search.q}\n type={search.type}\n view={search.view ?? 'grid'}\n onQueryChange={(q) => setSearch({ q }, true)}\n onTypeChange={(type) => setSearch({ type })}\n onViewChange={(view) => setSearch({ view })}\n />\n {selection.selected.size > 0 ? (\n <SelectionBar selected={selection.selected} onClear={selection.clear} />\n ) : null}\n <Library\n query={assetQuery}\n filtered={Boolean(search.q || search.type)}\n view={search.view ?? 'grid'}\n selected={selection.selected}\n selectable={canWrite}\n activeId={search.asset}\n onSelectChange={selection.toggle}\n onOpen={(asset) => setSearch({ asset: asset.id })}\n />\n </Dropzone>\n </div>\n <Details\n assetId={search.asset}\n onClose={() => setSearch({ asset: undefined })}\n onReplace={(assetId, file) =>\n uploader.enqueue([file], { folderId: null, visibility: 'public', replaceAssetId: assetId })\n }\n />\n </Page>\n );\n};\n","import { createLazyRoute } from '@tanstack/react-router';\nimport { Media } from '@/features/Media';\n\n/** The media library, loaded on first visit. */\nexport const mediaLazyRoute = createLazyRoute('/app/media')({ component: Media });\n"],"ignoreList":[0,1,2],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"media-CeZGDGh7.js","names":["__iconData","__iconData","z.object","z.string","z.number","zodResolver","i18next","useState","i18next","_Fragment","Trash2","_Fragment","useState","_Fragment","AlertTriangle","useState","useRef","z.object","zodResolver","i18next","useId","Loader2","useRef","MoreHorizontal","_Fragment","Trash2","useMemo","useState","useCallback","useState","i18next","useState","i18next","Loader2","useId","useState","useMemo","_Fragment","__toESM","require_jsx_runtime","LoaderCircle","useMoveMediaAssets","useMediaAsset","useUpdateMediaAsset","useDeleteMediaAsset","useMediaFolders","useDeleteMediaFolder","useMediaUsage","useCreateMediaFolder","useUpdateMediaFolder","useNavigate","Link","hasErrorCode","Lock","X","SubmitButton","Page","Sheet","SheetDescription","SheetFooter","PageHeader","TriangleAlert","SheetBody","SheetTitle","StatusChip","SheetHeader","ErrorState","Badge","SheetContent","LoadingState","ShapioApiError","useTranslation","createLucideIcon","useSearch","RowTitle","createLazyRoute","toast","PopoverTrigger","PopoverContent","Popover","instance","describeError","Check","Button","Input","Skeleton","FormError","Alert","ConfirmDialog","AlertDescription","InlineConfirm","ExternalLink","Trash","FieldGroup","FieldContent","FieldLabel","FieldDescription","Field","FocalPoint","Ellipsis","Variants","useMediaPermissions","FileIcon","Pencil","fileKindLabel","MEDIA_STATUS_DISPLAY","isImage","formatBytes","FolderPlus","Globe","Library","Images","Toolbar","UploadQueue","Upload","UploadButton","useMediaUploader","Inbox","DropdownMenuItem","DropdownMenuSeparator","DropdownMenuTrigger","DropdownMenuContent","DropdownMenu","cn","Switch","useController","FormTextField","requiredText","FormFieldError","u","useForm","settle","object","number","string","useDiscardGuard","ROOT_FOLDER","MIME_FILTER_BY_TYPE","SuggestAltButton","Panel","useContentSchema","CopyButton","FormTextareaField","entryLink","__iconData$2","FolderInput","__iconData$1","FolderOpen","__iconData","Folder","import_react","require_react","detailsSchema","valuesFor","asset","changesFrom","values","useAssetDetailsForm","update","form","reset","result","usageCountOf","details","error","useDeleteAssetFlow","remove","blocked","setBlocked","forceOpen","setForceOpen","forceUsageCount","setForceUsageCount","deleted","target","onDeleted","usageCount","isOwner","import_jsx_runtime","DeleteAction","deletion","t","MetadataForm","focal","image","event","onSubmit","readOnly","alt","value","previewImageUrl","variant","Preview","Section","title","children","Row","model","usage","Usage","assetId","item","schema","Visibility","confirming","setConfirming","isPrivate","next","consequence","canManage","Details","query","open","onClose","status","requestOpenChange","canWrite","file","onReplace","discardPrompt","hasFiles","Dropzone","dragging","setDragging","depth","enabled","className","files","onFiles","buildFolderTree","byParent","folders","folder","candidate","build","parentId","a","b","flattenFolderTree","nodes","node","folderSchema","useFolderForm","createFolder","updateFolder","initialName","edit","trimmed","name","onDone","mutation","EditRow","errorId","setFocus","message","creating","pending","FOLDER_ROW_CLASSES","Menu","handingOff","handOff","action","actions","Item","current","currentId","Icon","renameEdit","editing","childEdit","onEditDone","onSelect","child","ScopeButton","icon","label","FolderTree","tree","topLevelEdit","useAssetSelection","selected","setSelected","checked","id","openerOf","selector","useFolderActions","setEditing","deletingId","setDeletingId","deleteFolder","returnFocus","useMediaSearch","search","navigate","previous","changes","moveFocusWithArrows","buttons","index","button","last","useMoveToFolder","move","setTarget","folderId","assetIds","onMoved","Choice","MovePopover","titleId","setOpen","choices","SelectionBar","onClear","mediaLazyRoute","uploader","selection","folderActions","setSearch","uploadFolder","upload","assetQuery"],"sources":["../../../../node_modules/.pnpm/lucide-react@1.49.0_@types+react@19.3.0_react@19.3.0/node_modules/lucide-react/dist/esm/icons/folder-input.mjs","../../../../node_modules/.pnpm/lucide-react@1.49.0_@types+react@19.3.0_react@19.3.0/node_modules/lucide-react/dist/esm/icons/folder-open.mjs","../../../../node_modules/.pnpm/lucide-react@1.49.0_@types+react@19.3.0_react@19.3.0/node_modules/lucide-react/dist/esm/icons/folder.mjs","../../src/features/Media/hooks/useAssetDetailsForm.ts","../../src/features/Media/hooks/useDeleteAssetFlow.ts","../../src/features/Media/Details/DeleteAction/index.tsx","../../src/features/Media/Details/MetadataForm/index.tsx","../../src/features/Media/Details/Preview/index.tsx","../../src/features/Media/Details/Section/index.tsx","../../src/features/Media/Details/Usage/Row/index.tsx","../../src/features/Media/Details/Usage/index.tsx","../../src/features/Media/Details/Visibility/index.tsx","../../src/features/Media/Details/index.tsx","../../src/features/Media/Dropzone/index.tsx","../../src/features/Media/helpers/folderTree.ts","../../src/features/Media/hooks/useFolderForm.ts","../../src/features/Media/FolderTree/EditRow/index.tsx","../../src/features/Media/FolderTree/constants.ts","../../src/features/Media/FolderTree/Menu/index.tsx","../../src/features/Media/FolderTree/Item/index.tsx","../../src/features/Media/FolderTree/ScopeButton/index.tsx","../../src/features/Media/FolderTree/index.tsx","../../src/features/Media/hooks/useAssetSelection.ts","../../src/features/Media/hooks/useFolderActions.ts","../../src/features/Media/hooks/useMediaSearch.ts","../../src/features/Media/helpers/arrowFocus.ts","../../src/features/Media/hooks/useMoveToFolder.ts","../../src/features/Media/MovePopover/Choice/index.tsx","../../src/features/Media/MovePopover/index.tsx","../../src/features/Media/SelectionBar/index.tsx","../../src/features/Media/index.tsx","../../src/app/lazyRoutes/media.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.49.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"folder-input\",\n size: 24,\n node: [\n [\n \"path\",\n {\n d: \"M2 9V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H20a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-1\",\n key: \"fm4g5t\"\n }\n ],\n [\"path\", { d: \"M2 13h10\", key: \"pgb2dq\" }],\n [\"path\", { d: \"m9 16 3-3-3-3\", key: \"6m91ic\" }]\n ]\n};\n__iconData.node;\nconst FolderInput = createLucideIcon(__iconData);\n\nexport { __iconData, FolderInput as default };\n//# sourceMappingURL=folder-input.mjs.map\n","/**\n * @license lucide-react v1.49.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"folder-open\",\n size: 24,\n node: [\n [\n \"path\",\n {\n d: \"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2\",\n key: \"usdka0\"\n }\n ]\n ]\n};\n__iconData.node;\nconst FolderOpen = createLucideIcon(__iconData);\n\nexport { __iconData, FolderOpen as default };\n//# sourceMappingURL=folder-open.mjs.map\n","/**\n * @license lucide-react v1.49.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"folder\",\n size: 24,\n node: [\n [\n \"path\",\n {\n d: \"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\",\n key: \"1kt360\"\n }\n ]\n ]\n};\n__iconData.node;\nconst Folder = createLucideIcon(__iconData);\n\nexport { __iconData, Folder as default };\n//# sourceMappingURL=folder.mjs.map\n","import { zodResolver } from '@hookform/resolvers/zod';\nimport type { MediaAsset, UpdateMediaAssetInput } from '@shapio/client';\nimport { useEffect } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { toast } from 'sonner';\nimport { z } from 'zod';\nimport { useUpdateMediaAsset } from '@/api/media';\nimport { i18next } from '@/app/i18n';\nimport { settle } from '@/helpers/settle';\nimport { requiredText } from '@/helpers/validation';\n\nconst MAX_FILENAME = 255;\nconst MAX_ALT = 1000;\nconst MAX_CAPTION = 4000;\n\nconst detailsSchema = z.object({\n filename: requiredText().max(MAX_FILENAME, 'validation.tooLong'),\n alt: z.string().max(MAX_ALT, 'validation.tooLong'),\n caption: z.string().max(MAX_CAPTION, 'validation.tooLong'),\n focalPoint: z.object({ x: z.number().min(0).max(1), y: z.number().min(0).max(1) }).nullable(),\n});\n\nexport type AssetDetailsValues = z.infer<typeof detailsSchema>;\n\nconst valuesFor = (asset: MediaAsset | undefined): AssetDetailsValues => ({\n filename: asset?.filename ?? '',\n alt: asset?.alt ?? '',\n caption: asset?.caption ?? '',\n focalPoint: asset?.focalPoint ?? null,\n});\n\n/** Only what changed is sent, with the version the editor saw (409 VERSION_CONFLICT if it moved). */\nconst changesFrom = (asset: MediaAsset, values: AssetDetailsValues): UpdateMediaAssetInput => ({\n expectedVersion: asset.version,\n ...(values.filename !== asset.filename ? { filename: values.filename.trim() } : {}),\n ...(values.alt !== asset.alt ? { alt: values.alt } : {}),\n ...(values.caption !== asset.caption ? { caption: values.caption } : {}),\n ...(JSON.stringify(values.focalPoint) !== JSON.stringify(asset.focalPoint)\n ? { focalPoint: values.focalPoint }\n : {}),\n});\n\n/** File name, alt text, caption and focal point of one asset. */\nexport const useAssetDetailsForm = (asset: MediaAsset | undefined) => {\n const update = useUpdateMediaAsset();\n const form = useForm<AssetDetailsValues>({\n resolver: zodResolver(detailsSchema),\n defaultValues: valuesFor(asset),\n });\n const { reset } = form;\n // A different asset (or a fresh load of this one) starts from what the server has.\n useEffect(() => {\n reset(valuesFor(asset));\n update.reset();\n // The mutation object changes identity on every render.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [asset?.id, reset]);\n const onSubmit = form.handleSubmit(async (values) => {\n if (!asset) {\n return;\n }\n const result = await settle(update.mutateAsync({ id: asset.id, input: changesFrom(asset, values) }));\n if (result.ok) {\n reset(valuesFor(result.value));\n toast.success(i18next.t('media.details.saved'));\n }\n });\n return { form, onSubmit, pending: update.isPending, error: update.error };\n};\n","import { ShapioApiError, type MediaAsset } from '@shapio/client';\nimport { useState } from 'react';\nimport { toast } from 'sonner';\nimport { hasErrorCode } from '@/api/errors';\nimport { useDeleteMediaAsset } from '@/api/media';\nimport { i18next } from '@/app/i18n';\n\nconst usageCountOf = (error: unknown): number => {\n const details =\n error instanceof ShapioApiError ? (error.details as { usageCount?: unknown } | undefined) : undefined;\n return typeof details?.usageCount === 'number' ? details.usageCount : 0;\n};\n\n/**\n * Delete, with the server's protection surfaced: a referenced asset answers 409 MEDIA_IN_USE. For an owner\n * the inline confirmation then hands over to a blocking \"Delete anyway\" dialog (which sends `force`); for\n * anyone else the inline confirmation stays open and explains why it can't be deleted.\n */\nexport const useDeleteAssetFlow = (\n asset: MediaAsset | undefined,\n isOwner: boolean,\n onDeleted: () => void,\n) => {\n const remove = useDeleteMediaAsset();\n const [blocked, setBlocked] = useState<{ assetId: string; usageCount: number } | undefined>(undefined);\n const [forceOpen, setForceOpen] = useState(false);\n // Kept while the dialog animates out, so its text doesn't change.\n const [forceUsageCount, setForceUsageCount] = useState(0);\n const deleted = (target: MediaAsset) => {\n toast.success(i18next.t('media.delete.done', { name: target.filename }));\n onDeleted();\n };\n return {\n /** Set once a non-owner's delete was refused because content uses the file. */\n blockedUsageCount: blocked && blocked.assetId === asset?.id ? blocked.usageCount : undefined,\n /** The inline confirmation's action: rejects (and the popover shows why) unless it was handed over. */\n confirm: async () => {\n if (!asset) {\n return;\n }\n try {\n await remove.mutateAsync({ id: asset.id, force: false });\n } catch (error) {\n if (!hasErrorCode(error, 'MEDIA_IN_USE')) {\n throw error;\n }\n const usageCount = usageCountOf(error);\n if (!isOwner) {\n setBlocked({ assetId: asset.id, usageCount });\n throw error;\n }\n remove.reset();\n setForceUsageCount(usageCount);\n setForceOpen(true);\n return;\n }\n deleted(asset);\n },\n force: {\n open: forceOpen,\n usageCount: forceUsageCount,\n pending: remove.isPending,\n error: remove.error,\n onOpenChange: setForceOpen,\n confirm: () => {\n if (asset) {\n remove.mutate(\n { id: asset.id, force: true },\n {\n onSuccess: () => {\n setForceOpen(false);\n deleted(asset);\n },\n },\n );\n }\n },\n },\n };\n};\n","import type { MediaAsset } from '@shapio/client';\nimport { Trash2 } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { ConfirmDialog } from '@/components/ConfirmDialog';\nimport { InlineConfirm } from '@/components/InlineConfirm';\nimport { Button } from '@/components/ui/button';\nimport { useMediaPermissions } from '@/hooks/useMediaPermissions';\nimport { useDeleteAssetFlow } from '../../hooks/useDeleteAssetFlow';\n\ntype DeleteActionProps = { asset: MediaAsset; onDeleted: () => void };\n\n/**\n * \"Delete file\", confirmed inline. If content still uses the file, the confirmation says so; only an owner\n * can then delete it anyway, through a blocking dialog (it leaves that content pointing at a missing file).\n */\nexport const DeleteAction = ({ asset, onDeleted }: DeleteActionProps) => {\n const { t } = useTranslation();\n const { isOwner } = useMediaPermissions();\n const deletion = useDeleteAssetFlow(asset, isOwner, onDeleted);\n const blocked = deletion.blockedUsageCount;\n return (\n <>\n <InlineConfirm\n tone=\"danger\"\n align=\"start\"\n side=\"top\"\n title={t('media.delete.title', { name: asset.filename })}\n description={\n blocked === undefined\n ? t('media.delete.description')\n : `${t('media.delete.inUseDescription', { count: blocked })} ${t('media.delete.onlyOwners')}`\n }\n confirmLabel={t('common.delete')}\n onConfirm={deletion.confirm}\n trigger={\n <Button variant=\"destructive-ghost\">\n <Trash2 aria-hidden=\"true\" />\n {t('media.delete.action')}\n </Button>\n }\n />\n <ConfirmDialog\n open={deletion.force.open}\n onOpenChange={deletion.force.onOpenChange}\n title={t('media.delete.inUseTitle')}\n description={`${t('media.delete.inUseDescription', { count: deletion.force.usageCount })} ${t(\n 'media.delete.ownerMayForce',\n )}`}\n confirmLabel={t('media.delete.force')}\n destructive\n pending={deletion.force.pending}\n error={deletion.force.error}\n onConfirm={deletion.force.confirm}\n />\n </>\n );\n};\n","import type { MediaAsset } from '@shapio/client';\nimport { useController, type UseFormReturn } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport { FocalPoint } from '@/components/FocalPoint';\nimport { FormError } from '@/components/FormError';\nimport { FormTextareaField } from '@/components/FormTextareaField';\nimport { FormTextField } from '@/components/FormTextField';\nimport { SubmitButton } from '@/components/SubmitButton';\nimport { SuggestAltButton } from '@/components/SuggestAltButton';\nimport { FieldGroup } from '@/components/ui/field';\nimport { isImage } from '../../helpers/fileKind';\nimport type { AssetDetailsValues } from '../../hooks/useAssetDetailsForm';\n\ntype MetadataFormProps = {\n asset: MediaAsset;\n form: UseFormReturn<AssetDetailsValues>;\n onSubmit: () => void;\n pending: boolean;\n error: unknown;\n readOnly: boolean;\n};\n\n/** File name, alt text, caption and (images) focal point; saved together. */\nexport const MetadataForm = ({ asset, form, onSubmit, pending, error, readOnly }: MetadataFormProps) => {\n const { t } = useTranslation();\n const focal = useController({ control: form.control, name: 'focalPoint' });\n const image = isImage(asset.mimeType);\n return (\n <form\n noValidate\n aria-label={t('media.details.formLabel')}\n onSubmit={(event) => {\n event.preventDefault();\n onSubmit();\n }}\n >\n <fieldset disabled={readOnly} className=\"contents\">\n <FieldGroup>\n <FormTextField\n control={form.control}\n name=\"filename\"\n label={t('media.fields.filename')}\n autoComplete=\"off\"\n />\n {image ? (\n <FormTextareaField\n control={form.control}\n name=\"alt\"\n label={t('media.fields.alt')}\n rows={2}\n placeholder={t('media.details.altHint')}\n />\n ) : null}\n {image && !readOnly ? (\n <SuggestAltButton\n assetId={asset.id}\n mimeType={asset.mimeType}\n onSuggest={(alt) => form.setValue('alt', alt, { shouldDirty: true, shouldValidate: true })}\n />\n ) : null}\n <FormTextareaField\n control={form.control}\n name=\"caption\"\n label={t('media.fields.caption')}\n rows={2}\n />\n {image && !readOnly ? (\n <FocalPoint\n imageUrl={asset.url}\n value={focal.field.value}\n onChange={(value) => focal.field.onChange(value)}\n />\n ) : null}\n <FormError error={error} />\n {readOnly ? null : (\n <div className=\"flex justify-end\">\n <SubmitButton\n pending={pending}\n pendingLabel={t('common.saving')}\n disabled={!form.formState.isDirty}\n >\n {t('common.saveChanges')}\n </SubmitButton>\n </div>\n )}\n </FieldGroup>\n </fieldset>\n </form>\n );\n};\n","import type { MediaAsset } from '@shapio/client';\nimport { ExternalLink } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { Button } from '@/components/ui/button';\nimport { FileIcon } from '../../FileIcon';\nimport { isImage } from '../../helpers/fileKind';\n\ntype PreviewProps = { asset: MediaAsset };\n\n/** The widest ready variant up to 1280 px, else the original. */\nconst previewImageUrl = (asset: MediaAsset): string =>\n asset.variants.find((variant) => variant.name === 'w1280' && variant.url)?.url ??\n asset.variants.find((variant) => variant.name === 'w640' && variant.url)?.url ??\n asset.url;\n\n/** Images, video and audio play inline; other files show their type and an Open link. */\nexport const Preview = ({ asset }: PreviewProps) => {\n const { t } = useTranslation();\n if (isImage(asset.mimeType)) {\n return (\n <img\n src={previewImageUrl(asset)}\n alt={asset.alt || t('media.details.previewOf', { name: asset.filename })}\n className=\"max-h-72 w-full rounded-lg border bg-muted object-contain\"\n />\n );\n }\n if (asset.mimeType.startsWith('video/')) {\n return (\n <video\n src={asset.url}\n controls\n preload=\"metadata\"\n className=\"max-h-72 w-full rounded-lg border bg-muted\"\n />\n );\n }\n if (asset.mimeType.startsWith('audio/')) {\n return <audio src={asset.url} controls preload=\"metadata\" className=\"w-full\" />;\n }\n return (\n <div className=\"flex flex-col items-center gap-3 rounded-lg border bg-muted px-4 py-8\">\n <FileIcon mimeType={asset.mimeType} className=\"size-10 text-muted-foreground\" />\n <Button asChild variant=\"outline\" size=\"sm\">\n <a href={asset.url} target=\"_blank\" rel=\"noopener noreferrer\">\n <ExternalLink aria-hidden=\"true\" />\n {t('media.details.openFile')}\n </a>\n </Button>\n </div>\n );\n};\n","import type { ReactNode } from 'react';\n\ntype SectionProps = { title: string; children: ReactNode };\n\n/** A titled block of the details sheet. */\nexport const Section = ({ title, children }: SectionProps) => (\n <section className=\"space-y-3\">\n <h3 className=\"text-sm font-semibold\">{title}</h3>\n {children}\n </section>\n);\n","import type { MediaUsage } from '@shapio/client';\nimport type { ModelDefinition } from '@shapio/schema';\nimport { Link } from '@tanstack/react-router';\nimport { useTranslation } from 'react-i18next';\nimport { RowTitle } from '@/components/RowTitle';\nimport { StatusChip } from '@/components/StatusChip';\nimport { Badge } from '@/components/ui/badge';\nimport { entryLink } from '@/features/Inbox/helpers/entryLink';\n\ntype RowProps = {\n usage: MediaUsage;\n /** The entry's model, when the admin may read it; without it the entry is named but not linked. */\n model: ModelDefinition | undefined;\n};\n\n/** One entry version using the asset: its title linking to the entry in that locale, the type, locale and state. */\nexport const Row = ({ usage, model }: RowProps) => {\n const { t } = useTranslation();\n return (\n <li className=\"flex min-w-0 items-center gap-2 px-3 py-2\">\n <div className=\"min-w-0 flex-1 space-y-0.5\">\n {model ? (\n <>\n <RowTitle asChild className=\"block truncate text-sm\">\n <Link {...entryLink(model.apiKey, usage.entryId, model.kind, { locale: usage.locale })}>\n {usage.title ?? t('content.untitled')}\n </Link>\n </RowTitle>\n <p className=\"truncate text-meta text-muted-foreground\">{model.label}</p>\n </>\n ) : (\n <p className=\"truncate text-sm text-muted-foreground\">{t('media.usage.hidden')}</p>\n )}\n </div>\n <Badge variant=\"outline\" className=\"font-mono\">\n {usage.locale}\n </Badge>\n <StatusChip\n size=\"sm\"\n tone={usage.state === 'published' ? 'success' : 'neutral'}\n label={usage.state === 'published' ? t('media.usage.published') : t('media.usage.draft')}\n />\n </li>\n );\n};\n","import { useTranslation } from 'react-i18next';\nimport { useMediaUsage } from '@/api/media';\nimport { ErrorState } from '@/components/ErrorState';\nimport { Skeleton } from '@/components/ui/skeleton';\nimport { useContentSchema } from '@/features/Content/hooks/useContentSchema';\nimport { Row } from './Row';\n\ntype UsageProps = { assetId: string };\n\n/** \"Used in\": the entries whose draft or published version references the asset, by title and type. */\nexport const Usage = ({ assetId }: UsageProps) => {\n const { t } = useTranslation();\n const usage = useMediaUsage(assetId);\n const { schema } = useContentSchema();\n if (usage.isPending) {\n return <Skeleton className=\"h-8 w-full\" />;\n }\n if (usage.isError) {\n return <ErrorState error={usage.error} onRetry={() => void usage.refetch()} />;\n }\n if (usage.data.total === 0) {\n return <p className=\"text-sm text-muted-foreground\">{t('media.usage.none')}</p>;\n }\n return (\n <div className=\"space-y-2\">\n <p className=\"text-sm\">{t('media.usage.count', { count: usage.data.total })}</p>\n <ul className=\"divide-y rounded-lg border\">\n {usage.data.items.map((item) => (\n <Row\n key={`${item.entryId}:${item.fieldId}:${item.locale}:${item.state}`}\n usage={item}\n model={schema?.models.get(item.modelId)}\n />\n ))}\n </ul>\n </div>\n );\n};\n","import type { MediaAsset } from '@shapio/client';\nimport { Globe, Lock } from 'lucide-react';\nimport { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { toast } from 'sonner';\nimport { useUpdateMediaAsset } from '@/api/media';\nimport { InlineConfirm } from '@/components/InlineConfirm';\nimport { Field, FieldContent, FieldDescription, FieldLabel } from '@/components/ui/field';\nimport { Switch } from '@/components/ui/switch';\n\ntype VisibilityProps = { asset: MediaAsset; canManage: boolean };\n\n/**\n * Public files have a stable URL anyone can open; private files only open through signed links that\n * expire. One line says what the current setting means. Changing it needs `media.manage` and is confirmed\n * beside the switch, because it changes who can see the file.\n */\nexport const Visibility = ({ asset, canManage }: VisibilityProps) => {\n const { t } = useTranslation();\n const update = useUpdateMediaAsset();\n const [confirming, setConfirming] = useState(false);\n const isPrivate = asset.visibility === 'private';\n const next = isPrivate ? 'public' : 'private';\n const consequence = isPrivate\n ? t('media.visibility.privateExplanation')\n : t('media.visibility.publicExplanation');\n return (\n <Field orientation=\"horizontal\">\n <FieldContent>\n <div className=\"flex items-center gap-1.5\">\n {isPrivate ? (\n <Lock aria-hidden=\"true\" className=\"size-4 text-muted-foreground\" />\n ) : (\n <Globe aria-hidden=\"true\" className=\"size-4 text-muted-foreground\" />\n )}\n <FieldLabel htmlFor=\"asset-private\">{t('media.visibility.privateLabel')}</FieldLabel>\n </div>\n <FieldDescription id=\"asset-private-description\">\n {canManage ? consequence : `${consequence} ${t('media.visibility.needsManage')}`}\n </FieldDescription>\n </FieldContent>\n <InlineConfirm\n tone={next === 'public' ? 'danger' : 'default'}\n open={confirming}\n onOpenChange={setConfirming}\n title={\n next === 'private' ? t('media.visibility.makePrivateTitle') : t('media.visibility.makePublicTitle')\n }\n description={\n next === 'private'\n ? t('media.visibility.makePrivateDescription')\n : t('media.visibility.makePublicDescription')\n }\n confirmLabel={\n next === 'private' ? t('media.visibility.makePrivate') : t('media.visibility.makePublic')\n }\n onConfirm={() =>\n update\n .mutateAsync({ id: asset.id, input: { expectedVersion: asset.version, visibility: next } })\n .then(() => toast.success(t('media.visibility.changed')))\n }\n >\n <Switch\n id=\"asset-private\"\n checked={isPrivate}\n disabled={!canManage || update.isPending}\n aria-describedby=\"asset-private-description\"\n onCheckedChange={() => setConfirming(true)}\n />\n </InlineConfirm>\n </Field>\n );\n};\n","import { AlertTriangle } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { useMediaAsset } from '@/api/media';\nimport { CopyButton } from '@/components/CopyButton';\nimport { ErrorState } from '@/components/ErrorState';\nimport { LoadingState } from '@/components/LoadingState';\nimport { StatusChip } from '@/components/StatusChip';\nimport { Alert, AlertDescription } from '@/components/ui/alert';\nimport {\n Sheet,\n SheetBody,\n SheetContent,\n SheetDescription,\n SheetFooter,\n SheetHeader,\n SheetTitle,\n} from '@/components/ui/sheet';\nimport { useDiscardGuard } from '@/hooks/useDiscardGuard';\nimport { useMediaPermissions } from '@/hooks/useMediaPermissions';\nimport { fileKindLabel } from '../helpers/fileKind';\nimport { formatBytes } from '../helpers/formatBytes';\nimport { MEDIA_STATUS_DISPLAY } from '../helpers/statusDisplay';\nimport { useAssetDetailsForm } from '../hooks/useAssetDetailsForm';\nimport { UploadButton } from '../UploadButton';\nimport { DeleteAction } from './DeleteAction';\nimport { MetadataForm } from './MetadataForm';\nimport { Preview } from './Preview';\nimport { Section } from './Section';\nimport { Usage } from './Usage';\nimport { Variants } from './Variants';\nimport { Visibility } from './Visibility';\n\ntype DetailsProps = {\n assetId: string | undefined;\n onClose: () => void;\n onReplace: (assetId: string, file: File) => void;\n};\n\n/** One asset: preview, metadata, focal point, visibility, variants, \"used in\", replace and delete. */\nexport const Details = ({ assetId, onClose, onReplace }: DetailsProps) => {\n const { t } = useTranslation();\n const query = useMediaAsset(assetId);\n const asset = query.data;\n const { canWrite, canManage } = useMediaPermissions();\n const details = useAssetDetailsForm(asset);\n const { requestOpenChange, discardPrompt } = useDiscardGuard({\n dirty: details.form.formState.isDirty,\n pending: details.pending,\n onOpenChange: (open) => {\n if (!open) {\n details.form.reset();\n onClose();\n }\n },\n });\n const status = asset ? MEDIA_STATUS_DISPLAY[asset.status] : undefined;\n return (\n <>\n <Sheet open={assetId !== undefined} onOpenChange={requestOpenChange}>\n <SheetContent size=\"sm\">\n <SheetHeader>\n <SheetTitle className=\"pr-8 break-all\">{asset?.filename ?? t('media.details.title')}</SheetTitle>\n <SheetDescription className=\"text-meta\">\n {asset\n ? [\n fileKindLabel(asset.filename, asset.mimeType),\n formatBytes(asset.sizeBytes),\n asset.width && asset.height\n ? t('media.dimensions', { width: asset.width, height: asset.height })\n : '',\n ]\n .filter(Boolean)\n .join(' · ')\n : t('common.loading')}\n </SheetDescription>\n {asset && status ? (\n // In the fixed header, not the scrolling body: the focus trap wraps here without scrolling.\n <div className=\"flex flex-wrap items-center gap-2 pt-1\">\n <StatusChip tone={status.tone} label={t(status.labelKey)} />\n {asset.visibility === 'private' ? (\n <StatusChip tone=\"muted\" label={t('media.visibility.private')} />\n ) : null}\n <span className=\"ml-auto\">\n <CopyButton value={asset.url} />\n </span>\n </div>\n ) : null}\n </SheetHeader>\n <SheetBody className=\"space-y-6\">\n {query.isPending ? <LoadingState rows={3} /> : null}\n {query.isError ? <ErrorState error={query.error} onRetry={() => void query.refetch()} /> : null}\n {asset && status ? (\n <>\n <div className=\"space-y-3\">\n <Preview asset={asset} />\n {asset.urlExpiresAt ? (\n <p className=\"text-meta text-muted-foreground\">{t('media.details.signedLinkNote')}</p>\n ) : null}\n {asset.processingError ? (\n <Alert variant=\"destructive\">\n <AlertTriangle aria-hidden=\"true\" />\n <AlertDescription>{asset.processingError}</AlertDescription>\n </Alert>\n ) : null}\n </div>\n <Section title={t('media.details.metadata')}>\n <MetadataForm\n asset={asset}\n form={details.form}\n onSubmit={() => void details.onSubmit()}\n pending={details.pending}\n error={details.error}\n readOnly={!canWrite}\n />\n </Section>\n <Section title={t('media.usage.title')}>\n <Usage assetId={asset.id} />\n </Section>\n <Section title={t('media.visibility.title')}>\n <Visibility asset={asset} canManage={canManage} />\n </Section>\n <Section title={t('media.variants.title')}>\n <Variants asset={asset} />\n </Section>\n </>\n ) : null}\n </SheetBody>\n {asset && (canWrite || canManage) ? (\n <SheetFooter className=\"flex-row flex-wrap justify-between\">\n {canManage ? <DeleteAction asset={asset} onDeleted={onClose} /> : null}\n {canWrite ? (\n <UploadButton\n variant=\"outline\"\n multiple={false}\n label={t('media.details.replace')}\n onFiles={([file]) => (file ? onReplace(asset.id, file) : undefined)}\n className=\"ml-auto\"\n />\n ) : null}\n </SheetFooter>\n ) : null}\n </SheetContent>\n </Sheet>\n {discardPrompt}\n </>\n );\n};\n","import { Upload } from 'lucide-react';\nimport { useRef, useState, type DragEvent, type ReactNode } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { cn } from '@/helpers/cn';\n\ntype DropzoneProps = {\n enabled: boolean;\n onFiles: (files: File[]) => void;\n children: ReactNode;\n className?: string;\n};\n\nconst hasFiles = (event: DragEvent) => event.dataTransfer.types.includes('Files');\n\n/**\n * Drop files anywhere over the library to upload them. A pointer shortcut only: the Upload button is the\n * keyboard and screen-reader path, so the overlay is hidden from assistive technology.\n */\nexport const Dropzone = ({ enabled, onFiles, children, className }: DropzoneProps) => {\n const { t } = useTranslation();\n const [dragging, setDragging] = useState(false);\n const depth = useRef(0);\n if (!enabled) {\n return <div className={className}>{children}</div>;\n }\n return (\n <div\n className={cn('relative', className)}\n onDragEnter={(event) => {\n if (hasFiles(event)) {\n depth.current += 1;\n setDragging(true);\n }\n }}\n onDragLeave={() => {\n depth.current = Math.max(0, depth.current - 1);\n if (depth.current === 0) {\n setDragging(false);\n }\n }}\n onDragOver={(event) => {\n if (hasFiles(event)) {\n event.preventDefault();\n event.dataTransfer.dropEffect = 'copy';\n }\n }}\n onDrop={(event) => {\n event.preventDefault();\n depth.current = 0;\n setDragging(false);\n const files = [...event.dataTransfer.files];\n if (files.length > 0) {\n onFiles(files);\n }\n }}\n >\n {children}\n {dragging ? (\n <div\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-0 z-20 flex flex-col items-center justify-center gap-2 rounded-xl border-2 border-dashed border-primary bg-background/90 text-primary\"\n >\n <Upload className=\"size-8\" />\n <p className=\"font-semibold\">{t('media.upload.dropHere')}</p>\n </div>\n ) : null}\n </div>\n );\n};\n","import type { MediaFolder } from '@shapio/client';\n\nexport type FolderNode = MediaFolder & { children: FolderNode[]; depth: number };\n\n/** Builds the folder tree from the flat list, siblings sorted by name. Orphans (parent missing) go to the root. */\nexport const buildFolderTree = (folders: readonly MediaFolder[]): FolderNode[] => {\n const byParent = Map.groupBy(folders, (folder) =>\n folder.parentId && folders.some((candidate) => candidate.id === folder.parentId) ? folder.parentId : null,\n );\n const build = (parentId: string | null, depth: number): FolderNode[] =>\n [...(byParent.get(parentId) ?? [])]\n .sort((a, b) => a.name.localeCompare(b.name))\n .map((folder) => ({ ...folder, depth, children: build(folder.id, depth + 1) }));\n return build(null, 0);\n};\n\n/** Depth-first: every folder with its depth, for pickers that show the tree as an indented list. */\nexport const flattenFolderTree = (nodes: readonly FolderNode[]): FolderNode[] =>\n nodes.flatMap((node) => [node, ...flattenFolderTree(node.children)]);\n\n/** The folder and everything under it (a folder cannot move into these). */\nexport const descendantIds = (folders: readonly MediaFolder[], id: string): Set<string> => {\n const result = new Set([id]);\n let grew = true;\n while (grew) {\n grew = false;\n for (const folder of folders) {\n if (folder.parentId && result.has(folder.parentId) && !result.has(folder.id)) {\n result.add(folder.id);\n grew = true;\n }\n }\n }\n return result;\n};\n","import { zodResolver } from '@hookform/resolvers/zod';\nimport type { MediaFolder } from '@shapio/client';\nimport { useForm } from 'react-hook-form';\nimport { toast } from 'sonner';\nimport { z } from 'zod';\nimport { useCreateMediaFolder, useUpdateMediaFolder } from '@/api/media';\nimport { i18next } from '@/app/i18n';\nimport { settle } from '@/helpers/settle';\nimport { requiredText } from '@/helpers/validation';\n\nconst MAX_NAME_LENGTH = 255;\n\nconst folderSchema = z.object({ name: requiredText().max(MAX_NAME_LENGTH, 'validation.tooLong') });\n\nexport type FolderValues = z.infer<typeof folderSchema>;\n\n/** What the inline folder row edits: a new folder (under `parentId`) or the name of `folder`. */\nexport type FolderEdit =\n { mode: 'create'; parentId: string | null } | { mode: 'rename'; folder: MediaFolder };\n\n/** The inline folder row's form: creates a folder or renames one, then calls `onDone`. */\nexport const useFolderForm = (edit: FolderEdit, onDone: () => void) => {\n const createFolder = useCreateMediaFolder();\n const updateFolder = useUpdateMediaFolder();\n const initialName = edit.mode === 'rename' ? edit.folder.name : '';\n const form = useForm<FolderValues>({\n resolver: zodResolver(folderSchema),\n defaultValues: { name: initialName },\n });\n const onSubmit = form.handleSubmit(async ({ name }) => {\n const trimmed = name.trim();\n if (edit.mode === 'rename' && trimmed === edit.folder.name) {\n onDone();\n return;\n }\n const result = await settle(\n edit.mode === 'rename'\n ? updateFolder.mutateAsync({\n id: edit.folder.id,\n input: { expectedVersion: edit.folder.version, name: trimmed },\n })\n : createFolder.mutateAsync({ name: trimmed, parentId: edit.parentId }),\n );\n if (result.ok) {\n toast.success(\n i18next.t(edit.mode === 'rename' ? 'media.folders.renamed' : 'media.folders.created', {\n name: trimmed,\n }),\n );\n onDone();\n }\n });\n const mutation = edit.mode === 'rename' ? updateFolder : createFolder;\n return { form, onSubmit, initialName, pending: mutation.isPending, error: mutation.error };\n};\n","import { Check, FolderPlus, Loader2, Pencil, X } from 'lucide-react';\nimport { useEffect, useId, type FocusEvent, type KeyboardEvent } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { FormFieldError } from '@/components/FormFieldError';\nimport { Button } from '@/components/ui/button';\nimport { Input } from '@/components/ui/input';\nimport { describeError } from '@/helpers/describeError';\nimport { useFolderForm, type FolderEdit } from '../../hooks/useFolderForm';\n\ntype EditRowProps = {\n edit: FolderEdit;\n /** `returnFocus`: false when focus already left the row (a click elsewhere), so it isn't pulled back. */\n onDone: (returnFocus: boolean) => void;\n};\n\n/**\n * A folder name being typed in place, in the tree (the caller's list item): a new folder or a rename. Enter saves, Escape cancels;\n * leaving the row without changing anything cancels too.\n */\nexport const EditRow = ({ edit, onDone }: EditRowProps) => {\n const { t } = useTranslation();\n const errorId = useId();\n const { form, onSubmit, initialName, pending, error } = useFolderForm(edit, () => onDone(true));\n const { setFocus } = form;\n useEffect(() => {\n setFocus('name', { shouldSelect: true });\n }, [setFocus]);\n const fieldError = form.formState.errors.name?.message;\n const message = fieldError ?? (error ? describeError(error) : undefined);\n const creating = edit.mode === 'create';\n const cancelOnEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && !pending) {\n event.preventDefault();\n event.stopPropagation();\n onDone(true);\n }\n };\n const cancelWhenLeftUnchanged = (event: FocusEvent<HTMLFormElement>) => {\n const next = event.relatedTarget;\n if (next instanceof Node && event.currentTarget.contains(next)) {\n return;\n }\n if (!pending && form.getValues('name').trim() === initialName) {\n onDone(false);\n }\n };\n return (\n <div>\n <form\n noValidate\n onSubmit={(event) => void onSubmit(event)}\n onKeyDown={cancelOnEscape}\n onBlur={cancelWhenLeftUnchanged}\n className=\"flex items-center gap-1 py-0.5 pl-1\"\n >\n {creating ? (\n <FolderPlus aria-hidden=\"true\" className=\"size-4 shrink-0 text-muted-foreground\" />\n ) : (\n <Pencil aria-hidden=\"true\" className=\"size-4 shrink-0 text-muted-foreground\" />\n )}\n <Input\n {...form.register('name')}\n inputSize=\"sm\"\n autoComplete=\"off\"\n spellCheck={false}\n readOnly={pending}\n aria-label={\n creating ? t('media.folders.newName') : t('media.folders.renameLabel', { name: edit.folder.name })\n }\n aria-invalid={message ? true : undefined}\n aria-describedby={message ? errorId : undefined}\n className=\"h-8 px-2\"\n />\n <Button\n type=\"submit\"\n variant=\"ghost\"\n size=\"icon-xs\"\n disabled={pending}\n aria-label={creating ? t('media.folders.create') : t('media.folders.saveName')}\n >\n {pending ? <Loader2 aria-hidden=\"true\" className=\"animate-spin\" /> : <Check aria-hidden=\"true\" />}\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n disabled={pending}\n aria-label={t('common.cancel')}\n onClick={() => onDone(true)}\n >\n <X aria-hidden=\"true\" />\n </Button>\n </form>\n <div className=\"pl-6\">\n <FormFieldError id={errorId} message={message} />\n </div>\n </div>\n );\n};\n","/** A 36px folder-rail row: muted until hovered, accent pill while it is the current scope. */\nexport const FOLDER_ROW_CLASSES =\n 'flex h-9 min-w-0 items-center gap-2.5 rounded-lg text-left text-sm font-medium text-muted-foreground outline-none hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-[current=true]:bg-accent aria-[current=true]:font-semibold aria-[current=true]:text-accent-foreground [&_svg]:size-4 [&_svg]:shrink-0';\n","import type { MediaFolder } from '@shapio/client';\nimport { FolderPlus, MoreHorizontal, Pencil, Trash2 } from 'lucide-react';\nimport { useRef } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { InlineConfirm } from '@/components/InlineConfirm';\nimport { Button } from '@/components/ui/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu';\n\nexport type FolderActions = {\n onCreate: (parentId: string | null) => void;\n onRename: (folder: MediaFolder) => void;\n /** The folder whose delete confirmation is open. */\n deletingId: string | undefined;\n onDeleteOpenChange: (folder: MediaFolder, open: boolean) => void;\n onDelete: (folder: MediaFolder) => Promise<unknown>;\n};\n\ntype MenuProps = { folder: MediaFolder; canManage: boolean; actions: FolderActions };\n\n/**\n * A folder's \"…\" menu: new subfolder and rename (an inline row takes focus), delete (confirmed in a popover\n * anchored to this button).\n */\nexport const Menu = ({ folder, canManage, actions }: MenuProps) => {\n const { t } = useTranslation();\n // A menu item hands focus to the inline row or the delete confirmation instead of the menu button.\n const handingOff = useRef(false);\n const handOff = (action: () => void) => () => {\n handingOff.current = true;\n action();\n };\n return (\n <DropdownMenu>\n <InlineConfirm\n tone=\"danger\"\n open={actions.deletingId === folder.id}\n onOpenChange={(open) => actions.onDeleteOpenChange(folder, open)}\n title={t('media.folders.deleteTitle', { name: folder.name })}\n description={t('media.folders.deleteDescription')}\n confirmLabel={t('common.delete')}\n onConfirm={() => actions.onDelete(folder)}\n >\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon-xs\"\n aria-label={t('media.folders.actions', { name: folder.name })}\n className=\"absolute right-1.5\"\n data-folder-menu={folder.id}\n >\n <MoreHorizontal aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n </InlineConfirm>\n <DropdownMenuContent\n align=\"end\"\n onCloseAutoFocus={(event) => {\n if (handingOff.current) {\n handingOff.current = false;\n event.preventDefault();\n }\n }}\n >\n <DropdownMenuItem onSelect={handOff(() => actions.onCreate(folder.id))}>\n <FolderPlus aria-hidden=\"true\" />\n {t('media.folders.newSubfolder')}\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={handOff(() => actions.onRename(folder))}>\n <Pencil aria-hidden=\"true\" />\n {t('media.folders.rename')}\n </DropdownMenuItem>\n {canManage ? (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n variant=\"destructive\"\n onSelect={handOff(() => actions.onDeleteOpenChange(folder, true))}\n >\n <Trash2 aria-hidden=\"true\" />\n {t('common.delete')}\n </DropdownMenuItem>\n </>\n ) : null}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n};\n","import { Folder, FolderOpen } from 'lucide-react';\nimport { cn } from '@/helpers/cn';\nimport type { FolderNode } from '../../helpers/folderTree';\nimport type { FolderEdit } from '../../hooks/useFolderForm';\nimport { FOLDER_ROW_CLASSES } from '../constants';\nimport { EditRow } from '../EditRow';\nimport { Menu, type FolderActions } from '../Menu';\n\ntype ItemProps = {\n node: FolderNode;\n currentId: string | undefined;\n canWrite: boolean;\n canManage: boolean;\n actions: FolderActions;\n /** The inline row being edited anywhere in the tree. */\n editing: FolderEdit | undefined;\n onEditDone: (returnFocus: boolean) => void;\n onSelect: (id: string) => void;\n};\n\n/** A folder (button + actions menu, or its name being edited) and its subfolders, as a nested list. */\nexport const Item = ({\n node,\n currentId,\n canWrite,\n canManage,\n actions,\n editing,\n onEditDone,\n onSelect,\n}: ItemProps) => {\n const current = node.id === currentId;\n const Icon = current ? FolderOpen : Folder;\n const renameEdit = editing?.mode === 'rename' && editing.folder.id === node.id ? editing : undefined;\n const childEdit = editing?.mode === 'create' && editing.parentId === node.id ? editing : undefined;\n return (\n <li>\n {renameEdit ? (\n <EditRow edit={renameEdit} onDone={onEditDone} />\n ) : (\n <div className=\"relative flex items-center\">\n <button\n type=\"button\"\n aria-current={current ? 'true' : undefined}\n onClick={() => onSelect(node.id)}\n className={cn(FOLDER_ROW_CLASSES, 'flex-1 pl-2.5', canWrite ? 'pr-9' : 'pr-2.5')}\n >\n <Icon aria-hidden=\"true\" />\n <span className=\"truncate\">{node.name}</span>\n <span className=\"ml-auto text-xs font-medium text-muted-foreground tabular-nums\">\n {node.assetCount}\n </span>\n </button>\n {canWrite ? <Menu folder={node} canManage={canManage} actions={actions} /> : null}\n </div>\n )}\n {node.children.length > 0 || childEdit ? (\n <ul className=\"mt-0.5 ml-4 space-y-0.5 border-l pl-1.5\">\n {childEdit ? (\n <li>\n <EditRow edit={childEdit} onDone={onEditDone} />\n </li>\n ) : null}\n {node.children.map((child) => (\n <Item\n key={child.id}\n node={child}\n currentId={currentId}\n canWrite={canWrite}\n canManage={canManage}\n actions={actions}\n editing={editing}\n onEditDone={onEditDone}\n onSelect={onSelect}\n />\n ))}\n </ul>\n ) : null}\n </li>\n );\n};\n","import type { ReactNode } from 'react';\nimport { cn } from '@/helpers/cn';\nimport { FOLDER_ROW_CLASSES } from '../constants';\n\ntype ScopeButtonProps = { current: boolean; icon: ReactNode; label: string; onClick: () => void };\n\n/** \"All media\" and \"Not in a folder\": scopes above the folder list. */\nexport const ScopeButton = ({ current, icon, label, onClick }: ScopeButtonProps) => (\n <button\n type=\"button\"\n aria-current={current ? 'true' : undefined}\n onClick={onClick}\n className={cn(FOLDER_ROW_CLASSES, 'w-full px-2.5')}\n >\n {icon}\n <span className=\"truncate\">{label}</span>\n </button>\n);\n","import type { MediaFolder } from '@shapio/client';\nimport { Images, Inbox } from 'lucide-react';\nimport { useMemo } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Panel } from '@/components/Panel';\nimport { Skeleton } from '@/components/ui/skeleton';\nimport { ROOT_FOLDER } from '../constants';\nimport { buildFolderTree } from '../helpers/folderTree';\nimport type { FolderEdit } from '../hooks/useFolderForm';\nimport { EditRow } from './EditRow';\nimport { Item } from './Item';\nimport type { FolderActions } from './Menu';\nimport { ScopeButton } from './ScopeButton';\n\ntype FolderTreeProps = {\n folders: readonly MediaFolder[] | undefined;\n /** A folder ID, `root`, or undefined for every folder. */\n current: string | undefined;\n canWrite: boolean;\n canManage: boolean;\n actions: FolderActions;\n /** The folder name being typed in place (a new folder or a rename), if any. */\n editing: FolderEdit | undefined;\n onEditDone: (returnFocus: boolean) => void;\n onSelect: (folder: string | undefined) => void;\n className?: string;\n};\n\n/**\n * The folder rail: \"All media\", \"Not in a folder\", then every folder with rename / new subfolder / delete.\n * New top-level folders come from the page header; new and renamed folders are named in place.\n */\nexport const FolderTree = ({\n folders,\n current,\n canWrite,\n canManage,\n actions,\n editing,\n onEditDone,\n onSelect,\n className,\n}: FolderTreeProps) => {\n const { t } = useTranslation();\n const tree = useMemo(() => buildFolderTree(folders ?? []), [folders]);\n const topLevelEdit = editing?.mode === 'create' && editing.parentId === null ? editing : undefined;\n return (\n <Panel title={t('media.folders.title')} flush className={className} bodyClassName=\"p-2\">\n <nav aria-label={t('media.folders.title')} className=\"space-y-1\">\n <ul className=\"space-y-0.5\">\n <li>\n <ScopeButton\n current={current === undefined}\n icon={<Images aria-hidden=\"true\" />}\n label={t('media.folders.all')}\n onClick={() => onSelect(undefined)}\n />\n </li>\n <li>\n <ScopeButton\n current={current === ROOT_FOLDER}\n icon={<Inbox aria-hidden=\"true\" />}\n label={t('media.folders.unfiled')}\n onClick={() => onSelect(ROOT_FOLDER)}\n />\n </li>\n </ul>\n {folders === undefined ? (\n <Skeleton className=\"h-8 w-full\" />\n ) : tree.length > 0 || topLevelEdit ? (\n <ul className=\"space-y-0.5 border-t pt-1\">\n {topLevelEdit ? (\n <li>\n <EditRow edit={topLevelEdit} onDone={onEditDone} />\n </li>\n ) : null}\n {tree.map((node) => (\n <Item\n key={node.id}\n node={node}\n currentId={current}\n canWrite={canWrite}\n canManage={canManage}\n actions={actions}\n editing={editing}\n onEditDone={onEditDone}\n onSelect={onSelect}\n />\n ))}\n </ul>\n ) : null}\n </nav>\n </Panel>\n );\n};\n","import { useCallback, useState } from 'react';\n\n/** The assets ticked for bulk actions. */\nexport const useAssetSelection = () => {\n const [selected, setSelected] = useState<ReadonlySet<string>>(new Set());\n const toggle = useCallback(\n (id: string, checked: boolean) =>\n setSelected((current) => {\n const next = new Set(current);\n if (checked) {\n next.add(id);\n } else {\n next.delete(id);\n }\n return next;\n }),\n [],\n );\n const clear = useCallback(() => setSelected(new Set()), []);\n return { selected, toggle, clear };\n};\n","import type { MediaFolder } from '@shapio/client';\nimport { useState } from 'react';\nimport { toast } from 'sonner';\nimport { useDeleteMediaFolder } from '@/api/media';\nimport { i18next } from '@/app/i18n';\nimport type { FolderActions } from '../FolderTree/Menu';\nimport type { FolderEdit } from './useFolderForm';\n\n/**\n * Where focus returns after an inline folder row: the page header's \"New folder\" button (`data-new-folder`)\n * for a top-level folder, otherwise the folder's actions button (`data-folder-menu` = its ID).\n */\nconst openerOf = (edit: FolderEdit): HTMLElement | null => {\n const id = edit.mode === 'rename' ? edit.folder.id : edit.parentId;\n const selector = id === null ? '[data-new-folder]' : `[data-folder-menu=\"${CSS.escape(id)}\"]`;\n return document.querySelector<HTMLElement>(selector);\n};\n\n/**\n * Create, rename and delete folders: the inline row being edited (create/rename happen in the tree, not a\n * dialog) and the folder whose delete confirmation is open.\n */\nexport const useFolderActions = (onDeleted: (folder: MediaFolder) => void) => {\n const [editing, setEditing] = useState<FolderEdit | undefined>(undefined);\n const [deletingId, setDeletingId] = useState<string | undefined>(undefined);\n const deleteFolder = useDeleteMediaFolder();\n const actions: FolderActions = {\n onCreate: (parentId) => setEditing({ mode: 'create', parentId }),\n onRename: (folder) => setEditing({ mode: 'rename', folder }),\n deletingId,\n onDeleteOpenChange: (folder, open) => setDeletingId(open ? folder.id : undefined),\n onDelete: (folder) =>\n deleteFolder.mutateAsync(folder.id).then(() => {\n toast.success(i18next.t('media.folders.deleted', { name: folder.name }));\n onDeleted(folder);\n }),\n };\n return {\n actions,\n editing,\n /**\n * Closes the inline row. With `returnFocus`, focus goes back to what opened it (the header button or\n * the folder's actions button) once the tree has re-rendered; not when focus already moved elsewhere.\n */\n stopEditing: (returnFocus: boolean) => {\n const edit = editing;\n setEditing(undefined);\n if (edit && returnFocus) {\n requestAnimationFrame(() => openerOf(edit)?.focus());\n }\n },\n };\n};\n","import { useNavigate, useSearch } from '@tanstack/react-router';\nimport type { MediaSearch } from '@/app/searchSchemas';\nimport { MIME_FILTER_BY_TYPE } from '../constants';\n\n/** Folder, filters, view and the open asset live in the URL (bookmarkable, back-button friendly). */\nexport const useMediaSearch = () => {\n const search = useSearch({ from: '/app/media' });\n const navigate = useNavigate({ from: '/media' });\n const setSearch = (changes: Partial<MediaSearch>, replace = false) =>\n void navigate({ search: (previous) => ({ ...previous, ...changes }), replace });\n return {\n search,\n setSearch,\n /** The API query for the current folder and filters. */\n assetQuery: {\n ...(search.folder ? { folder: search.folder } : {}),\n ...(search.q ? { search: search.q } : {}),\n ...(search.type ? { mimeType: MIME_FILTER_BY_TYPE[search.type] } : {}),\n },\n };\n};\n","import type { KeyboardEvent } from 'react';\n\n/**\n * Up/Down (and Home/End) move focus between the enabled buttons inside `event.currentTarget`, for short\n * pick lists where Tab alone would be slow.\n */\nexport const moveFocusWithArrows = (event: KeyboardEvent<HTMLElement>) => {\n const keys = ['ArrowDown', 'ArrowUp', 'Home', 'End'];\n if (!keys.includes(event.key)) {\n return;\n }\n const buttons = [...event.currentTarget.querySelectorAll<HTMLButtonElement>('button:not(:disabled)')];\n if (buttons.length === 0) {\n return;\n }\n event.preventDefault();\n const index = buttons.findIndex((button) => button === document.activeElement);\n const last = buttons.length - 1;\n const next =\n event.key === 'Home'\n ? 0\n : event.key === 'End'\n ? last\n : event.key === 'ArrowDown'\n ? Math.min(index + 1, last)\n : Math.max(index - 1, 0);\n buttons[next]?.focus();\n};\n","import { useState } from 'react';\nimport { toast } from 'sonner';\nimport { useMoveMediaAssets } from '@/api/media';\nimport { i18next } from '@/app/i18n';\nimport { settle } from '@/helpers/settle';\n\n/** The move target while a move runs: a folder ID, or null for \"no folder\". */\ntype MoveTarget = string | null;\n\n/** Moves assets into a folder (or out of every folder) and reports it; `onMoved` runs on success. */\nexport const useMoveToFolder = (assetIds: readonly string[], onMoved: () => void) => {\n const move = useMoveMediaAssets();\n const [target, setTarget] = useState<MoveTarget | undefined>(undefined);\n return {\n /** The folder being moved into while the request runs. */\n target: move.isPending ? target : undefined,\n pending: move.isPending,\n error: move.error,\n reset: move.reset,\n moveTo: async (folderId: MoveTarget) => {\n setTarget(folderId);\n const result = await settle(move.mutateAsync({ assetIds: [...assetIds], folderId }));\n if (result.ok) {\n toast.success(i18next.t('media.move.done', { count: result.value.moved.length }));\n onMoved();\n }\n },\n };\n};\n","import { Loader2 } from 'lucide-react';\nimport type { CSSProperties, ReactNode } from 'react';\nimport { cn } from '@/helpers/cn';\nimport { FOLDER_ROW_CLASSES } from '../../FolderTree/constants';\n\ntype ChoiceProps = {\n icon: ReactNode;\n label: string;\n /** Nesting level, indents the row (a runtime value, passed as a CSS variable). */\n depth: number;\n pending: boolean;\n disabled: boolean;\n onClick: () => void;\n};\n\n/** One folder in the move popover, indented by its depth; a spinner while the move into it runs. */\nexport const Choice = ({ icon, label, depth, pending, disabled, onClick }: ChoiceProps) => (\n <li>\n <button\n type=\"button\"\n disabled={disabled}\n aria-busy={pending || undefined}\n onClick={onClick}\n style={{ '--depth': depth } as CSSProperties}\n className={cn(\n FOLDER_ROW_CLASSES,\n 'w-full pr-2.5 pl-[calc(0.625rem+var(--depth)*1rem)] disabled:opacity-50',\n )}\n >\n {pending ? <Loader2 aria-hidden=\"true\" className=\"animate-spin\" /> : icon}\n <span className=\"truncate\">{label}</span>\n </button>\n </li>\n);\n","import { Folder, FolderInput, Inbox } from 'lucide-react';\nimport { useId, useMemo, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useMediaFolders } from '@/api/media';\nimport { FormError } from '@/components/FormError';\nimport { Button } from '@/components/ui/button';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';\nimport { Skeleton } from '@/components/ui/skeleton';\nimport { moveFocusWithArrows } from '../helpers/arrowFocus';\nimport { buildFolderTree, flattenFolderTree } from '../helpers/folderTree';\nimport { useMoveToFolder } from '../hooks/useMoveToFolder';\nimport { Choice } from './Choice';\n\ntype MovePopoverProps = { assetIds: readonly string[]; onMoved: () => void };\n\n/**\n * \"Move to…\" for the selected files: a popover with the folder tree; choosing a folder moves them at once.\n * Up and Down move through the folders.\n */\nexport const MovePopover = ({ assetIds, onMoved }: MovePopoverProps) => {\n const { t } = useTranslation();\n const titleId = useId();\n const [open, setOpen] = useState(false);\n const folders = useMediaFolders();\n const choices = useMemo(() => flattenFolderTree(buildFolderTree(folders.data ?? [])), [folders.data]);\n const move = useMoveToFolder(assetIds, () => {\n setOpen(false);\n onMoved();\n });\n const changeOpen = (next: boolean) => {\n if (move.pending) {\n return;\n }\n if (next) {\n move.reset();\n }\n setOpen(next);\n };\n return (\n <Popover open={open} onOpenChange={changeOpen} modal>\n <PopoverTrigger asChild>\n <Button size=\"sm\" variant=\"outline\">\n <FolderInput aria-hidden=\"true\" />\n {t('media.move.action')}\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" aria-labelledby={titleId} className=\"w-72 space-y-2 p-2\">\n <p id={titleId} className=\"px-2.5 pt-1 text-sm font-semibold\">\n {t('media.move.title', { count: assetIds.length })}\n </p>\n <ul className=\"max-h-72 space-y-0.5 overflow-y-auto\" onKeyDown={moveFocusWithArrows}>\n <Choice\n icon={<Inbox aria-hidden=\"true\" />}\n label={t('media.folders.none')}\n depth={0}\n pending={move.target === null}\n disabled={move.pending}\n onClick={() => void move.moveTo(null)}\n />\n {choices.map((folder) => (\n <Choice\n key={folder.id}\n icon={<Folder aria-hidden=\"true\" />}\n label={folder.name}\n depth={folder.depth}\n pending={move.target === folder.id}\n disabled={move.pending}\n onClick={() => void move.moveTo(folder.id)}\n />\n ))}\n </ul>\n {folders.isPending ? <Skeleton className=\"h-8 w-full\" /> : null}\n <FormError error={move.error} />\n </PopoverContent>\n </Popover>\n );\n};\n","import { X } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { Button } from '@/components/ui/button';\nimport { MovePopover } from '../MovePopover';\n\ntype SelectionBarProps = { selected: ReadonlySet<string>; onClear: () => void };\n\n/** Bulk actions for the ticked assets. Announced when the selection changes. */\nexport const SelectionBar = ({ selected, onClear }: SelectionBarProps) => {\n const { t } = useTranslation();\n return (\n <div className=\"flex flex-wrap items-center gap-2 rounded-xl border bg-accent py-1.5 pr-1.5 pl-4 text-accent-foreground\">\n <span role=\"status\" aria-live=\"polite\" className=\"mr-auto text-sm font-medium\">\n {t('media.selectedCount', { count: selected.size })}\n </span>\n <MovePopover assetIds={[...selected]} onMoved={onClear} />\n <Button size=\"sm\" variant=\"ghost\" onClick={onClear}>\n <X aria-hidden=\"true\" />\n {t('media.clearSelection')}\n </Button>\n </div>\n );\n};\n","import { FolderPlus } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { useMediaFolders } from '@/api/media';\nimport { Page } from '@/components/Page';\nimport { PageHeader } from '@/components/PageHeader';\nimport { Button } from '@/components/ui/button';\nimport { useMediaPermissions } from '@/hooks/useMediaPermissions';\nimport { useMediaUploader } from '@/hooks/useMediaUploader';\nimport { ROOT_FOLDER } from './constants';\nimport { Details } from './Details';\nimport { Dropzone } from './Dropzone';\nimport { FolderTree } from './FolderTree';\nimport { useAssetSelection } from './hooks/useAssetSelection';\nimport { useFolderActions } from './hooks/useFolderActions';\nimport { useMediaSearch } from './hooks/useMediaSearch';\nimport { Library } from './Library';\nimport { SelectionBar } from './SelectionBar';\nimport { Toolbar } from './Toolbar';\nimport { UploadButton } from './UploadButton';\nimport { UploadQueue } from './UploadQueue';\n\n/** The media library: folders, search and filters, uploads (drop or pick), bulk move and asset details. Folders are created and renamed in place. */\nexport const Media = () => {\n const { t } = useTranslation();\n const { search, setSearch, assetQuery } = useMediaSearch();\n const folders = useMediaFolders();\n const { canWrite, canManage } = useMediaPermissions();\n const uploader = useMediaUploader();\n const selection = useAssetSelection();\n const folderActions = useFolderActions((folder) => {\n if (search.folder === folder.id) {\n setSearch({ folder: undefined });\n }\n });\n const uploadFolder = search.folder && search.folder !== ROOT_FOLDER ? search.folder : null;\n const upload = (files: File[]) => uploader.enqueue(files, { folderId: uploadFolder, visibility: 'public' });\n return (\n <Page width=\"full\">\n <PageHeader\n title={t('media.title')}\n actions={\n canWrite ? (\n <>\n <Button variant=\"outline\" data-new-folder onClick={() => folderActions.actions.onCreate(null)}>\n <FolderPlus aria-hidden=\"true\" />\n {t('media.folders.new')}\n </Button>\n <UploadButton label={t('media.upload.action')} onFiles={upload} />\n </>\n ) : null\n }\n />\n <div className=\"grid gap-6 lg:grid-cols-[13.75rem_minmax(0,1fr)]\">\n <FolderTree\n folders={folders.data}\n current={search.folder}\n canWrite={canWrite}\n canManage={canManage}\n actions={folderActions.actions}\n editing={folderActions.editing}\n onEditDone={folderActions.stopEditing}\n onSelect={(folder) => {\n selection.clear();\n setSearch({ folder });\n }}\n className=\"lg:self-start\"\n />\n <Dropzone enabled={canWrite} onFiles={upload} className=\"min-h-96 min-w-0 space-y-4\">\n <UploadQueue onRetry={uploader.retry} onDismiss={uploader.dismiss} />\n <Toolbar\n query={search.q}\n type={search.type}\n view={search.view ?? 'grid'}\n onQueryChange={(q) => setSearch({ q }, true)}\n onTypeChange={(type) => setSearch({ type })}\n onViewChange={(view) => setSearch({ view })}\n />\n {selection.selected.size > 0 ? (\n <SelectionBar selected={selection.selected} onClear={selection.clear} />\n ) : null}\n <Library\n query={assetQuery}\n filtered={Boolean(search.q || search.type)}\n view={search.view ?? 'grid'}\n selected={selection.selected}\n selectable={canWrite}\n activeId={search.asset}\n onSelectChange={selection.toggle}\n onOpen={(asset) => setSearch({ asset: asset.id })}\n />\n </Dropzone>\n </div>\n <Details\n assetId={search.asset}\n onClose={() => setSearch({ asset: undefined })}\n onReplace={(assetId, file) =>\n uploader.enqueue([file], { folderId: null, visibility: 'public', replaceAssetId: assetId })\n }\n />\n </Page>\n );\n};\n","import { createLazyRoute } from '@tanstack/react-router';\nimport { Media } from '@/features/Media';\n\n/** The media library, loaded on first visit. */\nexport const mediaLazyRoute = createLazyRoute('/app/media')({ component: Media });\n"],"ignoreList":[0,1,2],"mappings":"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"}
|