@shapio/cms 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/assets/{AssistError-hVUWpP3F.js → AssistError-BITJ_tpg.js} +2 -2
- package/dist/admin/assets/{AssistError-hVUWpP3F.js.map → AssistError-BITJ_tpg.js.map} +1 -1
- package/dist/admin/assets/{BlockMenuItems-B0g93m6M.js → BlockMenuItems-CcluK965.js} +2 -2
- package/dist/admin/assets/{BlockMenuItems-B0g93m6M.js.map → BlockMenuItems-CcluK965.js.map} +1 -1
- package/dist/admin/assets/Body-BXa9DhtH.js +2 -0
- package/dist/admin/assets/{Body-CFQKONK4.js.map → Body-BXa9DhtH.js.map} +1 -1
- package/dist/admin/assets/Builder-DcpRfXuc.js +2 -0
- package/dist/admin/assets/Builder-DcpRfXuc.js.map +1 -0
- package/dist/admin/assets/{ConfirmDialog-D6rs75TP.js → ConfirmDialog-B9nWhIIz.js} +2 -2
- package/dist/admin/assets/{ConfirmDialog-D6rs75TP.js.map → ConfirmDialog-B9nWhIIz.js.map} +1 -1
- package/dist/admin/assets/{CopyButton-Bc7crFDE.js → CopyButton-BoWb-xi1.js} +2 -2
- package/dist/admin/assets/{CopyButton-Bc7crFDE.js.map → CopyButton-BoWb-xi1.js.map} +1 -1
- package/dist/admin/assets/{CursorPager-BFPD_adV.js → CursorPager-BnxmTk47.js} +2 -2
- package/dist/admin/assets/{CursorPager-BFPD_adV.js.map → CursorPager-BnxmTk47.js.map} +1 -1
- package/dist/admin/assets/{ExternalLink-Cdfcyyed.js → ExternalLink-Eeb9mONJ.js} +2 -2
- package/dist/admin/assets/{ExternalLink-Cdfcyyed.js.map → ExternalLink-Eeb9mONJ.js.map} +1 -1
- package/dist/admin/assets/Form-DZRLD3vH.js +2 -0
- package/dist/admin/assets/Form-DZRLD3vH.js.map +1 -0
- package/dist/admin/assets/{FormCheckboxGroup-Bicl1CBP.js → FormCheckboxGroup-uIC2XQIL.js} +2 -2
- package/dist/admin/assets/{FormCheckboxGroup-Bicl1CBP.js.map → FormCheckboxGroup-uIC2XQIL.js.map} +1 -1
- package/dist/admin/assets/{FormRadioGroup-34iVSV4L.js → FormRadioGroup-hd95vPOu.js} +2 -2
- package/dist/admin/assets/{FormRadioGroup-34iVSV4L.js.map → FormRadioGroup-hd95vPOu.js.map} +1 -1
- package/dist/admin/assets/{FormSelectField-Ba4fIu-8.js → FormSelectField-D7VHmnx5.js} +2 -2
- package/dist/admin/assets/{FormSelectField-Ba4fIu-8.js.map → FormSelectField-D7VHmnx5.js.map} +1 -1
- package/dist/admin/assets/{FormSwitchField-DN6bfPC0.js → FormSwitchField-ft8Jbe6E.js} +2 -2
- package/dist/admin/assets/{FormSwitchField-DN6bfPC0.js.map → FormSwitchField-ft8Jbe6E.js.map} +1 -1
- package/dist/admin/assets/{FormTextareaField-WsNjLm32.js → FormTextareaField-DzyOzfZb.js} +2 -2
- package/dist/admin/assets/{FormTextareaField-WsNjLm32.js.map → FormTextareaField-DzyOzfZb.js.map} +1 -1
- package/dist/admin/assets/{HintedLabel-jKLM0ETt.js → HintedLabel-CvC46uy_.js} +2 -2
- package/dist/admin/assets/{HintedLabel-jKLM0ETt.js.map → HintedLabel-CvC46uy_.js.map} +1 -1
- package/dist/admin/assets/{InfoHint-DBqcrmZ3.js → InfoHint-GJLRVumb.js} +2 -2
- package/dist/admin/assets/{InfoHint-DBqcrmZ3.js.map → InfoHint-GJLRVumb.js.map} +1 -1
- package/dist/admin/assets/{InsertMenuItem-CRKXblK5.js → InsertMenuItem-D976G0Rj.js} +2 -2
- package/dist/admin/assets/{InsertMenuItem-CRKXblK5.js.map → InsertMenuItem-D976G0Rj.js.map} +1 -1
- package/dist/admin/assets/LinkTabs-BZSlA57U.js +2 -0
- package/dist/admin/assets/{LinkTabs-Bn2JVqOL.js.map → LinkTabs-BZSlA57U.js.map} +1 -1
- package/dist/admin/assets/Match-DdxTHHM4.js +2 -0
- package/dist/admin/assets/{Match-DaYgKrk7.js.map → Match-DdxTHHM4.js.map} +1 -1
- package/dist/admin/assets/{Panel-6wFe96Gr.js → Panel-iIKjEURi.js} +2 -2
- package/dist/admin/assets/{Panel-6wFe96Gr.js.map → Panel-iIKjEURi.js.map} +1 -1
- package/dist/admin/assets/{QueryView-DFZtm0fn.js → QueryView-D6aZQJRN.js} +2 -2
- package/dist/admin/assets/{QueryView-DFZtm0fn.js.map → QueryView-D6aZQJRN.js.map} +1 -1
- package/dist/admin/assets/{RadioTile-DsTyz7ml.js → RadioTile-BpB79rIK.js} +2 -2
- package/dist/admin/assets/{RadioTile-DsTyz7ml.js.map → RadioTile-BpB79rIK.js.map} +1 -1
- package/dist/admin/assets/{RichTextField-BGkH403g.js → RichTextField-BuHCONPu.js} +2 -2
- package/dist/admin/assets/{RichTextField-BGkH403g.js.map → RichTextField-BuHCONPu.js.map} +1 -1
- package/dist/admin/assets/{RowTitle-sFt6NjO4.js → RowTitle--uFCpx8n.js} +2 -2
- package/dist/admin/assets/{RowTitle-sFt6NjO4.js.map → RowTitle--uFCpx8n.js.map} +1 -1
- package/dist/admin/assets/{SecretReveal-Z6MOFdcL.js → SecretReveal-DFpzeNE0.js} +2 -2
- package/dist/admin/assets/{SecretReveal-Z6MOFdcL.js.map → SecretReveal-DFpzeNE0.js.map} +1 -1
- package/dist/admin/assets/SharedGlyph-Cqkx30tn.js +2 -0
- package/dist/admin/assets/SharedGlyph-Cqkx30tn.js.map +1 -0
- package/dist/admin/assets/{StepList-BTP_EMzx.js → StepList-BY5MuJPJ.js} +2 -2
- package/dist/admin/assets/{StepList-BTP_EMzx.js.map → StepList-BY5MuJPJ.js.map} +1 -1
- package/dist/admin/assets/Structure-CqRa2t7z.js +2 -0
- package/dist/admin/assets/{Structure-D5-hCUuF.js.map → Structure-CqRa2t7z.js.map} +1 -1
- package/dist/admin/assets/SubNavLink-B2o4kSZ9.js +2 -0
- package/dist/admin/assets/{SubNavLink-C5oN5mzB.js.map → SubNavLink-B2o4kSZ9.js.map} +1 -1
- package/dist/admin/assets/{SuggestAltButton-BuN35BBL.js → SuggestAltButton-4rf2xhEJ.js} +2 -2
- package/dist/admin/assets/{SuggestAltButton-BuN35BBL.js.map → SuggestAltButton-4rf2xhEJ.js.map} +1 -1
- package/dist/admin/assets/TextLink-D15oyXlc.js +2 -0
- package/dist/admin/assets/{TextLink-B4a6j3r6.js.map → TextLink-D15oyXlc.js.map} +1 -1
- package/dist/admin/assets/{Thumbnail-u8NE5NhQ.js → Thumbnail-CP5mfgNY.js} +2 -2
- package/dist/admin/assets/{Thumbnail-u8NE5NhQ.js.map → Thumbnail-CP5mfgNY.js.map} +1 -1
- package/dist/admin/assets/UnsavedChangesGuard-DgOASh0p.js +2 -0
- package/dist/admin/assets/{UnsavedChangesGuard-BYwMTDsE.js.map → UnsavedChangesGuard-DgOASh0p.js.map} +1 -1
- package/dist/admin/assets/{UserAvatar-D-yX0ozh.js → UserAvatar-BocvNVL-.js} +2 -2
- package/dist/admin/assets/{UserAvatar-D-yX0ozh.js.map → UserAvatar-BocvNVL-.js.map} +1 -1
- package/dist/admin/assets/{arrow-up-Ws7W9KsZ.js → arrow-up-gf_j6SVQ.js} +2 -2
- package/dist/admin/assets/{arrow-up-Ws7W9KsZ.js.map → arrow-up-gf_j6SVQ.js.map} +1 -1
- package/dist/admin/assets/auth-pcS9CCXu.js +2 -0
- package/dist/admin/assets/auth-pcS9CCXu.js.map +1 -0
- package/dist/admin/assets/badge-DD0mE96i.js +2 -0
- package/dist/admin/assets/{badge-CMox6-v3.js.map → badge-DD0mE96i.js.map} +1 -1
- package/dist/admin/assets/boxes-DcK-kaSa.js +2 -0
- package/dist/admin/assets/boxes-DcK-kaSa.js.map +1 -0
- package/dist/admin/assets/{calendar-clock-9W0Lkt89.js → calendar-clock-DEwACe0M.js} +2 -2
- package/dist/admin/assets/{calendar-clock-9W0Lkt89.js.map → calendar-clock-DEwACe0M.js.map} +1 -1
- package/dist/admin/assets/{changeSets-CO7JdILW.js → changeSets-BjUEfYbj.js} +2 -2
- package/dist/admin/assets/{changeSets-CO7JdILW.js.map → changeSets-BjUEfYbj.js.map} +1 -1
- package/dist/admin/assets/chevron-left-BsQYDUEC.js +2 -0
- package/dist/admin/assets/{chevron-left-DyqYjcMB.js.map → chevron-left-BsQYDUEC.js.map} +1 -1
- package/dist/admin/assets/{circle-check-aJ2DW5t4.js → circle-check-Dq1owihe.js} +2 -2
- package/dist/admin/assets/{circle-check-aJ2DW5t4.js.map → circle-check-Dq1owihe.js.map} +1 -1
- package/dist/admin/assets/{circle-x-BnRBht9z.js → circle-x-Dx6zIZko.js} +2 -2
- package/dist/admin/assets/{circle-x-BnRBht9z.js.map → circle-x-Dx6zIZko.js.map} +1 -1
- package/dist/admin/assets/{clock-DRtFQbTs.js → clock-DQvkffqQ.js} +2 -2
- package/dist/admin/assets/{clock-DRtFQbTs.js.map → clock-DQvkffqQ.js.map} +1 -1
- package/dist/admin/assets/cn-BQ3voEft.js +2 -0
- package/dist/admin/assets/cn-BQ3voEft.js.map +1 -0
- package/dist/admin/assets/coerce-OsqQRj19.js +2 -0
- package/dist/admin/assets/{coerce-COM3rk1i.js.map → coerce-OsqQRj19.js.map} +1 -1
- package/dist/admin/assets/constants-SrImR6C3.js +2 -0
- package/dist/admin/assets/constants-SrImR6C3.js.map +1 -0
- package/dist/admin/assets/content-_SLbbnfX.js +3 -0
- package/dist/admin/assets/content-_SLbbnfX.js.map +1 -0
- package/dist/admin/assets/{contentCounts-Ct0tYgHD.js → contentCounts-Ch3uMXVU.js} +2 -2
- package/dist/admin/assets/{contentCounts-Ct0tYgHD.js.map → contentCounts-Ch3uMXVU.js.map} +1 -1
- package/dist/admin/assets/contentTypes-BCOdUK_Z.js +2 -0
- package/dist/admin/assets/contentTypes-BCOdUK_Z.js.map +1 -0
- package/dist/admin/assets/{copy-B5B8RjV0.js → copy-BDc3r0fO.js} +2 -2
- package/dist/admin/assets/{copy-B5B8RjV0.js.map → copy-BDc3r0fO.js.map} +1 -1
- package/dist/admin/assets/{dateTimeLocal-BuBv3it2.js → dateTimeLocal-C92tyKwz.js} +2 -2
- package/dist/admin/assets/{dateTimeLocal-BuBv3it2.js.map → dateTimeLocal-C92tyKwz.js.map} +1 -1
- package/dist/admin/assets/develop-DS9TlDmv.js +11 -0
- package/dist/admin/assets/develop-DS9TlDmv.js.map +1 -0
- package/dist/admin/assets/{dropdown-menu-CW3fabv5.js → dropdown-menu-gmP2Rp3n.js} +2 -2
- package/dist/admin/assets/{dropdown-menu-CW3fabv5.js.map → dropdown-menu-gmP2Rp3n.js.map} +1 -1
- package/dist/admin/assets/{ellipsis-DNdmromA.js → ellipsis-NK0pWgqU.js} +2 -2
- package/dist/admin/assets/{ellipsis-DNdmromA.js.map → ellipsis-NK0pWgqU.js.map} +1 -1
- package/dist/admin/assets/{external-link-YnuWXDBk.js → external-link-D3Aoi2yX.js} +2 -2
- package/dist/admin/assets/{external-link-YnuWXDBk.js.map → external-link-D3Aoi2yX.js.map} +1 -1
- package/dist/admin/assets/{file-text-CB7Bc0GA.js → file-text-DxXAmmxL.js} +2 -2
- package/dist/admin/assets/{file-text-CB7Bc0GA.js.map → file-text-DxXAmmxL.js.map} +1 -1
- package/dist/admin/assets/fileRoute-C2tOrKhO.js +2 -0
- package/dist/admin/assets/{fileRoute-BYwireXG.js.map → fileRoute-C2tOrKhO.js.map} +1 -1
- package/dist/admin/assets/followPlural-CN6cQfNk.js +2 -0
- package/dist/admin/assets/followPlural-CN6cQfNk.js.map +1 -0
- package/dist/admin/assets/{globe-Bvs3UC3V.js → globe-CuElSilX.js} +2 -2
- package/dist/admin/assets/{globe-Bvs3UC3V.js.map → globe-CuElSilX.js.map} +1 -1
- package/dist/admin/assets/{image-CeoxwJeM.js → image-CsH8dZve.js} +2 -2
- package/dist/admin/assets/{image-CeoxwJeM.js.map → image-CsH8dZve.js.map} +1 -1
- package/dist/admin/assets/{image-off-iVqYw2Zc.js → image-off-B_uBCsYu.js} +2 -2
- package/dist/admin/assets/{image-off-iVqYw2Zc.js.map → image-off-B_uBCsYu.js.map} +1 -1
- package/dist/admin/assets/{inbox-DYbEOpaQ.js → inbox-3iAHL3pC.js} +2 -2
- package/dist/admin/assets/{inbox-DYbEOpaQ.js.map → inbox-3iAHL3pC.js.map} +1 -1
- package/dist/admin/assets/inbox-DsuXNaKE.js +2 -0
- package/dist/admin/assets/{inbox-wDoqym--.js.map → inbox-DsuXNaKE.js.map} +1 -1
- package/dist/admin/assets/index-BSzXA60W.js +4 -0
- package/dist/admin/assets/index-BSzXA60W.js.map +1 -0
- package/dist/admin/assets/{key-round-Bcw6qqcb.js → key-round-B17HiT3K.js} +2 -2
- package/dist/admin/assets/{key-round-Bcw6qqcb.js.map → key-round-B17HiT3K.js.map} +1 -1
- package/dist/admin/assets/link-2-off-hWGS8LW6.js +2 -0
- package/dist/admin/assets/link-2-off-hWGS8LW6.js.map +1 -0
- package/dist/admin/assets/{link-CKr_uUfb.js → link-bhHmG4Tc.js} +2 -2
- package/dist/admin/assets/{link-CKr_uUfb.js.map → link-bhHmG4Tc.js.map} +1 -1
- package/dist/admin/assets/{list-BElvKZw_.js → list-DRtRdjBC.js} +2 -2
- package/dist/admin/assets/{list-BElvKZw_.js.map → list-DRtRdjBC.js.map} +1 -1
- package/dist/admin/assets/{locales-Bnv3qcdZ.js → locales-BzPbz8FF.js} +2 -2
- package/dist/admin/assets/{locales-Bnv3qcdZ.js.map → locales-BzPbz8FF.js.map} +1 -1
- package/dist/admin/assets/media-WLnWaL7U.js +2 -0
- package/dist/admin/assets/{media-DjK3xGFN.js.map → media-WLnWaL7U.js.map} +1 -1
- package/dist/admin/assets/{media-BfDqe_2P.js → media-Xzot1ueY.js} +2 -2
- package/dist/admin/assets/{media-BfDqe_2P.js.map → media-Xzot1ueY.js.map} +1 -1
- package/dist/admin/assets/network-DHGqLwji.js +2 -0
- package/dist/admin/assets/network-DHGqLwji.js.map +1 -0
- package/dist/admin/assets/{pencil-Zd05MDs2.js → pencil-Bdp2z9D_.js} +2 -2
- package/dist/admin/assets/{pencil-Zd05MDs2.js.map → pencil-Bdp2z9D_.js.map} +1 -1
- package/dist/admin/assets/{plus-B0gd63Da.js → plus-BN_iSsnp.js} +2 -2
- package/dist/admin/assets/{plus-B0gd63Da.js.map → plus-BN_iSsnp.js.map} +1 -1
- package/dist/admin/assets/{preload-helper-CJKHb_rG.js → preload-helper-DAbCfXID.js} +2 -2
- package/dist/admin/assets/{preload-helper-CJKHb_rG.js.map → preload-helper-DAbCfXID.js.map} +1 -1
- package/dist/admin/assets/publishing-d9yhMwgA.js +2 -0
- package/dist/admin/assets/{publishing-vCVjaSGF.js.map → publishing-d9yhMwgA.js.map} +1 -1
- package/dist/admin/assets/{radio-group-DVR0mTpo.js → radio-group-DHIxK-IU.js} +2 -2
- package/dist/admin/assets/{radio-group-DVR0mTpo.js.map → radio-group-DHIxK-IU.js.map} +1 -1
- package/dist/admin/assets/{rotate-ccw-BOTDOdHf.js → rotate-ccw-CBoZle-b.js} +2 -2
- package/dist/admin/assets/{rotate-ccw-BOTDOdHf.js.map → rotate-ccw-CBoZle-b.js.map} +1 -1
- package/dist/admin/assets/{schedules-CG-ZphRK.js → schedules-Dy89Nm6P.js} +2 -2
- package/dist/admin/assets/{schedules-CG-ZphRK.js.map → schedules-Dy89Nm6P.js.map} +1 -1
- package/dist/admin/assets/schema-B4smPFcR.js +2 -0
- package/dist/admin/assets/schema-B4smPFcR.js.map +1 -0
- package/dist/admin/assets/{scroll-text-D-gHqYwR.js → scroll-text-UbyzpWh-.js} +2 -2
- package/dist/admin/assets/{scroll-text-D-gHqYwR.js.map → scroll-text-UbyzpWh-.js.map} +1 -1
- package/dist/admin/assets/{search-BcPL1qyc.js → search-_YlNpPvU.js} +2 -2
- package/dist/admin/assets/{search-BcPL1qyc.js.map → search-_YlNpPvU.js.map} +1 -1
- package/dist/admin/assets/searchSchema-CvOhn4FV.js +2 -0
- package/dist/admin/assets/{searchSchema-BGrRDBL_.js.map → searchSchema-CvOhn4FV.js.map} +1 -1
- package/dist/admin/assets/searchSchemas-BxRnxenn.js +2 -0
- package/dist/admin/assets/searchSchemas-BxRnxenn.js.map +1 -0
- package/dist/admin/assets/{sections-i9TeeK-h.js → sections-Bb3Q4bcY.js} +2 -2
- package/dist/admin/assets/{sections-i9TeeK-h.js.map → sections-Bb3Q4bcY.js.map} +1 -1
- package/dist/admin/assets/{sections-BrGcWOnw.js → sections-DiySZZHb.js} +2 -2
- package/dist/admin/assets/{sections-BrGcWOnw.js.map → sections-DiySZZHb.js.map} +1 -1
- package/dist/admin/assets/{select--nGB4WjU.js → select-tHVWX85X.js} +2 -2
- package/dist/admin/assets/{select--nGB4WjU.js.map → select-tHVWX85X.js.map} +1 -1
- package/dist/admin/assets/{send-Bu3RRfdI.js → send-BqECHYi6.js} +2 -2
- package/dist/admin/assets/{send-Bu3RRfdI.js.map → send-BqECHYi6.js.map} +1 -1
- package/dist/admin/assets/settings-D-v8gL8F.js +2 -0
- package/dist/admin/assets/settings-D-v8gL8F.js.map +1 -0
- package/dist/admin/assets/skeleton-C3QLIh7W.js +42 -0
- package/dist/admin/assets/skeleton-C3QLIh7W.js.map +1 -0
- package/dist/admin/assets/snapshots-BQrhsCmC.js +2 -0
- package/dist/admin/assets/{snapshots-CKjK-vkL.js.map → snapshots-BQrhsCmC.js.map} +1 -1
- package/dist/admin/assets/{sparkles-B_NX7PAY.js → sparkles-BW4CbD6W.js} +2 -2
- package/dist/admin/assets/{sparkles-B_NX7PAY.js.map → sparkles-BW4CbD6W.js.map} +1 -1
- package/dist/admin/assets/src-XaU0N8C-.js +4 -0
- package/dist/admin/assets/src-XaU0N8C-.js.map +1 -0
- package/dist/admin/assets/{stableId-Dmr2Afn_.js → stableId-C9Yq5iUw.js} +2 -2
- package/dist/admin/assets/{stableId-Dmr2Afn_.js.map → stableId-C9Yq5iUw.js.map} +1 -1
- package/dist/admin/assets/{store-B5xrQ1Ex.js → store-BphwUzV5.js} +2 -2
- package/dist/admin/assets/{store-B5xrQ1Ex.js.map → store-BphwUzV5.js.map} +1 -1
- package/dist/admin/assets/{switch-B-FbT-l8.js → switch-BVy02Vc8.js} +2 -2
- package/dist/admin/assets/{switch-B-FbT-l8.js.map → switch-BVy02Vc8.js.map} +1 -1
- package/dist/admin/assets/{table-DQzCPm7J.js → table-CZYtdoHn.js} +2 -2
- package/dist/admin/assets/{table-DQzCPm7J.js.map → table-CZYtdoHn.js.map} +1 -1
- package/dist/admin/assets/tabs-quHbeVxA.js +5 -0
- package/dist/admin/assets/{tabs-YThoOiE3.js.map → tabs-quHbeVxA.js.map} +1 -1
- package/dist/admin/assets/{textarea-_wcx8Mn1.js → textarea-B8Vl5gJ1.js} +2 -2
- package/dist/admin/assets/{textarea-_wcx8Mn1.js.map → textarea-B8Vl5gJ1.js.map} +1 -1
- package/dist/admin/assets/titles-B2z5ckxG.js +2 -0
- package/dist/admin/assets/{titles-DyCBLXue.js.map → titles-B2z5ckxG.js.map} +1 -1
- package/dist/admin/assets/{tokens-CqsxrApC.js → tokens-Fh_OeIlf.js} +2 -2
- package/dist/admin/assets/{tokens-CqsxrApC.js.map → tokens-Fh_OeIlf.js.map} +1 -1
- package/dist/admin/assets/{tooltip-BMe4HylJ.js → tooltip-DwqM3opE.js} +2 -2
- package/dist/admin/assets/{tooltip-BMe4HylJ.js.map → tooltip-DwqM3opE.js.map} +1 -1
- package/dist/admin/assets/{undo-2-DMOHOH6w.js → undo-2-D4Fz4JMZ.js} +2 -2
- package/dist/admin/assets/{undo-2-DMOHOH6w.js.map → undo-2-D4Fz4JMZ.js.map} +1 -1
- package/dist/admin/assets/{useAuditLabels-CSw_kwLs.js → useAuditLabels-DKrsrciQ.js} +2 -2
- package/dist/admin/assets/{useAuditLabels-CSw_kwLs.js.map → useAuditLabels-DKrsrciQ.js.map} +1 -1
- package/dist/admin/assets/useConfirmTarget-Dp8mCulm.js +2 -0
- package/dist/admin/assets/useConfirmTarget-Dp8mCulm.js.map +1 -0
- package/dist/admin/assets/{useContentSchema-CS5QQcRk.js → useContentSchema-Bv4_6VJR.js} +2 -2
- package/dist/admin/assets/{useContentSchema-CS5QQcRk.js.map → useContentSchema-Bv4_6VJR.js.map} +1 -1
- package/dist/admin/assets/{useCursorPager-Dt_axwd1.js → useCursorPager-B1upg5EU.js} +2 -2
- package/dist/admin/assets/{useCursorPager-Dt_axwd1.js.map → useCursorPager-B1upg5EU.js.map} +1 -1
- package/dist/admin/assets/{useDiscardGuard-7rRGpd4q.js → useDiscardGuard-34ynGJIk.js} +2 -2
- package/dist/admin/assets/{useDiscardGuard-7rRGpd4q.js.map → useDiscardGuard-34ynGJIk.js.map} +1 -1
- package/dist/admin/assets/{useMediaUploader-CBUcNW6d.js → useMediaUploader-QXSjZStv.js} +2 -2
- package/dist/admin/assets/{useMediaUploader-CBUcNW6d.js.map → useMediaUploader-QXSjZStv.js.map} +1 -1
- package/dist/admin/assets/{usePaletteItems-bbTIqpPu.js → usePaletteItems-62-TZhy7.js} +2 -2
- package/dist/admin/assets/{usePaletteItems-bbTIqpPu.js.map → usePaletteItems-62-TZhy7.js.map} +1 -1
- package/dist/admin/assets/usePlaces-CY6f2DmI.js +2 -0
- package/dist/admin/assets/usePlaces-CY6f2DmI.js.map +1 -0
- package/dist/admin/assets/{useQueries-DKGIdq6A.js → useQueries-BuKJBA0M.js} +2 -2
- package/dist/admin/assets/{useQueries-DKGIdq6A.js.map → useQueries-BuKJBA0M.js.map} +1 -1
- package/dist/admin/assets/useSchemaScopeAccess-DUBeS9kU.js +2 -0
- package/dist/admin/assets/useSchemaScopeAccess-DUBeS9kU.js.map +1 -0
- package/dist/admin/assets/{users-C1ZSee3N.js → users-BOn2ohJQ.js} +2 -2
- package/dist/admin/assets/{users-C1ZSee3N.js.map → users-BOn2ohJQ.js.map} +1 -1
- package/dist/admin/assets/{users-DMfQL0s4.js → users-BkKc4MNB.js} +2 -2
- package/dist/admin/assets/{users-DMfQL0s4.js.map → users-BkKc4MNB.js.map} +1 -1
- package/dist/admin/assets/{zod-Pf5A-ax4.js → zod-BHAd1wTC.js} +2 -2
- package/dist/admin/assets/{zod-Pf5A-ax4.js.map → zod-BHAd1wTC.js.map} +1 -1
- package/dist/admin/index.html +56 -55
- package/dist/cli.js +383 -163
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +1 -1
- package/dist/{public-CKU0Gkfq.d.ts → public-CGO8RBn3.d.ts} +10 -2
- package/dist/{worker-C-MSYr4l.js → worker-BLXy8aRW.js} +2307 -1220
- package/dist/worker-BLXy8aRW.js.map +1 -0
- package/package.json +5 -6
- package/dist/admin/assets/Body-CFQKONK4.js +0 -2
- package/dist/admin/assets/Builder-Do5KVHV9.js +0 -2
- package/dist/admin/assets/Builder-Do5KVHV9.js.map +0 -1
- package/dist/admin/assets/LinkTabs-Bn2JVqOL.js +0 -2
- package/dist/admin/assets/Match-DaYgKrk7.js +0 -2
- package/dist/admin/assets/Structure-D5-hCUuF.js +0 -2
- package/dist/admin/assets/SubNavLink-C5oN5mzB.js +0 -2
- package/dist/admin/assets/TextLink-B4a6j3r6.js +0 -2
- package/dist/admin/assets/UnsavedChangesGuard-BYwMTDsE.js +0 -2
- package/dist/admin/assets/auth-b3_9QbtL.js +0 -2
- package/dist/admin/assets/auth-b3_9QbtL.js.map +0 -1
- package/dist/admin/assets/badge-CMox6-v3.js +0 -2
- package/dist/admin/assets/chevron-left-DyqYjcMB.js +0 -2
- package/dist/admin/assets/cn-DnXL75B0.js +0 -2
- package/dist/admin/assets/cn-DnXL75B0.js.map +0 -1
- package/dist/admin/assets/coerce-COM3rk1i.js +0 -2
- package/dist/admin/assets/constants-CS1ziZO0.js +0 -2
- package/dist/admin/assets/constants-CS1ziZO0.js.map +0 -1
- package/dist/admin/assets/content-Dic2fof_.js +0 -3
- package/dist/admin/assets/content-Dic2fof_.js.map +0 -1
- package/dist/admin/assets/contentTypes-D4_Ax9rb.js +0 -2
- package/dist/admin/assets/contentTypes-D4_Ax9rb.js.map +0 -1
- package/dist/admin/assets/develop-Brnb5YPC.js +0 -11
- package/dist/admin/assets/develop-Brnb5YPC.js.map +0 -1
- package/dist/admin/assets/errors-DfoXUVDI.js +0 -2
- package/dist/admin/assets/errors-DfoXUVDI.js.map +0 -1
- package/dist/admin/assets/fileRoute-BYwireXG.js +0 -2
- package/dist/admin/assets/inbox-wDoqym--.js +0 -2
- package/dist/admin/assets/index-57Mn6XLO.js +0 -4
- package/dist/admin/assets/index-57Mn6XLO.js.map +0 -1
- package/dist/admin/assets/link-2-DhM2vi4v.js +0 -2
- package/dist/admin/assets/link-2-DhM2vi4v.js.map +0 -1
- package/dist/admin/assets/link-2-off-DpDOMsa-.js +0 -2
- package/dist/admin/assets/link-2-off-DpDOMsa-.js.map +0 -1
- package/dist/admin/assets/media-DjK3xGFN.js +0 -2
- package/dist/admin/assets/network-CAJ76ILr.js +0 -2
- package/dist/admin/assets/network-CAJ76ILr.js.map +0 -1
- package/dist/admin/assets/publishing-vCVjaSGF.js +0 -2
- package/dist/admin/assets/schema-KXXSPVJn.js +0 -2
- package/dist/admin/assets/schema-KXXSPVJn.js.map +0 -1
- package/dist/admin/assets/searchSchema-BGrRDBL_.js +0 -2
- package/dist/admin/assets/searchSchemas-ChN9hhuQ.js +0 -2
- package/dist/admin/assets/searchSchemas-ChN9hhuQ.js.map +0 -1
- package/dist/admin/assets/settings-68BAxrPM.js +0 -2
- package/dist/admin/assets/settings-68BAxrPM.js.map +0 -1
- package/dist/admin/assets/skeleton-DUvclBAr.js +0 -42
- package/dist/admin/assets/skeleton-DUvclBAr.js.map +0 -1
- package/dist/admin/assets/snapshots-CKjK-vkL.js +0 -2
- package/dist/admin/assets/src-D6DABe5J.js +0 -4
- package/dist/admin/assets/src-D6DABe5J.js.map +0 -1
- package/dist/admin/assets/tabs-YThoOiE3.js +0 -5
- package/dist/admin/assets/titles-DyCBLXue.js +0 -2
- package/dist/admin/assets/useConfirmTarget-9JmfiY2X.js +0 -2
- package/dist/admin/assets/useConfirmTarget-9JmfiY2X.js.map +0 -1
- package/dist/admin/assets/usePlaces-D1raoQ2s.js +0 -2
- package/dist/admin/assets/usePlaces-D1raoQ2s.js.map +0 -1
- package/dist/worker-C-MSYr4l.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCursorPager-Dt_axwd1.js","names":["silent","useState","__toESM","useQuery","queryKeys","useMutation","useQueryClient","createLucideIcon","adminApi","withCsrf","keepPreviousData","PUBLISHING_POLL_INTERVAL_MS","ACTIVE_RUN_STATUSES","ACTIVE_DELIVERY_STATUSES","__iconData","Rocket","import_react","require_react","useResetOnOpen","open","reset","values","resetMutation","silent$1","pollWhileActive","active","useDeploymentConnections","query","connection","useDeploymentConnection","id","useDeploymentRuns","state","run","useDeploymentRun","useInvalidateDeployments","queryClient","useCreateDeploymentConnection","invalidate","input","useUpdateDeploymentConnection","useDeleteDeploymentConnection","useTestDeploymentConnection","useTriggerDeployment","useRetryDeploymentRun","PUBLICATION_ACTION_LABELS","PROVIDER_LABELS","TRIGGER_POLICY_LABELS","RUN_TRIGGER_LABELS","TIMELINE_SOURCE_LABELS","silent","useWebhooks","useWebhookEvents","useWebhook","useWebhookDeliveries","cursor","delivery","useInvalidateWebhooks","useCreateWebhook","useUpdateWebhook","webhook","useDeleteWebhook","useRotateWebhookSecret","useTestWebhook","useRedeliverWebhook","deliveryId","useCursorPager","previousCursors","setPreviousCursors","setCursor","cursors","nextCursor"],"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/rocket.mjs","../../src/features/Publishing/hooks/useResetOnOpen.ts","../../src/api/deployments.ts","../../src/features/Publishing/constants.ts","../../src/api/webhooks.ts","../../src/features/Publishing/hooks/useCursorPager.ts"],"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: \"rocket\",\n size: 24,\n node: [\n [\"path\", { d: \"M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5\", key: \"qeys4\" }],\n [\n \"path\",\n {\n d: \"M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09\",\n key: \"u4xsad\"\n }\n ],\n [\n \"path\",\n {\n d: \"M9 12a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.4 22.4 0 0 1-4 2z\",\n key: \"676m9\"\n }\n ],\n [\"path\", { d: \"M9 12H4s.55-3.03 2-4c1.62-1.08 5 .05 5 .05\", key: \"92ym6u\" }]\n ]\n};\n__iconData.node;\nconst Rocket = createLucideIcon(__iconData);\n\nexport { __iconData, Rocket as default };\n//# sourceMappingURL=rocket.mjs.map\n","import { useEffect } from 'react';\nimport type { FieldValues, UseFormReset } from 'react-hook-form';\n\n/**\n * A sheet or popover form starts clean every time it opens: default values, and no error left over from the last\n * attempt. `values` must be stable (a module constant or memoized).\n */\nexport const useResetOnOpen = <TValues extends FieldValues>(\n open: boolean,\n reset: UseFormReset<TValues>,\n values: TValues,\n resetMutation: () => void,\n) => {\n useEffect(() => {\n if (open) {\n reset(values);\n resetMutation();\n }\n }, [open, reset, values, resetMutation]);\n};\n","import type {\n CreateDeploymentConnectionInput,\n DeploymentConnection,\n DeploymentRunQuery,\n UpdateDeploymentConnectionInput,\n} from '@shapio/client';\nimport { keepPreviousData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { ACTIVE_RUN_STATUSES, PUBLISHING_POLL_INTERVAL_MS } from '@/constants/publishing';\nimport { adminApi } from './client';\nimport { withCsrf } from './csrf';\nimport { queryKeys } from './queryKeys';\n\nconst silent = { silent: true } as const;\n\n/** Polls while the latest runs are still in progress, so statuses move on screen without a reload. */\nconst pollWhileActive = (active: boolean) => (active ? PUBLISHING_POLL_INTERVAL_MS : false);\n\nexport const useDeploymentConnections = () =>\n useQuery({\n queryKey: queryKeys.publishing.deployments.connections,\n queryFn: () => adminApi.deployments.connections.list(),\n refetchInterval: (query) =>\n pollWhileActive(\n query.state.data?.some((connection) =>\n connection.latestRun ? ACTIVE_RUN_STATUSES.has(connection.latestRun.status) : false,\n ) ?? false,\n ),\n meta: silent,\n });\n\nexport const useDeploymentConnection = (id: string) =>\n useQuery({\n queryKey: queryKeys.publishing.deployments.connection(id),\n queryFn: () => adminApi.deployments.connections.get(id),\n refetchInterval: (query) =>\n pollWhileActive(\n query.state.data?.latestRun ? ACTIVE_RUN_STATUSES.has(query.state.data.latestRun.status) : false,\n ),\n meta: silent,\n });\n\nexport const useDeploymentRuns = (query: DeploymentRunQuery) =>\n useQuery({\n queryKey: queryKeys.publishing.deployments.runs(query),\n queryFn: () => adminApi.deployments.runs.list(query),\n placeholderData: keepPreviousData,\n refetchInterval: (state) =>\n pollWhileActive(state.state.data?.items.some((run) => ACTIVE_RUN_STATUSES.has(run.status)) ?? false),\n meta: silent,\n });\n\n/** One run, polled until it reaches a final state (deployed, failed or unknown). */\nexport const useDeploymentRun = (id: string) =>\n useQuery({\n queryKey: queryKeys.publishing.deployments.run(id),\n queryFn: () => adminApi.deployments.runs.get(id),\n refetchInterval: (query) =>\n pollWhileActive(query.state.data ? ACTIVE_RUN_STATUSES.has(query.state.data.status) : false),\n meta: silent,\n });\n\nconst useInvalidateDeployments = () => {\n const queryClient = useQueryClient();\n return () => queryClient.invalidateQueries({ queryKey: queryKeys.publishing.deployments.all });\n};\n\nexport const useCreateDeploymentConnection = () => {\n const invalidate = useInvalidateDeployments();\n return useMutation({\n mutationKey: ['deployments', 'create'],\n meta: silent,\n mutationFn: (input: CreateDeploymentConnectionInput) =>\n withCsrf(() => adminApi.deployments.connections.create(input)),\n onSuccess: invalidate,\n });\n};\n\n/** 409 when `expectedVersion` is stale: the caller reloads and tells the user. */\nexport const useUpdateDeploymentConnection = () => {\n const queryClient = useQueryClient();\n const invalidate = useInvalidateDeployments();\n return useMutation({\n mutationKey: ['deployments', 'update'],\n meta: silent,\n mutationFn: ({ id, input }: { id: string; input: UpdateDeploymentConnectionInput }) =>\n withCsrf(() => adminApi.deployments.connections.update(id, input)),\n onSuccess: (connection: DeploymentConnection) => {\n queryClient.setQueryData(queryKeys.publishing.deployments.connection(connection.id), connection);\n return invalidate();\n },\n });\n};\n\nexport const useDeleteDeploymentConnection = () => {\n const queryClient = useQueryClient();\n const invalidate = useInvalidateDeployments();\n return useMutation({\n mutationKey: ['deployments', 'delete'],\n mutationFn: (id: string) => withCsrf(() => adminApi.deployments.connections.remove(id)),\n onSuccess: (_result, id) => {\n queryClient.removeQueries({ queryKey: queryKeys.publishing.deployments.connection(id) });\n return invalidate();\n },\n });\n};\n\n/** Runs the provider's checks (credentials, reachability); the result is shown, not cached. */\nexport const useTestDeploymentConnection = () =>\n useMutation({\n mutationKey: ['deployments', 'test'],\n mutationFn: (id: string) => withCsrf(() => adminApi.deployments.connections.test(id)),\n });\n\nexport const useTriggerDeployment = () => {\n const invalidate = useInvalidateDeployments();\n return useMutation({\n mutationKey: ['deployments', 'trigger'],\n mutationFn: (id: string) => withCsrf(() => adminApi.deployments.connections.trigger(id)),\n onSuccess: invalidate,\n });\n};\n\nexport const useRetryDeploymentRun = () => {\n const invalidate = useInvalidateDeployments();\n return useMutation({\n mutationKey: ['deployments', 'retry'],\n mutationFn: (id: string) => withCsrf(() => adminApi.deployments.runs.retry(id)),\n onSuccess: invalidate,\n });\n};\n","import type { DeploymentProvider, DeploymentTriggerPolicy, PublicationAction } from '@shapio/client';\n\nexport const PUBLICATION_ACTION_LABELS = {\n publish: 'publishing.actions.publish',\n unpublish: 'publishing.actions.unpublish',\n} as const satisfies Record<PublicationAction, string>;\n\nexport const PROVIDER_LABELS = {\n generic_webhook: 'publishing.deployments.providers.generic_webhook',\n cloudflare_pages: 'publishing.deployments.providers.cloudflare_pages',\n vercel: 'publishing.deployments.providers.vercel',\n netlify: 'publishing.deployments.providers.netlify',\n github: 'publishing.deployments.providers.github',\n} as const satisfies Record<DeploymentProvider, string>;\n\nexport const TRIGGER_POLICY_LABELS = {\n publish: 'publishing.deployments.triggers.publish',\n change_set: 'publishing.deployments.triggers.changeSet',\n schema: 'publishing.deployments.triggers.schema',\n manual: 'publishing.deployments.triggers.manual',\n} as const satisfies Record<DeploymentTriggerPolicy, string>;\n\nexport const RUN_TRIGGER_LABELS = {\n publish: 'publishing.deployments.runTriggers.publish',\n change_set: 'publishing.deployments.runTriggers.changeSet',\n schema: 'publishing.deployments.runTriggers.schema',\n manual: 'publishing.deployments.runTriggers.manual',\n retry: 'publishing.deployments.runTriggers.retry',\n} as const;\n\nexport const TIMELINE_SOURCE_LABELS = {\n shapio: 'publishing.deployments.sources.shapio',\n callback: 'publishing.deployments.sources.callback',\n provider: 'publishing.deployments.sources.provider',\n} as const;\n\n/** Longest error text shown in a table cell; the full text is in the details. */\nexport const ERROR_PREVIEW_LENGTH = 120;\n","import type { CreateWebhookInput, UpdateWebhookInput, Webhook } from '@shapio/client';\nimport { keepPreviousData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport {\n ACTIVE_DELIVERY_STATUSES,\n PUBLISHING_PAGE_SIZE,\n PUBLISHING_POLL_INTERVAL_MS,\n} from '@/constants/publishing';\nimport { adminApi } from './client';\nimport { withCsrf } from './csrf';\nimport { queryKeys } from './queryKeys';\n\nconst silent = { silent: true } as const;\n\nexport const useWebhooks = () =>\n useQuery({\n queryKey: queryKeys.publishing.webhooks.list,\n queryFn: () => adminApi.webhooks.list(),\n meta: silent,\n });\n\n/** The event types a webhook can subscribe to (a fixed catalogue: cached for the session). */\nexport const useWebhookEvents = () =>\n useQuery({\n queryKey: queryKeys.publishing.webhooks.events,\n queryFn: () => adminApi.webhooks.events(),\n staleTime: Infinity,\n meta: silent,\n });\n\nexport const useWebhook = (id: string) =>\n useQuery({\n queryKey: queryKeys.publishing.webhooks.webhook(id),\n queryFn: () => adminApi.webhooks.get(id),\n meta: silent,\n });\n\n/** One page of the delivery log, polled while a delivery on it still has attempts left. */\nexport const useWebhookDeliveries = (id: string, cursor: string | undefined) =>\n useQuery({\n queryKey: queryKeys.publishing.webhooks.deliveries(id, cursor),\n queryFn: () => adminApi.webhooks.deliveries(id, { cursor, limit: PUBLISHING_PAGE_SIZE }),\n placeholderData: keepPreviousData,\n refetchInterval: (query) =>\n query.state.data?.items.some((delivery) => ACTIVE_DELIVERY_STATUSES.has(delivery.status))\n ? PUBLISHING_POLL_INTERVAL_MS\n : false,\n meta: silent,\n });\n\nconst useInvalidateWebhooks = () => {\n const queryClient = useQueryClient();\n return () => queryClient.invalidateQueries({ queryKey: queryKeys.publishing.webhooks.all });\n};\n\nexport const useCreateWebhook = () => {\n const invalidate = useInvalidateWebhooks();\n return useMutation({\n mutationKey: ['webhooks', 'create'],\n meta: silent,\n mutationFn: (input: CreateWebhookInput) => withCsrf(() => adminApi.webhooks.create(input)),\n onSuccess: invalidate,\n });\n};\n\n/** 409 when `expectedVersion` is stale: the caller reloads and tells the user. */\nexport const useUpdateWebhook = () => {\n const queryClient = useQueryClient();\n const invalidate = useInvalidateWebhooks();\n return useMutation({\n mutationKey: ['webhooks', 'update'],\n meta: silent,\n mutationFn: ({ id, input }: { id: string; input: UpdateWebhookInput }) =>\n withCsrf(() => adminApi.webhooks.update(id, input)),\n onSuccess: (webhook: Webhook) => {\n queryClient.setQueryData(queryKeys.publishing.webhooks.webhook(webhook.id), webhook);\n return invalidate();\n },\n });\n};\n\nexport const useDeleteWebhook = () => {\n const invalidate = useInvalidateWebhooks();\n return useMutation({\n mutationKey: ['webhooks', 'delete'],\n mutationFn: (id: string) => withCsrf(() => adminApi.webhooks.remove(id)),\n onSuccess: invalidate,\n });\n};\n\nexport const useRotateWebhookSecret = () => {\n const invalidate = useInvalidateWebhooks();\n return useMutation({\n mutationKey: ['webhooks', 'rotateSecret'],\n mutationFn: (id: string) => withCsrf(() => adminApi.webhooks.rotateSecret(id)),\n onSuccess: invalidate,\n });\n};\n\n/** Queues a `webhook.test` delivery; the delivery log shows its outcome. */\nexport const useTestWebhook = () => {\n const invalidate = useInvalidateWebhooks();\n return useMutation({\n mutationKey: ['webhooks', 'test'],\n mutationFn: (id: string) => withCsrf(() => adminApi.webhooks.test(id)),\n onSuccess: invalidate,\n });\n};\n\nexport const useRedeliverWebhook = () => {\n const invalidate = useInvalidateWebhooks();\n return useMutation({\n mutationKey: ['webhooks', 'redeliver'],\n mutationFn: ({ id, deliveryId }: { id: string; deliveryId: string }) =>\n withCsrf(() => adminApi.webhooks.redeliver(id, deliveryId)),\n onSuccess: invalidate,\n });\n};\n","import { useState } from 'react';\n\ntype CursorPagerProps = {\n onFirst: (() => void) | undefined;\n onPrevious: (() => void) | undefined;\n onNext: (() => void) | undefined;\n};\n\n/**\n * First / Previous / Next for a forward-only cursor list (newest first). The current cursor lives wherever\n * the caller keeps it (usually the URL); the cursors of earlier pages are remembered here.\n */\nexport const useCursorPager = (\n cursor: string | undefined,\n setCursor: (cursor: string | undefined) => void,\n) => {\n const [previousCursors, setPreviousCursors] = useState<(string | undefined)[]>([]);\n const pagerProps = (nextCursor: string | null): CursorPagerProps => ({\n onFirst:\n cursor === undefined\n ? undefined\n : () => {\n setPreviousCursors([]);\n setCursor(undefined);\n },\n onPrevious:\n previousCursors.length === 0\n ? undefined\n : () => {\n setCursor(previousCursors.at(-1));\n setPreviousCursors((cursors) => cursors.slice(0, -1));\n },\n onNext: nextCursor\n ? () => {\n setPreviousCursors((cursors) => [...cursors, cursor]);\n setCursor(nextCursor);\n }\n : undefined,\n });\n return { pagerProps, resetPager: () => setPreviousCursors([]) };\n};\n"],"ignoreList":[0],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useCursorPager-B1upg5EU.js","names":["silent","useState","__toESM","useQuery","queryKeys","useMutation","useQueryClient","createLucideIcon","adminApi","withCsrf","keepPreviousData","PUBLISHING_POLL_INTERVAL_MS","ACTIVE_RUN_STATUSES","ACTIVE_DELIVERY_STATUSES","__iconData","Rocket","import_react","require_react","useResetOnOpen","open","reset","values","resetMutation","silent$1","pollWhileActive","active","useDeploymentConnections","query","connection","useDeploymentConnection","id","useDeploymentRuns","state","run","useDeploymentRun","useInvalidateDeployments","queryClient","useCreateDeploymentConnection","invalidate","input","useUpdateDeploymentConnection","useDeleteDeploymentConnection","useTestDeploymentConnection","useTriggerDeployment","useRetryDeploymentRun","PUBLICATION_ACTION_LABELS","PROVIDER_LABELS","TRIGGER_POLICY_LABELS","RUN_TRIGGER_LABELS","TIMELINE_SOURCE_LABELS","silent","useWebhooks","useWebhookEvents","useWebhook","useWebhookDeliveries","cursor","delivery","useInvalidateWebhooks","useCreateWebhook","useUpdateWebhook","webhook","useDeleteWebhook","useRotateWebhookSecret","useTestWebhook","useRedeliverWebhook","deliveryId","useCursorPager","previousCursors","setPreviousCursors","setCursor","cursors","nextCursor"],"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/rocket.mjs","../../src/features/Publishing/hooks/useResetOnOpen.ts","../../src/api/deployments.ts","../../src/features/Publishing/constants.ts","../../src/api/webhooks.ts","../../src/features/Publishing/hooks/useCursorPager.ts"],"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: \"rocket\",\n size: 24,\n node: [\n [\"path\", { d: \"M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5\", key: \"qeys4\" }],\n [\n \"path\",\n {\n d: \"M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09\",\n key: \"u4xsad\"\n }\n ],\n [\n \"path\",\n {\n d: \"M9 12a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.4 22.4 0 0 1-4 2z\",\n key: \"676m9\"\n }\n ],\n [\"path\", { d: \"M9 12H4s.55-3.03 2-4c1.62-1.08 5 .05 5 .05\", key: \"92ym6u\" }]\n ]\n};\n__iconData.node;\nconst Rocket = createLucideIcon(__iconData);\n\nexport { __iconData, Rocket as default };\n//# sourceMappingURL=rocket.mjs.map\n","import { useEffect } from 'react';\nimport type { FieldValues, UseFormReset } from 'react-hook-form';\n\n/**\n * A sheet or popover form starts clean every time it opens: default values, and no error left over from the last\n * attempt. `values` must be stable (a module constant or memoized).\n */\nexport const useResetOnOpen = <TValues extends FieldValues>(\n open: boolean,\n reset: UseFormReset<TValues>,\n values: TValues,\n resetMutation: () => void,\n) => {\n useEffect(() => {\n if (open) {\n reset(values);\n resetMutation();\n }\n }, [open, reset, values, resetMutation]);\n};\n","import type {\n CreateDeploymentConnectionInput,\n DeploymentConnection,\n DeploymentRunQuery,\n UpdateDeploymentConnectionInput,\n} from '@shapio/client';\nimport { keepPreviousData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { ACTIVE_RUN_STATUSES, PUBLISHING_POLL_INTERVAL_MS } from '@/constants/publishing';\nimport { adminApi } from './client';\nimport { withCsrf } from './csrf';\nimport { queryKeys } from './queryKeys';\n\nconst silent = { silent: true } as const;\n\n/** Polls while the latest runs are still in progress, so statuses move on screen without a reload. */\nconst pollWhileActive = (active: boolean) => (active ? PUBLISHING_POLL_INTERVAL_MS : false);\n\nexport const useDeploymentConnections = () =>\n useQuery({\n queryKey: queryKeys.publishing.deployments.connections,\n queryFn: () => adminApi.deployments.connections.list(),\n refetchInterval: (query) =>\n pollWhileActive(\n query.state.data?.some((connection) =>\n connection.latestRun ? ACTIVE_RUN_STATUSES.has(connection.latestRun.status) : false,\n ) ?? false,\n ),\n meta: silent,\n });\n\nexport const useDeploymentConnection = (id: string) =>\n useQuery({\n queryKey: queryKeys.publishing.deployments.connection(id),\n queryFn: () => adminApi.deployments.connections.get(id),\n refetchInterval: (query) =>\n pollWhileActive(\n query.state.data?.latestRun ? ACTIVE_RUN_STATUSES.has(query.state.data.latestRun.status) : false,\n ),\n meta: silent,\n });\n\nexport const useDeploymentRuns = (query: DeploymentRunQuery) =>\n useQuery({\n queryKey: queryKeys.publishing.deployments.runs(query),\n queryFn: () => adminApi.deployments.runs.list(query),\n placeholderData: keepPreviousData,\n refetchInterval: (state) =>\n pollWhileActive(state.state.data?.items.some((run) => ACTIVE_RUN_STATUSES.has(run.status)) ?? false),\n meta: silent,\n });\n\n/** One run, polled until it reaches a final state (deployed, failed or unknown). */\nexport const useDeploymentRun = (id: string) =>\n useQuery({\n queryKey: queryKeys.publishing.deployments.run(id),\n queryFn: () => adminApi.deployments.runs.get(id),\n refetchInterval: (query) =>\n pollWhileActive(query.state.data ? ACTIVE_RUN_STATUSES.has(query.state.data.status) : false),\n meta: silent,\n });\n\nconst useInvalidateDeployments = () => {\n const queryClient = useQueryClient();\n return () => queryClient.invalidateQueries({ queryKey: queryKeys.publishing.deployments.all });\n};\n\nexport const useCreateDeploymentConnection = () => {\n const invalidate = useInvalidateDeployments();\n return useMutation({\n mutationKey: ['deployments', 'create'],\n meta: silent,\n mutationFn: (input: CreateDeploymentConnectionInput) =>\n withCsrf(() => adminApi.deployments.connections.create(input)),\n onSuccess: invalidate,\n });\n};\n\n/** 409 when `expectedVersion` is stale: the caller reloads and tells the user. */\nexport const useUpdateDeploymentConnection = () => {\n const queryClient = useQueryClient();\n const invalidate = useInvalidateDeployments();\n return useMutation({\n mutationKey: ['deployments', 'update'],\n meta: silent,\n mutationFn: ({ id, input }: { id: string; input: UpdateDeploymentConnectionInput }) =>\n withCsrf(() => adminApi.deployments.connections.update(id, input)),\n onSuccess: (connection: DeploymentConnection) => {\n queryClient.setQueryData(queryKeys.publishing.deployments.connection(connection.id), connection);\n return invalidate();\n },\n });\n};\n\nexport const useDeleteDeploymentConnection = () => {\n const queryClient = useQueryClient();\n const invalidate = useInvalidateDeployments();\n return useMutation({\n mutationKey: ['deployments', 'delete'],\n mutationFn: (id: string) => withCsrf(() => adminApi.deployments.connections.remove(id)),\n onSuccess: (_result, id) => {\n queryClient.removeQueries({ queryKey: queryKeys.publishing.deployments.connection(id) });\n return invalidate();\n },\n });\n};\n\n/** Runs the provider's checks (credentials, reachability); the result is shown, not cached. */\nexport const useTestDeploymentConnection = () =>\n useMutation({\n mutationKey: ['deployments', 'test'],\n mutationFn: (id: string) => withCsrf(() => adminApi.deployments.connections.test(id)),\n });\n\nexport const useTriggerDeployment = () => {\n const invalidate = useInvalidateDeployments();\n return useMutation({\n mutationKey: ['deployments', 'trigger'],\n mutationFn: (id: string) => withCsrf(() => adminApi.deployments.connections.trigger(id)),\n onSuccess: invalidate,\n });\n};\n\nexport const useRetryDeploymentRun = () => {\n const invalidate = useInvalidateDeployments();\n return useMutation({\n mutationKey: ['deployments', 'retry'],\n mutationFn: (id: string) => withCsrf(() => adminApi.deployments.runs.retry(id)),\n onSuccess: invalidate,\n });\n};\n","import type { DeploymentProvider, DeploymentTriggerPolicy, PublicationAction } from '@shapio/client';\n\nexport const PUBLICATION_ACTION_LABELS = {\n publish: 'publishing.actions.publish',\n unpublish: 'publishing.actions.unpublish',\n} as const satisfies Record<PublicationAction, string>;\n\nexport const PROVIDER_LABELS = {\n generic_webhook: 'publishing.deployments.providers.generic_webhook',\n cloudflare_pages: 'publishing.deployments.providers.cloudflare_pages',\n vercel: 'publishing.deployments.providers.vercel',\n netlify: 'publishing.deployments.providers.netlify',\n github: 'publishing.deployments.providers.github',\n} as const satisfies Record<DeploymentProvider, string>;\n\nexport const TRIGGER_POLICY_LABELS = {\n publish: 'publishing.deployments.triggers.publish',\n change_set: 'publishing.deployments.triggers.changeSet',\n schema: 'publishing.deployments.triggers.schema',\n manual: 'publishing.deployments.triggers.manual',\n} as const satisfies Record<DeploymentTriggerPolicy, string>;\n\nexport const RUN_TRIGGER_LABELS = {\n publish: 'publishing.deployments.runTriggers.publish',\n change_set: 'publishing.deployments.runTriggers.changeSet',\n schema: 'publishing.deployments.runTriggers.schema',\n manual: 'publishing.deployments.runTriggers.manual',\n retry: 'publishing.deployments.runTriggers.retry',\n} as const;\n\nexport const TIMELINE_SOURCE_LABELS = {\n shapio: 'publishing.deployments.sources.shapio',\n callback: 'publishing.deployments.sources.callback',\n provider: 'publishing.deployments.sources.provider',\n} as const;\n\n/** Longest error text shown in a table cell; the full text is in the details. */\nexport const ERROR_PREVIEW_LENGTH = 120;\n","import type { CreateWebhookInput, UpdateWebhookInput, Webhook } from '@shapio/client';\nimport { keepPreviousData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport {\n ACTIVE_DELIVERY_STATUSES,\n PUBLISHING_PAGE_SIZE,\n PUBLISHING_POLL_INTERVAL_MS,\n} from '@/constants/publishing';\nimport { adminApi } from './client';\nimport { withCsrf } from './csrf';\nimport { queryKeys } from './queryKeys';\n\nconst silent = { silent: true } as const;\n\nexport const useWebhooks = () =>\n useQuery({\n queryKey: queryKeys.publishing.webhooks.list,\n queryFn: () => adminApi.webhooks.list(),\n meta: silent,\n });\n\n/** The event types a webhook can subscribe to (a fixed catalogue: cached for the session). */\nexport const useWebhookEvents = () =>\n useQuery({\n queryKey: queryKeys.publishing.webhooks.events,\n queryFn: () => adminApi.webhooks.events(),\n staleTime: Infinity,\n meta: silent,\n });\n\nexport const useWebhook = (id: string) =>\n useQuery({\n queryKey: queryKeys.publishing.webhooks.webhook(id),\n queryFn: () => adminApi.webhooks.get(id),\n meta: silent,\n });\n\n/** One page of the delivery log, polled while a delivery on it still has attempts left. */\nexport const useWebhookDeliveries = (id: string, cursor: string | undefined) =>\n useQuery({\n queryKey: queryKeys.publishing.webhooks.deliveries(id, cursor),\n queryFn: () => adminApi.webhooks.deliveries(id, { cursor, limit: PUBLISHING_PAGE_SIZE }),\n placeholderData: keepPreviousData,\n refetchInterval: (query) =>\n query.state.data?.items.some((delivery) => ACTIVE_DELIVERY_STATUSES.has(delivery.status))\n ? PUBLISHING_POLL_INTERVAL_MS\n : false,\n meta: silent,\n });\n\nconst useInvalidateWebhooks = () => {\n const queryClient = useQueryClient();\n return () => queryClient.invalidateQueries({ queryKey: queryKeys.publishing.webhooks.all });\n};\n\nexport const useCreateWebhook = () => {\n const invalidate = useInvalidateWebhooks();\n return useMutation({\n mutationKey: ['webhooks', 'create'],\n meta: silent,\n mutationFn: (input: CreateWebhookInput) => withCsrf(() => adminApi.webhooks.create(input)),\n onSuccess: invalidate,\n });\n};\n\n/** 409 when `expectedVersion` is stale: the caller reloads and tells the user. */\nexport const useUpdateWebhook = () => {\n const queryClient = useQueryClient();\n const invalidate = useInvalidateWebhooks();\n return useMutation({\n mutationKey: ['webhooks', 'update'],\n meta: silent,\n mutationFn: ({ id, input }: { id: string; input: UpdateWebhookInput }) =>\n withCsrf(() => adminApi.webhooks.update(id, input)),\n onSuccess: (webhook: Webhook) => {\n queryClient.setQueryData(queryKeys.publishing.webhooks.webhook(webhook.id), webhook);\n return invalidate();\n },\n });\n};\n\nexport const useDeleteWebhook = () => {\n const invalidate = useInvalidateWebhooks();\n return useMutation({\n mutationKey: ['webhooks', 'delete'],\n mutationFn: (id: string) => withCsrf(() => adminApi.webhooks.remove(id)),\n onSuccess: invalidate,\n });\n};\n\nexport const useRotateWebhookSecret = () => {\n const invalidate = useInvalidateWebhooks();\n return useMutation({\n mutationKey: ['webhooks', 'rotateSecret'],\n mutationFn: (id: string) => withCsrf(() => adminApi.webhooks.rotateSecret(id)),\n onSuccess: invalidate,\n });\n};\n\n/** Queues a `webhook.test` delivery; the delivery log shows its outcome. */\nexport const useTestWebhook = () => {\n const invalidate = useInvalidateWebhooks();\n return useMutation({\n mutationKey: ['webhooks', 'test'],\n mutationFn: (id: string) => withCsrf(() => adminApi.webhooks.test(id)),\n onSuccess: invalidate,\n });\n};\n\nexport const useRedeliverWebhook = () => {\n const invalidate = useInvalidateWebhooks();\n return useMutation({\n mutationKey: ['webhooks', 'redeliver'],\n mutationFn: ({ id, deliveryId }: { id: string; deliveryId: string }) =>\n withCsrf(() => adminApi.webhooks.redeliver(id, deliveryId)),\n onSuccess: invalidate,\n });\n};\n","import { useState } from 'react';\n\ntype CursorPagerProps = {\n onFirst: (() => void) | undefined;\n onPrevious: (() => void) | undefined;\n onNext: (() => void) | undefined;\n};\n\n/**\n * First / Previous / Next for a forward-only cursor list (newest first). The current cursor lives wherever\n * the caller keeps it (usually the URL); the cursors of earlier pages are remembered here.\n */\nexport const useCursorPager = (\n cursor: string | undefined,\n setCursor: (cursor: string | undefined) => void,\n) => {\n const [previousCursors, setPreviousCursors] = useState<(string | undefined)[]>([]);\n const pagerProps = (nextCursor: string | null): CursorPagerProps => ({\n onFirst:\n cursor === undefined\n ? undefined\n : () => {\n setPreviousCursors([]);\n setCursor(undefined);\n },\n onPrevious:\n previousCursors.length === 0\n ? undefined\n : () => {\n setCursor(previousCursors.at(-1));\n setPreviousCursors((cursors) => cursors.slice(0, -1));\n },\n onNext: nextCursor\n ? () => {\n setPreviousCursors((cursors) => [...cursors, cursor]);\n setCursor(nextCursor);\n }\n : undefined,\n });\n return { pagerProps, resetPager: () => setPreviousCursors([]) };\n};\n"],"ignoreList":[0],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{i as e}from"./rolldown-runtime-Dd_uD5pT.js";import{t}from"./react-CQOZoUwg.js";import{t as n}from"./jsx-runtime-DREnUpxT.js";import{j as r}from"./cn-
|
|
2
|
-
//# sourceMappingURL=useDiscardGuard-
|
|
1
|
+
import{i as e}from"./rolldown-runtime-Dd_uD5pT.js";import{t}from"./react-CQOZoUwg.js";import{t as n}from"./jsx-runtime-DREnUpxT.js";import{j as r}from"./cn-BQ3voEft.js";import{t as i}from"./ConfirmDialog-B9nWhIIz.js";var a=e(t(),1),o=e(n(),1),s=({dirty:e,pending:t=!1,onOpenChange:n})=>{let{t:s}=r(),[c,l]=(0,a.useState)(!1);return{requestOpenChange:r=>{if(!r&&e&&!t){l(!0);return}n(r)},discardPrompt:(0,o.jsx)(i,{open:c,onOpenChange:l,title:s(`unsaved.title`),description:s(`unsaved.description`),cancelLabel:s(`unsaved.stay`),confirmLabel:s(`unsaved.leave`),destructive:!0,onConfirm:()=>{l(!1),n(!1)}})}};export{s as t};
|
|
2
|
+
//# sourceMappingURL=useDiscardGuard-34ynGJIk.js.map
|
package/dist/admin/assets/{useDiscardGuard-7rRGpd4q.js.map → useDiscardGuard-34ynGJIk.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDiscardGuard-
|
|
1
|
+
{"version":3,"file":"useDiscardGuard-34ynGJIk.js","names":["useState","_jsx","__toESM","require_jsx_runtime","useTranslation","ConfirmDialog","import_react","require_react","import_jsx_runtime","useDiscardGuard","confirmingDiscard","setConfirmingDiscard","open","dirty","pending","onOpenChange","t"],"sources":["../../src/hooks/useDiscardGuard.tsx"],"sourcesContent":["import { useState, type ReactNode } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { ConfirmDialog } from '@/components/ConfirmDialog';\n\ntype UseDiscardGuardOptions = {\n /** Unsaved edits: closing asks before discarding them. */\n dirty: boolean;\n /** While a save runs, closing is not intercepted (the caller blocks it or lets it finish). */\n pending?: boolean;\n /** The overlay's own open/close handler, called once closing is allowed. */\n onOpenChange: (open: boolean) => void;\n};\n\n/**\n * Dirty-close protection for a sheet (or any overlay with `onOpenChange`). Pass `requestOpenChange` to the\n * overlay instead of `onOpenChange` and render `discardPrompt` beside it: Escape, the overlay, the close\n * button and Cancel then ask \"Discard unsaved changes?\" before closing over unsaved edits.\n */\nexport const useDiscardGuard = ({\n dirty,\n pending = false,\n onOpenChange,\n}: UseDiscardGuardOptions): { requestOpenChange: (open: boolean) => void; discardPrompt: ReactNode } => {\n const { t } = useTranslation();\n const [confirmingDiscard, setConfirmingDiscard] = useState(false);\n const requestOpenChange = (open: boolean) => {\n if (!open && dirty && !pending) {\n setConfirmingDiscard(true);\n return;\n }\n onOpenChange(open);\n };\n const discardPrompt = (\n <ConfirmDialog\n open={confirmingDiscard}\n onOpenChange={setConfirmingDiscard}\n title={t('unsaved.title')}\n description={t('unsaved.description')}\n cancelLabel={t('unsaved.stay')}\n confirmLabel={t('unsaved.leave')}\n destructive\n onConfirm={() => {\n setConfirmingDiscard(false);\n onOpenChange(false);\n }}\n />\n );\n return { requestOpenChange, discardPrompt };\n};\n"],"mappings":"mPAkBaS,GAAmB,CAC9B,QACA,UAAU,GACV,kBACsG,CACtG,GAAM,CAAE,KAAML,EAAe,EACvB,CAACM,EAAmBC,IAAA,EAAwBX,EAAAA,SAAAA,CAAS,EAAK,EAuBhE,MAAO,CAAE,kBAtBkB,GAAkB,CAC3C,GAAI,CAACY,GAAQC,GAAS,CAACC,EAAS,CAC9BH,EAAqB,EAAI,EACzB,MACF,CACAI,EAAaH,CAAI,CACnB,EAgB4B,eAAA,EAd1BX,EAAAA,IAAAA,CAACI,EAAD,CACE,KAAMK,EACN,aAAcC,EACd,MAAOK,EAAE,eAAe,EACxB,YAAaA,EAAE,qBAAqB,EACpC,YAAaA,EAAE,cAAc,EAC7B,aAAcA,EAAE,eAAe,EAC/B,YAAA,GACA,cAAiB,CACfL,EAAqB,EAAK,EAC1BI,EAAa,EAAK,CACpB,CACD,CAEyB,CAAc,CAC5C"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{i as e}from"./rolldown-runtime-Dd_uD5pT.js";import{t}from"./react-CQOZoUwg.js";import{t as n}from"./jsx-runtime-DREnUpxT.js";import{I as r,L as i,P as a,bt as o,i as s,j as c,l,p as u,r as d,s as f,t as p,u as ee}from"./cn-DnXL75B0.js";import{a as te}from"./media-BfDqe_2P.js";import{A as m,O as h,n as g,o as ne,r as re,v as ie}from"./badge-CMox6-v3.js";import{i as ae,n as oe,t as _}from"./RowTitle-sFt6NjO4.js";import{G as se,H as ce,d as v,f as le,o as y,p as ue,t as de}from"./InfoHint-DBqcrmZ3.js";import{N as b,i as x,k as fe,n as S}from"./skeleton-DUvclBAr.js";import{a as pe,i as me,n as he,o as ge,r as C,s as _e,t as ve}from"./select--nGB4WjU.js";import{n as w}from"./ConfirmDialog-D6rs75TP.js";import{t as ye}from"./circle-check-aJ2DW5t4.js";import{t as be}from"./circle-x-BnRBht9z.js";import{n as T,o as E,s as D,t as O}from"./Thumbnail-u8NE5NhQ.js";import{t as k}from"./list-BElvKZw_.js";import{t as A}from"./rotate-ccw-BOTDOdHf.js";import{t as j}from"./search-BcPL1qyc.js";import{a as M,i as N,n as xe,o as P,r as F,s as Se,t as Ce}from"./table-DQzCPm7J.js";import{t as we}from"./useSearchInput-1fDoEtXe.js";import{t as Te}from"./constants-DCtq_UOe.js";import{t as Ee}from"./Panel-6wFe96Gr.js";var I={name:`crosshair`,size:24,node:[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`line`,{x1:`22`,x2:`18`,y1:`12`,y2:`12`,key:`l9bcsi`}],[`line`,{x1:`6`,x2:`2`,y1:`12`,y2:`12`,key:`13hhkx`}],[`line`,{x1:`12`,x2:`12`,y1:`6`,y2:`2`,key:`10w3f3`}],[`line`,{x1:`12`,x2:`12`,y1:`22`,y2:`18`,key:`15g9kq`}]]};I.node;var L=s(I),R={name:`images`,size:24,node:[[`path`,{d:`m22 11-1.296-1.296a2.4 2.4 0 0 0-3.408 0L11 16`,key:`9kzy35`}],[`path`,{d:`M4 8a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2`,key:`1t0f0t`}],[`circle`,{cx:`13`,cy:`7`,r:`1`,fill:`currentColor`,key:`1obus6`}],[`rect`,{x:`8`,y:`2`,width:`14`,height:`14`,rx:`2`,key:`1gvhby`}]]};R.node;var z=s(R),B={name:`layout-grid`,size:24,node:[[`rect`,{width:`7`,height:`7`,x:`3`,y:`3`,rx:`1`,key:`1g98yp`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`3`,rx:`1`,key:`6d4xhi`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`14`,rx:`1`,key:`nxv5o0`}],[`rect`,{width:`7`,height:`7`,x:`3`,y:`14`,rx:`1`,key:`1bb6yr`}]]};B.node;var V=s(B),H={name:`upload`,size:24,node:[[`path`,{d:`M12 3v12`,key:`1x0j5s`}],[`path`,{d:`m17 8-5-5-5 5`,key:`7q97r8`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}]]};H.node;var U=s(H),W=e(t(),1),G=e(n(),1),K=100,De={x:.5,y:.5},q=e=>Math.min(1,Math.max(0,e)),Oe=({imageUrl:e,value:t,onChange:n})=>{let{t:r}=c(),i=(0,W.useId)(),a=t??De,o=e=>{let t=e.currentTarget.getBoundingClientRect();n({x:q((e.clientX-t.left)/t.width),y:q((e.clientY-t.top)/t.height)})},s=(e,t)=>{let r=Number(t);t!==``&&Number.isFinite(r)&&n({...a,[e]:q(r/K)})};return(0,G.jsxs)(ue,{"aria-labelledby":`${i}-title`,children:[(0,G.jsxs)(le,{variant:`label`,className:`flex items-center gap-1`,children:[(0,G.jsx)(`span`,{id:`${i}-title`,children:r(`media.focal.title`)}),(0,G.jsx)(de,{about:r(`media.focal.title`),children:r(`media.focal.hint`)})]}),(0,G.jsxs)(`div`,{"aria-hidden":`true`,onClick:o,className:`relative w-fit max-w-full cursor-crosshair overflow-hidden rounded-lg border`,style:{"--focal-x":`${a.x*K}%`,"--focal-y":`${a.y*K}%`},children:[(0,G.jsx)(`img`,{src:e,alt:``,className:`block max-h-64 w-auto`,draggable:!1}),t?(0,G.jsx)(`span`,{className:`absolute top-[var(--focal-y)] left-[var(--focal-x)] flex size-6 -translate-1/2 items-center justify-center rounded-full border-2 border-background bg-primary text-primary-foreground shadow`,children:(0,G.jsx)(L,{className:`size-3.5`})}):null]}),(0,G.jsxs)(`div`,{className:`flex flex-wrap items-end gap-3`,children:[(0,G.jsxs)(y,{className:`w-28`,children:[(0,G.jsx)(v,{htmlFor:`${i}-x`,children:r(`media.focal.x`)}),(0,G.jsx)(S,{id:`${i}-x`,type:`number`,min:0,max:K,step:1,value:t?Math.round(t.x*K):``,placeholder:r(`media.focal.unset`),onChange:e=>s(`x`,e.target.value)})]}),(0,G.jsxs)(y,{className:`w-28`,children:[(0,G.jsx)(v,{htmlFor:`${i}-y`,children:r(`media.focal.y`)}),(0,G.jsx)(S,{id:`${i}-y`,type:`number`,min:0,max:K,step:1,value:t?Math.round(t.y*K):``,placeholder:r(`media.focal.unset`),onChange:e=>s(`y`,e.target.value)})]}),(0,G.jsx)(x,{type:`button`,variant:`ghost`,size:`sm`,disabled:!t,onClick:()=>n(null),children:r(`media.focal.clear`)})]})]})},ke=(e,t,n)=>{let r=t===void 0?-1:e.indexOf(t),i=e.indexOf(n);if(r!==-1&&i!==-1)return e.slice(Math.min(r,i),Math.max(r,i)+1)},J=(e,t)=>{let n=(0,W.useRef)(void 0);return{select:({id:r,checked:i,shiftKey:a})=>{let o=a?ke(e,n.current,r):void 0;if(o)for(let e of o)t(e,!0);else t(r,i);n.current=r}}},Ae=({asset:e,selected:t,selectable:n,active:r,onSelect:i,onOpen:a})=>{let{t:o}=c(),s=E[e.status];return(0,G.jsxs)(`li`,{className:p(`group relative overflow-hidden rounded-xl border bg-card transition-shadow focus-within:ring-[3px] focus-within:ring-ring/50 hover:border-input`,(t||r)&&`border-primary ring-2 ring-primary hover:border-primary`),children:[(0,G.jsxs)(`button`,{type:`button`,onClick:e=>{if(e.shiftKey&&n){i(!t,!0);return}a()},className:`flex w-full flex-col text-left outline-none`,"aria-label":o(`media.openDetails`,{name:e.filename}),children:[(0,G.jsx)(O,{asset:e,className:`aspect-square w-full border-b`}),(0,G.jsxs)(`span`,{className:`flex min-w-0 flex-col gap-0.5 px-3 py-2.5`,children:[(0,G.jsx)(`span`,{className:`truncate text-sm font-medium`,title:e.filename,children:e.filename}),(0,G.jsxs)(`span`,{className:`flex min-w-0 items-center gap-1.5 text-meta text-muted-foreground`,children:[(0,G.jsxs)(`span`,{className:`truncate`,children:[T(e.filename,e.mimeType),` · `,D(e.sizeBytes)]}),e.visibility===`private`?(0,G.jsx)(m,{"aria-hidden":`true`,className:`size-3.5 shrink-0`}):null]})]})]}),e.status===`ready`?null:(0,G.jsx)(g,{tone:s.tone,label:o(s.labelKey),size:`sm`,className:`pointer-events-none absolute top-2 right-2`}),n?(0,G.jsx)(w,{checked:t,onClick:e=>{e.shiftKey&&(e.preventDefault(),i(!t,!0))},onCheckedChange:e=>i(e===!0,!1),"aria-label":o(`media.select`,{name:e.filename}),className:`absolute top-2 left-2 bg-card`}):null]})},je=({assets:e,selected:t,selectable:n,activeId:r,onSelectChange:i,onOpen:a})=>{let{t:o}=c(),s=J(e.map(e=>e.id),i);return(0,G.jsx)(`ul`,{"aria-label":o(`media.assetsLabel`,{count:e.length}),className:`grid grid-cols-[repeat(auto-fill,minmax(160px,1fr))] gap-4`,children:e.map(e=>(0,G.jsx)(Ae,{asset:e,selected:t.has(e.id),selectable:n,active:e.id===r,onSelect:(t,n)=>s.select({id:e.id,checked:t,shiftKey:n}),onOpen:()=>a(e)},e.id))})},Me=({assets:e,selected:t,selectable:n,onSelectChange:r,onOpen:i})=>{let{t:a}=c(),o=J(e.map(e=>e.id),r);return(0,G.jsx)(Se,{children:(0,G.jsxs)(Ce,{children:[(0,G.jsx)(M,{children:(0,G.jsxs)(P,{children:[n?(0,G.jsx)(N,{className:`w-10`,children:(0,G.jsx)(`span`,{className:`sr-only`,children:a(`media.selection`)})}):null,(0,G.jsx)(N,{children:a(`media.fields.filename`)}),(0,G.jsx)(N,{children:a(`media.fields.type`)}),(0,G.jsx)(N,{className:`text-right`,children:a(`media.fields.size`)}),(0,G.jsx)(N,{children:a(`media.fields.status`)}),(0,G.jsx)(N,{children:a(`media.fields.uploaded`)})]})}),(0,G.jsx)(xe,{children:e.map(e=>{let r=E[e.status],s=t.has(e.id);return(0,G.jsxs)(P,{"data-state":s?`selected`:void 0,children:[n?(0,G.jsx)(F,{children:(0,G.jsx)(w,{checked:s,onClick:t=>{t.shiftKey&&(t.preventDefault(),o.select({id:e.id,checked:!s,shiftKey:!0}))},onCheckedChange:t=>o.select({id:e.id,checked:t===!0,shiftKey:!1}),"aria-label":a(`media.select`,{name:e.filename})})}):null,(0,G.jsx)(F,{className:`max-w-96`,children:(0,G.jsxs)(`span`,{className:`flex min-w-0 items-center gap-3`,children:[(0,G.jsx)(O,{asset:e,className:`size-8 shrink-0 rounded-md`}),(0,G.jsx)(_,{asChild:!0,className:`min-w-0 truncate text-left`,children:(0,G.jsx)(`button`,{type:`button`,onClick:()=>i(e),children:e.filename})}),e.visibility===`private`?(0,G.jsx)(m,{role:`img`,"aria-label":a(`media.visibility.private`),className:`size-3.5 shrink-0 text-muted-foreground`}):null]})}),(0,G.jsx)(F,{className:`text-muted-foreground`,title:e.mimeType,children:T(e.filename,e.mimeType)}),(0,G.jsx)(F,{className:`text-right tabular-nums`,children:D(e.sizeBytes)}),(0,G.jsx)(F,{children:(0,G.jsx)(g,{tone:r.tone,label:a(r.labelKey),size:`sm`})}),(0,G.jsx)(F,{className:`whitespace-nowrap`,title:oe(e.createdAt),children:ae(e.createdAt)})]},e.id)})})]})})},Ne=({query:e,filtered:t,view:n,selected:r,selectable:i,activeId:a,onSelectChange:o,onOpen:s})=>{let{t:l}=c(),u=te(e);if(u.isPending)return(0,G.jsx)(ie,{rows:4});if(u.isError)return(0,G.jsx)(re,{error:u.error,onRetry:()=>void u.refetch()});let d=u.data.pages.flatMap(e=>e.items);if(d.length===0){let n=t||e.folder!==void 0;return(0,G.jsx)(ne,{icon:z,size:n?`panel`:`page`,title:l(t?`media.emptyFiltered`:n?`media.emptyFolder`:`media.empty`)})}return(0,G.jsxs)(`div`,{className:`space-y-4`,children:[n===`grid`?(0,G.jsx)(je,{assets:d,selected:r,selectable:i,activeId:a,onSelectChange:o,onOpen:s}):(0,G.jsx)(Me,{assets:d,selected:r,selectable:i,onSelectChange:o,onOpen:s}),u.hasNextPage?(0,G.jsx)(`div`,{className:`flex justify-center`,children:(0,G.jsx)(x,{variant:`outline`,disabled:u.isFetchingNextPage,"aria-busy":u.isFetchingNextPage||void 0,onClick:()=>void u.fetchNextPage(),children:u.isFetchingNextPage?l(`common.loading`):l(`media.loadMore`)})}):null]})},Y=`all`,Pe={image:`media.types.image`,video:`media.types.video`,audio:`media.types.audio`,pdf:`media.types.pdf`},Fe=({query:e,type:t,view:n,onQueryChange:r,onTypeChange:i,onViewChange:a})=>{let{t:o}=c(),{text:s,setText:l}=we(e,r);return(0,G.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,G.jsxs)(`div`,{className:`relative min-w-48 flex-1`,children:[(0,G.jsx)(j,{"aria-hidden":`true`,className:`absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground`}),(0,G.jsx)(S,{type:`search`,value:s,onChange:e=>l(e.target.value),"aria-label":o(`media.search`),placeholder:o(`media.searchPlaceholder`),inputSize:`sm`,className:`pl-8`})]}),(0,G.jsxs)(ve,{value:t??Y,onValueChange:e=>i(e===Y?void 0:e),children:[(0,G.jsx)(me,{size:`sm`,"aria-label":o(`media.typeFilter`),className:`w-36`,children:(0,G.jsx)(pe,{})}),(0,G.jsxs)(he,{children:[(0,G.jsx)(C,{value:Y,children:o(`media.types.all`)}),Te.map(e=>(0,G.jsx)(C,{value:e,children:o(Pe[e])},e))]})]}),(0,G.jsxs)(`div`,{role:`group`,"aria-label":o(`media.view`),className:`flex h-9 items-center gap-0.5 rounded-lg border border-input px-px`,children:[(0,G.jsx)(x,{variant:n===`grid`?`secondary`:`ghost`,size:`icon-sm`,"aria-pressed":n===`grid`,"aria-label":o(`media.viewGrid`),onClick:()=>a(`grid`),children:(0,G.jsx)(V,{"aria-hidden":`true`})}),(0,G.jsx)(x,{variant:n===`list`?`secondary`:`ghost`,size:`icon-sm`,"aria-pressed":n===`list`,"aria-label":o(`media.viewList`),onClick:()=>a(`list`),children:(0,G.jsx)(k,{"aria-hidden":`true`})})]})]})},Ie=({label:e,multiple:t=!0,onFiles:n,...r})=>{let i=(0,W.useRef)(null);return(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(x,{...r,onClick:()=>i.current?.click(),children:[(0,G.jsx)(U,{"aria-hidden":`true`}),e]}),(0,G.jsx)(`input`,{ref:i,type:`file`,multiple:t,tabIndex:-1,"aria-hidden":`true`,className:`sr-only`,onChange:e=>{let t=[...e.target.files??[]];e.target.value=``,t.length>0&&n(t)}})]})},X=u()(e=>({items:[],add:t=>e(e=>({items:[...e.items,t]})),update:(t,n)=>e(e=>({items:e.items.map(e=>e.id===t?{...e,...n}:e)})),remove:t=>e(e=>({items:e.items.filter(e=>e.id!==t)})),clearFinished:()=>e(e=>({items:e.items.filter(e=>e.status!==`done`)}))})),Z=class extends Error{status;body;constructor(e,t){super(`Upload failed with status ${e}`),this.name=`UploadTransferError`,this.status=e,this.body=t}},Le=({url:e,form:t,onProgress:n,signal:r})=>new Promise((i,a)=>{let o=new XMLHttpRequest;o.open(`POST`,e),o.withCredentials=!1,o.upload.onprogress=e=>{e.lengthComputable&&e.total>0&&n(e.loaded/e.total)},o.onload=()=>{if(o.status>=200&&o.status<300){n(1),i();return}a(new Z(o.status,o.responseText))},o.onerror=()=>a(new Z(0,``)),o.onabort=()=>a(new DOMException(`Upload cancelled`,`AbortError`)),r?.addEventListener(`abort`,()=>o.abort(),{once:!0}),o.send(t)}),Re=e=>e instanceof Z?e.status===0?b.t(`media.upload.unreachable`):e.status===413||/EntityTooLarge/.test(e.body)?b.t(`errors.codes.FILE_TOO_LARGE`):b.t(`media.upload.transferFailed`,{status:e.status}):fe(e),Q=100,ze=({item:e,onRetry:t,onDismiss:n})=>{let{t:r}=c(),i=Math.round(e.progress*Q),a=e.status===`uploading`?r(`media.upload.uploading`,{percent:i}):e.status===`confirming`?r(`media.upload.checking`):e.status===`done`?r(`media.upload.done`):Re(e.error);return(0,G.jsxs)(`li`,{className:`flex items-start gap-3 px-5 py-2.5`,children:[(0,G.jsx)(`span`,{className:`mt-0.5 shrink-0`,children:e.status===`done`?(0,G.jsx)(ye,{"aria-hidden":`true`,className:`size-4 text-success`}):e.status===`failed`?(0,G.jsx)(be,{"aria-hidden":`true`,className:`size-4 text-destructive`}):(0,G.jsx)(d,{"aria-hidden":`true`,className:`size-4 animate-spin text-muted-foreground motion-reduce:animate-none`})}),(0,G.jsxs)(`div`,{className:`min-w-0 flex-1 space-y-1`,children:[(0,G.jsxs)(`p`,{className:`flex items-baseline gap-2 text-sm`,children:[(0,G.jsx)(`span`,{className:`truncate font-medium`,children:e.file.name}),(0,G.jsx)(`span`,{className:`shrink-0 text-meta text-muted-foreground`,children:D(e.file.size)})]}),e.status===`uploading`||e.status===`confirming`?(0,G.jsx)(`div`,{role:`progressbar`,"aria-label":r(`media.upload.progress`,{name:e.file.name}),"aria-valuemin":0,"aria-valuemax":Q,"aria-valuenow":i,className:`h-1.5 overflow-hidden rounded-full bg-muted`,style:{"--upload-progress":`${i}%`},children:(0,G.jsx)(`div`,{className:`h-full w-[var(--upload-progress)] bg-primary transition-[width]`})}):null,(0,G.jsx)(`p`,{className:p(`text-meta`,e.status===`failed`?`text-destructive`:`text-muted-foreground`),children:a})]}),e.status===`failed`?(0,G.jsx)(x,{variant:`ghost`,size:`icon-sm`,"aria-label":r(`media.upload.retry`,{name:e.file.name}),onClick:t,children:(0,G.jsx)(A,{"aria-hidden":`true`})}):null,e.status===`failed`||e.status===`done`?(0,G.jsx)(x,{variant:`ghost`,size:`icon-sm`,"aria-label":r(`media.upload.dismiss`,{name:e.file.name}),onClick:n,children:(0,G.jsx)(h,{"aria-hidden":`true`})}):null]})},Be=({onRetry:e,onDismiss:t})=>{let{t:n}=c(),r=X(e=>e.items),i=X(e=>e.clearFinished),[a,o]=(0,W.useState)(!1);if(r.length===0)return null;let s=r.filter(e=>e.status===`uploading`||e.status===`confirming`).length,l=r.filter(e=>e.status===`failed`).length,u=r.length-s-l,d=s===0&&l===0,f=!d||a;return(0,G.jsx)(Ee,{title:n(`media.upload.queueTitle`),titleAs:`h2`,flush:f,actions:(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`span`,{role:`status`,"aria-live":`polite`,className:`text-meta text-muted-foreground`,children:d?n(`media.upload.doneSummary`,{count:u}):n(`media.upload.summary`,{active:s,failed:l})}),d?(0,G.jsx)(x,{variant:`ghost`,size:`icon-sm`,"aria-expanded":f,"aria-label":n(f?`media.upload.hideFinished`:`media.upload.showFinished`),onClick:()=>o(e=>!e),children:f?(0,G.jsx)(ge,{"aria-hidden":`true`}):(0,G.jsx)(_e,{"aria-hidden":`true`})}):null,u>0?(0,G.jsx)(x,{variant:`ghost`,size:`sm`,onClick:i,children:n(`media.upload.clearFinished`)}):null]}),bodyClassName:f?void 0:`hidden`,children:f?(0,G.jsx)(`ul`,{className:`max-h-64 divide-y overflow-y-auto`,children:r.map(n=>(0,G.jsx)(ze,{item:n,onRetry:()=>e(n.id),onDismiss:()=>t(n.id)},n.id))}):null})},Ve=`application/octet-stream`,He=e=>{let t={filename:e.file.name,mimeType:e.file.type||Ve,sizeBytes:e.file.size};return f(()=>e.replaceAssetId?l.media.assets.replace(e.replaceAssetId,t):l.media.uploads.create({...t,folderId:e.folderId,visibility:e.visibility}))},$=async(e,t,n)=>{let a=await He(e);return await Le({url:i(a,ee()),form:r(a,e.file,e.file.name),onProgress:t}),n(),f(()=>l.media.uploads.confirm(a.grantId))},Ue=()=>{let e=o(),{add:t,update:n,remove:r}=X.getState(),i=(0,W.useCallback)(async t=>{n(t.id,{status:`uploading`,progress:0,error:void 0});try{let e=await $(t,e=>n(t.id,{progress:e}),()=>n(t.id,{status:`confirming`}));n(t.id,{status:`done`,assetId:e.id}),t.replaceAssetId&&se.success(b.t(`media.upload.replaced`,{name:t.file.name}))}catch(e){ce(e,`uploading ${t.file.name}`),n(t.id,{status:`failed`,error:e})}finally{await e.invalidateQueries({queryKey:a.media.all})}},[e,n]);return{enqueue:(0,W.useCallback)((e,n)=>{for(let r of e){let e={id:crypto.randomUUID(),file:r,folderId:n.folderId,visibility:n.visibility,replaceAssetId:n.replaceAssetId,status:`uploading`,progress:0,error:void 0,assetId:void 0};t(e),i(e)}},[t,i]),retry:(0,W.useCallback)(e=>{let t=X.getState().items.find(t=>t.id===e);t&&i(t)},[i]),dismiss:r,uploadOne:(0,W.useCallback)(async t=>{try{let n=await $({file:t,folderId:null,visibility:`public`,replaceAssetId:void 0},()=>void 0,()=>void 0);return e.setQueryData(a.media.asset(n.id),n),{id:n.id,alt:n.alt||null}}finally{await e.invalidateQueries({queryKey:a.media.all})}},[e])}};export{Ne as a,V as c,Fe as i,z as l,Be as n,Oe as o,Ie as r,U as s,Ue as t,L as u};
|
|
2
|
-
//# sourceMappingURL=useMediaUploader-
|
|
1
|
+
import{i as e}from"./rolldown-runtime-Dd_uD5pT.js";import{t}from"./react-CQOZoUwg.js";import{t as n}from"./jsx-runtime-DREnUpxT.js";import{I as r,L as i,P as a,bt as o,i as s,j as c,l,p as u,r as d,s as f,t as p,u as ee}from"./cn-BQ3voEft.js";import{a as te}from"./media-Xzot1ueY.js";import{A as m,O as h,n as g,o as ne,r as re,v as ie}from"./badge-DD0mE96i.js";import{i as ae,n as oe,t as _}from"./RowTitle--uFCpx8n.js";import{G as se,H as ce,d as v,f as le,o as y,p as ue,t as de}from"./InfoHint-GJLRVumb.js";import{N as b,i as x,k as fe,n as S}from"./skeleton-C3QLIh7W.js";import{a as pe,i as me,n as he,o as ge,r as C,s as _e,t as ve}from"./select-tHVWX85X.js";import{n as w}from"./ConfirmDialog-B9nWhIIz.js";import{t as ye}from"./circle-check-Dq1owihe.js";import{t as be}from"./circle-x-Dx6zIZko.js";import{n as T,o as E,s as D,t as O}from"./Thumbnail-CP5mfgNY.js";import{t as k}from"./list-DRtRdjBC.js";import{t as A}from"./rotate-ccw-CBoZle-b.js";import{t as j}from"./search-_YlNpPvU.js";import{a as M,i as N,n as xe,o as P,r as F,s as Se,t as Ce}from"./table-CZYtdoHn.js";import{t as we}from"./useSearchInput-1fDoEtXe.js";import{t as Te}from"./constants-DCtq_UOe.js";import{t as Ee}from"./Panel-iIKjEURi.js";var I={name:`crosshair`,size:24,node:[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`line`,{x1:`22`,x2:`18`,y1:`12`,y2:`12`,key:`l9bcsi`}],[`line`,{x1:`6`,x2:`2`,y1:`12`,y2:`12`,key:`13hhkx`}],[`line`,{x1:`12`,x2:`12`,y1:`6`,y2:`2`,key:`10w3f3`}],[`line`,{x1:`12`,x2:`12`,y1:`22`,y2:`18`,key:`15g9kq`}]]};I.node;var L=s(I),R={name:`images`,size:24,node:[[`path`,{d:`m22 11-1.296-1.296a2.4 2.4 0 0 0-3.408 0L11 16`,key:`9kzy35`}],[`path`,{d:`M4 8a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2`,key:`1t0f0t`}],[`circle`,{cx:`13`,cy:`7`,r:`1`,fill:`currentColor`,key:`1obus6`}],[`rect`,{x:`8`,y:`2`,width:`14`,height:`14`,rx:`2`,key:`1gvhby`}]]};R.node;var z=s(R),B={name:`layout-grid`,size:24,node:[[`rect`,{width:`7`,height:`7`,x:`3`,y:`3`,rx:`1`,key:`1g98yp`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`3`,rx:`1`,key:`6d4xhi`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`14`,rx:`1`,key:`nxv5o0`}],[`rect`,{width:`7`,height:`7`,x:`3`,y:`14`,rx:`1`,key:`1bb6yr`}]]};B.node;var V=s(B),H={name:`upload`,size:24,node:[[`path`,{d:`M12 3v12`,key:`1x0j5s`}],[`path`,{d:`m17 8-5-5-5 5`,key:`7q97r8`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}]]};H.node;var U=s(H),W=e(t(),1),G=e(n(),1),K=100,De={x:.5,y:.5},q=e=>Math.min(1,Math.max(0,e)),Oe=({imageUrl:e,value:t,onChange:n})=>{let{t:r}=c(),i=(0,W.useId)(),a=t??De,o=e=>{let t=e.currentTarget.getBoundingClientRect();n({x:q((e.clientX-t.left)/t.width),y:q((e.clientY-t.top)/t.height)})},s=(e,t)=>{let r=Number(t);t!==``&&Number.isFinite(r)&&n({...a,[e]:q(r/K)})};return(0,G.jsxs)(ue,{"aria-labelledby":`${i}-title`,children:[(0,G.jsxs)(le,{variant:`label`,className:`flex items-center gap-1`,children:[(0,G.jsx)(`span`,{id:`${i}-title`,children:r(`media.focal.title`)}),(0,G.jsx)(de,{about:r(`media.focal.title`),children:r(`media.focal.hint`)})]}),(0,G.jsxs)(`div`,{"aria-hidden":`true`,onClick:o,className:`relative w-fit max-w-full cursor-crosshair overflow-hidden rounded-lg border`,style:{"--focal-x":`${a.x*K}%`,"--focal-y":`${a.y*K}%`},children:[(0,G.jsx)(`img`,{src:e,alt:``,className:`block max-h-64 w-auto`,draggable:!1}),t?(0,G.jsx)(`span`,{className:`absolute top-[var(--focal-y)] left-[var(--focal-x)] flex size-6 -translate-1/2 items-center justify-center rounded-full border-2 border-background bg-primary text-primary-foreground shadow`,children:(0,G.jsx)(L,{className:`size-3.5`})}):null]}),(0,G.jsxs)(`div`,{className:`flex flex-wrap items-end gap-3`,children:[(0,G.jsxs)(y,{className:`w-28`,children:[(0,G.jsx)(v,{htmlFor:`${i}-x`,children:r(`media.focal.x`)}),(0,G.jsx)(S,{id:`${i}-x`,type:`number`,min:0,max:K,step:1,value:t?Math.round(t.x*K):``,placeholder:r(`media.focal.unset`),onChange:e=>s(`x`,e.target.value)})]}),(0,G.jsxs)(y,{className:`w-28`,children:[(0,G.jsx)(v,{htmlFor:`${i}-y`,children:r(`media.focal.y`)}),(0,G.jsx)(S,{id:`${i}-y`,type:`number`,min:0,max:K,step:1,value:t?Math.round(t.y*K):``,placeholder:r(`media.focal.unset`),onChange:e=>s(`y`,e.target.value)})]}),(0,G.jsx)(x,{type:`button`,variant:`ghost`,size:`sm`,disabled:!t,onClick:()=>n(null),children:r(`media.focal.clear`)})]})]})},ke=(e,t,n)=>{let r=t===void 0?-1:e.indexOf(t),i=e.indexOf(n);if(r!==-1&&i!==-1)return e.slice(Math.min(r,i),Math.max(r,i)+1)},J=(e,t)=>{let n=(0,W.useRef)(void 0);return{select:({id:r,checked:i,shiftKey:a})=>{let o=a?ke(e,n.current,r):void 0;if(o)for(let e of o)t(e,!0);else t(r,i);n.current=r}}},Ae=({asset:e,selected:t,selectable:n,active:r,onSelect:i,onOpen:a})=>{let{t:o}=c(),s=E[e.status];return(0,G.jsxs)(`li`,{className:p(`group relative overflow-hidden rounded-xl border bg-card transition-shadow focus-within:ring-[3px] focus-within:ring-ring/50 hover:border-input`,(t||r)&&`border-primary ring-2 ring-primary hover:border-primary`),children:[(0,G.jsxs)(`button`,{type:`button`,onClick:e=>{if(e.shiftKey&&n){i(!t,!0);return}a()},className:`flex w-full flex-col text-left outline-none`,"aria-label":o(`media.openDetails`,{name:e.filename}),children:[(0,G.jsx)(O,{asset:e,className:`aspect-square w-full border-b`}),(0,G.jsxs)(`span`,{className:`flex min-w-0 flex-col gap-0.5 px-3 py-2.5`,children:[(0,G.jsx)(`span`,{className:`truncate text-sm font-medium`,title:e.filename,children:e.filename}),(0,G.jsxs)(`span`,{className:`flex min-w-0 items-center gap-1.5 text-meta text-muted-foreground`,children:[(0,G.jsxs)(`span`,{className:`truncate`,children:[T(e.filename,e.mimeType),` · `,D(e.sizeBytes)]}),e.visibility===`private`?(0,G.jsx)(m,{"aria-hidden":`true`,className:`size-3.5 shrink-0`}):null]})]})]}),e.status===`ready`?null:(0,G.jsx)(g,{tone:s.tone,label:o(s.labelKey),size:`sm`,className:`pointer-events-none absolute top-2 right-2`}),n?(0,G.jsx)(w,{checked:t,onClick:e=>{e.shiftKey&&(e.preventDefault(),i(!t,!0))},onCheckedChange:e=>i(e===!0,!1),"aria-label":o(`media.select`,{name:e.filename}),className:`absolute top-2 left-2 bg-card`}):null]})},je=({assets:e,selected:t,selectable:n,activeId:r,onSelectChange:i,onOpen:a})=>{let{t:o}=c(),s=J(e.map(e=>e.id),i);return(0,G.jsx)(`ul`,{"aria-label":o(`media.assetsLabel`,{count:e.length}),className:`grid grid-cols-[repeat(auto-fill,minmax(160px,1fr))] gap-4`,children:e.map(e=>(0,G.jsx)(Ae,{asset:e,selected:t.has(e.id),selectable:n,active:e.id===r,onSelect:(t,n)=>s.select({id:e.id,checked:t,shiftKey:n}),onOpen:()=>a(e)},e.id))})},Me=({assets:e,selected:t,selectable:n,onSelectChange:r,onOpen:i})=>{let{t:a}=c(),o=J(e.map(e=>e.id),r);return(0,G.jsx)(Se,{children:(0,G.jsxs)(Ce,{children:[(0,G.jsx)(M,{children:(0,G.jsxs)(P,{children:[n?(0,G.jsx)(N,{className:`w-10`,children:(0,G.jsx)(`span`,{className:`sr-only`,children:a(`media.selection`)})}):null,(0,G.jsx)(N,{children:a(`media.fields.filename`)}),(0,G.jsx)(N,{children:a(`media.fields.type`)}),(0,G.jsx)(N,{className:`text-right`,children:a(`media.fields.size`)}),(0,G.jsx)(N,{children:a(`media.fields.status`)}),(0,G.jsx)(N,{children:a(`media.fields.uploaded`)})]})}),(0,G.jsx)(xe,{children:e.map(e=>{let r=E[e.status],s=t.has(e.id);return(0,G.jsxs)(P,{"data-state":s?`selected`:void 0,children:[n?(0,G.jsx)(F,{children:(0,G.jsx)(w,{checked:s,onClick:t=>{t.shiftKey&&(t.preventDefault(),o.select({id:e.id,checked:!s,shiftKey:!0}))},onCheckedChange:t=>o.select({id:e.id,checked:t===!0,shiftKey:!1}),"aria-label":a(`media.select`,{name:e.filename})})}):null,(0,G.jsx)(F,{className:`max-w-96`,children:(0,G.jsxs)(`span`,{className:`flex min-w-0 items-center gap-3`,children:[(0,G.jsx)(O,{asset:e,className:`size-8 shrink-0 rounded-md`}),(0,G.jsx)(_,{asChild:!0,className:`min-w-0 truncate text-left`,children:(0,G.jsx)(`button`,{type:`button`,onClick:()=>i(e),children:e.filename})}),e.visibility===`private`?(0,G.jsx)(m,{role:`img`,"aria-label":a(`media.visibility.private`),className:`size-3.5 shrink-0 text-muted-foreground`}):null]})}),(0,G.jsx)(F,{className:`text-muted-foreground`,title:e.mimeType,children:T(e.filename,e.mimeType)}),(0,G.jsx)(F,{className:`text-right tabular-nums`,children:D(e.sizeBytes)}),(0,G.jsx)(F,{children:(0,G.jsx)(g,{tone:r.tone,label:a(r.labelKey),size:`sm`})}),(0,G.jsx)(F,{className:`whitespace-nowrap`,title:oe(e.createdAt),children:ae(e.createdAt)})]},e.id)})})]})})},Ne=({query:e,filtered:t,view:n,selected:r,selectable:i,activeId:a,onSelectChange:o,onOpen:s})=>{let{t:l}=c(),u=te(e);if(u.isPending)return(0,G.jsx)(ie,{rows:4});if(u.isError)return(0,G.jsx)(re,{error:u.error,onRetry:()=>void u.refetch()});let d=u.data.pages.flatMap(e=>e.items);if(d.length===0){let n=t||e.folder!==void 0;return(0,G.jsx)(ne,{icon:z,size:n?`panel`:`page`,title:l(t?`media.emptyFiltered`:n?`media.emptyFolder`:`media.empty`)})}return(0,G.jsxs)(`div`,{className:`space-y-4`,children:[n===`grid`?(0,G.jsx)(je,{assets:d,selected:r,selectable:i,activeId:a,onSelectChange:o,onOpen:s}):(0,G.jsx)(Me,{assets:d,selected:r,selectable:i,onSelectChange:o,onOpen:s}),u.hasNextPage?(0,G.jsx)(`div`,{className:`flex justify-center`,children:(0,G.jsx)(x,{variant:`outline`,disabled:u.isFetchingNextPage,"aria-busy":u.isFetchingNextPage||void 0,onClick:()=>void u.fetchNextPage(),children:u.isFetchingNextPage?l(`common.loading`):l(`media.loadMore`)})}):null]})},Y=`all`,Pe={image:`media.types.image`,video:`media.types.video`,audio:`media.types.audio`,pdf:`media.types.pdf`},Fe=({query:e,type:t,view:n,onQueryChange:r,onTypeChange:i,onViewChange:a})=>{let{t:o}=c(),{text:s,setText:l}=we(e,r);return(0,G.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,G.jsxs)(`div`,{className:`relative min-w-48 flex-1`,children:[(0,G.jsx)(j,{"aria-hidden":`true`,className:`absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground`}),(0,G.jsx)(S,{type:`search`,value:s,onChange:e=>l(e.target.value),"aria-label":o(`media.search`),placeholder:o(`media.searchPlaceholder`),inputSize:`sm`,className:`pl-8`})]}),(0,G.jsxs)(ve,{value:t??Y,onValueChange:e=>i(e===Y?void 0:e),children:[(0,G.jsx)(me,{size:`sm`,"aria-label":o(`media.typeFilter`),className:`w-36`,children:(0,G.jsx)(pe,{})}),(0,G.jsxs)(he,{children:[(0,G.jsx)(C,{value:Y,children:o(`media.types.all`)}),Te.map(e=>(0,G.jsx)(C,{value:e,children:o(Pe[e])},e))]})]}),(0,G.jsxs)(`div`,{role:`group`,"aria-label":o(`media.view`),className:`flex h-9 items-center gap-0.5 rounded-lg border border-input px-px`,children:[(0,G.jsx)(x,{variant:n===`grid`?`secondary`:`ghost`,size:`icon-sm`,"aria-pressed":n===`grid`,"aria-label":o(`media.viewGrid`),onClick:()=>a(`grid`),children:(0,G.jsx)(V,{"aria-hidden":`true`})}),(0,G.jsx)(x,{variant:n===`list`?`secondary`:`ghost`,size:`icon-sm`,"aria-pressed":n===`list`,"aria-label":o(`media.viewList`),onClick:()=>a(`list`),children:(0,G.jsx)(k,{"aria-hidden":`true`})})]})]})},Ie=({label:e,multiple:t=!0,onFiles:n,...r})=>{let i=(0,W.useRef)(null);return(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(x,{...r,onClick:()=>i.current?.click(),children:[(0,G.jsx)(U,{"aria-hidden":`true`}),e]}),(0,G.jsx)(`input`,{ref:i,type:`file`,multiple:t,tabIndex:-1,"aria-hidden":`true`,className:`sr-only`,onChange:e=>{let t=[...e.target.files??[]];e.target.value=``,t.length>0&&n(t)}})]})},X=u()(e=>({items:[],add:t=>e(e=>({items:[...e.items,t]})),update:(t,n)=>e(e=>({items:e.items.map(e=>e.id===t?{...e,...n}:e)})),remove:t=>e(e=>({items:e.items.filter(e=>e.id!==t)})),clearFinished:()=>e(e=>({items:e.items.filter(e=>e.status!==`done`)}))})),Z=class extends Error{status;body;constructor(e,t){super(`Upload failed with status ${e}`),this.name=`UploadTransferError`,this.status=e,this.body=t}},Le=({url:e,form:t,onProgress:n,signal:r})=>new Promise((i,a)=>{let o=new XMLHttpRequest;o.open(`POST`,e),o.withCredentials=!1,o.upload.onprogress=e=>{e.lengthComputable&&e.total>0&&n(e.loaded/e.total)},o.onload=()=>{if(o.status>=200&&o.status<300){n(1),i();return}a(new Z(o.status,o.responseText))},o.onerror=()=>a(new Z(0,``)),o.onabort=()=>a(new DOMException(`Upload cancelled`,`AbortError`)),r?.addEventListener(`abort`,()=>o.abort(),{once:!0}),o.send(t)}),Re=e=>e instanceof Z?e.status===0?b.t(`media.upload.unreachable`):e.status===413||/EntityTooLarge/.test(e.body)?b.t(`errors.codes.FILE_TOO_LARGE`):b.t(`media.upload.transferFailed`,{status:e.status}):fe(e),Q=100,ze=({item:e,onRetry:t,onDismiss:n})=>{let{t:r}=c(),i=Math.round(e.progress*Q),a=e.status===`uploading`?r(`media.upload.uploading`,{percent:i}):e.status===`confirming`?r(`media.upload.checking`):e.status===`done`?r(`media.upload.done`):Re(e.error);return(0,G.jsxs)(`li`,{className:`flex items-start gap-3 px-5 py-2.5`,children:[(0,G.jsx)(`span`,{className:`mt-0.5 shrink-0`,children:e.status===`done`?(0,G.jsx)(ye,{"aria-hidden":`true`,className:`size-4 text-success`}):e.status===`failed`?(0,G.jsx)(be,{"aria-hidden":`true`,className:`size-4 text-destructive`}):(0,G.jsx)(d,{"aria-hidden":`true`,className:`size-4 animate-spin text-muted-foreground motion-reduce:animate-none`})}),(0,G.jsxs)(`div`,{className:`min-w-0 flex-1 space-y-1`,children:[(0,G.jsxs)(`p`,{className:`flex items-baseline gap-2 text-sm`,children:[(0,G.jsx)(`span`,{className:`truncate font-medium`,children:e.file.name}),(0,G.jsx)(`span`,{className:`shrink-0 text-meta text-muted-foreground`,children:D(e.file.size)})]}),e.status===`uploading`||e.status===`confirming`?(0,G.jsx)(`div`,{role:`progressbar`,"aria-label":r(`media.upload.progress`,{name:e.file.name}),"aria-valuemin":0,"aria-valuemax":Q,"aria-valuenow":i,className:`h-1.5 overflow-hidden rounded-full bg-muted`,style:{"--upload-progress":`${i}%`},children:(0,G.jsx)(`div`,{className:`h-full w-[var(--upload-progress)] bg-primary transition-[width]`})}):null,(0,G.jsx)(`p`,{className:p(`text-meta`,e.status===`failed`?`text-destructive`:`text-muted-foreground`),children:a})]}),e.status===`failed`?(0,G.jsx)(x,{variant:`ghost`,size:`icon-sm`,"aria-label":r(`media.upload.retry`,{name:e.file.name}),onClick:t,children:(0,G.jsx)(A,{"aria-hidden":`true`})}):null,e.status===`failed`||e.status===`done`?(0,G.jsx)(x,{variant:`ghost`,size:`icon-sm`,"aria-label":r(`media.upload.dismiss`,{name:e.file.name}),onClick:n,children:(0,G.jsx)(h,{"aria-hidden":`true`})}):null]})},Be=({onRetry:e,onDismiss:t})=>{let{t:n}=c(),r=X(e=>e.items),i=X(e=>e.clearFinished),[a,o]=(0,W.useState)(!1);if(r.length===0)return null;let s=r.filter(e=>e.status===`uploading`||e.status===`confirming`).length,l=r.filter(e=>e.status===`failed`).length,u=r.length-s-l,d=s===0&&l===0,f=!d||a;return(0,G.jsx)(Ee,{title:n(`media.upload.queueTitle`),titleAs:`h2`,flush:f,actions:(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`span`,{role:`status`,"aria-live":`polite`,className:`text-meta text-muted-foreground`,children:d?n(`media.upload.doneSummary`,{count:u}):n(`media.upload.summary`,{active:s,failed:l})}),d?(0,G.jsx)(x,{variant:`ghost`,size:`icon-sm`,"aria-expanded":f,"aria-label":n(f?`media.upload.hideFinished`:`media.upload.showFinished`),onClick:()=>o(e=>!e),children:f?(0,G.jsx)(ge,{"aria-hidden":`true`}):(0,G.jsx)(_e,{"aria-hidden":`true`})}):null,u>0?(0,G.jsx)(x,{variant:`ghost`,size:`sm`,onClick:i,children:n(`media.upload.clearFinished`)}):null]}),bodyClassName:f?void 0:`hidden`,children:f?(0,G.jsx)(`ul`,{className:`max-h-64 divide-y overflow-y-auto`,children:r.map(n=>(0,G.jsx)(ze,{item:n,onRetry:()=>e(n.id),onDismiss:()=>t(n.id)},n.id))}):null})},Ve=`application/octet-stream`,He=e=>{let t={filename:e.file.name,mimeType:e.file.type||Ve,sizeBytes:e.file.size};return f(()=>e.replaceAssetId?l.media.assets.replace(e.replaceAssetId,t):l.media.uploads.create({...t,folderId:e.folderId,visibility:e.visibility}))},$=async(e,t,n)=>{let a=await He(e);return await Le({url:i(a,ee()),form:r(a,e.file,e.file.name),onProgress:t}),n(),f(()=>l.media.uploads.confirm(a.grantId))},Ue=()=>{let e=o(),{add:t,update:n,remove:r}=X.getState(),i=(0,W.useCallback)(async t=>{n(t.id,{status:`uploading`,progress:0,error:void 0});try{let e=await $(t,e=>n(t.id,{progress:e}),()=>n(t.id,{status:`confirming`}));n(t.id,{status:`done`,assetId:e.id}),t.replaceAssetId&&se.success(b.t(`media.upload.replaced`,{name:t.file.name}))}catch(e){ce(e,`uploading ${t.file.name}`),n(t.id,{status:`failed`,error:e})}finally{await e.invalidateQueries({queryKey:a.media.all})}},[e,n]);return{enqueue:(0,W.useCallback)((e,n)=>{for(let r of e){let e={id:crypto.randomUUID(),file:r,folderId:n.folderId,visibility:n.visibility,replaceAssetId:n.replaceAssetId,status:`uploading`,progress:0,error:void 0,assetId:void 0};t(e),i(e)}},[t,i]),retry:(0,W.useCallback)(e=>{let t=X.getState().items.find(t=>t.id===e);t&&i(t)},[i]),dismiss:r,uploadOne:(0,W.useCallback)(async t=>{try{let n=await $({file:t,folderId:null,visibility:`public`,replaceAssetId:void 0},()=>void 0,()=>void 0);return e.setQueryData(a.media.asset(n.id),n),{id:n.id,alt:n.alt||null}}finally{await e.invalidateQueries({queryKey:a.media.all})}},[e])}};export{Ne as a,V as c,Fe as i,z as l,Be as n,Oe as o,Ie as r,U as s,Ue as t,L as u};
|
|
2
|
+
//# sourceMappingURL=useMediaUploader-QXSjZStv.js.map
|
package/dist/admin/assets/{useMediaUploader-CBUcNW6d.js.map → useMediaUploader-QXSjZStv.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMediaUploader-CBUcNW6d.js","names":["__iconData","__iconData","__iconData","PERCENT","useId","useRef","useRef","_Fragment","i18next","CheckCircle2","XCircle","Loader2","useState","_Fragment","useCallback","i18next","__toESM","require_jsx_runtime","buildUploadForm","resolveUploadUrl","queryKeys","useQueryClient","createLucideIcon","useTranslation","create","LoaderCircle","withCsrf","cn","apiBaseUrl","useMediaAssets","Lock","X","StatusChip","EmptyState","ErrorState","LoadingState","formatRelativeTime","formatDateTime","RowTitle","toast","logError","FieldLabel","FieldLegend","Field","FieldSet","InfoHint","instance","Button","describeError","Input","SelectValue","SelectTrigger","SelectContent","ChevronUp","SelectItem","ChevronDown","Select","Checkbox","CircleCheck","CircleX","fileKindLabel","MEDIA_STATUS_DISPLAY","formatBytes","Thumbnail","List","RotateCcw","Search","TableHeader","TableHead","TableBody","TableRow","TableCell","TableCard","Table","useSearchInput","MEDIA_TYPE_FILTERS","Panel","__iconData$3","Crosshair","__iconData$2","Images","__iconData$1","LayoutGrid","__iconData","Upload","import_react","require_react","import_jsx_runtime","PERCENT$1","CENTRE","clamp","value","FocalPoint","id","point","place","box","event","onChange","setAxis","number","text","axis","t","imageUrl","selectionRange","from","anchor","ids","to","target","useRangeSelection","range","shiftKey","rangeId","onSelectChange","checked","Card","status","asset","selected","active","selectable","onSelect","onOpen","AssetGrid","assets","activeId","AssetTable","isSelected","Library","query","items","page","scoped","filtered","view","ALL_TYPES","TYPE_LABEL_KEYS","Toolbar","onQueryChange","setText","type","onTypeChange","filter","onViewChange","UploadButton","buttonProps","input","label","files","onFiles","useMediaUploadsStore","set","state","item","patch","UploadTransferError","body","uploadWithProgress","request","url","onProgress","resolve","reject","signal","form","describeUploadError","error","PERCENT","Row","percent","statusText","onRetry","onDismiss","UploadQueue","clearFinished","showFinished","setShowFinished","failed","done","settled","expanded","current","FALLBACK_MIME_TYPE","requestGrant","details","adminApi","uploadFile","grant","onConfirming","useMediaUploader","queryClient","run","update","file","options","add","candidate","remove"],"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/crosshair.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/images.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/layout-grid.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/upload.mjs","../../src/components/FocalPoint/index.tsx","../../src/features/Media/helpers/selectionRange.ts","../../src/features/Media/hooks/useRangeSelection.ts","../../src/features/Media/AssetGrid/Card/index.tsx","../../src/features/Media/AssetGrid/index.tsx","../../src/features/Media/AssetTable/index.tsx","../../src/features/Media/Library/index.tsx","../../src/features/Media/Toolbar/index.tsx","../../src/features/Media/UploadButton/index.tsx","../../src/stores/mediaUploads.ts","../../src/helpers/uploadWithProgress.ts","../../src/features/Media/helpers/describeUploadError.ts","../../src/features/Media/UploadQueue/Row/index.tsx","../../src/features/Media/UploadQueue/index.tsx","../../src/hooks/useMediaUploader.ts"],"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: \"crosshair\",\n size: 24,\n node: [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"line\", { x1: \"22\", x2: \"18\", y1: \"12\", y2: \"12\", key: \"l9bcsi\" }],\n [\"line\", { x1: \"6\", x2: \"2\", y1: \"12\", y2: \"12\", key: \"13hhkx\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"6\", y2: \"2\", key: \"10w3f3\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"22\", y2: \"18\", key: \"15g9kq\" }]\n ]\n};\n__iconData.node;\nconst Crosshair = createLucideIcon(__iconData);\n\nexport { __iconData, Crosshair as default };\n//# sourceMappingURL=crosshair.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: \"images\",\n size: 24,\n node: [\n [\"path\", { d: \"m22 11-1.296-1.296a2.4 2.4 0 0 0-3.408 0L11 16\", key: \"9kzy35\" }],\n [\"path\", { d: \"M4 8a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2\", key: \"1t0f0t\" }],\n [\"circle\", { cx: \"13\", cy: \"7\", r: \"1\", fill: \"currentColor\", key: \"1obus6\" }],\n [\"rect\", { x: \"8\", y: \"2\", width: \"14\", height: \"14\", rx: \"2\", key: \"1gvhby\" }]\n ]\n};\n__iconData.node;\nconst Images = createLucideIcon(__iconData);\n\nexport { __iconData, Images as default };\n//# sourceMappingURL=images.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: \"layout-grid\",\n size: 24,\n node: [\n [\"rect\", { width: \"7\", height: \"7\", x: \"3\", y: \"3\", rx: \"1\", key: \"1g98yp\" }],\n [\"rect\", { width: \"7\", height: \"7\", x: \"14\", y: \"3\", rx: \"1\", key: \"6d4xhi\" }],\n [\"rect\", { width: \"7\", height: \"7\", x: \"14\", y: \"14\", rx: \"1\", key: \"nxv5o0\" }],\n [\"rect\", { width: \"7\", height: \"7\", x: \"3\", y: \"14\", rx: \"1\", key: \"1bb6yr\" }]\n ]\n};\n__iconData.node;\nconst LayoutGrid = createLucideIcon(__iconData);\n\nexport { __iconData, LayoutGrid as default };\n//# sourceMappingURL=layout-grid.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: \"upload\",\n size: 24,\n node: [\n [\"path\", { d: \"M12 3v12\", key: \"1x0j5s\" }],\n [\"path\", { d: \"m17 8-5-5-5 5\", key: \"7q97r8\" }],\n [\"path\", { d: \"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\", key: \"ih7n3h\" }]\n ]\n};\n__iconData.node;\nconst Upload = createLucideIcon(__iconData);\n\nexport { __iconData, Upload as default };\n//# sourceMappingURL=upload.mjs.map\n","import type { MediaFocalPoint } from '@shapio/client';\nimport { Crosshair } from 'lucide-react';\nimport { useId, type CSSProperties, type MouseEvent } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { InfoHint } from '@/components/InfoHint';\nimport { Button } from '@/components/ui/button';\nimport { Field, FieldLabel, FieldLegend, FieldSet } from '@/components/ui/field';\nimport { Input } from '@/components/ui/input';\n\ntype FocalPointProps = {\n imageUrl: string;\n value: MediaFocalPoint | null;\n onChange: (value: MediaFocalPoint | null) => void;\n};\n\nconst PERCENT = 100;\nconst CENTRE: MediaFocalPoint = { x: 0.5, y: 0.5 };\n\nconst clamp = (value: number) => Math.min(1, Math.max(0, value));\n\n/**\n * The point crops keep in view. Click the image to place it; the percentage inputs are the keyboard path\n * (the image itself is a pointer shortcut and hidden from assistive technology).\n */\nexport const FocalPoint = ({ imageUrl, value, onChange }: FocalPointProps) => {\n const { t } = useTranslation();\n // Unique per instance: the media details sheet and the entry's settings drawer can both show one.\n const id = useId();\n const point = value ?? CENTRE;\n const place = (event: MouseEvent<HTMLDivElement>) => {\n const box = event.currentTarget.getBoundingClientRect();\n onChange({\n x: clamp((event.clientX - box.left) / box.width),\n y: clamp((event.clientY - box.top) / box.height),\n });\n };\n const setAxis = (axis: 'x' | 'y', text: string) => {\n const number = Number(text);\n if (text !== '' && Number.isFinite(number)) {\n onChange({ ...point, [axis]: clamp(number / PERCENT) });\n }\n };\n return (\n <FieldSet aria-labelledby={`${id}-title`}>\n <FieldLegend variant=\"label\" className=\"flex items-center gap-1\">\n <span id={`${id}-title`}>{t('media.focal.title')}</span>\n <InfoHint about={t('media.focal.title')}>{t('media.focal.hint')}</InfoHint>\n </FieldLegend>\n <div\n aria-hidden=\"true\"\n onClick={place}\n className=\"relative w-fit max-w-full cursor-crosshair overflow-hidden rounded-lg border\"\n style={\n { '--focal-x': `${point.x * PERCENT}%`, '--focal-y': `${point.y * PERCENT}%` } as CSSProperties\n }\n >\n <img src={imageUrl} alt=\"\" className=\"block max-h-64 w-auto\" draggable={false} />\n {value ? (\n <span className=\"absolute top-[var(--focal-y)] left-[var(--focal-x)] flex size-6 -translate-1/2 items-center justify-center rounded-full border-2 border-background bg-primary text-primary-foreground shadow\">\n <Crosshair className=\"size-3.5\" />\n </span>\n ) : null}\n </div>\n <div className=\"flex flex-wrap items-end gap-3\">\n <Field className=\"w-28\">\n <FieldLabel htmlFor={`${id}-x`}>{t('media.focal.x')}</FieldLabel>\n <Input\n id={`${id}-x`}\n type=\"number\"\n min={0}\n max={PERCENT}\n step={1}\n value={value ? Math.round(value.x * PERCENT) : ''}\n placeholder={t('media.focal.unset')}\n onChange={(event) => setAxis('x', event.target.value)}\n />\n </Field>\n <Field className=\"w-28\">\n <FieldLabel htmlFor={`${id}-y`}>{t('media.focal.y')}</FieldLabel>\n <Input\n id={`${id}-y`}\n type=\"number\"\n min={0}\n max={PERCENT}\n step={1}\n value={value ? Math.round(value.y * PERCENT) : ''}\n placeholder={t('media.focal.unset')}\n onChange={(event) => setAxis('y', event.target.value)}\n />\n </Field>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" disabled={!value} onClick={() => onChange(null)}>\n {t('media.focal.clear')}\n </Button>\n </div>\n </FieldSet>\n );\n};\n","/**\n * The items a shift-click selects: from the anchor (the last item toggled) to the clicked one, inclusive,\n * in list order. Undefined when there is no usable anchor (then the click toggles one item).\n */\nexport const selectionRange = (\n ids: readonly string[],\n anchor: string | undefined,\n target: string,\n): string[] | undefined => {\n const from = anchor === undefined ? -1 : ids.indexOf(anchor);\n const to = ids.indexOf(target);\n if (from === -1 || to === -1) {\n return undefined;\n }\n return ids.slice(Math.min(from, to), Math.max(from, to) + 1);\n};\n","import { useRef } from 'react';\nimport { selectionRange } from '../helpers/selectionRange';\n\ntype SelectRequest = { id: string; checked: boolean; shiftKey: boolean };\n\n/**\n * Shift-click selection over an ordered list: a plain toggle sets the anchor; a shift toggle selects\n * everything from the anchor to the clicked item. Works through `onSelectChange` alone, so any owner of the\n * selection (the library, the media picker) gets ranges without new props.\n */\nexport const useRangeSelection = (\n ids: readonly string[],\n onSelectChange: (id: string, checked: boolean) => void,\n) => {\n const anchor = useRef<string | undefined>(undefined);\n const select = ({ id, checked, shiftKey }: SelectRequest) => {\n const range = shiftKey ? selectionRange(ids, anchor.current, id) : undefined;\n if (range) {\n for (const rangeId of range) {\n onSelectChange(rangeId, true);\n }\n } else {\n onSelectChange(id, checked);\n }\n anchor.current = id;\n };\n return { select };\n};\n","import type { MediaAsset } from '@shapio/client';\nimport { Lock } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { StatusChip } from '@/components/StatusChip';\nimport { Checkbox } from '@/components/ui/checkbox';\nimport { cn } from '@/helpers/cn';\nimport { fileKindLabel } from '../../helpers/fileKind';\nimport { formatBytes } from '../../helpers/formatBytes';\nimport { MEDIA_STATUS_DISPLAY } from '../../helpers/statusDisplay';\nimport { Thumbnail } from '../../Thumbnail';\n\ntype CardProps = {\n asset: MediaAsset;\n selected: boolean;\n selectable: boolean;\n active: boolean;\n /** `shiftKey`: extend the selection to here from the last item toggled. */\n onSelect: (checked: boolean, shiftKey: boolean) => void;\n onOpen: () => void;\n};\n\n/**\n * One asset tile: a button that opens its details (shift-click selects instead), and a checkbox for bulk\n * actions. The square thumbnail, then the name and \"PNG · 120 kB\".\n */\nexport const Card = ({ asset, selected, selectable, active, onSelect, onOpen }: CardProps) => {\n const { t } = useTranslation();\n const status = MEDIA_STATUS_DISPLAY[asset.status];\n return (\n <li\n className={cn(\n 'group relative overflow-hidden rounded-xl border bg-card transition-shadow focus-within:ring-[3px] focus-within:ring-ring/50 hover:border-input',\n (selected || active) && 'border-primary ring-2 ring-primary hover:border-primary',\n )}\n >\n <button\n type=\"button\"\n onClick={(event) => {\n if (event.shiftKey && selectable) {\n onSelect(!selected, true);\n return;\n }\n onOpen();\n }}\n className=\"flex w-full flex-col text-left outline-none\"\n aria-label={t('media.openDetails', { name: asset.filename })}\n >\n <Thumbnail asset={asset} className=\"aspect-square w-full border-b\" />\n <span className=\"flex min-w-0 flex-col gap-0.5 px-3 py-2.5\">\n <span className=\"truncate text-sm font-medium\" title={asset.filename}>\n {asset.filename}\n </span>\n <span className=\"flex min-w-0 items-center gap-1.5 text-meta text-muted-foreground\">\n <span className=\"truncate\">\n {fileKindLabel(asset.filename, asset.mimeType)} · {formatBytes(asset.sizeBytes)}\n </span>\n {asset.visibility === 'private' ? (\n <Lock aria-hidden=\"true\" className=\"size-3.5 shrink-0\" />\n ) : null}\n </span>\n </span>\n </button>\n {asset.status === 'ready' ? null : (\n <StatusChip\n tone={status.tone}\n label={t(status.labelKey)}\n size=\"sm\"\n className=\"pointer-events-none absolute top-2 right-2\"\n />\n )}\n {selectable ? (\n <Checkbox\n checked={selected}\n onClick={(event) => {\n if (event.shiftKey) {\n event.preventDefault();\n onSelect(!selected, true);\n }\n }}\n onCheckedChange={(checked) => onSelect(checked === true, false)}\n aria-label={t('media.select', { name: asset.filename })}\n className=\"absolute top-2 left-2 bg-card\"\n />\n ) : null}\n </li>\n );\n};\n","import type { MediaAsset } from '@shapio/client';\nimport { useTranslation } from 'react-i18next';\nimport { useRangeSelection } from '../hooks/useRangeSelection';\nimport { Card } from './Card';\n\ntype AssetGridProps = {\n assets: readonly MediaAsset[];\n selected: ReadonlySet<string>;\n selectable: boolean;\n activeId: string | undefined;\n onSelectChange: (id: string, checked: boolean) => void;\n onOpen: (asset: MediaAsset) => void;\n};\n\n/** Square tiles that fill the width; shift-click (tile or checkbox) selects a range. */\nexport const AssetGrid = ({\n assets,\n selected,\n selectable,\n activeId,\n onSelectChange,\n onOpen,\n}: AssetGridProps) => {\n const { t } = useTranslation();\n const range = useRangeSelection(\n assets.map((asset) => asset.id),\n onSelectChange,\n );\n return (\n <ul\n aria-label={t('media.assetsLabel', { count: assets.length })}\n className=\"grid grid-cols-[repeat(auto-fill,minmax(160px,1fr))] gap-4\"\n >\n {assets.map((asset) => (\n <Card\n key={asset.id}\n asset={asset}\n selected={selected.has(asset.id)}\n selectable={selectable}\n active={asset.id === activeId}\n onSelect={(checked, shiftKey) => range.select({ id: asset.id, checked, shiftKey })}\n onOpen={() => onOpen(asset)}\n />\n ))}\n </ul>\n );\n};\n","import type { MediaAsset } from '@shapio/client';\nimport { Lock } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { RowTitle } from '@/components/RowTitle';\nimport { StatusChip } from '@/components/StatusChip';\nimport { TableCard } from '@/components/TableCard';\nimport { Checkbox } from '@/components/ui/checkbox';\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';\nimport { formatDateTime, formatRelativeTime } from '@/helpers/formatDate';\nimport { fileKindLabel } from '../helpers/fileKind';\nimport { formatBytes } from '../helpers/formatBytes';\nimport { MEDIA_STATUS_DISPLAY } from '../helpers/statusDisplay';\nimport { useRangeSelection } from '../hooks/useRangeSelection';\nimport { Thumbnail } from '../Thumbnail';\n\ntype AssetTableProps = {\n assets: readonly MediaAsset[];\n selected: ReadonlySet<string>;\n selectable: boolean;\n onSelectChange: (id: string, checked: boolean) => void;\n onOpen: (asset: MediaAsset) => void;\n};\n\n/** The list view: name, type, size, status and date per asset; shift-click a checkbox to select a range. */\nexport const AssetTable = ({ assets, selected, selectable, onSelectChange, onOpen }: AssetTableProps) => {\n const { t } = useTranslation();\n const range = useRangeSelection(\n assets.map((asset) => asset.id),\n onSelectChange,\n );\n return (\n <TableCard>\n <Table>\n <TableHeader>\n <TableRow>\n {selectable ? (\n <TableHead className=\"w-10\">\n <span className=\"sr-only\">{t('media.selection')}</span>\n </TableHead>\n ) : null}\n <TableHead>{t('media.fields.filename')}</TableHead>\n <TableHead>{t('media.fields.type')}</TableHead>\n <TableHead className=\"text-right\">{t('media.fields.size')}</TableHead>\n <TableHead>{t('media.fields.status')}</TableHead>\n <TableHead>{t('media.fields.uploaded')}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {assets.map((asset) => {\n const status = MEDIA_STATUS_DISPLAY[asset.status];\n const isSelected = selected.has(asset.id);\n return (\n <TableRow key={asset.id} data-state={isSelected ? 'selected' : undefined}>\n {selectable ? (\n <TableCell>\n <Checkbox\n checked={isSelected}\n onClick={(event) => {\n if (event.shiftKey) {\n event.preventDefault();\n range.select({ id: asset.id, checked: !isSelected, shiftKey: true });\n }\n }}\n onCheckedChange={(checked) =>\n range.select({ id: asset.id, checked: checked === true, shiftKey: false })\n }\n aria-label={t('media.select', { name: asset.filename })}\n />\n </TableCell>\n ) : null}\n <TableCell className=\"max-w-96\">\n <span className=\"flex min-w-0 items-center gap-3\">\n <Thumbnail asset={asset} className=\"size-8 shrink-0 rounded-md\" />\n <RowTitle asChild className=\"min-w-0 truncate text-left\">\n <button type=\"button\" onClick={() => onOpen(asset)}>\n {asset.filename}\n </button>\n </RowTitle>\n {asset.visibility === 'private' ? (\n <Lock\n role=\"img\"\n aria-label={t('media.visibility.private')}\n className=\"size-3.5 shrink-0 text-muted-foreground\"\n />\n ) : null}\n </span>\n </TableCell>\n <TableCell className=\"text-muted-foreground\" title={asset.mimeType}>\n {fileKindLabel(asset.filename, asset.mimeType)}\n </TableCell>\n <TableCell className=\"text-right tabular-nums\">{formatBytes(asset.sizeBytes)}</TableCell>\n <TableCell>\n <StatusChip tone={status.tone} label={t(status.labelKey)} size=\"sm\" />\n </TableCell>\n <TableCell className=\"whitespace-nowrap\" title={formatDateTime(asset.createdAt)}>\n {formatRelativeTime(asset.createdAt)}\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </TableCard>\n );\n};\n","import type { MediaAsset } from '@shapio/client';\nimport { Images } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { useMediaAssets } from '@/api/media';\nimport { EmptyState } from '@/components/EmptyState';\nimport { ErrorState } from '@/components/ErrorState';\nimport { LoadingState } from '@/components/LoadingState';\nimport { Button } from '@/components/ui/button';\nimport { AssetGrid } from '../AssetGrid';\nimport { AssetTable } from '../AssetTable';\nimport type { MediaView } from '../constants';\n\ntype LibraryProps = {\n query: Parameters<typeof useMediaAssets>[0];\n filtered: boolean;\n view: MediaView;\n selected: ReadonlySet<string>;\n selectable: boolean;\n activeId: string | undefined;\n onSelectChange: (id: string, checked: boolean) => void;\n onOpen: (asset: MediaAsset) => void;\n};\n\n/** The assets of the current folder and filters: loading, error, empty, grid or list, and \"Load more\". */\nexport const Library = ({\n query,\n filtered,\n view,\n selected,\n selectable,\n activeId,\n onSelectChange,\n onOpen,\n}: LibraryProps) => {\n const { t } = useTranslation();\n const assets = useMediaAssets(query);\n if (assets.isPending) {\n return <LoadingState rows={4} />;\n }\n if (assets.isError) {\n return <ErrorState error={assets.error} onRetry={() => void assets.refetch()} />;\n }\n const items = assets.data.pages.flatMap((page) => page.items);\n if (items.length === 0) {\n // The whole library is empty: a page-sized empty state. An empty folder or search: a quieter one.\n const scoped = filtered || query.folder !== undefined;\n return (\n <EmptyState\n icon={Images}\n size={scoped ? 'panel' : 'page'}\n title={filtered ? t('media.emptyFiltered') : scoped ? t('media.emptyFolder') : t('media.empty')}\n />\n );\n }\n return (\n <div className=\"space-y-4\">\n {view === 'grid' ? (\n <AssetGrid\n assets={items}\n selected={selected}\n selectable={selectable}\n activeId={activeId}\n onSelectChange={onSelectChange}\n onOpen={onOpen}\n />\n ) : (\n <AssetTable\n assets={items}\n selected={selected}\n selectable={selectable}\n onSelectChange={onSelectChange}\n onOpen={onOpen}\n />\n )}\n {assets.hasNextPage ? (\n <div className=\"flex justify-center\">\n <Button\n variant=\"outline\"\n disabled={assets.isFetchingNextPage}\n aria-busy={assets.isFetchingNextPage || undefined}\n onClick={() => void assets.fetchNextPage()}\n >\n {assets.isFetchingNextPage ? t('common.loading') : t('media.loadMore')}\n </Button>\n </div>\n ) : null}\n </div>\n );\n};\n","import { LayoutGrid, List, Search } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { Button } from '@/components/ui/button';\nimport { Input } from '@/components/ui/input';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';\nimport { useSearchInput } from '@/hooks/useSearchInput';\nimport { MEDIA_TYPE_FILTERS, type MediaTypeFilter, type MediaView } from '../constants';\n\ntype ToolbarProps = {\n query: string | undefined;\n type: MediaTypeFilter | undefined;\n view: MediaView;\n onQueryChange: (query: string | undefined) => void;\n onTypeChange: (type: MediaTypeFilter | undefined) => void;\n onViewChange: (view: MediaView) => void;\n};\n\nconst ALL_TYPES = 'all';\n\nconst TYPE_LABEL_KEYS = {\n image: 'media.types.image',\n video: 'media.types.video',\n audio: 'media.types.audio',\n pdf: 'media.types.pdf',\n} as const satisfies Record<MediaTypeFilter, string>;\n\n/** Search, type filter and grid/list switch. */\nexport const Toolbar = ({ query, type, view, onQueryChange, onTypeChange, onViewChange }: ToolbarProps) => {\n const { t } = useTranslation();\n const { text, setText } = useSearchInput(query, onQueryChange);\n return (\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"relative min-w-48 flex-1\">\n <Search\n aria-hidden=\"true\"\n className=\"absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground\"\n />\n <Input\n type=\"search\"\n value={text}\n onChange={(event) => setText(event.target.value)}\n aria-label={t('media.search')}\n placeholder={t('media.searchPlaceholder')}\n inputSize=\"sm\"\n className=\"pl-8\"\n />\n </div>\n <Select\n value={type ?? ALL_TYPES}\n onValueChange={(value) => onTypeChange(value === ALL_TYPES ? undefined : (value as MediaTypeFilter))}\n >\n <SelectTrigger size=\"sm\" aria-label={t('media.typeFilter')} className=\"w-36\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL_TYPES}>{t('media.types.all')}</SelectItem>\n {MEDIA_TYPE_FILTERS.map((filter) => (\n <SelectItem key={filter} value={filter}>\n {t(TYPE_LABEL_KEYS[filter])}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <div\n role=\"group\"\n aria-label={t('media.view')}\n className=\"flex h-9 items-center gap-0.5 rounded-lg border border-input px-px\"\n >\n <Button\n variant={view === 'grid' ? 'secondary' : 'ghost'}\n size=\"icon-sm\"\n aria-pressed={view === 'grid'}\n aria-label={t('media.viewGrid')}\n onClick={() => onViewChange('grid')}\n >\n <LayoutGrid aria-hidden=\"true\" />\n </Button>\n <Button\n variant={view === 'list' ? 'secondary' : 'ghost'}\n size=\"icon-sm\"\n aria-pressed={view === 'list'}\n aria-label={t('media.viewList')}\n onClick={() => onViewChange('list')}\n >\n <List aria-hidden=\"true\" />\n </Button>\n </div>\n </div>\n );\n};\n","import { Upload } from 'lucide-react';\nimport { useRef, type ComponentProps } from 'react';\nimport { Button } from '@/components/ui/button';\n\ntype UploadButtonProps = Omit<ComponentProps<typeof Button>, 'onClick'> & {\n label: string;\n multiple?: boolean;\n onFiles: (files: File[]) => void;\n};\n\n/** A button that opens the file picker (the keyboard path; dropping files is the pointer shortcut). */\nexport const UploadButton = ({ label, multiple = true, onFiles, ...buttonProps }: UploadButtonProps) => {\n const input = useRef<HTMLInputElement>(null);\n return (\n <>\n <Button {...buttonProps} onClick={() => input.current?.click()}>\n <Upload aria-hidden=\"true\" />\n {label}\n </Button>\n <input\n ref={input}\n type=\"file\"\n multiple={multiple}\n tabIndex={-1}\n aria-hidden=\"true\"\n className=\"sr-only\"\n onChange={(event) => {\n const files = [...(event.target.files ?? [])];\n event.target.value = '';\n if (files.length > 0) {\n onFiles(files);\n }\n }}\n />\n </>\n );\n};\n","import type { MediaVisibility } from '@shapio/client';\nimport { create } from 'zustand';\n\nexport type UploadStatus = 'uploading' | 'confirming' | 'done' | 'failed';\n\nexport type UploadItem = {\n id: string;\n file: File;\n folderId: string | null;\n visibility: MediaVisibility;\n /** Set when the upload replaces this asset's file. */\n replaceAssetId: string | undefined;\n status: UploadStatus;\n /** 0 to 1 while the bytes are sent. */\n progress: number;\n error: unknown;\n assetId: string | undefined;\n};\n\ntype MediaUploadsState = {\n items: UploadItem[];\n add: (item: UploadItem) => void;\n update: (id: string, patch: Partial<UploadItem>) => void;\n remove: (id: string) => void;\n clearFinished: () => void;\n};\n\n/** Uploads in flight and recently finished (client-only; kept while the admin is open, not persisted). */\nexport const useMediaUploadsStore = create<MediaUploadsState>()((set) => ({\n items: [],\n add: (item) => set((state) => ({ items: [...state.items, item] })),\n update: (id, patch) =>\n set((state) => ({ items: state.items.map((item) => (item.id === id ? { ...item, ...patch } : item)) })),\n remove: (id) => set((state) => ({ items: state.items.filter((item) => item.id !== id) })),\n clearFinished: () => set((state) => ({ items: state.items.filter((item) => item.status !== 'done') })),\n}));\n","/** The storage (bucket or Shapio's upload route) refused the bytes; `status` 0 means the request never completed. */\nexport class UploadTransferError extends Error {\n readonly status: number;\n readonly body: string;\n\n constructor(status: number, body: string) {\n super(`Upload failed with status ${status}`);\n this.name = 'UploadTransferError';\n this.status = status;\n this.body = body;\n }\n}\n\ntype UploadWithProgressInput = {\n url: string;\n form: FormData;\n onProgress: (fraction: number) => void;\n signal?: AbortSignal;\n};\n\n/**\n * POSTs a multipart form with upload progress (fetch cannot report it, so this uses XMLHttpRequest).\n * No credentials are sent: the grant's fields authorise the upload, whether it goes to a bucket or to Shapio.\n */\nexport const uploadWithProgress = ({ url, form, onProgress, signal }: UploadWithProgressInput) =>\n new Promise<void>((resolve, reject) => {\n const request = new XMLHttpRequest();\n request.open('POST', url);\n request.withCredentials = false;\n request.upload.onprogress = (event) => {\n if (event.lengthComputable && event.total > 0) {\n onProgress(event.loaded / event.total);\n }\n };\n request.onload = () => {\n if (request.status >= 200 && request.status < 300) {\n onProgress(1);\n resolve();\n return;\n }\n reject(new UploadTransferError(request.status, request.responseText));\n };\n request.onerror = () => reject(new UploadTransferError(0, ''));\n request.onabort = () => reject(new DOMException('Upload cancelled', 'AbortError'));\n signal?.addEventListener('abort', () => request.abort(), { once: true });\n request.send(form);\n });\n","import { i18next } from '@/app/i18n';\nimport { describeError } from '@/helpers/describeError';\nimport { UploadTransferError } from '@/helpers/uploadWithProgress';\n\n/** Why an upload failed, for the queue. Storage refusals (bucket or upload route) get their own message. */\nexport const describeUploadError = (error: unknown): string => {\n if (error instanceof UploadTransferError) {\n if (error.status === 0) {\n return i18next.t('media.upload.unreachable');\n }\n if (error.status === 413 || /EntityTooLarge/.test(error.body)) {\n return i18next.t('errors.codes.FILE_TOO_LARGE');\n }\n return i18next.t('media.upload.transferFailed', { status: error.status });\n }\n return describeError(error);\n};\n","import { CheckCircle2, Loader2, RotateCcw, X, XCircle } from 'lucide-react';\nimport type { CSSProperties } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Button } from '@/components/ui/button';\nimport { cn } from '@/helpers/cn';\nimport type { UploadItem } from '@/stores/mediaUploads';\nimport { describeUploadError } from '../../helpers/describeUploadError';\nimport { formatBytes } from '../../helpers/formatBytes';\n\ntype RowProps = { item: UploadItem; onRetry: () => void; onDismiss: () => void };\n\nconst PERCENT = 100;\n\n/** One upload: name, size, progress (a real progressbar), and Retry/Dismiss when it failed. */\nexport const Row = ({ item, onRetry, onDismiss }: RowProps) => {\n const { t } = useTranslation();\n const percent = Math.round(item.progress * PERCENT);\n const statusText =\n item.status === 'uploading'\n ? t('media.upload.uploading', { percent })\n : item.status === 'confirming'\n ? t('media.upload.checking')\n : item.status === 'done'\n ? t('media.upload.done')\n : describeUploadError(item.error);\n return (\n <li className=\"flex items-start gap-3 px-5 py-2.5\">\n <span className=\"mt-0.5 shrink-0\">\n {item.status === 'done' ? (\n <CheckCircle2 aria-hidden=\"true\" className=\"size-4 text-success\" />\n ) : item.status === 'failed' ? (\n <XCircle aria-hidden=\"true\" className=\"size-4 text-destructive\" />\n ) : (\n <Loader2\n aria-hidden=\"true\"\n className=\"size-4 animate-spin text-muted-foreground motion-reduce:animate-none\"\n />\n )}\n </span>\n <div className=\"min-w-0 flex-1 space-y-1\">\n <p className=\"flex items-baseline gap-2 text-sm\">\n <span className=\"truncate font-medium\">{item.file.name}</span>\n <span className=\"shrink-0 text-meta text-muted-foreground\">{formatBytes(item.file.size)}</span>\n </p>\n {item.status === 'uploading' || item.status === 'confirming' ? (\n <div\n role=\"progressbar\"\n aria-label={t('media.upload.progress', { name: item.file.name })}\n aria-valuemin={0}\n aria-valuemax={PERCENT}\n aria-valuenow={percent}\n className=\"h-1.5 overflow-hidden rounded-full bg-muted\"\n style={{ '--upload-progress': `${percent}%` } as CSSProperties}\n >\n <div className=\"h-full w-[var(--upload-progress)] bg-primary transition-[width]\" />\n </div>\n ) : null}\n <p\n className={cn('text-meta', item.status === 'failed' ? 'text-destructive' : 'text-muted-foreground')}\n >\n {statusText}\n </p>\n </div>\n {item.status === 'failed' ? (\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={t('media.upload.retry', { name: item.file.name })}\n onClick={onRetry}\n >\n <RotateCcw aria-hidden=\"true\" />\n </Button>\n ) : null}\n {item.status === 'failed' || item.status === 'done' ? (\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={t('media.upload.dismiss', { name: item.file.name })}\n onClick={onDismiss}\n >\n <X aria-hidden=\"true\" />\n </Button>\n ) : null}\n </li>\n );\n};\n","import { ChevronDown, ChevronUp } from 'lucide-react';\nimport { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Panel } from '@/components/Panel';\nimport { Button } from '@/components/ui/button';\nimport { useMediaUploadsStore } from '@/stores/mediaUploads';\nimport { Row } from './Row';\n\ntype UploadQueueProps = { onRetry: (id: string) => void; onDismiss: (id: string) => void };\n\n/**\n * Uploads in progress and recently finished, newest last, as a compact panel. Once nothing is running or\n * failed it collapses to one line (\"3 uploaded\"); failures stay open until retried or dismissed.\n */\nexport const UploadQueue = ({ onRetry, onDismiss }: UploadQueueProps) => {\n const { t } = useTranslation();\n const items = useMediaUploadsStore((state) => state.items);\n const clearFinished = useMediaUploadsStore((state) => state.clearFinished);\n const [showFinished, setShowFinished] = useState(false);\n if (items.length === 0) {\n return null;\n }\n const active = items.filter((item) => item.status === 'uploading' || item.status === 'confirming').length;\n const failed = items.filter((item) => item.status === 'failed').length;\n const done = items.length - active - failed;\n const settled = active === 0 && failed === 0;\n const expanded = !settled || showFinished;\n return (\n <Panel\n title={t('media.upload.queueTitle')}\n titleAs=\"h2\"\n flush={expanded}\n actions={\n <>\n <span role=\"status\" aria-live=\"polite\" className=\"text-meta text-muted-foreground\">\n {settled\n ? t('media.upload.doneSummary', { count: done })\n : t('media.upload.summary', { active, failed })}\n </span>\n {settled ? (\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-expanded={expanded}\n aria-label={expanded ? t('media.upload.hideFinished') : t('media.upload.showFinished')}\n onClick={() => setShowFinished((current) => !current)}\n >\n {expanded ? <ChevronUp aria-hidden=\"true\" /> : <ChevronDown aria-hidden=\"true\" />}\n </Button>\n ) : null}\n {done > 0 ? (\n <Button variant=\"ghost\" size=\"sm\" onClick={clearFinished}>\n {t('media.upload.clearFinished')}\n </Button>\n ) : null}\n </>\n }\n bodyClassName={expanded ? undefined : 'hidden'}\n >\n {expanded ? (\n <ul className=\"max-h-64 divide-y overflow-y-auto\">\n {items.map((item) => (\n <Row\n key={item.id}\n item={item}\n onRetry={() => onRetry(item.id)}\n onDismiss={() => onDismiss(item.id)}\n />\n ))}\n </ul>\n ) : null}\n </Panel>\n );\n};\n","import { buildUploadForm, type MediaAsset, type MediaVisibility, type UploadGrant } from '@shapio/client';\nimport { useQueryClient } from '@tanstack/react-query';\nimport { useCallback } from 'react';\nimport { toast } from 'sonner';\nimport { adminApi, apiBaseUrl } from '@/api/client';\nimport { withCsrf } from '@/api/csrf';\nimport { queryKeys } from '@/api/queryKeys';\nimport { i18next } from '@/app/i18n';\nimport { logError } from '@/helpers/reportError';\nimport { resolveUploadUrl } from '@/helpers/resolveUploadUrl';\nimport { uploadWithProgress } from '@/helpers/uploadWithProgress';\nimport { useMediaUploadsStore, type UploadItem } from '@/stores/mediaUploads';\n\nconst FALLBACK_MIME_TYPE = 'application/octet-stream';\n\ntype UploadTarget = Pick<UploadItem, 'file' | 'folderId' | 'visibility' | 'replaceAssetId'>;\n\nconst requestGrant = (item: UploadTarget): Promise<UploadGrant> => {\n const details = {\n filename: item.file.name,\n mimeType: item.file.type || FALLBACK_MIME_TYPE,\n sizeBytes: item.file.size,\n };\n return withCsrf(() =>\n item.replaceAssetId\n ? adminApi.media.assets.replace(item.replaceAssetId, details)\n : adminApi.media.uploads.create({ ...details, folderId: item.folderId, visibility: item.visibility }),\n );\n};\n\n/** Grant, send (with progress), confirm: one file into the library. Throws when any step fails. */\nconst uploadFile = async (\n item: UploadTarget,\n onProgress: (progress: number) => void,\n onConfirming: () => void,\n): Promise<MediaAsset> => {\n const grant = await requestGrant(item);\n await uploadWithProgress({\n url: resolveUploadUrl(grant, apiBaseUrl()),\n form: buildUploadForm(grant, item.file, item.file.name),\n onProgress,\n });\n onConfirming();\n return withCsrf(() => adminApi.media.uploads.confirm(grant.grantId));\n};\n\n/** What an editor gets back from `uploadOne`: the new asset's ID and its library alt text. */\nexport type UploadedMedia = { id: string; alt: string | null };\n\ntype EnqueueOptions = { folderId: string | null; visibility: MediaVisibility; replaceAssetId?: string };\n\n/**\n * The upload flow, the same for local disk and S3: ask for a grant, send the form to the grant's URL\n * (with progress), then confirm so the server checks the bytes and records the asset. A failed upload stays\n * in the queue with its error; retrying starts again with a fresh grant (grants are single-use).\n */\nexport const useMediaUploader = () => {\n const queryClient = useQueryClient();\n const { add, update, remove } = useMediaUploadsStore.getState();\n\n const run = useCallback(\n async (item: UploadItem) => {\n update(item.id, { status: 'uploading', progress: 0, error: undefined });\n try {\n const asset = await uploadFile(\n item,\n (progress) => update(item.id, { progress }),\n () => update(item.id, { status: 'confirming' }),\n );\n update(item.id, { status: 'done', assetId: asset.id });\n if (item.replaceAssetId) {\n toast.success(i18next.t('media.upload.replaced', { name: item.file.name }));\n }\n } catch (error) {\n logError(error, `uploading ${item.file.name}`);\n update(item.id, { status: 'failed', error });\n } finally {\n await queryClient.invalidateQueries({ queryKey: queryKeys.media.all });\n }\n },\n [queryClient, update],\n );\n\n const enqueue = useCallback(\n (files: readonly File[], options: EnqueueOptions) => {\n for (const file of files) {\n const item: UploadItem = {\n id: crypto.randomUUID(),\n file,\n folderId: options.folderId,\n visibility: options.visibility,\n replaceAssetId: options.replaceAssetId,\n status: 'uploading',\n progress: 0,\n error: undefined,\n assetId: undefined,\n };\n add(item);\n void run(item);\n }\n },\n [add, run],\n );\n\n const retry = useCallback(\n (id: string) => {\n const item = useMediaUploadsStore.getState().items.find((candidate) => candidate.id === id);\n if (item) {\n void run(item);\n }\n },\n [run],\n );\n\n /**\n * One file uploaded outside the queue (a file dropped into rich text): resolves with the new asset, or\n * rejects so the caller can undo its placeholder. Public, in the root folder.\n */\n const uploadOne = useCallback(\n async (file: File): Promise<UploadedMedia> => {\n try {\n const asset = await uploadFile(\n { file, folderId: null, visibility: 'public', replaceAssetId: undefined },\n () => undefined,\n () => undefined,\n );\n queryClient.setQueryData(queryKeys.media.asset(asset.id), asset);\n return { id: asset.id, alt: asset.alt || null };\n } finally {\n await queryClient.invalidateQueries({ queryKey: queryKeys.media.all });\n }\n },\n [queryClient],\n );\n\n return { enqueue, retry, dismiss: remove, uploadOne };\n};\n"],"ignoreList":[0,1,2,3],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useMediaUploader-QXSjZStv.js","names":["__iconData","__iconData","__iconData","PERCENT","useId","useRef","useRef","_Fragment","i18next","CheckCircle2","XCircle","Loader2","useState","_Fragment","useCallback","i18next","__toESM","require_jsx_runtime","buildUploadForm","resolveUploadUrl","queryKeys","useQueryClient","createLucideIcon","useTranslation","create","LoaderCircle","withCsrf","cn","apiBaseUrl","useMediaAssets","Lock","X","StatusChip","EmptyState","ErrorState","LoadingState","formatRelativeTime","formatDateTime","RowTitle","toast","logError","FieldLabel","FieldLegend","Field","FieldSet","InfoHint","instance","Button","describeError","Input","SelectValue","SelectTrigger","SelectContent","ChevronUp","SelectItem","ChevronDown","Select","Checkbox","CircleCheck","CircleX","fileKindLabel","MEDIA_STATUS_DISPLAY","formatBytes","Thumbnail","List","RotateCcw","Search","TableHeader","TableHead","TableBody","TableRow","TableCell","TableCard","Table","useSearchInput","MEDIA_TYPE_FILTERS","Panel","__iconData$3","Crosshair","__iconData$2","Images","__iconData$1","LayoutGrid","__iconData","Upload","import_react","require_react","import_jsx_runtime","PERCENT$1","CENTRE","clamp","value","FocalPoint","id","point","place","box","event","onChange","setAxis","number","text","axis","t","imageUrl","selectionRange","from","anchor","ids","to","target","useRangeSelection","range","shiftKey","rangeId","onSelectChange","checked","Card","status","asset","selected","active","selectable","onSelect","onOpen","AssetGrid","assets","activeId","AssetTable","isSelected","Library","query","items","page","scoped","filtered","view","ALL_TYPES","TYPE_LABEL_KEYS","Toolbar","onQueryChange","setText","type","onTypeChange","filter","onViewChange","UploadButton","buttonProps","input","label","files","onFiles","useMediaUploadsStore","set","state","item","patch","UploadTransferError","body","uploadWithProgress","request","url","onProgress","resolve","reject","signal","form","describeUploadError","error","PERCENT","Row","percent","statusText","onRetry","onDismiss","UploadQueue","clearFinished","showFinished","setShowFinished","failed","done","settled","expanded","current","FALLBACK_MIME_TYPE","requestGrant","details","adminApi","uploadFile","grant","onConfirming","useMediaUploader","queryClient","run","update","file","options","add","candidate","remove"],"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/crosshair.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/images.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/layout-grid.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/upload.mjs","../../src/components/FocalPoint/index.tsx","../../src/features/Media/helpers/selectionRange.ts","../../src/features/Media/hooks/useRangeSelection.ts","../../src/features/Media/AssetGrid/Card/index.tsx","../../src/features/Media/AssetGrid/index.tsx","../../src/features/Media/AssetTable/index.tsx","../../src/features/Media/Library/index.tsx","../../src/features/Media/Toolbar/index.tsx","../../src/features/Media/UploadButton/index.tsx","../../src/stores/mediaUploads.ts","../../src/helpers/uploadWithProgress.ts","../../src/features/Media/helpers/describeUploadError.ts","../../src/features/Media/UploadQueue/Row/index.tsx","../../src/features/Media/UploadQueue/index.tsx","../../src/hooks/useMediaUploader.ts"],"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: \"crosshair\",\n size: 24,\n node: [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"line\", { x1: \"22\", x2: \"18\", y1: \"12\", y2: \"12\", key: \"l9bcsi\" }],\n [\"line\", { x1: \"6\", x2: \"2\", y1: \"12\", y2: \"12\", key: \"13hhkx\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"6\", y2: \"2\", key: \"10w3f3\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"22\", y2: \"18\", key: \"15g9kq\" }]\n ]\n};\n__iconData.node;\nconst Crosshair = createLucideIcon(__iconData);\n\nexport { __iconData, Crosshair as default };\n//# sourceMappingURL=crosshair.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: \"images\",\n size: 24,\n node: [\n [\"path\", { d: \"m22 11-1.296-1.296a2.4 2.4 0 0 0-3.408 0L11 16\", key: \"9kzy35\" }],\n [\"path\", { d: \"M4 8a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2\", key: \"1t0f0t\" }],\n [\"circle\", { cx: \"13\", cy: \"7\", r: \"1\", fill: \"currentColor\", key: \"1obus6\" }],\n [\"rect\", { x: \"8\", y: \"2\", width: \"14\", height: \"14\", rx: \"2\", key: \"1gvhby\" }]\n ]\n};\n__iconData.node;\nconst Images = createLucideIcon(__iconData);\n\nexport { __iconData, Images as default };\n//# sourceMappingURL=images.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: \"layout-grid\",\n size: 24,\n node: [\n [\"rect\", { width: \"7\", height: \"7\", x: \"3\", y: \"3\", rx: \"1\", key: \"1g98yp\" }],\n [\"rect\", { width: \"7\", height: \"7\", x: \"14\", y: \"3\", rx: \"1\", key: \"6d4xhi\" }],\n [\"rect\", { width: \"7\", height: \"7\", x: \"14\", y: \"14\", rx: \"1\", key: \"nxv5o0\" }],\n [\"rect\", { width: \"7\", height: \"7\", x: \"3\", y: \"14\", rx: \"1\", key: \"1bb6yr\" }]\n ]\n};\n__iconData.node;\nconst LayoutGrid = createLucideIcon(__iconData);\n\nexport { __iconData, LayoutGrid as default };\n//# sourceMappingURL=layout-grid.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: \"upload\",\n size: 24,\n node: [\n [\"path\", { d: \"M12 3v12\", key: \"1x0j5s\" }],\n [\"path\", { d: \"m17 8-5-5-5 5\", key: \"7q97r8\" }],\n [\"path\", { d: \"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\", key: \"ih7n3h\" }]\n ]\n};\n__iconData.node;\nconst Upload = createLucideIcon(__iconData);\n\nexport { __iconData, Upload as default };\n//# sourceMappingURL=upload.mjs.map\n","import type { MediaFocalPoint } from '@shapio/client';\nimport { Crosshair } from 'lucide-react';\nimport { useId, type CSSProperties, type MouseEvent } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { InfoHint } from '@/components/InfoHint';\nimport { Button } from '@/components/ui/button';\nimport { Field, FieldLabel, FieldLegend, FieldSet } from '@/components/ui/field';\nimport { Input } from '@/components/ui/input';\n\ntype FocalPointProps = {\n imageUrl: string;\n value: MediaFocalPoint | null;\n onChange: (value: MediaFocalPoint | null) => void;\n};\n\nconst PERCENT = 100;\nconst CENTRE: MediaFocalPoint = { x: 0.5, y: 0.5 };\n\nconst clamp = (value: number) => Math.min(1, Math.max(0, value));\n\n/**\n * The point crops keep in view. Click the image to place it; the percentage inputs are the keyboard path\n * (the image itself is a pointer shortcut and hidden from assistive technology).\n */\nexport const FocalPoint = ({ imageUrl, value, onChange }: FocalPointProps) => {\n const { t } = useTranslation();\n // Unique per instance: the media details sheet and the entry's settings drawer can both show one.\n const id = useId();\n const point = value ?? CENTRE;\n const place = (event: MouseEvent<HTMLDivElement>) => {\n const box = event.currentTarget.getBoundingClientRect();\n onChange({\n x: clamp((event.clientX - box.left) / box.width),\n y: clamp((event.clientY - box.top) / box.height),\n });\n };\n const setAxis = (axis: 'x' | 'y', text: string) => {\n const number = Number(text);\n if (text !== '' && Number.isFinite(number)) {\n onChange({ ...point, [axis]: clamp(number / PERCENT) });\n }\n };\n return (\n <FieldSet aria-labelledby={`${id}-title`}>\n <FieldLegend variant=\"label\" className=\"flex items-center gap-1\">\n <span id={`${id}-title`}>{t('media.focal.title')}</span>\n <InfoHint about={t('media.focal.title')}>{t('media.focal.hint')}</InfoHint>\n </FieldLegend>\n <div\n aria-hidden=\"true\"\n onClick={place}\n className=\"relative w-fit max-w-full cursor-crosshair overflow-hidden rounded-lg border\"\n style={\n { '--focal-x': `${point.x * PERCENT}%`, '--focal-y': `${point.y * PERCENT}%` } as CSSProperties\n }\n >\n <img src={imageUrl} alt=\"\" className=\"block max-h-64 w-auto\" draggable={false} />\n {value ? (\n <span className=\"absolute top-[var(--focal-y)] left-[var(--focal-x)] flex size-6 -translate-1/2 items-center justify-center rounded-full border-2 border-background bg-primary text-primary-foreground shadow\">\n <Crosshair className=\"size-3.5\" />\n </span>\n ) : null}\n </div>\n <div className=\"flex flex-wrap items-end gap-3\">\n <Field className=\"w-28\">\n <FieldLabel htmlFor={`${id}-x`}>{t('media.focal.x')}</FieldLabel>\n <Input\n id={`${id}-x`}\n type=\"number\"\n min={0}\n max={PERCENT}\n step={1}\n value={value ? Math.round(value.x * PERCENT) : ''}\n placeholder={t('media.focal.unset')}\n onChange={(event) => setAxis('x', event.target.value)}\n />\n </Field>\n <Field className=\"w-28\">\n <FieldLabel htmlFor={`${id}-y`}>{t('media.focal.y')}</FieldLabel>\n <Input\n id={`${id}-y`}\n type=\"number\"\n min={0}\n max={PERCENT}\n step={1}\n value={value ? Math.round(value.y * PERCENT) : ''}\n placeholder={t('media.focal.unset')}\n onChange={(event) => setAxis('y', event.target.value)}\n />\n </Field>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" disabled={!value} onClick={() => onChange(null)}>\n {t('media.focal.clear')}\n </Button>\n </div>\n </FieldSet>\n );\n};\n","/**\n * The items a shift-click selects: from the anchor (the last item toggled) to the clicked one, inclusive,\n * in list order. Undefined when there is no usable anchor (then the click toggles one item).\n */\nexport const selectionRange = (\n ids: readonly string[],\n anchor: string | undefined,\n target: string,\n): string[] | undefined => {\n const from = anchor === undefined ? -1 : ids.indexOf(anchor);\n const to = ids.indexOf(target);\n if (from === -1 || to === -1) {\n return undefined;\n }\n return ids.slice(Math.min(from, to), Math.max(from, to) + 1);\n};\n","import { useRef } from 'react';\nimport { selectionRange } from '../helpers/selectionRange';\n\ntype SelectRequest = { id: string; checked: boolean; shiftKey: boolean };\n\n/**\n * Shift-click selection over an ordered list: a plain toggle sets the anchor; a shift toggle selects\n * everything from the anchor to the clicked item. Works through `onSelectChange` alone, so any owner of the\n * selection (the library, the media picker) gets ranges without new props.\n */\nexport const useRangeSelection = (\n ids: readonly string[],\n onSelectChange: (id: string, checked: boolean) => void,\n) => {\n const anchor = useRef<string | undefined>(undefined);\n const select = ({ id, checked, shiftKey }: SelectRequest) => {\n const range = shiftKey ? selectionRange(ids, anchor.current, id) : undefined;\n if (range) {\n for (const rangeId of range) {\n onSelectChange(rangeId, true);\n }\n } else {\n onSelectChange(id, checked);\n }\n anchor.current = id;\n };\n return { select };\n};\n","import type { MediaAsset } from '@shapio/client';\nimport { Lock } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { StatusChip } from '@/components/StatusChip';\nimport { Checkbox } from '@/components/ui/checkbox';\nimport { cn } from '@/helpers/cn';\nimport { fileKindLabel } from '../../helpers/fileKind';\nimport { formatBytes } from '../../helpers/formatBytes';\nimport { MEDIA_STATUS_DISPLAY } from '../../helpers/statusDisplay';\nimport { Thumbnail } from '../../Thumbnail';\n\ntype CardProps = {\n asset: MediaAsset;\n selected: boolean;\n selectable: boolean;\n active: boolean;\n /** `shiftKey`: extend the selection to here from the last item toggled. */\n onSelect: (checked: boolean, shiftKey: boolean) => void;\n onOpen: () => void;\n};\n\n/**\n * One asset tile: a button that opens its details (shift-click selects instead), and a checkbox for bulk\n * actions. The square thumbnail, then the name and \"PNG · 120 kB\".\n */\nexport const Card = ({ asset, selected, selectable, active, onSelect, onOpen }: CardProps) => {\n const { t } = useTranslation();\n const status = MEDIA_STATUS_DISPLAY[asset.status];\n return (\n <li\n className={cn(\n 'group relative overflow-hidden rounded-xl border bg-card transition-shadow focus-within:ring-[3px] focus-within:ring-ring/50 hover:border-input',\n (selected || active) && 'border-primary ring-2 ring-primary hover:border-primary',\n )}\n >\n <button\n type=\"button\"\n onClick={(event) => {\n if (event.shiftKey && selectable) {\n onSelect(!selected, true);\n return;\n }\n onOpen();\n }}\n className=\"flex w-full flex-col text-left outline-none\"\n aria-label={t('media.openDetails', { name: asset.filename })}\n >\n <Thumbnail asset={asset} className=\"aspect-square w-full border-b\" />\n <span className=\"flex min-w-0 flex-col gap-0.5 px-3 py-2.5\">\n <span className=\"truncate text-sm font-medium\" title={asset.filename}>\n {asset.filename}\n </span>\n <span className=\"flex min-w-0 items-center gap-1.5 text-meta text-muted-foreground\">\n <span className=\"truncate\">\n {fileKindLabel(asset.filename, asset.mimeType)} · {formatBytes(asset.sizeBytes)}\n </span>\n {asset.visibility === 'private' ? (\n <Lock aria-hidden=\"true\" className=\"size-3.5 shrink-0\" />\n ) : null}\n </span>\n </span>\n </button>\n {asset.status === 'ready' ? null : (\n <StatusChip\n tone={status.tone}\n label={t(status.labelKey)}\n size=\"sm\"\n className=\"pointer-events-none absolute top-2 right-2\"\n />\n )}\n {selectable ? (\n <Checkbox\n checked={selected}\n onClick={(event) => {\n if (event.shiftKey) {\n event.preventDefault();\n onSelect(!selected, true);\n }\n }}\n onCheckedChange={(checked) => onSelect(checked === true, false)}\n aria-label={t('media.select', { name: asset.filename })}\n className=\"absolute top-2 left-2 bg-card\"\n />\n ) : null}\n </li>\n );\n};\n","import type { MediaAsset } from '@shapio/client';\nimport { useTranslation } from 'react-i18next';\nimport { useRangeSelection } from '../hooks/useRangeSelection';\nimport { Card } from './Card';\n\ntype AssetGridProps = {\n assets: readonly MediaAsset[];\n selected: ReadonlySet<string>;\n selectable: boolean;\n activeId: string | undefined;\n onSelectChange: (id: string, checked: boolean) => void;\n onOpen: (asset: MediaAsset) => void;\n};\n\n/** Square tiles that fill the width; shift-click (tile or checkbox) selects a range. */\nexport const AssetGrid = ({\n assets,\n selected,\n selectable,\n activeId,\n onSelectChange,\n onOpen,\n}: AssetGridProps) => {\n const { t } = useTranslation();\n const range = useRangeSelection(\n assets.map((asset) => asset.id),\n onSelectChange,\n );\n return (\n <ul\n aria-label={t('media.assetsLabel', { count: assets.length })}\n className=\"grid grid-cols-[repeat(auto-fill,minmax(160px,1fr))] gap-4\"\n >\n {assets.map((asset) => (\n <Card\n key={asset.id}\n asset={asset}\n selected={selected.has(asset.id)}\n selectable={selectable}\n active={asset.id === activeId}\n onSelect={(checked, shiftKey) => range.select({ id: asset.id, checked, shiftKey })}\n onOpen={() => onOpen(asset)}\n />\n ))}\n </ul>\n );\n};\n","import type { MediaAsset } from '@shapio/client';\nimport { Lock } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { RowTitle } from '@/components/RowTitle';\nimport { StatusChip } from '@/components/StatusChip';\nimport { TableCard } from '@/components/TableCard';\nimport { Checkbox } from '@/components/ui/checkbox';\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';\nimport { formatDateTime, formatRelativeTime } from '@/helpers/formatDate';\nimport { fileKindLabel } from '../helpers/fileKind';\nimport { formatBytes } from '../helpers/formatBytes';\nimport { MEDIA_STATUS_DISPLAY } from '../helpers/statusDisplay';\nimport { useRangeSelection } from '../hooks/useRangeSelection';\nimport { Thumbnail } from '../Thumbnail';\n\ntype AssetTableProps = {\n assets: readonly MediaAsset[];\n selected: ReadonlySet<string>;\n selectable: boolean;\n onSelectChange: (id: string, checked: boolean) => void;\n onOpen: (asset: MediaAsset) => void;\n};\n\n/** The list view: name, type, size, status and date per asset; shift-click a checkbox to select a range. */\nexport const AssetTable = ({ assets, selected, selectable, onSelectChange, onOpen }: AssetTableProps) => {\n const { t } = useTranslation();\n const range = useRangeSelection(\n assets.map((asset) => asset.id),\n onSelectChange,\n );\n return (\n <TableCard>\n <Table>\n <TableHeader>\n <TableRow>\n {selectable ? (\n <TableHead className=\"w-10\">\n <span className=\"sr-only\">{t('media.selection')}</span>\n </TableHead>\n ) : null}\n <TableHead>{t('media.fields.filename')}</TableHead>\n <TableHead>{t('media.fields.type')}</TableHead>\n <TableHead className=\"text-right\">{t('media.fields.size')}</TableHead>\n <TableHead>{t('media.fields.status')}</TableHead>\n <TableHead>{t('media.fields.uploaded')}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {assets.map((asset) => {\n const status = MEDIA_STATUS_DISPLAY[asset.status];\n const isSelected = selected.has(asset.id);\n return (\n <TableRow key={asset.id} data-state={isSelected ? 'selected' : undefined}>\n {selectable ? (\n <TableCell>\n <Checkbox\n checked={isSelected}\n onClick={(event) => {\n if (event.shiftKey) {\n event.preventDefault();\n range.select({ id: asset.id, checked: !isSelected, shiftKey: true });\n }\n }}\n onCheckedChange={(checked) =>\n range.select({ id: asset.id, checked: checked === true, shiftKey: false })\n }\n aria-label={t('media.select', { name: asset.filename })}\n />\n </TableCell>\n ) : null}\n <TableCell className=\"max-w-96\">\n <span className=\"flex min-w-0 items-center gap-3\">\n <Thumbnail asset={asset} className=\"size-8 shrink-0 rounded-md\" />\n <RowTitle asChild className=\"min-w-0 truncate text-left\">\n <button type=\"button\" onClick={() => onOpen(asset)}>\n {asset.filename}\n </button>\n </RowTitle>\n {asset.visibility === 'private' ? (\n <Lock\n role=\"img\"\n aria-label={t('media.visibility.private')}\n className=\"size-3.5 shrink-0 text-muted-foreground\"\n />\n ) : null}\n </span>\n </TableCell>\n <TableCell className=\"text-muted-foreground\" title={asset.mimeType}>\n {fileKindLabel(asset.filename, asset.mimeType)}\n </TableCell>\n <TableCell className=\"text-right tabular-nums\">{formatBytes(asset.sizeBytes)}</TableCell>\n <TableCell>\n <StatusChip tone={status.tone} label={t(status.labelKey)} size=\"sm\" />\n </TableCell>\n <TableCell className=\"whitespace-nowrap\" title={formatDateTime(asset.createdAt)}>\n {formatRelativeTime(asset.createdAt)}\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </TableCard>\n );\n};\n","import type { MediaAsset } from '@shapio/client';\nimport { Images } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { useMediaAssets } from '@/api/media';\nimport { EmptyState } from '@/components/EmptyState';\nimport { ErrorState } from '@/components/ErrorState';\nimport { LoadingState } from '@/components/LoadingState';\nimport { Button } from '@/components/ui/button';\nimport { AssetGrid } from '../AssetGrid';\nimport { AssetTable } from '../AssetTable';\nimport type { MediaView } from '../constants';\n\ntype LibraryProps = {\n query: Parameters<typeof useMediaAssets>[0];\n filtered: boolean;\n view: MediaView;\n selected: ReadonlySet<string>;\n selectable: boolean;\n activeId: string | undefined;\n onSelectChange: (id: string, checked: boolean) => void;\n onOpen: (asset: MediaAsset) => void;\n};\n\n/** The assets of the current folder and filters: loading, error, empty, grid or list, and \"Load more\". */\nexport const Library = ({\n query,\n filtered,\n view,\n selected,\n selectable,\n activeId,\n onSelectChange,\n onOpen,\n}: LibraryProps) => {\n const { t } = useTranslation();\n const assets = useMediaAssets(query);\n if (assets.isPending) {\n return <LoadingState rows={4} />;\n }\n if (assets.isError) {\n return <ErrorState error={assets.error} onRetry={() => void assets.refetch()} />;\n }\n const items = assets.data.pages.flatMap((page) => page.items);\n if (items.length === 0) {\n // The whole library is empty: a page-sized empty state. An empty folder or search: a quieter one.\n const scoped = filtered || query.folder !== undefined;\n return (\n <EmptyState\n icon={Images}\n size={scoped ? 'panel' : 'page'}\n title={filtered ? t('media.emptyFiltered') : scoped ? t('media.emptyFolder') : t('media.empty')}\n />\n );\n }\n return (\n <div className=\"space-y-4\">\n {view === 'grid' ? (\n <AssetGrid\n assets={items}\n selected={selected}\n selectable={selectable}\n activeId={activeId}\n onSelectChange={onSelectChange}\n onOpen={onOpen}\n />\n ) : (\n <AssetTable\n assets={items}\n selected={selected}\n selectable={selectable}\n onSelectChange={onSelectChange}\n onOpen={onOpen}\n />\n )}\n {assets.hasNextPage ? (\n <div className=\"flex justify-center\">\n <Button\n variant=\"outline\"\n disabled={assets.isFetchingNextPage}\n aria-busy={assets.isFetchingNextPage || undefined}\n onClick={() => void assets.fetchNextPage()}\n >\n {assets.isFetchingNextPage ? t('common.loading') : t('media.loadMore')}\n </Button>\n </div>\n ) : null}\n </div>\n );\n};\n","import { LayoutGrid, List, Search } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { Button } from '@/components/ui/button';\nimport { Input } from '@/components/ui/input';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';\nimport { useSearchInput } from '@/hooks/useSearchInput';\nimport { MEDIA_TYPE_FILTERS, type MediaTypeFilter, type MediaView } from '../constants';\n\ntype ToolbarProps = {\n query: string | undefined;\n type: MediaTypeFilter | undefined;\n view: MediaView;\n onQueryChange: (query: string | undefined) => void;\n onTypeChange: (type: MediaTypeFilter | undefined) => void;\n onViewChange: (view: MediaView) => void;\n};\n\nconst ALL_TYPES = 'all';\n\nconst TYPE_LABEL_KEYS = {\n image: 'media.types.image',\n video: 'media.types.video',\n audio: 'media.types.audio',\n pdf: 'media.types.pdf',\n} as const satisfies Record<MediaTypeFilter, string>;\n\n/** Search, type filter and grid/list switch. */\nexport const Toolbar = ({ query, type, view, onQueryChange, onTypeChange, onViewChange }: ToolbarProps) => {\n const { t } = useTranslation();\n const { text, setText } = useSearchInput(query, onQueryChange);\n return (\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"relative min-w-48 flex-1\">\n <Search\n aria-hidden=\"true\"\n className=\"absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground\"\n />\n <Input\n type=\"search\"\n value={text}\n onChange={(event) => setText(event.target.value)}\n aria-label={t('media.search')}\n placeholder={t('media.searchPlaceholder')}\n inputSize=\"sm\"\n className=\"pl-8\"\n />\n </div>\n <Select\n value={type ?? ALL_TYPES}\n onValueChange={(value) => onTypeChange(value === ALL_TYPES ? undefined : (value as MediaTypeFilter))}\n >\n <SelectTrigger size=\"sm\" aria-label={t('media.typeFilter')} className=\"w-36\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL_TYPES}>{t('media.types.all')}</SelectItem>\n {MEDIA_TYPE_FILTERS.map((filter) => (\n <SelectItem key={filter} value={filter}>\n {t(TYPE_LABEL_KEYS[filter])}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <div\n role=\"group\"\n aria-label={t('media.view')}\n className=\"flex h-9 items-center gap-0.5 rounded-lg border border-input px-px\"\n >\n <Button\n variant={view === 'grid' ? 'secondary' : 'ghost'}\n size=\"icon-sm\"\n aria-pressed={view === 'grid'}\n aria-label={t('media.viewGrid')}\n onClick={() => onViewChange('grid')}\n >\n <LayoutGrid aria-hidden=\"true\" />\n </Button>\n <Button\n variant={view === 'list' ? 'secondary' : 'ghost'}\n size=\"icon-sm\"\n aria-pressed={view === 'list'}\n aria-label={t('media.viewList')}\n onClick={() => onViewChange('list')}\n >\n <List aria-hidden=\"true\" />\n </Button>\n </div>\n </div>\n );\n};\n","import { Upload } from 'lucide-react';\nimport { useRef, type ComponentProps } from 'react';\nimport { Button } from '@/components/ui/button';\n\ntype UploadButtonProps = Omit<ComponentProps<typeof Button>, 'onClick'> & {\n label: string;\n multiple?: boolean;\n onFiles: (files: File[]) => void;\n};\n\n/** A button that opens the file picker (the keyboard path; dropping files is the pointer shortcut). */\nexport const UploadButton = ({ label, multiple = true, onFiles, ...buttonProps }: UploadButtonProps) => {\n const input = useRef<HTMLInputElement>(null);\n return (\n <>\n <Button {...buttonProps} onClick={() => input.current?.click()}>\n <Upload aria-hidden=\"true\" />\n {label}\n </Button>\n <input\n ref={input}\n type=\"file\"\n multiple={multiple}\n tabIndex={-1}\n aria-hidden=\"true\"\n className=\"sr-only\"\n onChange={(event) => {\n const files = [...(event.target.files ?? [])];\n event.target.value = '';\n if (files.length > 0) {\n onFiles(files);\n }\n }}\n />\n </>\n );\n};\n","import type { MediaVisibility } from '@shapio/client';\nimport { create } from 'zustand';\n\nexport type UploadStatus = 'uploading' | 'confirming' | 'done' | 'failed';\n\nexport type UploadItem = {\n id: string;\n file: File;\n folderId: string | null;\n visibility: MediaVisibility;\n /** Set when the upload replaces this asset's file. */\n replaceAssetId: string | undefined;\n status: UploadStatus;\n /** 0 to 1 while the bytes are sent. */\n progress: number;\n error: unknown;\n assetId: string | undefined;\n};\n\ntype MediaUploadsState = {\n items: UploadItem[];\n add: (item: UploadItem) => void;\n update: (id: string, patch: Partial<UploadItem>) => void;\n remove: (id: string) => void;\n clearFinished: () => void;\n};\n\n/** Uploads in flight and recently finished (client-only; kept while the admin is open, not persisted). */\nexport const useMediaUploadsStore = create<MediaUploadsState>()((set) => ({\n items: [],\n add: (item) => set((state) => ({ items: [...state.items, item] })),\n update: (id, patch) =>\n set((state) => ({ items: state.items.map((item) => (item.id === id ? { ...item, ...patch } : item)) })),\n remove: (id) => set((state) => ({ items: state.items.filter((item) => item.id !== id) })),\n clearFinished: () => set((state) => ({ items: state.items.filter((item) => item.status !== 'done') })),\n}));\n","/** The storage (bucket or Shapio's upload route) refused the bytes; `status` 0 means the request never completed. */\nexport class UploadTransferError extends Error {\n readonly status: number;\n readonly body: string;\n\n constructor(status: number, body: string) {\n super(`Upload failed with status ${status}`);\n this.name = 'UploadTransferError';\n this.status = status;\n this.body = body;\n }\n}\n\ntype UploadWithProgressInput = {\n url: string;\n form: FormData;\n onProgress: (fraction: number) => void;\n signal?: AbortSignal;\n};\n\n/**\n * POSTs a multipart form with upload progress (fetch cannot report it, so this uses XMLHttpRequest).\n * No credentials are sent: the grant's fields authorise the upload, whether it goes to a bucket or to Shapio.\n */\nexport const uploadWithProgress = ({ url, form, onProgress, signal }: UploadWithProgressInput) =>\n new Promise<void>((resolve, reject) => {\n const request = new XMLHttpRequest();\n request.open('POST', url);\n request.withCredentials = false;\n request.upload.onprogress = (event) => {\n if (event.lengthComputable && event.total > 0) {\n onProgress(event.loaded / event.total);\n }\n };\n request.onload = () => {\n if (request.status >= 200 && request.status < 300) {\n onProgress(1);\n resolve();\n return;\n }\n reject(new UploadTransferError(request.status, request.responseText));\n };\n request.onerror = () => reject(new UploadTransferError(0, ''));\n request.onabort = () => reject(new DOMException('Upload cancelled', 'AbortError'));\n signal?.addEventListener('abort', () => request.abort(), { once: true });\n request.send(form);\n });\n","import { i18next } from '@/app/i18n';\nimport { describeError } from '@/helpers/describeError';\nimport { UploadTransferError } from '@/helpers/uploadWithProgress';\n\n/** Why an upload failed, for the queue. Storage refusals (bucket or upload route) get their own message. */\nexport const describeUploadError = (error: unknown): string => {\n if (error instanceof UploadTransferError) {\n if (error.status === 0) {\n return i18next.t('media.upload.unreachable');\n }\n if (error.status === 413 || /EntityTooLarge/.test(error.body)) {\n return i18next.t('errors.codes.FILE_TOO_LARGE');\n }\n return i18next.t('media.upload.transferFailed', { status: error.status });\n }\n return describeError(error);\n};\n","import { CheckCircle2, Loader2, RotateCcw, X, XCircle } from 'lucide-react';\nimport type { CSSProperties } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Button } from '@/components/ui/button';\nimport { cn } from '@/helpers/cn';\nimport type { UploadItem } from '@/stores/mediaUploads';\nimport { describeUploadError } from '../../helpers/describeUploadError';\nimport { formatBytes } from '../../helpers/formatBytes';\n\ntype RowProps = { item: UploadItem; onRetry: () => void; onDismiss: () => void };\n\nconst PERCENT = 100;\n\n/** One upload: name, size, progress (a real progressbar), and Retry/Dismiss when it failed. */\nexport const Row = ({ item, onRetry, onDismiss }: RowProps) => {\n const { t } = useTranslation();\n const percent = Math.round(item.progress * PERCENT);\n const statusText =\n item.status === 'uploading'\n ? t('media.upload.uploading', { percent })\n : item.status === 'confirming'\n ? t('media.upload.checking')\n : item.status === 'done'\n ? t('media.upload.done')\n : describeUploadError(item.error);\n return (\n <li className=\"flex items-start gap-3 px-5 py-2.5\">\n <span className=\"mt-0.5 shrink-0\">\n {item.status === 'done' ? (\n <CheckCircle2 aria-hidden=\"true\" className=\"size-4 text-success\" />\n ) : item.status === 'failed' ? (\n <XCircle aria-hidden=\"true\" className=\"size-4 text-destructive\" />\n ) : (\n <Loader2\n aria-hidden=\"true\"\n className=\"size-4 animate-spin text-muted-foreground motion-reduce:animate-none\"\n />\n )}\n </span>\n <div className=\"min-w-0 flex-1 space-y-1\">\n <p className=\"flex items-baseline gap-2 text-sm\">\n <span className=\"truncate font-medium\">{item.file.name}</span>\n <span className=\"shrink-0 text-meta text-muted-foreground\">{formatBytes(item.file.size)}</span>\n </p>\n {item.status === 'uploading' || item.status === 'confirming' ? (\n <div\n role=\"progressbar\"\n aria-label={t('media.upload.progress', { name: item.file.name })}\n aria-valuemin={0}\n aria-valuemax={PERCENT}\n aria-valuenow={percent}\n className=\"h-1.5 overflow-hidden rounded-full bg-muted\"\n style={{ '--upload-progress': `${percent}%` } as CSSProperties}\n >\n <div className=\"h-full w-[var(--upload-progress)] bg-primary transition-[width]\" />\n </div>\n ) : null}\n <p\n className={cn('text-meta', item.status === 'failed' ? 'text-destructive' : 'text-muted-foreground')}\n >\n {statusText}\n </p>\n </div>\n {item.status === 'failed' ? (\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={t('media.upload.retry', { name: item.file.name })}\n onClick={onRetry}\n >\n <RotateCcw aria-hidden=\"true\" />\n </Button>\n ) : null}\n {item.status === 'failed' || item.status === 'done' ? (\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={t('media.upload.dismiss', { name: item.file.name })}\n onClick={onDismiss}\n >\n <X aria-hidden=\"true\" />\n </Button>\n ) : null}\n </li>\n );\n};\n","import { ChevronDown, ChevronUp } from 'lucide-react';\nimport { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Panel } from '@/components/Panel';\nimport { Button } from '@/components/ui/button';\nimport { useMediaUploadsStore } from '@/stores/mediaUploads';\nimport { Row } from './Row';\n\ntype UploadQueueProps = { onRetry: (id: string) => void; onDismiss: (id: string) => void };\n\n/**\n * Uploads in progress and recently finished, newest last, as a compact panel. Once nothing is running or\n * failed it collapses to one line (\"3 uploaded\"); failures stay open until retried or dismissed.\n */\nexport const UploadQueue = ({ onRetry, onDismiss }: UploadQueueProps) => {\n const { t } = useTranslation();\n const items = useMediaUploadsStore((state) => state.items);\n const clearFinished = useMediaUploadsStore((state) => state.clearFinished);\n const [showFinished, setShowFinished] = useState(false);\n if (items.length === 0) {\n return null;\n }\n const active = items.filter((item) => item.status === 'uploading' || item.status === 'confirming').length;\n const failed = items.filter((item) => item.status === 'failed').length;\n const done = items.length - active - failed;\n const settled = active === 0 && failed === 0;\n const expanded = !settled || showFinished;\n return (\n <Panel\n title={t('media.upload.queueTitle')}\n titleAs=\"h2\"\n flush={expanded}\n actions={\n <>\n <span role=\"status\" aria-live=\"polite\" className=\"text-meta text-muted-foreground\">\n {settled\n ? t('media.upload.doneSummary', { count: done })\n : t('media.upload.summary', { active, failed })}\n </span>\n {settled ? (\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-expanded={expanded}\n aria-label={expanded ? t('media.upload.hideFinished') : t('media.upload.showFinished')}\n onClick={() => setShowFinished((current) => !current)}\n >\n {expanded ? <ChevronUp aria-hidden=\"true\" /> : <ChevronDown aria-hidden=\"true\" />}\n </Button>\n ) : null}\n {done > 0 ? (\n <Button variant=\"ghost\" size=\"sm\" onClick={clearFinished}>\n {t('media.upload.clearFinished')}\n </Button>\n ) : null}\n </>\n }\n bodyClassName={expanded ? undefined : 'hidden'}\n >\n {expanded ? (\n <ul className=\"max-h-64 divide-y overflow-y-auto\">\n {items.map((item) => (\n <Row\n key={item.id}\n item={item}\n onRetry={() => onRetry(item.id)}\n onDismiss={() => onDismiss(item.id)}\n />\n ))}\n </ul>\n ) : null}\n </Panel>\n );\n};\n","import { buildUploadForm, type MediaAsset, type MediaVisibility, type UploadGrant } from '@shapio/client';\nimport { useQueryClient } from '@tanstack/react-query';\nimport { useCallback } from 'react';\nimport { toast } from 'sonner';\nimport { adminApi, apiBaseUrl } from '@/api/client';\nimport { withCsrf } from '@/api/csrf';\nimport { queryKeys } from '@/api/queryKeys';\nimport { i18next } from '@/app/i18n';\nimport { logError } from '@/helpers/reportError';\nimport { resolveUploadUrl } from '@/helpers/resolveUploadUrl';\nimport { uploadWithProgress } from '@/helpers/uploadWithProgress';\nimport { useMediaUploadsStore, type UploadItem } from '@/stores/mediaUploads';\n\nconst FALLBACK_MIME_TYPE = 'application/octet-stream';\n\ntype UploadTarget = Pick<UploadItem, 'file' | 'folderId' | 'visibility' | 'replaceAssetId'>;\n\nconst requestGrant = (item: UploadTarget): Promise<UploadGrant> => {\n const details = {\n filename: item.file.name,\n mimeType: item.file.type || FALLBACK_MIME_TYPE,\n sizeBytes: item.file.size,\n };\n return withCsrf(() =>\n item.replaceAssetId\n ? adminApi.media.assets.replace(item.replaceAssetId, details)\n : adminApi.media.uploads.create({ ...details, folderId: item.folderId, visibility: item.visibility }),\n );\n};\n\n/** Grant, send (with progress), confirm: one file into the library. Throws when any step fails. */\nconst uploadFile = async (\n item: UploadTarget,\n onProgress: (progress: number) => void,\n onConfirming: () => void,\n): Promise<MediaAsset> => {\n const grant = await requestGrant(item);\n await uploadWithProgress({\n url: resolveUploadUrl(grant, apiBaseUrl()),\n form: buildUploadForm(grant, item.file, item.file.name),\n onProgress,\n });\n onConfirming();\n return withCsrf(() => adminApi.media.uploads.confirm(grant.grantId));\n};\n\n/** What an editor gets back from `uploadOne`: the new asset's ID and its library alt text. */\nexport type UploadedMedia = { id: string; alt: string | null };\n\ntype EnqueueOptions = { folderId: string | null; visibility: MediaVisibility; replaceAssetId?: string };\n\n/**\n * The upload flow, the same for local disk and S3: ask for a grant, send the form to the grant's URL\n * (with progress), then confirm so the server checks the bytes and records the asset. A failed upload stays\n * in the queue with its error; retrying starts again with a fresh grant (grants are single-use).\n */\nexport const useMediaUploader = () => {\n const queryClient = useQueryClient();\n const { add, update, remove } = useMediaUploadsStore.getState();\n\n const run = useCallback(\n async (item: UploadItem) => {\n update(item.id, { status: 'uploading', progress: 0, error: undefined });\n try {\n const asset = await uploadFile(\n item,\n (progress) => update(item.id, { progress }),\n () => update(item.id, { status: 'confirming' }),\n );\n update(item.id, { status: 'done', assetId: asset.id });\n if (item.replaceAssetId) {\n toast.success(i18next.t('media.upload.replaced', { name: item.file.name }));\n }\n } catch (error) {\n logError(error, `uploading ${item.file.name}`);\n update(item.id, { status: 'failed', error });\n } finally {\n await queryClient.invalidateQueries({ queryKey: queryKeys.media.all });\n }\n },\n [queryClient, update],\n );\n\n const enqueue = useCallback(\n (files: readonly File[], options: EnqueueOptions) => {\n for (const file of files) {\n const item: UploadItem = {\n id: crypto.randomUUID(),\n file,\n folderId: options.folderId,\n visibility: options.visibility,\n replaceAssetId: options.replaceAssetId,\n status: 'uploading',\n progress: 0,\n error: undefined,\n assetId: undefined,\n };\n add(item);\n void run(item);\n }\n },\n [add, run],\n );\n\n const retry = useCallback(\n (id: string) => {\n const item = useMediaUploadsStore.getState().items.find((candidate) => candidate.id === id);\n if (item) {\n void run(item);\n }\n },\n [run],\n );\n\n /**\n * One file uploaded outside the queue (a file dropped into rich text): resolves with the new asset, or\n * rejects so the caller can undo its placeholder. Public, in the root folder.\n */\n const uploadOne = useCallback(\n async (file: File): Promise<UploadedMedia> => {\n try {\n const asset = await uploadFile(\n { file, folderId: null, visibility: 'public', replaceAssetId: undefined },\n () => undefined,\n () => undefined,\n );\n queryClient.setQueryData(queryKeys.media.asset(asset.id), asset);\n return { id: asset.id, alt: asset.alt || null };\n } finally {\n await queryClient.invalidateQueries({ queryKey: queryKeys.media.all });\n }\n },\n [queryClient],\n );\n\n return { enqueue, retry, dismiss: remove, uploadOne };\n};\n"],"ignoreList":[0,1,2,3],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{i as e}from"./rolldown-runtime-Dd_uD5pT.js";import{t}from"./react-CQOZoUwg.js";import{t as n}from"./store-
|
|
2
|
-
//# sourceMappingURL=usePaletteItems-
|
|
1
|
+
import{i as e}from"./rolldown-runtime-Dd_uD5pT.js";import{t}from"./react-CQOZoUwg.js";import{t as n}from"./store-BphwUzV5.js";var r=e(t(),1),i=`(max-width: 1023px)`,a=e=>{let t=window.matchMedia(i);return t.addEventListener(`change`,e),()=>t.removeEventListener(`change`,e)},o=()=>window.matchMedia(i).matches;function s(){return r.useSyncExternalStore(a,o,()=>!1)}var c=(e,t)=>{let i=(0,r.useId)(),a=n(e=>e.register),o=n(e=>e.unregister);(0,r.useEffect)(()=>(a(i,{group:e,items:t}),()=>o(i)),[i,e,t,a,o])};export{s as n,c as t};
|
|
2
|
+
//# sourceMappingURL=usePaletteItems-62-TZhy7.js.map
|
package/dist/admin/assets/{usePaletteItems-bbTIqpPu.js.map → usePaletteItems-62-TZhy7.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePaletteItems-
|
|
1
|
+
{"version":3,"file":"usePaletteItems-62-TZhy7.js","names":["useId","__toESM","usePaletteStore","import_react","require_react","MOBILE_QUERY","subscribe","mql","onChange","getSnapshot","useIsMobile","usePaletteItems","id","register","state","unregister","group","items"],"sources":["../../src/hooks/use-mobile.ts","../../src/components/CommandPalette/hooks/usePaletteItems.ts"],"sourcesContent":["import * as React from 'react';\n\n// Shapio: the sidebar becomes a sheet below lg (DESIGN.md), not md.\nconst MOBILE_BREAKPOINT = 1024;\nconst MOBILE_QUERY = `(max-width: ${MOBILE_BREAKPOINT - 1}px)`;\n\n// Shapio: subscribes with useSyncExternalStore instead of setState in an effect (shadcn's original).\nconst subscribe = (onChange: () => void) => {\n const mql = window.matchMedia(MOBILE_QUERY);\n mql.addEventListener('change', onChange);\n return () => mql.removeEventListener('change', onChange);\n};\n\nconst getSnapshot = () => window.matchMedia(MOBILE_QUERY).matches;\n\nexport function useIsMobile() {\n return React.useSyncExternalStore(subscribe, getSnapshot, () => false);\n}\n","import { useEffect, useId } from 'react';\nimport { usePaletteStore } from '../store';\nimport type { PaletteItem, RegisteredGroup } from '../types';\n\n/**\n * Offers `items` in the palette while the calling component is mounted. Pass a memoized array: a new\n * array re-registers.\n */\nexport const usePaletteItems = (group: RegisteredGroup, items: readonly PaletteItem[]) => {\n const id = useId();\n const register = usePaletteStore((state) => state.register);\n const unregister = usePaletteStore((state) => state.unregister);\n useEffect(() => {\n register(id, { group, items });\n return () => unregister(id);\n }, [id, group, items, register, unregister]);\n};\n"],"mappings":"6IAIMK,EAAe,sBAGfC,EAAa,GAAyB,CAC1C,IAAMC,EAAM,OAAO,WAAWF,CAAY,EAE1C,OADAE,EAAI,iBAAiB,SAAUC,CAAQ,MAC1BD,EAAI,oBAAoB,SAAUC,CAAQ,CACzD,EAEMC,MAAoB,OAAO,WAAWJ,CAAY,CAAC,CAAC,QAE1D,SAAgBK,GAAc,CAC5B,OAAAP,EAAa,qBAAqBG,EAAWG,MAAmB,EAAK,CACvE,CCTA,IAAaE,GAAmB,EAAwB,IAAkC,CACxF,IAAMC,GAAA,EAAKZ,EAAAA,MAAAA,CAAM,EACXa,EAAWX,EAAiB,GAAUY,EAAM,QAAQ,EACpDC,EAAab,EAAiB,GAAUY,EAAM,UAAU,GAC9D,EAAAX,EAAA,UAAA,MACEU,EAASD,EAAI,CAAE,QAAO,OAAM,CAAC,MAChBG,EAAWH,CAAE,GACzB,CAACA,EAAII,EAAOC,EAAOJ,EAAUE,CAAU,CAAC,CAC7C"}
|