@leavepulse/ui 0.71.2 → 0.72.1
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/assets/{LpKeys-BxRhfQda.css → LpKeys-C5VMcBOW.css} +10 -5
- package/dist/assets/LpTabs-CDchzoRL.css +18 -0
- package/dist/chunks/{ContextMenuItems-eS7qx9gD.js → ContextMenuItems-BXumicbh.js} +1 -1
- package/dist/chunks/{DropzoneLinkField-DkFhdfEJ.js → DropzoneLinkField-DpOB20Lx.js} +2 -2
- package/dist/chunks/{FieldWrapper-YzbvvC3M.js → FieldWrapper-DHhRxO5G.js} +1 -1
- package/dist/chunks/{LayoutCanvas-Ba4A9QC5.js → LayoutCanvas-CNOAUk7D.js} +1 -1
- package/dist/chunks/{LayoutNode-CTTTLMDM.js → LayoutNode-DF5BMN0J.js} +1 -1
- package/dist/chunks/{LpActionBar-B7anGlkI.js → LpActionBar-BqicINE_.js} +3 -3
- package/dist/chunks/{LpAddressInput-Bu6ws3Fp.js → LpAddressInput-CkbKLufb.js} +7 -7
- package/dist/chunks/{LpAlert-BHi7ARqu.js → LpAlert-BigMdAbu.js} +3 -3
- package/dist/chunks/{LpAppShell-C5YW5pI7.js → LpAppShell-DIMy-vjP.js} +68 -18
- package/dist/chunks/{LpAutocomplete-DDqe2M5g.js → LpAutocomplete-DOu7FN5P.js} +2 -2
- package/dist/chunks/{LpAvatar-DqfKCIdr.js → LpAvatar-Cg6Az3wz.js} +1 -1
- package/dist/chunks/{LpBadge-C8fKEmTF.js → LpBadge-Huo8EKew.js} +3 -3
- package/dist/chunks/LpBottomNav-BZIpahzA.js +89 -0
- package/dist/chunks/{LpBreadcrumbs-DhcoStFa.js → LpBreadcrumbs-DGtpBhWt.js} +3 -3
- package/dist/chunks/{LpButton-BQDAFXBd.js → LpButton-CW34A1e4.js} +1 -1
- package/dist/chunks/{LpCalendar-NmrA47J9.js → LpCalendar-CuoWks-0.js} +1 -1
- package/dist/chunks/{LpCard-CqKLnEhl.js → LpCard-B0sFXQzc.js} +1 -1
- package/dist/chunks/{LpCheckbox-BoOuLnGB.js → LpCheckbox-iaD63DEF.js} +2 -2
- package/dist/chunks/{LpCodeBlock-Czu-fq1M.js → LpCodeBlock-CFFa_pJb.js} +2 -2
- package/dist/chunks/{LpCodeDisplay-C9pIMF2R.js → LpCodeDisplay-CFmGMAmP.js} +6 -6
- package/dist/chunks/{LpColorPicker-Ee1DZiRd.js → LpColorPicker-1y1QJHZR.js} +56 -28
- package/dist/chunks/{LpConfirmDialog-i15pulMT.js → LpConfirmDialog-BDystNtm.js} +3 -3
- package/dist/chunks/{LpConfirmHost-D0oGavtd.js → LpConfirmHost-oOsxJHfQ.js} +1 -1
- package/dist/chunks/{LpContextMenu-DXpFJjlO.js → LpContextMenu-rx2tCjwk.js} +2 -2
- package/dist/chunks/{LpCopyButton-Dmq7DmFw.js → LpCopyButton-BNcGbVXF.js} +2 -2
- package/dist/chunks/{LpCountdown-CXrEK0ev.js → LpCountdown-Cak7cq3X.js} +3 -3
- package/dist/chunks/{LpDataList-CFPtSsBB.js → LpDataList-B6Meb4M9.js} +3 -3
- package/dist/chunks/{LpDatePicker-cC9K-Pk8.js → LpDatePicker-CA0QTfBC.js} +4 -4
- package/dist/chunks/{LpDateRangePicker-BVQKPbvo.js → LpDateRangePicker-u3J51xXk.js} +2 -2
- package/dist/chunks/{LpDisclosure-hRnX3FWL.js → LpDisclosure-Cpa7Hc5T.js} +1 -1
- package/dist/chunks/{LpDrawer-u4rxnuR-.js → LpDrawer-RRamxbLV.js} +1 -1
- package/dist/chunks/{LpDropdownMenu-BgZ0Z_Im.js → LpDropdownMenu-Dl7Z4ZhS.js} +2 -2
- package/dist/chunks/{LpEditable-CjxuOVh_.js → LpEditable-BNogo5DL.js} +5 -5
- package/dist/chunks/{LpEmptyState-CKFTtQgJ.js → LpEmptyState-EQHiRYhG.js} +7 -3
- package/dist/chunks/{LpFieldNotice-CPI8EwtU.js → LpFieldNotice-CzQ2_5rQ.js} +1 -1
- package/dist/chunks/{LpFileTree-BH0gNlSJ.js → LpFileTree-CHgtVh14.js} +2 -2
- package/dist/chunks/{LpFileTreeNode-gPVB1oXM.js → LpFileTreeNode-LqHgHd3B.js} +5 -5
- package/dist/chunks/{LpFormField-gRASfyj2.js → LpFormField-CC57DdTi.js} +2 -2
- package/dist/chunks/{LpGauge-DFdt33x8.js → LpGauge-BO1PYYqD.js} +2 -2
- package/dist/chunks/{LpHintLayer-C2asBIfs.js → LpHintLayer-CvAj4aa6.js} +2 -2
- package/dist/chunks/{LpHints-CNZQ76JV.js → LpHints-BtRvHQQ0.js} +3 -3
- package/dist/chunks/{LpIcon-DkP-9mzK.js → LpIcon--5WSb3jJ.js} +1 -1
- package/dist/chunks/{LpInfraNode-yTh4-5qa.js → LpInfraNode-CxngdQAG.js} +2 -2
- package/dist/chunks/{LpInput-2H-5ILOB.js → LpInput-DqmL-438.js} +2 -2
- package/dist/chunks/{LpLightbox-lAt5uIfx.js → LpLightbox-7YP6zSDm.js} +3 -3
- package/dist/chunks/{LpLoader-DjJEX8hL.js → LpLoader-CUo1MX_0.js} +1 -1
- package/dist/chunks/{LpLogViewer-x78YfhJf.js → LpLogViewer-DQOIsnZ1.js} +6 -6
- package/dist/chunks/{LpMapPicker-Dp5RSCi9.js → LpMapPicker-Dm3vJHN2.js} +2 -2
- package/dist/chunks/{LpMediaGallery-D92oJfY_.js → LpMediaGallery-znEbvIEo.js} +3 -3
- package/dist/chunks/{LpModal-CpH0bNo7.js → LpModal-BnjZ2iem.js} +1 -1
- package/dist/chunks/{LpModalNav-Cuna8c_3.js → LpModalNav-CH1UE9Ch.js} +4 -4
- package/dist/chunks/{LpNotificationBell-BdUQqZhs.js → LpNotificationBell-CrywodQ_.js} +8 -8
- package/dist/chunks/{LpNumberField-DZY3Z670.js → LpNumberField-e0IBkWU1.js} +1 -1
- package/dist/chunks/{LpNumberFlow-Dwb9MV1A.js → LpNumberFlow-CcxEGUy0.js} +4 -2
- package/dist/chunks/{LpPagination-DbeACavM.js → LpPagination-BIIiYHXR.js} +1 -1
- package/dist/chunks/{LpPaletteTheme-DkikZ362.js → LpPaletteTheme-BzHBh-mN.js} +4 -4
- package/dist/chunks/{LpPasswordInput-BzAZsf5V.js → LpPasswordInput-DVgRgTVx.js} +2 -2
- package/dist/chunks/{LpPhoneInput-BMpd-0QR.js → LpPhoneInput-CETEp5W7.js} +2 -2
- package/dist/chunks/{LpPie-C1uIUFxu.js → LpPie-BjDbeytx.js} +6 -6
- package/dist/chunks/{LpPipeline-zjEM1Lwc.js → LpPipeline-zZUj7I6K.js} +4 -4
- package/dist/chunks/{LpProgress-WNaH4emv.js → LpProgress-rOlyafqp.js} +1 -1
- package/dist/chunks/{LpQuota-Cz9PvklM.js → LpQuota-B12yijdB.js} +3 -3
- package/dist/chunks/{LpRadioGroup-CsXeV9Ct.js → LpRadioGroup-ggaPL92T.js} +1 -1
- package/dist/chunks/{LpRangeCalendar-l-0nSFmY.js → LpRangeCalendar-CYYUYqJ7.js} +1 -1
- package/dist/chunks/{LpRelativeTime-UM8EkfrN.js → LpRelativeTime-DwgCb5-8.js} +1 -1
- package/dist/chunks/{LpRepeater-OvzByE5L.js → LpRepeater-BQB0twJ5.js} +3 -3
- package/dist/chunks/LpRollingText-B54Pje7P.js +86 -0
- package/dist/chunks/{LpScramble-TDO5Kdou.js → LpScramble-DbQyBjUY.js} +1 -1
- package/dist/chunks/{LpSecretField-DwQiPOko.js → LpSecretField-uoD6Fngf.js} +7 -7
- package/dist/chunks/{LpSection-DcQsieHG.js → LpSection-DFK_uoJE.js} +1 -1
- package/dist/chunks/{LpSegmented-D2VST0o3.js → LpSegmented-CeACsMMA.js} +4 -2
- package/dist/chunks/{LpSelect-D3pRJfRY.js → LpSelect-Cxq4yBGd.js} +3 -3
- package/dist/chunks/LpShift-C-UGuKMN.js +171 -0
- package/dist/chunks/LpSidebar-DXdbvgM6.js +494 -0
- package/dist/chunks/LpSidebarNav-CE6CVCb0.js +367 -0
- package/dist/chunks/LpSidebarRow-CF9VFZ2w.js +304 -0
- package/dist/chunks/{LpStat-Dzn6WFzi.js → LpStat-CjpXrC8R.js} +6 -4
- package/dist/chunks/{LpStatus-BQU1TUsv.js → LpStatus-g-8z9b_u.js} +3 -3
- package/dist/chunks/{LpStepMark-CXa7DJy_.js → LpStepMark-DU7xalwW.js} +3 -3
- package/dist/chunks/{LpStepper-C9RM_yTG.js → LpStepper-CbRXiXNs.js} +1 -1
- package/dist/chunks/{LpSwap-DzE6M3Mg.js → LpSwap-Xi4j9PR_.js} +1 -1
- package/dist/chunks/{LpSwitch-bGZxUDSx.js → LpSwitch-BWcXEahf.js} +1 -1
- package/dist/chunks/LpTabFace-CG0VqD8I.js +77 -0
- package/dist/chunks/{LpTableFilter-CTZMqFDU.js → LpTableFilter-CYtK9GsF.js} +3 -3
- package/dist/chunks/{LpTagsInput-DrjmrOge.js → LpTagsInput-D1RzCwb5.js} +5 -5
- package/dist/chunks/{LpTextarea-BbYqmG1S.js → LpTextarea-MdIzNTjw.js} +32 -7
- package/dist/chunks/{useTheme-BOV_-AiY.js → LpThemeProvider-8MG6yqU9.js} +66 -1
- package/dist/chunks/{LpThemeStudio-IupHqP0x.js → LpThemeStudio-B0Kk1bX0.js} +138 -104
- package/dist/chunks/LpThemeStudioSection-B7bt8Iyg.js +32 -0
- package/dist/chunks/{LpThemeSwitcher-DarPHuX8.js → LpThemeSwitcher-CI4I7ygL.js} +6 -6
- package/dist/chunks/{LpTimeField-DQ8WvPr2.js → LpTimeField-BawSVsmt.js} +1 -1
- package/dist/chunks/{LpToaster-BTTl_wuy.js → LpToaster-C-P1nmMS.js} +2 -2
- package/dist/chunks/{LpTopologyCanvas-Cq-MiJwo.js → LpTopologyCanvas-CbEZhsP1.js} +1 -1
- package/dist/chunks/{LpTour-BgCfNlaW.js → LpTour-DRyzgpjt.js} +1 -1
- package/dist/chunks/{LpTruncate-TcqfkyJM.js → LpTruncate-4WvCWqnW.js} +1 -1
- package/dist/chunks/{LpUptimeBar-BbhVTPnL.js → LpUptimeBar-B2LNSNxs.js} +4 -4
- package/dist/chunks/{MenuTitle-Dab3EGOp.js → MenuTitle-BmCNNTKH.js} +1 -1
- package/dist/chunks/{OptionContent-DPzNsybd.js → OptionContent-22UT8zLn.js} +1 -1
- package/dist/chunks/{PickerField-DwLw7j0L.js → PickerField-Bfh8id3d.js} +2 -2
- package/dist/chunks/{RevealToggle-BVFM_FAU.js → RevealToggle-jBLJwVwO.js} +2 -2
- package/dist/chunks/{TourCard--2IfgnUU.js → TourCard-BOBcGbEo.js} +5 -5
- package/dist/chunks/{icons-CLu1iR1j.js → icons-DMITlfw5.js} +1 -1
- package/dist/component-names.d.ts +1 -1
- package/dist/components/ContextMenuItems.vue.js +1 -1
- package/dist/components/DropzoneLinkField.vue.js +1 -1
- package/dist/components/FieldWrapper.vue.js +1 -1
- package/dist/components/LayoutCanvas.vue.js +1 -1
- package/dist/components/LayoutNode.vue.js +1 -1
- package/dist/components/LpActionBar.vue.js +1 -1
- package/dist/components/LpAddressInput.vue.js +1 -1
- package/dist/components/LpAlert.vue.js +1 -1
- package/dist/components/LpAppShell.vue.d.ts +67 -2
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpAutocomplete.vue.js +1 -1
- package/dist/components/LpAvatar.vue.js +1 -1
- package/dist/components/LpBadge.vue.js +1 -1
- package/dist/components/LpBottomNav.vue.d.ts +28 -0
- package/dist/components/LpBottomNav.vue.js +4 -0
- package/dist/components/LpBreadcrumbs.vue.js +1 -1
- package/dist/components/LpButton.vue.js +1 -1
- package/dist/components/LpCalendar.vue.js +1 -1
- package/dist/components/LpCard.vue.js +1 -1
- package/dist/components/LpChart.vue.js +4 -4
- package/dist/components/LpCheckbox.vue.js +1 -1
- package/dist/components/LpCodeBlock.vue.js +1 -1
- package/dist/components/LpCodeDisplay.vue.js +1 -1
- package/dist/components/LpColorPicker.vue.d.ts +15 -2
- package/dist/components/LpColorPicker.vue.js +1 -1
- package/dist/components/LpCommandPalette.vue.js +4 -4
- package/dist/components/LpConfirmDialog.vue.js +1 -1
- package/dist/components/LpConfirmHost.vue.js +1 -1
- package/dist/components/LpContextMenu.vue.js +1 -1
- package/dist/components/LpCopyButton.vue.js +1 -1
- package/dist/components/LpCountdown.vue.js +1 -1
- package/dist/components/LpDataList.vue.js +1 -1
- package/dist/components/LpDatePicker.vue.js +1 -1
- package/dist/components/LpDateRangePicker.vue.js +1 -1
- package/dist/components/LpDisclosure.vue.js +1 -1
- package/dist/components/LpDock.vue.js +1 -1
- package/dist/components/LpDrawer.vue.js +1 -1
- package/dist/components/LpDropdownMenu.vue.js +1 -1
- package/dist/components/LpDropzone.vue.js +2 -2
- package/dist/components/LpEditable.vue.js +1 -1
- package/dist/components/LpEmptyState.vue.d.ts +2 -0
- package/dist/components/LpEmptyState.vue.js +1 -1
- package/dist/components/LpFieldNotice.vue.js +1 -1
- package/dist/components/LpFileTree.vue.js +1 -1
- package/dist/components/LpFileTreeNode.vue.js +1 -1
- package/dist/components/LpFormField.vue.js +1 -1
- package/dist/components/LpGauge.vue.js +1 -1
- package/dist/components/LpHintLayer.vue.js +1 -1
- package/dist/components/LpHints.vue.js +1 -1
- package/dist/components/LpIcon.vue.js +1 -1
- package/dist/components/LpImageEditor.vue.js +3 -3
- package/dist/components/LpInfraNode.vue.js +1 -1
- package/dist/components/LpInput.vue.js +1 -1
- package/dist/components/LpKeys.vue.js +13 -10
- package/dist/components/LpLightbox.vue.js +1 -1
- package/dist/components/LpLoader.vue.js +1 -1
- package/dist/components/LpLogViewer.vue.d.ts +1 -1
- package/dist/components/LpLogViewer.vue.js +1 -1
- package/dist/components/LpMapPicker.vue.js +1 -1
- package/dist/components/LpMediaGallery.vue.js +1 -1
- package/dist/components/LpModal.vue.js +1 -1
- package/dist/components/LpModalNav.vue.js +1 -1
- package/dist/components/LpNotificationBell.vue.js +1 -1
- package/dist/components/LpNumberField.vue.js +1 -1
- package/dist/components/LpNumberFlow.vue.js +1 -1
- package/dist/components/LpPagination.vue.js +1 -1
- package/dist/components/LpPaletteFacts.vue.js +2 -2
- package/dist/components/LpPaletteHeader.vue.js +2 -2
- package/dist/components/LpPaletteStats.vue.js +2 -2
- package/dist/components/LpPaletteTheme.vue.js +1 -1
- package/dist/components/LpPasswordInput.vue.js +1 -1
- package/dist/components/LpPhoneInput.vue.js +1 -1
- package/dist/components/LpPie.vue.js +1 -1
- package/dist/components/LpPipeline.vue.js +1 -1
- package/dist/components/LpProgress.vue.js +1 -1
- package/dist/components/LpQuota.vue.js +1 -1
- package/dist/components/LpRadioGroup.vue.js +1 -1
- package/dist/components/LpRangeCalendar.vue.js +1 -1
- package/dist/components/LpRelativeTime.vue.js +1 -1
- package/dist/components/LpRepeater.vue.js +1 -1
- package/dist/components/LpRollingText.vue.d.ts +2 -2
- package/dist/components/LpRollingText.vue.js +1 -1
- package/dist/components/LpScramble.vue.js +1 -1
- package/dist/components/LpSecretField.vue.js +1 -1
- package/dist/components/LpSection.vue.js +1 -1
- package/dist/components/LpSegmented.vue.js +1 -1
- package/dist/components/LpSelect.vue.js +1 -1
- package/dist/components/LpShift.vue.d.ts +20 -0
- package/dist/components/LpShift.vue.js +1 -1
- package/dist/components/LpShortcutsDialog.vue.js +1 -1
- package/dist/components/LpSidebar.vue.d.ts +74 -23
- package/dist/components/LpSidebar.vue.js +1 -1
- package/dist/components/LpSidebarNav.vue.d.ts +31 -3
- package/dist/components/LpSidebarNav.vue.js +1 -1
- package/dist/components/LpSidebarRow.vue.d.ts +49 -0
- package/dist/components/LpSidebarRow.vue.js +4 -0
- package/dist/components/LpStat.vue.d.ts +11 -0
- package/dist/components/LpStat.vue.js +1 -1
- package/dist/components/LpStatus.vue.js +1 -1
- package/dist/components/LpStepMark.vue.js +1 -1
- package/dist/components/LpStepper.vue.js +1 -1
- package/dist/components/LpSwap.vue.js +1 -1
- package/dist/components/LpSwitch.vue.js +1 -1
- package/dist/components/LpTabFace.vue.d.ts +14 -0
- package/dist/components/LpTabFace.vue.js +4 -0
- package/dist/components/LpTable.vue.js +11 -11
- package/dist/components/LpTableFilter.vue.js +1 -1
- package/dist/components/LpTabs.vue.d.ts +4 -4
- package/dist/components/LpTabs.vue.js +18 -72
- package/dist/components/LpTagsInput.vue.js +1 -1
- package/dist/components/LpTextarea.vue.d.ts +19 -1
- package/dist/components/LpTextarea.vue.js +1 -1
- package/dist/components/LpThemeProvider.vue.js +1 -1
- package/dist/components/LpThemeStudio.vue.d.ts +2 -2
- package/dist/components/LpThemeStudio.vue.js +1 -1
- package/dist/components/LpThemeStudioSection.vue.d.ts +4 -1
- package/dist/components/LpThemeStudioSection.vue.js +1 -1
- package/dist/components/LpThemeSwitcher.vue.js +1 -1
- package/dist/components/LpTimeField.vue.js +1 -1
- package/dist/components/LpToaster.vue.js +1 -1
- package/dist/components/LpTopologyCanvas.vue.js +1 -1
- package/dist/components/LpTour.vue.js +1 -1
- package/dist/components/LpTruncate.vue.js +1 -1
- package/dist/components/LpUptimeBar.vue.js +1 -1
- package/dist/components/MenuTitle.vue.js +1 -1
- package/dist/components/OptionContent.vue.js +1 -1
- package/dist/components/PickerField.vue.js +1 -1
- package/dist/components/RevealToggle.vue.js +1 -1
- package/dist/components/TourCard.vue.js +1 -1
- package/dist/components/menuWhen.js +1 -1
- package/dist/components/rolling.d.ts +5 -0
- package/dist/components/rolling.js +23 -0
- package/dist/components/sidebar.d.ts +38 -0
- package/dist/components/sidebar.js +6 -1
- package/dist/components/tabs.d.ts +3 -0
- package/dist/components/tabs.js +6 -0
- package/dist/icons-all.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +154 -153
- package/package.json +1 -1
- package/src/component-names.ts +1 -0
- package/src/components/LpAppShell.vue +75 -7
- package/src/components/LpBottomNav.vue +84 -0
- package/src/components/LpColorPicker.vue +32 -1
- package/src/components/LpEmptyState.vue +4 -1
- package/src/components/LpKeys.vue +10 -1
- package/src/components/LpNumberFlow.vue +4 -2
- package/src/components/LpRollingText.vue +27 -2
- package/src/components/LpSegmented.vue +3 -1
- package/src/components/LpShift.vue +189 -2
- package/src/components/LpSidebar.vue +304 -18
- package/src/components/LpSidebarNav.vue +211 -78
- package/src/components/LpSidebarRow.vue +242 -0
- package/src/components/LpStat.vue +7 -1
- package/src/components/LpTabFace.vue +52 -0
- package/src/components/LpTabs.vue +6 -41
- package/src/components/LpTextarea.vue +34 -4
- package/src/components/LpThemeStudio.vue +91 -55
- package/src/components/LpThemeStudioSection.vue +15 -7
- package/src/components/rolling.ts +28 -0
- package/src/components/sidebar.ts +41 -0
- package/src/components/tabs.ts +9 -0
- package/src/index.ts +1 -0
- package/src/kit-icons.ts +1 -1
- package/dist/assets/LpTabs-DT0XPTc2.css +0 -18
- package/dist/chunks/LpRollingText-DiL717LK.js +0 -51
- package/dist/chunks/LpShift-DXNsauQZ.js +0 -40
- package/dist/chunks/LpSidebar-Bk7b-K4l.js +0 -256
- package/dist/chunks/LpSidebarNav-BR2AW3KT.js +0 -216
- package/dist/chunks/LpThemeProvider-DcbfOxsU.js +0 -69
- package/dist/chunks/LpThemeStudioSection-BwhqYDLf.js +0 -20
|
@@ -13,11 +13,14 @@
|
|
|
13
13
|
* auto-closes the drawer. With `responsive` off the component renders exactly
|
|
14
14
|
* the static <nav> it always has — existing call sites are unaffected.
|
|
15
15
|
*/
|
|
16
|
-
import { computed, ref, useId } from "vue"
|
|
16
|
+
import { computed, nextTick, ref, useId } from "vue"
|
|
17
|
+
import { parseCombo, useHotkeys } from "../composables/useHotkeys"
|
|
17
18
|
import { usePersisted } from "../composables/usePersisted"
|
|
18
19
|
import { useLabels } from "../composables/useLpConfig"
|
|
19
20
|
import LpDrawer from "./LpDrawer.vue"
|
|
21
|
+
import LpIcon from "./LpIcon.vue"
|
|
20
22
|
import LpInput from "./LpInput.vue"
|
|
23
|
+
import LpTooltip from "./LpTooltip.vue"
|
|
21
24
|
import LpSidebarNav from "./LpSidebarNav.vue"
|
|
22
25
|
import type { SidebarItem, SidebarSection } from "./sidebar"
|
|
23
26
|
|
|
@@ -50,7 +53,17 @@ const props = withDefaults(
|
|
|
50
53
|
/** Placeholder for that field (defaults to the `search` label). */
|
|
51
54
|
searchPlaceholder?: string
|
|
52
55
|
/** Text overrides: `nav` names the landmark, `search` the filter field. */
|
|
53
|
-
labels?: Partial<{
|
|
56
|
+
labels?: Partial<{
|
|
57
|
+
nav: string
|
|
58
|
+
search: string
|
|
59
|
+
pinned: string
|
|
60
|
+
pin: string
|
|
61
|
+
unpin: string
|
|
62
|
+
expand: string
|
|
63
|
+
compact: string
|
|
64
|
+
expandRail: string
|
|
65
|
+
resize: string
|
|
66
|
+
}>
|
|
54
67
|
/** The query, when the app wants to own it (v-model:search). */
|
|
55
68
|
search?: string
|
|
56
69
|
/** Show a skeleton placeholder instead of the items. */
|
|
@@ -126,6 +139,44 @@ const props = withDefaults(
|
|
|
126
139
|
* see LpSidebarNav for why a tall nav keeps it pinned.
|
|
127
140
|
*/
|
|
128
141
|
hoverFollow?: boolean
|
|
142
|
+
/**
|
|
143
|
+
* Icons only (v-model:compact): each row's name, count and the pages under
|
|
144
|
+
* it move into a card beside the icon. With `resizable` the person decides,
|
|
145
|
+
* and the choice is remembered under `persist`.
|
|
146
|
+
*/
|
|
147
|
+
compact?: boolean
|
|
148
|
+
/**
|
|
149
|
+
* The person sizes the rail: drag its edge (double-click resets), drag it
|
|
150
|
+
* narrow enough and it folds to icons, and a button and Ctrl+B fold it
|
|
151
|
+
* outright. One mechanism, not two: a narrow rail that only truncates its
|
|
152
|
+
* labels is the worst of both, so below a point it becomes the icon rail.
|
|
153
|
+
*/
|
|
154
|
+
resizable?: boolean
|
|
155
|
+
/** Rail width bounds while resizing, in px. */
|
|
156
|
+
minWidth?: number
|
|
157
|
+
maxWidth?: number
|
|
158
|
+
/** The key that folds the rail when `resizable`. False turns it off. */
|
|
159
|
+
compactHotkey?: string | false
|
|
160
|
+
/**
|
|
161
|
+
* Rows offer "Pin to top" in their menu, and pinned pages lead the nav
|
|
162
|
+
* (v-model:pinned, ids; remembered under `persist` when unbound).
|
|
163
|
+
*/
|
|
164
|
+
pinnable?: boolean
|
|
165
|
+
pinned?: string[]
|
|
166
|
+
/** How long the pointer rests on a row with a `preview` before its card opens, in ms. */
|
|
167
|
+
previewDelay?: number
|
|
168
|
+
/**
|
|
169
|
+
* Mark the app as not production: a coloured band along the top of the rail
|
|
170
|
+
* with the label hanging from it ("staging", "local"). It is there so an
|
|
171
|
+
* edit on the test copy is not mistaken for one on the real thing; leave it
|
|
172
|
+
* unset in production.
|
|
173
|
+
*/
|
|
174
|
+
environment?: string | { label: string; tone?: "warning" | "danger" | "action" | "brand" }
|
|
175
|
+
/**
|
|
176
|
+
* The app's hint system (createHintSystem). Rows that name a `hintPage`
|
|
177
|
+
* then mark unread news on it with a dot, with nothing for the app to wire.
|
|
178
|
+
*/
|
|
179
|
+
hints?: { unreadNews: (page?: string) => readonly unknown[] }
|
|
129
180
|
}>(),
|
|
130
181
|
{
|
|
131
182
|
skeletonRows: 6,
|
|
@@ -136,6 +187,11 @@ const props = withDefaults(
|
|
|
136
187
|
variant: "rail",
|
|
137
188
|
autoCollapseAfter: 14,
|
|
138
189
|
hoverFollow: false,
|
|
190
|
+
compact: undefined,
|
|
191
|
+
minWidth: 180,
|
|
192
|
+
maxWidth: 420,
|
|
193
|
+
compactHotkey: "Ctrl+B",
|
|
194
|
+
previewDelay: 900,
|
|
139
195
|
},
|
|
140
196
|
)
|
|
141
197
|
|
|
@@ -145,15 +201,47 @@ const emit = defineEmits<{
|
|
|
145
201
|
(e: "update:collapsed", keys: string[]): void
|
|
146
202
|
(e: "select", item: SidebarItem): void
|
|
147
203
|
(e: "update:search", value: string): void
|
|
204
|
+
(e: "update:compact", value: boolean): void
|
|
205
|
+
(e: "update:pinned", ids: string[]): void
|
|
148
206
|
}>()
|
|
149
207
|
|
|
150
|
-
|
|
208
|
+
defineSlots<{
|
|
209
|
+
/** The brand; `compact` says the rail is down to icons. */
|
|
210
|
+
header?: (props: { compact?: boolean }) => unknown
|
|
211
|
+
actions?: (props: { compact?: boolean }) => unknown
|
|
212
|
+
footer?: (props: { compact?: boolean }) => unknown
|
|
213
|
+
item?: (props: { item: SidebarItem; active: boolean }) => unknown
|
|
214
|
+
}>()
|
|
215
|
+
|
|
216
|
+
const text = useLabels(
|
|
217
|
+
"sidebar",
|
|
218
|
+
{
|
|
219
|
+
nav: "Sidebar",
|
|
220
|
+
search: "Search",
|
|
221
|
+
pinned: "Pinned",
|
|
222
|
+
pin: "Pin to top",
|
|
223
|
+
unpin: "Unpin",
|
|
224
|
+
expand: "Show the pages under it",
|
|
225
|
+
compact: "Collapse the sidebar",
|
|
226
|
+
expandRail: "Expand the sidebar",
|
|
227
|
+
resize: "Drag to resize, double-click to reset",
|
|
228
|
+
},
|
|
229
|
+
() => props.labels,
|
|
230
|
+
)
|
|
151
231
|
const placeholder = computed(() => props.searchPlaceholder ?? text.value.search)
|
|
152
232
|
|
|
233
|
+
function withNews(item: SidebarItem): SidebarItem {
|
|
234
|
+
const children = item.children?.map(withNews)
|
|
235
|
+
const pages = item.hintPage === undefined ? [] : Array.isArray(item.hintPage) ? item.hintPage : [item.hintPage]
|
|
236
|
+
const fresh = !!props.hints && pages.some((p) => props.hints!.unreadNews(p).length > 0)
|
|
237
|
+
return fresh || children ? { ...item, children, dot: item.dot || fresh } : item
|
|
238
|
+
}
|
|
239
|
+
|
|
153
240
|
// Normalise both inputs to a single section list.
|
|
154
|
-
const allGroups = computed<SidebarSection[]>(() =>
|
|
155
|
-
props.sections ?? (props.items ? [{ items: props.items }] : [])
|
|
156
|
-
)
|
|
241
|
+
const allGroups = computed<SidebarSection[]>(() => {
|
|
242
|
+
const groups = props.sections ?? (props.items ? [{ items: props.items }] : [])
|
|
243
|
+
return props.hints ? groups.map((g) => ({ ...g, items: g.items.map(withNews) })) : groups
|
|
244
|
+
})
|
|
157
245
|
|
|
158
246
|
/*
|
|
159
247
|
* The filter query. Controlled through v-model:search when the app wants it —
|
|
@@ -179,6 +267,13 @@ function matches(item: SidebarItem, needle: string): boolean {
|
|
|
179
267
|
return (item.keywords ?? []).some((k) => normalise(k).includes(needle))
|
|
180
268
|
}
|
|
181
269
|
|
|
270
|
+
/** The item if it matches, with every page under it; else only the pages under it that match. */
|
|
271
|
+
function narrowed(item: SidebarItem, needle: string): SidebarItem | null {
|
|
272
|
+
if (matches(item, needle)) return item
|
|
273
|
+
const children = (item.children ?? []).filter((c) => matches(c, needle))
|
|
274
|
+
return children.length ? { ...item, children } : null
|
|
275
|
+
}
|
|
276
|
+
|
|
182
277
|
const groups = computed<SidebarSection[]>(() => {
|
|
183
278
|
const needle = normalise(query.value.trim())
|
|
184
279
|
if (!needle) return allGroups.value
|
|
@@ -186,7 +281,10 @@ const groups = computed<SidebarSection[]>(() => {
|
|
|
186
281
|
// under it reads as a section that failed to load rather than one that
|
|
187
282
|
// matched nothing.
|
|
188
283
|
return allGroups.value
|
|
189
|
-
.map((section) => ({
|
|
284
|
+
.map((section) => ({
|
|
285
|
+
...section,
|
|
286
|
+
items: section.items.map((i) => narrowed(i, needle)).filter((i): i is SidebarItem => i !== null),
|
|
287
|
+
}))
|
|
190
288
|
.filter((section) => section.items.length > 0)
|
|
191
289
|
})
|
|
192
290
|
|
|
@@ -226,7 +324,7 @@ const autoCollapsed = computed<string[]>(() => {
|
|
|
226
324
|
const limit = props.autoCollapseAfter
|
|
227
325
|
if (!limit || navLength.value <= limit) return []
|
|
228
326
|
return groups.value
|
|
229
|
-
.filter((g) => g.collapsible && !g.items.some(itemActive))
|
|
327
|
+
.filter((g) => g.collapsible && !g.items.some((i) => itemActive(i) || !!i.children?.some(itemActive)))
|
|
230
328
|
.map(keyOf)
|
|
231
329
|
.filter(Boolean)
|
|
232
330
|
})
|
|
@@ -246,6 +344,117 @@ function toggleSection(key: string, collapsed: boolean) {
|
|
|
246
344
|
emit("update:collapsed", next)
|
|
247
345
|
}
|
|
248
346
|
|
|
347
|
+
/*
|
|
348
|
+
* Compact and width. Bound, the app owns them; unbound, the sidebar keeps them,
|
|
349
|
+
* across visits under `persist`.
|
|
350
|
+
*/
|
|
351
|
+
const ownCompact = usePersisted<boolean>(() => props.persist && `lp-sidebar:${props.persist}:compact`, false)
|
|
352
|
+
const isCompact = computed(() => props.compact ?? ownCompact.value)
|
|
353
|
+
function setCompact(value: boolean) {
|
|
354
|
+
ownCompact.value = value
|
|
355
|
+
emit("update:compact", value)
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const ENV_TONE = {
|
|
359
|
+
warning: "bg-accent text-ink-inverse",
|
|
360
|
+
danger: "bg-danger text-white",
|
|
361
|
+
action: "bg-action text-ink-inverse",
|
|
362
|
+
brand: "bg-brand text-ink-inverse",
|
|
363
|
+
} as const
|
|
364
|
+
const env = computed(() => {
|
|
365
|
+
const e = props.environment
|
|
366
|
+
if (!e) return null
|
|
367
|
+
const { label, tone = "warning" } = typeof e === "string" ? { label: e } : e
|
|
368
|
+
return { label, tone: ENV_TONE[tone] }
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
const DEFAULT_WIDTH = 240
|
|
372
|
+
const COMPACT_WIDTH = 64
|
|
373
|
+
const ownWidth = usePersisted<number>(() => props.resizable && props.persist && `lp-sidebar:${props.persist}:width`, DEFAULT_WIDTH)
|
|
374
|
+
const dragging = ref(false)
|
|
375
|
+
|
|
376
|
+
const railWidth = computed(() => {
|
|
377
|
+
if (isCompact.value) return `${COMPACT_WIDTH}px`
|
|
378
|
+
if (props.resizable) return `${ownWidth.value}px`
|
|
379
|
+
return props.width
|
|
380
|
+
})
|
|
381
|
+
|
|
382
|
+
/*
|
|
383
|
+
* Dragging past the narrowest width folds the rail to icons, and dragging a
|
|
384
|
+
* folded rail out unfolds it: below a point labels only truncate to nothing
|
|
385
|
+
* useful, and the icon rail is the honest form of "narrow".
|
|
386
|
+
*/
|
|
387
|
+
const FOLD_AT = 132
|
|
388
|
+
function startResize(event: PointerEvent) {
|
|
389
|
+
if (event.button !== 0) return
|
|
390
|
+
const handle = event.currentTarget as HTMLElement
|
|
391
|
+
handle.setPointerCapture(event.pointerId)
|
|
392
|
+
const from = event.clientX
|
|
393
|
+
const start = isCompact.value ? COMPACT_WIDTH : ownWidth.value
|
|
394
|
+
dragging.value = true
|
|
395
|
+
const move = (e: PointerEvent) => {
|
|
396
|
+
const wanted = start + (e.clientX - from)
|
|
397
|
+
if (wanted < FOLD_AT) {
|
|
398
|
+
// Folded by dragging: the width it unfolds to is the one it had, not
|
|
399
|
+
// the narrowest the drag passed through on its way down.
|
|
400
|
+
if (!isCompact.value) setCompact(true)
|
|
401
|
+
if (start !== COMPACT_WIDTH) ownWidth.value = start
|
|
402
|
+
return
|
|
403
|
+
}
|
|
404
|
+
if (isCompact.value) setCompact(false)
|
|
405
|
+
ownWidth.value = Math.round(Math.min(props.maxWidth, Math.max(props.minWidth, wanted)))
|
|
406
|
+
}
|
|
407
|
+
const stop = () => {
|
|
408
|
+
dragging.value = false
|
|
409
|
+
handle.removeEventListener("pointermove", move)
|
|
410
|
+
handle.removeEventListener("pointerup", stop)
|
|
411
|
+
handle.removeEventListener("pointercancel", stop)
|
|
412
|
+
}
|
|
413
|
+
handle.addEventListener("pointermove", move)
|
|
414
|
+
handle.addEventListener("pointerup", stop)
|
|
415
|
+
handle.addEventListener("pointercancel", stop)
|
|
416
|
+
}
|
|
417
|
+
const railEl = ref<HTMLElement | null>(null)
|
|
418
|
+
async function searchFromCompact() {
|
|
419
|
+
setCompact(false)
|
|
420
|
+
await nextTick()
|
|
421
|
+
railEl.value?.querySelector<HTMLInputElement>("input")?.focus()
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function resetWidth() {
|
|
425
|
+
ownWidth.value = DEFAULT_WIDTH
|
|
426
|
+
setCompact(false)
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
useHotkeys(() =>
|
|
430
|
+
props.resizable && props.compactHotkey
|
|
431
|
+
? [
|
|
432
|
+
{
|
|
433
|
+
...parseCombo(props.compactHotkey),
|
|
434
|
+
help: { group: text.value.nav, label: text.value.compact, combo: props.compactHotkey },
|
|
435
|
+
handler: () => setCompact(!isCompact.value),
|
|
436
|
+
},
|
|
437
|
+
]
|
|
438
|
+
: [],
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
/* Pinned pages, by id; unbound they are kept under `persist`. */
|
|
442
|
+
const ownPinned = usePersisted<string[]>(() => props.persist && `lp-sidebar:${props.persist}:pinned`, [], {
|
|
443
|
+
validate: (value): value is string[] => Array.isArray(value) && value.every((k) => typeof k === "string"),
|
|
444
|
+
})
|
|
445
|
+
const pinnedIds = computed(() => props.pinned ?? ownPinned.value)
|
|
446
|
+
const everyItem = computed(() => allGroups.value.flatMap((g) => g.items.flatMap((i) => [i, ...(i.children ?? [])])))
|
|
447
|
+
const pinnedItems = computed<SidebarItem[]>(() =>
|
|
448
|
+
props.pinnable
|
|
449
|
+
? pinnedIds.value.map((id) => everyItem.value.find((i) => i.id === id)).filter((i): i is SidebarItem => !!i)
|
|
450
|
+
: [],
|
|
451
|
+
)
|
|
452
|
+
function togglePin(id: string) {
|
|
453
|
+
const next = pinnedIds.value.includes(id) ? pinnedIds.value.filter((k) => k !== id) : [...pinnedIds.value, id]
|
|
454
|
+
ownPinned.value = next
|
|
455
|
+
emit("update:pinned", next)
|
|
456
|
+
}
|
|
457
|
+
|
|
249
458
|
function activate(item: SidebarItem) {
|
|
250
459
|
if (item.disabled) return
|
|
251
460
|
emit("update:modelValue", item.id)
|
|
@@ -291,12 +500,28 @@ defineOptions({ inheritAttrs: false })
|
|
|
291
500
|
<template>
|
|
292
501
|
<!-- Desktop / always-on rail -->
|
|
293
502
|
<nav
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
:
|
|
503
|
+
ref="railEl"
|
|
504
|
+
class="relative h-full shrink-0 flex-col gap-1"
|
|
505
|
+
:class="[
|
|
506
|
+
railClass,
|
|
507
|
+
chromeClass,
|
|
508
|
+
isCompact ? 'px-2 py-3' : 'p-3',
|
|
509
|
+
railWidth ? '' : 'w-60',
|
|
510
|
+
dragging ? '' : 'transition-[width] duration-(--duration-medium) ease-[var(--ease-emphasized)] motion-reduce:transition-none',
|
|
511
|
+
]"
|
|
512
|
+
:style="railWidth ? { width: railWidth } : undefined"
|
|
513
|
+
:data-compact="isCompact || undefined"
|
|
297
514
|
:aria-label="text.nav"
|
|
298
515
|
v-bind="$attrs"
|
|
299
516
|
>
|
|
517
|
+
<div v-if="env" class="pointer-events-none absolute inset-x-0 top-0 z-20 h-[3px]" :class="env.tone" />
|
|
518
|
+
<span
|
|
519
|
+
v-if="env && !isCompact"
|
|
520
|
+
class="pointer-events-none absolute left-1/2 top-0 z-20 -translate-x-1/2 rounded-b-small px-2 pb-0.5 text-[10px] font-semibold uppercase tracking-wide"
|
|
521
|
+
:class="env.tone"
|
|
522
|
+
>
|
|
523
|
+
{{ env.label }}
|
|
524
|
+
</span>
|
|
300
525
|
<!-- Rail: edge-to-edge (negative margins cancel the p-3) and h-16 to match
|
|
301
526
|
the app header, so its bottom hairline continues the header's border-b.
|
|
302
527
|
Panel: kept inside the padding — bleeding to the edge would cut across
|
|
@@ -305,18 +530,33 @@ defineOptions({ inheritAttrs: false })
|
|
|
305
530
|
v-if="$slots.header"
|
|
306
531
|
class="mb-3 flex shrink-0 items-center"
|
|
307
532
|
:class="[
|
|
308
|
-
variant === 'panel' ? 'pb-3' : '-mx-3 -mt-3 h-16 px-3',
|
|
533
|
+
variant === 'panel' ? 'pb-3' : isCompact ? '-mx-2 -mt-3 h-16 overflow-hidden' : '-mx-3 -mt-3 h-16 px-3',
|
|
309
534
|
divider ? 'border-b border-line' : '',
|
|
310
535
|
]"
|
|
311
536
|
>
|
|
312
|
-
<
|
|
537
|
+
<div v-if="isCompact" class="flex w-16 shrink-0 justify-center">
|
|
538
|
+
<slot name="header" :compact="true" />
|
|
539
|
+
</div>
|
|
540
|
+
<slot v-else name="header" :compact="false" />
|
|
313
541
|
</div>
|
|
314
542
|
|
|
315
543
|
<!-- The filter sits between the brand and the nav: it belongs to the list,
|
|
316
544
|
not to the header, and a person reaching for it is already looking at
|
|
317
545
|
the items. -->
|
|
546
|
+
<!-- Folded, the filter is a button: a field forty pixels wide holds no
|
|
547
|
+
query, so the rail opens to give it room and puts the caret in it. -->
|
|
548
|
+
<LpTooltip v-if="searchable && isCompact" :content="placeholder" side="right">
|
|
549
|
+
<button
|
|
550
|
+
type="button"
|
|
551
|
+
class="mb-2 ml-1 grid size-10 shrink-0 place-items-center rounded-control text-muted outline-none transition-colors hover:bg-ink/[0.05] hover:text-ink focus-visible:ring-2 focus-visible:ring-ring"
|
|
552
|
+
:aria-label="placeholder"
|
|
553
|
+
@click="searchFromCompact"
|
|
554
|
+
>
|
|
555
|
+
<LpIcon name="lucide:search" :size="17" />
|
|
556
|
+
</button>
|
|
557
|
+
</LpTooltip>
|
|
318
558
|
<LpInput
|
|
319
|
-
v-if="searchable"
|
|
559
|
+
v-if="searchable && !isCompact"
|
|
320
560
|
v-model="query"
|
|
321
561
|
size="sm"
|
|
322
562
|
icon="lucide:search"
|
|
@@ -328,6 +568,11 @@ defineOptions({ inheritAttrs: false })
|
|
|
328
568
|
<LpSidebarNav
|
|
329
569
|
:groups="groups"
|
|
330
570
|
:pill-id="railPillId"
|
|
571
|
+
:compact="isCompact"
|
|
572
|
+
:pinnable="pinnable"
|
|
573
|
+
:pinned="pinnedItems"
|
|
574
|
+
:preview-delay="previewDelay"
|
|
575
|
+
:labels="text"
|
|
331
576
|
:item-active="itemActive"
|
|
332
577
|
:loading="loading"
|
|
333
578
|
:skeleton-rows="skeletonRows"
|
|
@@ -336,21 +581,57 @@ defineOptions({ inheritAttrs: false })
|
|
|
336
581
|
:hover-follow="hoverFollow"
|
|
337
582
|
@activate="activate"
|
|
338
583
|
@toggle-section="toggleSection"
|
|
584
|
+
@toggle-pin="togglePin"
|
|
339
585
|
>
|
|
340
586
|
<template v-if="$slots.item" #item="slotProps">
|
|
341
587
|
<slot name="item" v-bind="slotProps" />
|
|
342
588
|
</template>
|
|
343
589
|
</LpSidebarNav>
|
|
344
590
|
|
|
591
|
+
<LpTooltip v-if="resizable" :content="isCompact ? text.expandRail : text.compact" side="right">
|
|
592
|
+
<button
|
|
593
|
+
type="button"
|
|
594
|
+
class="mt-1 flex h-8 shrink-0 items-center gap-2 rounded-control px-3 text-xs text-muted outline-none transition-colors hover:bg-ink/[0.05] hover:text-ink focus-visible:ring-2 focus-visible:ring-ring"
|
|
595
|
+
:class="isCompact ? 'ml-1 w-10 justify-center px-0' : ''"
|
|
596
|
+
:aria-label="isCompact ? text.expandRail : text.compact"
|
|
597
|
+
:aria-pressed="isCompact"
|
|
598
|
+
@click="setCompact(!isCompact)"
|
|
599
|
+
>
|
|
600
|
+
<LpIcon :name="isCompact ? 'lucide:panel-left-open' : 'lucide:panel-left-close'" :size="16" class="shrink-0" />
|
|
601
|
+
<span v-if="!isCompact" class="truncate">{{ text.compact }}</span>
|
|
602
|
+
</button>
|
|
603
|
+
</LpTooltip>
|
|
604
|
+
|
|
345
605
|
<!-- Actions (search, "new …") sit just above the footer, pinned to the
|
|
346
606
|
bottom of the rail and outside the scroll region — not trailing the
|
|
347
607
|
nav list. -->
|
|
348
|
-
<div v-if="$slots.actions" class="mt-2 flex shrink-0 flex-col gap-2">
|
|
349
|
-
<slot name="actions" />
|
|
608
|
+
<div v-if="$slots.actions" class="mt-2 flex shrink-0 flex-col gap-2" :class="isCompact ? 'w-12 items-center' : ''">
|
|
609
|
+
<slot name="actions" :compact="isCompact" />
|
|
350
610
|
</div>
|
|
351
611
|
|
|
352
|
-
<div v-if="$slots.footer" class="mt-2 shrink-0 border-t border-line pt-3">
|
|
353
|
-
<
|
|
612
|
+
<div v-if="$slots.footer" class="mt-2 shrink-0 overflow-hidden border-t border-line pt-3">
|
|
613
|
+
<div v-if="isCompact" class="flex w-12 justify-center">
|
|
614
|
+
<slot name="footer" :compact="true" />
|
|
615
|
+
</div>
|
|
616
|
+
<slot v-else name="footer" :compact="false" />
|
|
617
|
+
</div>
|
|
618
|
+
|
|
619
|
+
<!-- The edge itself is the handle: a few pixels either side of the
|
|
620
|
+
hairline, a brand line while it is held. -->
|
|
621
|
+
<div
|
|
622
|
+
v-if="resizable && variant === 'rail'"
|
|
623
|
+
role="separator"
|
|
624
|
+
aria-orientation="vertical"
|
|
625
|
+
:aria-label="text.resize"
|
|
626
|
+
:title="text.resize"
|
|
627
|
+
class="group/resize absolute inset-y-0 -right-1.5 z-10 w-3 cursor-col-resize touch-none"
|
|
628
|
+
@pointerdown="startResize"
|
|
629
|
+
@dblclick="resetWidth"
|
|
630
|
+
>
|
|
631
|
+
<span
|
|
632
|
+
class="absolute inset-y-0 left-1/2 w-0.5 -translate-x-1/2 bg-brand opacity-0 transition-opacity duration-(--duration-fast) group-hover/resize:opacity-60"
|
|
633
|
+
:class="dragging ? '!opacity-100' : ''"
|
|
634
|
+
/>
|
|
354
635
|
</div>
|
|
355
636
|
</nav>
|
|
356
637
|
|
|
@@ -389,6 +670,10 @@ defineOptions({ inheritAttrs: false })
|
|
|
389
670
|
<LpSidebarNav
|
|
390
671
|
:groups="groups"
|
|
391
672
|
:pill-id="drawerPillId"
|
|
673
|
+
:pinnable="pinnable"
|
|
674
|
+
:pinned="pinnedItems"
|
|
675
|
+
:preview-delay="previewDelay"
|
|
676
|
+
:labels="text"
|
|
392
677
|
:item-active="itemActive"
|
|
393
678
|
:loading="loading"
|
|
394
679
|
:skeleton-rows="skeletonRows"
|
|
@@ -397,6 +682,7 @@ defineOptions({ inheritAttrs: false })
|
|
|
397
682
|
:hover-follow="hoverFollow"
|
|
398
683
|
@activate="activate"
|
|
399
684
|
@toggle-section="toggleSection"
|
|
685
|
+
@toggle-pin="togglePin"
|
|
400
686
|
>
|
|
401
687
|
<template v-if="$slots.item" #item="slotProps">
|
|
402
688
|
<slot name="item" v-bind="slotProps" />
|