@leavepulse/ui 0.56.0 → 0.58.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/chunks/{ContextMenuItems-BtKU7074.js → ContextMenuItems-BY5sTVQF.js} +1 -1
- package/dist/chunks/{LayoutCanvas-BkaGXTjx.js → LayoutCanvas-BcGLJVBq.js} +1 -1
- package/dist/chunks/{LayoutNode-B3_9E1Xa.js → LayoutNode-BkBn6dvM.js} +1 -1
- package/dist/chunks/{LpActionBar-C3hkVsFz.js → LpActionBar-DCN-_pZP.js} +2 -2
- package/dist/chunks/{LpAddressInput-NUHmplCd.js → LpAddressInput-Dio6Sqed.js} +7 -7
- package/dist/chunks/{LpAlert-B6ilrM7T.js → LpAlert-CXMn1GYE.js} +1 -1
- package/dist/chunks/{LpAppShell-BEGjSqFl.js → LpAppShell-Be6T96td.js} +3 -3
- package/dist/chunks/{LpAutocomplete-C8IgSMsi.js → LpAutocomplete-hJ_6CHlh.js} +1 -1
- package/dist/chunks/{LpAvatar-LTvy0OkE.js → LpAvatar-BxNs23Xu.js} +2 -2
- package/dist/chunks/{LpBreadcrumbs-D4TsoFju.js → LpBreadcrumbs-BLzOEgAF.js} +1 -1
- package/dist/chunks/{LpButton-BdfZFNqi.js → LpButton-vhlwmpBy.js} +1 -1
- package/dist/chunks/{LpCalendar-DrA2McTU.js → LpCalendar-BLoE8Qm7.js} +1 -1
- package/dist/chunks/{LpCard-DbjO5yaF.js → LpCard-DhR7u0d8.js} +1 -1
- package/dist/chunks/{LpCheckbox-DvVYeOD-.js → LpCheckbox-B_C8sOoT.js} +1 -1
- package/dist/chunks/{LpCodeBlock-ca7ANFyW.js → LpCodeBlock-CXsqJwDy.js} +1 -1
- package/dist/chunks/{LpColorPicker-D1sQqtXS.js → LpColorPicker-DQ88niXq.js} +2 -2
- package/dist/chunks/{LpConfirmDialog-CrbUZgJE.js → LpConfirmDialog-DxlSdjmk.js} +3 -3
- package/dist/chunks/{LpConfirmHost-BgMIV8r9.js → LpConfirmHost-BcrmTNu_.js} +1 -1
- package/dist/chunks/{LpContextMenu-EF_90u3g.js → LpContextMenu-B1NGfpp1.js} +2 -2
- package/dist/chunks/{LpDatePicker-BrdFtSTy.js → LpDatePicker-B-VMHMgy.js} +3 -3
- package/dist/chunks/{LpDateRangePicker-Drd7EbIz.js → LpDateRangePicker-B68KPKPl.js} +6 -15
- package/dist/chunks/{LpDisclosure-Cc23-JOT.js → LpDisclosure-Ct-VBHxt.js} +1 -1
- package/dist/chunks/{LpDrawer-CBFVD624.js → LpDrawer-DSknigxH.js} +5 -7
- package/dist/chunks/{LpDropdownMenu-DrpJJBp0.js → LpDropdownMenu-C7oHVlKY.js} +2 -2
- package/dist/chunks/{LpEmptyState-BJbZXC8D.js → LpEmptyState-CBwwkkdA.js} +1 -1
- package/dist/chunks/{LpFieldNotice-wtieLUTj.js → LpFieldNotice-9hH4ITZa.js} +1 -1
- package/dist/chunks/{LpFileTree-3E4w4Rjr.js → LpFileTree-CMA0_rsB.js} +2 -2
- package/dist/chunks/{LpFileTreeNode-B4uB8Ks_.js → LpFileTreeNode-B4T258hF.js} +3 -3
- package/dist/chunks/{LpFormField-CtVYj6tO.js → LpFormField-BpQ6WJPe.js} +1 -1
- package/dist/chunks/LpHintLayer-B5-6FyEf.js +154 -0
- package/dist/chunks/LpHints-BqoZXHZk.js +109 -0
- package/dist/chunks/{LpIcon-DYtaid0K.js → LpIcon-B5guGKrW.js} +1 -1
- package/dist/chunks/{LpInput-D-YGQbEv.js → LpInput-WvyP02ID.js} +2 -2
- package/dist/chunks/{LpLightbox-EVXzAq62.js → LpLightbox-Dq-e36uT.js} +1 -1
- package/dist/chunks/{LpLogViewer-BfgtXVKm.js → LpLogViewer-DwiYE32z.js} +2 -2
- package/dist/chunks/{LpMapPicker-Cc84LaM3.js → LpMapPicker-BH5csaBt.js} +1 -1
- package/dist/chunks/{LpMediaGallery-BnlkN_1f.js → LpMediaGallery-B1kDypJ-.js} +2 -2
- package/dist/chunks/{LpModal-JNa3B_Lr.js → LpModal-BxYssnXg.js} +1 -1
- package/dist/chunks/{LpModalNav-DXBilXr0.js → LpModalNav-Bn2ws64b.js} +4 -4
- package/dist/chunks/{LpNotificationBell-DEL-RoHS.js → LpNotificationBell-DJfs4JjQ.js} +4 -4
- package/dist/chunks/{LpNumberField-B77O-z28.js → LpNumberField-CJPjmoDz.js} +1 -1
- package/dist/chunks/{LpPagination-BcDlo3r_.js → LpPagination-DehAaJLY.js} +1 -1
- package/dist/chunks/{LpPasswordInput-eKzQhbQP.js → LpPasswordInput-Bg5uTZbx.js} +2 -2
- package/dist/chunks/{LpPhoneInput-BCbrrhgE.js → LpPhoneInput-DStwcbnQ.js} +2 -2
- package/dist/chunks/{LpPie-B7ti5qCH.js → LpPie-DeTkbbOK.js} +3 -3
- package/dist/chunks/{LpRangeCalendar-DZuaRV0W.js → LpRangeCalendar-D5sDID9W.js} +1 -1
- package/dist/chunks/{LpSection-tKEH0jYf.js → LpSection-B19VPYmr.js} +1 -1
- package/dist/chunks/{LpSegmented-C09EEam2.js → LpSegmented-D3Eam8sa.js} +1 -1
- package/dist/chunks/{LpSelect-DNIL6MB9.js → LpSelect-DynjWK1A.js} +1 -1
- package/dist/chunks/{LpSidebar-C2oolgwy.js → LpSidebar-CshW0fqC.js} +3 -3
- package/dist/chunks/{LpSidebarNav-C9dHu-2b.js → LpSidebarNav-C9b3i9G2.js} +2 -2
- package/dist/chunks/{LpStat-B-7udBRP.js → LpStat-BS2TEXYK.js} +1 -1
- package/dist/chunks/{LpStepper-C7XiVKZj.js → LpStepper-BSglWF45.js} +1 -1
- package/dist/chunks/{LpTableFilter-CrW7_Rj4.js → LpTableFilter-CwHXVxJt.js} +2 -2
- package/dist/chunks/{LpTableOfContents-BUcAfGPQ.js → LpTableOfContents-DYuqkByy.js} +2 -8
- package/dist/chunks/{LpTabs-BMSBB78h.js → LpTabs-BBGRHY38.js} +1 -1
- package/dist/chunks/{LpTagsInput-D1SuqbhB.js → LpTagsInput-CHbQoAAA.js} +3 -3
- package/dist/chunks/{LpTextarea-uuScWo6-.js → LpTextarea-Bz2IWhTH.js} +1 -1
- package/dist/chunks/{LpThemeSwitcher-Fz85BCRS.js → LpThemeSwitcher-B_qhSl7q.js} +2 -2
- package/dist/chunks/{LpTimeField-Cqe7fXnh.js → LpTimeField-DvGXgdES.js} +1 -1
- package/dist/chunks/{LpToaster-DTtWuKvq.js → LpToaster-Bo9Q4QBP.js} +1 -1
- package/dist/chunks/{LpTooltip-CXVKcOXT.js → LpTooltip-suFCM34F.js} +2 -2
- package/dist/chunks/LpTour-D7m9ZxNk.js +334 -0
- package/dist/chunks/{LpUptimeBar-ugcv25xj.js → LpUptimeBar-B4ltCfno.js} +1 -1
- package/dist/chunks/{MenuTitle-J3ZDYjpV.js → MenuTitle-DQP6hc2N.js} +1 -1
- package/dist/chunks/TourCard-DCHOjr6e.js +100 -0
- package/dist/chunks/icons-QqBscG5I.js +43 -0
- package/dist/component-names.d.ts +1 -1
- package/dist/components/ContextMenuItems.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.js +1 -1
- package/dist/components/LpAutocomplete.vue.js +1 -1
- package/dist/components/LpAvatar.vue.js +1 -1
- 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 +2 -2
- package/dist/components/LpCheckbox.vue.js +1 -1
- package/dist/components/LpCodeBlock.vue.js +1 -1
- package/dist/components/LpColorPicker.vue.js +1 -1
- package/dist/components/LpCommandPalette.vue.js +2 -2
- 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/LpDatePicker.vue.js +1 -1
- package/dist/components/LpDateRangePicker.vue.js +1 -1
- package/dist/components/LpDisclosure.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 +1 -1
- 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/LpHintLayer.vue.d.ts +33 -0
- package/dist/components/LpHintLayer.vue.js +4 -0
- package/dist/components/LpHints.vue.d.ts +20 -0
- package/dist/components/LpHints.vue.js +4 -0
- package/dist/components/LpIcon.vue.js +1 -1
- package/dist/components/LpImageEditor.vue.js +2 -2
- package/dist/components/LpInput.vue.js +1 -1
- package/dist/components/LpLightbox.vue.js +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/LpPagination.vue.js +1 -1
- package/dist/components/LpPaletteFacts.vue.js +1 -1
- package/dist/components/LpPaletteHeader.vue.js +2 -2
- 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/LpRangeCalendar.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/LpShortcutsDialog.vue.js +1 -1
- package/dist/components/LpSidebar.vue.js +1 -1
- package/dist/components/LpSidebarNav.vue.js +1 -1
- package/dist/components/LpStat.vue.js +1 -1
- package/dist/components/LpStepper.vue.js +1 -1
- package/dist/components/LpTable.vue.js +6 -6
- package/dist/components/LpTableFilter.vue.js +1 -1
- package/dist/components/LpTableOfContents.vue.js +1 -1
- package/dist/components/LpTabs.vue.js +1 -1
- package/dist/components/LpTagsInput.vue.js +1 -1
- package/dist/components/LpTextarea.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/LpTooltip.vue.js +1 -1
- package/dist/components/LpTour.vue.d.ts +98 -0
- package/dist/components/LpTour.vue.js +4 -0
- package/dist/components/LpUptimeBar.vue.js +1 -1
- package/dist/components/MenuTitle.vue.js +1 -1
- package/dist/components/TourCard.vue.d.ts +28 -0
- package/dist/components/TourCard.vue.js +4 -0
- package/dist/components/tour.d.ts +21 -0
- package/dist/components/tour.js +38 -0
- package/dist/composables/scroll.d.ts +17 -0
- package/dist/composables/scroll.js +29 -0
- package/dist/composables/useGamepadNav.js +2 -7
- package/dist/composables/useHintSystem.d.ts +195 -0
- package/dist/composables/useHintSystem.js +334 -0
- package/dist/composables/useHints.d.ts +18 -0
- package/dist/composables/useHints.js +120 -0
- package/dist/composables/useMediaQuery.d.ts +2 -0
- package/dist/composables/useMediaQuery.js +18 -0
- package/dist/composables/usePaintSelect.js +1 -7
- package/dist/icons-all.js +1 -1
- package/dist/index.d.ts +13 -0
- package/dist/index.js +89 -64
- package/package.json +1 -1
- package/src/component-names.ts +3 -0
- package/src/components/LpDateRangePicker.vue +3 -12
- package/src/components/LpDrawer.vue +4 -7
- package/src/components/LpHintLayer.vue +148 -0
- package/src/components/LpHints.vue +116 -0
- package/src/components/LpTableOfContents.vue +2 -14
- package/src/components/LpTooltip.vue +2 -4
- package/src/components/LpTour.vue +358 -0
- package/src/components/TourCard.vue +41 -0
- package/src/components/tour.ts +57 -0
- package/src/composables/scroll.ts +54 -0
- package/src/composables/useGamepadNav.ts +2 -7
- package/src/composables/useHintSystem.ts +512 -0
- package/src/composables/useHints.ts +151 -0
- package/src/composables/useMediaQuery.ts +20 -0
- package/src/composables/usePaintSelect.ts +1 -8
- package/src/index.ts +27 -0
- package/src/kit-icons.ts +1 -1
- package/src/tokens/tokens.css +1 -0
- package/dist/chunks/icons-CkA0njzm.js +0 -43
package/dist/index.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import { _ } from "./chunks/LayoutCanvas-
|
|
2
|
-
import { _ as _2 } from "./chunks/LpAddressInput-
|
|
3
|
-
import { _ as _3 } from "./chunks/LpMapPicker-
|
|
1
|
+
import { _ } from "./chunks/LayoutCanvas-BcGLJVBq.js";
|
|
2
|
+
import { _ as _2 } from "./chunks/LpAddressInput-Dio6Sqed.js";
|
|
3
|
+
import { _ as _3 } from "./chunks/LpMapPicker-BH5csaBt.js";
|
|
4
4
|
import { OSM_TILES, createNominatimProvider, emptyAddress, formatAddress, project, tileUrl, unproject } from "./components/address.js";
|
|
5
|
-
import { _ as _4 } from "./chunks/LpActionBar-
|
|
6
|
-
import { _ as _5 } from "./chunks/LpAlert-
|
|
7
|
-
import { _ as _6 } from "./chunks/LpAppShell-
|
|
8
|
-
import { _ as _7 } from "./chunks/LpAutocomplete-
|
|
9
|
-
import { _ as _8 } from "./chunks/LpAvatar-
|
|
5
|
+
import { _ as _4 } from "./chunks/LpActionBar-DCN-_pZP.js";
|
|
6
|
+
import { _ as _5 } from "./chunks/LpAlert-CXMn1GYE.js";
|
|
7
|
+
import { _ as _6 } from "./chunks/LpAppShell-Be6T96td.js";
|
|
8
|
+
import { _ as _7 } from "./chunks/LpAutocomplete-hJ_6CHlh.js";
|
|
9
|
+
import { _ as _8 } from "./chunks/LpAvatar-BxNs23Xu.js";
|
|
10
10
|
import { _ as _9 } from "./chunks/LpBadge-Fe0D1bYx.js";
|
|
11
|
-
import { _ as _10 } from "./chunks/LpBreadcrumbs-
|
|
12
|
-
import { _ as _11 } from "./chunks/LpButton-
|
|
13
|
-
import { _ as _12 } from "./chunks/LpCalendar-
|
|
14
|
-
import { _ as _13 } from "./chunks/LpCard-
|
|
11
|
+
import { _ as _10 } from "./chunks/LpBreadcrumbs-BLzOEgAF.js";
|
|
12
|
+
import { _ as _11 } from "./chunks/LpButton-vhlwmpBy.js";
|
|
13
|
+
import { _ as _12 } from "./chunks/LpCalendar-BLoE8Qm7.js";
|
|
14
|
+
import { _ as _13 } from "./chunks/LpCard-DhR7u0d8.js";
|
|
15
15
|
import { default as default2 } from "./components/LpChart.vue.js";
|
|
16
16
|
import { backgroundOf, csvField, downloadFile, fileStem, inlineSvg, resolveCssColor, svgToPng, toCsv } from "./components/exportData.js";
|
|
17
17
|
import { CHART_PALETTE, axisTicks, chartSummary, formatTick, markerIndex, niceScale, resolveSlices } from "./components/chart.js";
|
|
18
|
-
import { _ as _14 } from "./chunks/LpCheckbox-
|
|
19
|
-
import { _ as _15 } from "./chunks/LpCodeBlock-
|
|
18
|
+
import { _ as _14 } from "./chunks/LpCheckbox-B_C8sOoT.js";
|
|
19
|
+
import { _ as _15 } from "./chunks/LpCodeBlock-CXsqJwDy.js";
|
|
20
20
|
import { tokenizeLines } from "./components/codeHighlight.js";
|
|
21
|
-
import { _ as _16 } from "./chunks/LpColorPicker-
|
|
21
|
+
import { _ as _16 } from "./chunks/LpColorPicker-DQ88niXq.js";
|
|
22
22
|
import { DEFAULT_SWATCHES, clampHsv, formatColor, hsvToHsl, hsvToRgb, isLight, normalizeHue, opaqueCss, parseColor, parseHex, rgbToHex, rgbToHsv } from "./components/color.js";
|
|
23
23
|
import { default as default3 } from "./components/LpCommandPalette.vue.js";
|
|
24
24
|
import { applyQueryFilters, highlightParts, parseCommandQuery, parsePaletteQuery, rankCommandItems } from "./components/commandSearch.js";
|
|
@@ -30,46 +30,46 @@ import { default as default6 } from "./components/LpPaletteStats.vue.js";
|
|
|
30
30
|
import { default as default7 } from "./components/LpPaletteSwatches.vue.js";
|
|
31
31
|
import { default as default8 } from "./components/LpKeys.vue.js";
|
|
32
32
|
import { comboKeys, comboSteps } from "./components/keys.js";
|
|
33
|
-
import { _ as _18 } from "./chunks/LpConfirmDialog-
|
|
34
|
-
import { _ as _19 } from "./chunks/LpConfirmHost-
|
|
33
|
+
import { _ as _18 } from "./chunks/LpConfirmDialog-DxlSdjmk.js";
|
|
34
|
+
import { _ as _19 } from "./chunks/LpConfirmHost-BcrmTNu_.js";
|
|
35
35
|
import { confirm, useConfirm } from "./components/confirm.js";
|
|
36
|
-
import { _ as _20 } from "./chunks/LpContextMenu-
|
|
37
|
-
import { _ as _21 } from "./chunks/LpDatePicker-
|
|
38
|
-
import { _ as _22 } from "./chunks/LpDateRangePicker-
|
|
39
|
-
import { _ as _23 } from "./chunks/LpRangeCalendar-
|
|
36
|
+
import { _ as _20 } from "./chunks/LpContextMenu-B1NGfpp1.js";
|
|
37
|
+
import { _ as _21 } from "./chunks/LpDatePicker-B-VMHMgy.js";
|
|
38
|
+
import { _ as _22 } from "./chunks/LpDateRangePicker-B68KPKPl.js";
|
|
39
|
+
import { _ as _23 } from "./chunks/LpRangeCalendar-D5sDID9W.js";
|
|
40
40
|
import { clampRange, defaultRangePresets, formatRange, normalizeRange, sameRange } from "./components/dateRange.js";
|
|
41
|
-
import { _ as _24 } from "./chunks/LpDisclosure-
|
|
41
|
+
import { _ as _24 } from "./chunks/LpDisclosure-Ct-VBHxt.js";
|
|
42
42
|
import { _ as _25 } from "./chunks/LpDivider-CUX46KR0.js";
|
|
43
|
-
import { _ as _26 } from "./chunks/LpDrawer-
|
|
44
|
-
import { _ as _27 } from "./chunks/LpDropdownMenu-
|
|
43
|
+
import { _ as _26 } from "./chunks/LpDrawer-DSknigxH.js";
|
|
44
|
+
import { _ as _27 } from "./chunks/LpDropdownMenu-C7oHVlKY.js";
|
|
45
45
|
import { default as default9 } from "./components/LpDropzone.vue.js";
|
|
46
|
-
import { _ as _28 } from "./chunks/LpEmptyState-
|
|
47
|
-
import { _ as _29 } from "./chunks/LpFileTree-
|
|
46
|
+
import { _ as _28 } from "./chunks/LpEmptyState-CBwwkkdA.js";
|
|
47
|
+
import { _ as _29 } from "./chunks/LpFileTree-CMA0_rsB.js";
|
|
48
48
|
import { ancestorIds, checkStateOf, checkedCount, computeStats, fileIcon, formatModified, formatSize, sortNodes, subtreeIds, subtreeSize } from "./components/fileTree.js";
|
|
49
|
-
import { _ as _30 } from "./chunks/LpFieldNotice-
|
|
50
|
-
import { _ as _31 } from "./chunks/LpFormField-
|
|
51
|
-
import { _ as _32 } from "./chunks/LpIcon-
|
|
52
|
-
import { i, b, a, c } from "./chunks/icons-
|
|
49
|
+
import { _ as _30 } from "./chunks/LpFieldNotice-9hH4ITZa.js";
|
|
50
|
+
import { _ as _31 } from "./chunks/LpFormField-BpQ6WJPe.js";
|
|
51
|
+
import { _ as _32 } from "./chunks/LpIcon-B5guGKrW.js";
|
|
52
|
+
import { i, b, a, c } from "./chunks/icons-QqBscG5I.js";
|
|
53
53
|
import { default as default10 } from "./components/LpImageEditor.vue.js";
|
|
54
54
|
import { _ as _33 } from "./chunks/LpInfraNode-Ds_8SZgN.js";
|
|
55
|
-
import { _ as _34 } from "./chunks/LpInput-
|
|
56
|
-
import { _ as _35 } from "./chunks/LpLightbox-
|
|
55
|
+
import { _ as _34 } from "./chunks/LpInput-WvyP02ID.js";
|
|
56
|
+
import { _ as _35 } from "./chunks/LpLightbox-Dq-e36uT.js";
|
|
57
57
|
import { fileNameOf } from "./components/lightbox.js";
|
|
58
58
|
import { _ as _36 } from "./chunks/LpLink-Krkjhe_y.js";
|
|
59
|
-
import { _ as _37 } from "./chunks/LpLogViewer-
|
|
59
|
+
import { _ as _37 } from "./chunks/LpLogViewer-DwiYE32z.js";
|
|
60
60
|
import { countLevels, matchPositions, matchesTerm, ringWindow, stepMatch } from "./components/logSearch.js";
|
|
61
|
-
import { _ as _38 } from "./chunks/LpMediaGallery-
|
|
62
|
-
import { _ as _39 } from "./chunks/LpModal-
|
|
63
|
-
import { _ as _40 } from "./chunks/LpModalNav-
|
|
64
|
-
import { _ as _41 } from "./chunks/LpNotificationBell-
|
|
65
|
-
import { _ as _42 } from "./chunks/LpNumberField-
|
|
66
|
-
import { _ as _43 } from "./chunks/LpTimeField-
|
|
61
|
+
import { _ as _38 } from "./chunks/LpMediaGallery-B1kDypJ-.js";
|
|
62
|
+
import { _ as _39 } from "./chunks/LpModal-BxYssnXg.js";
|
|
63
|
+
import { _ as _40 } from "./chunks/LpModalNav-Bn2ws64b.js";
|
|
64
|
+
import { _ as _41 } from "./chunks/LpNotificationBell-DJfs4JjQ.js";
|
|
65
|
+
import { _ as _42 } from "./chunks/LpNumberField-CJPjmoDz.js";
|
|
66
|
+
import { _ as _43 } from "./chunks/LpTimeField-DvGXgdES.js";
|
|
67
67
|
import { _ as _44 } from "./chunks/LpNumberFlow-z4WPZcZu.js";
|
|
68
68
|
import { _ as _45 } from "./chunks/LpOtpInput-PbeNJ5In.js";
|
|
69
|
-
import { _ as _46 } from "./chunks/LpPagination-
|
|
70
|
-
import { _ as _47 } from "./chunks/LpPasswordInput-
|
|
71
|
-
import { _ as _48 } from "./chunks/LpPie-
|
|
72
|
-
import { _ as _49 } from "./chunks/LpPhoneInput-
|
|
69
|
+
import { _ as _46 } from "./chunks/LpPagination-DehAaJLY.js";
|
|
70
|
+
import { _ as _47 } from "./chunks/LpPasswordInput-Bg5uTZbx.js";
|
|
71
|
+
import { _ as _48 } from "./chunks/LpPie-DeTkbbOK.js";
|
|
72
|
+
import { _ as _49 } from "./chunks/LpPhoneInput-DStwcbnQ.js";
|
|
73
73
|
import { filterCountries, flagEmoji, loadCountries, matchCountryByValue } from "./components/countries.js";
|
|
74
74
|
import { _ as _50 } from "./chunks/LpPopover-DCKeqiVn.js";
|
|
75
75
|
import { _ as _51 } from "./chunks/LpProgress-CBU1iI69.js";
|
|
@@ -77,36 +77,41 @@ import { _ as _52 } from "./chunks/LpRadio-CWA5Eb3M.js";
|
|
|
77
77
|
import { _ as _53 } from "./chunks/LpRadioGroup-CCn-Q2_c.js";
|
|
78
78
|
import { _ as _54 } from "./chunks/LpRollingText-DB7upf-5.js";
|
|
79
79
|
import { _ as _55 } from "./chunks/LpScrollArea-Hz3-JWUG.js";
|
|
80
|
-
import { _ as _56 } from "./chunks/LpSegmented-
|
|
81
|
-
import { _ as _57 } from "./chunks/LpSection-
|
|
82
|
-
import { _ as _58 } from "./chunks/LpSelect-
|
|
80
|
+
import { _ as _56 } from "./chunks/LpSegmented-D3Eam8sa.js";
|
|
81
|
+
import { _ as _57 } from "./chunks/LpSection-B19VPYmr.js";
|
|
82
|
+
import { _ as _58 } from "./chunks/LpSelect-DynjWK1A.js";
|
|
83
83
|
import { _ as _59 } from "./chunks/LpServiceNode-D8uJ8sGk.js";
|
|
84
84
|
import { _ as _60 } from "./chunks/LpShift-DXNsauQZ.js";
|
|
85
85
|
import { default as default11 } from "./components/LpShortcutsDialog.vue.js";
|
|
86
|
-
import { _ as _61 } from "./chunks/LpSidebar-
|
|
86
|
+
import { _ as _61 } from "./chunks/LpSidebar-CshW0fqC.js";
|
|
87
87
|
import { _ as _62 } from "./chunks/LpSkeleton-BB6XIV-w.js";
|
|
88
88
|
import { _ as _63 } from "./chunks/LpSlider-Cuzmrd7p.js";
|
|
89
89
|
import { _ as _64 } from "./chunks/LpRangeSlider-C1yF9-nP.js";
|
|
90
90
|
import { _ as _65 } from "./chunks/LpVideoBackdrop-qWRYBOTQ.js";
|
|
91
91
|
import { formatClipTime, isNativeLoop, planLoop, seamProgress, seamReached } from "./components/videoBackdrop.js";
|
|
92
92
|
import { _ as _66 } from "./chunks/LpSparkline-CB80N8SJ.js";
|
|
93
|
-
import { _ as _67 } from "./chunks/LpStat-
|
|
94
|
-
import { _ as _68 } from "./chunks/LpStepper-
|
|
93
|
+
import { _ as _67 } from "./chunks/LpStat-BS2TEXYK.js";
|
|
94
|
+
import { _ as _68 } from "./chunks/LpStepper-BSglWF45.js";
|
|
95
95
|
import { _ as _69 } from "./chunks/LpSwitch-DG2AhXIL.js";
|
|
96
96
|
import { default as default12 } from "./components/LpTable.vue.js";
|
|
97
97
|
import { compareValues } from "./components/tableSort.js";
|
|
98
|
-
import { _ as _70 } from "./chunks/LpTableOfContents-
|
|
99
|
-
import { _ as _71 } from "./chunks/LpTabs-
|
|
100
|
-
import { _ as _72 } from "./chunks/LpTagsInput-
|
|
98
|
+
import { _ as _70 } from "./chunks/LpTableOfContents-DYuqkByy.js";
|
|
99
|
+
import { _ as _71 } from "./chunks/LpTabs-BBGRHY38.js";
|
|
100
|
+
import { _ as _72 } from "./chunks/LpTagsInput-CHbQoAAA.js";
|
|
101
101
|
import { addTags, splitTags } from "./components/tags.js";
|
|
102
|
-
import { _ as _73 } from "./chunks/LpTextarea-
|
|
103
|
-
import { _ as _74 } from "./chunks/LpThemeSwitcher-
|
|
102
|
+
import { _ as _73 } from "./chunks/LpTextarea-Bz2IWhTH.js";
|
|
103
|
+
import { _ as _74 } from "./chunks/LpThemeSwitcher-B_qhSl7q.js";
|
|
104
104
|
import { _ as _75 } from "./chunks/LpTilt-B7KHX1zH.js";
|
|
105
|
-
import { _ as _76 } from "./chunks/LpToaster-
|
|
106
|
-
import { _ as _77 } from "./chunks/LpTooltip-
|
|
107
|
-
import { _ as _78 } from "./chunks/
|
|
108
|
-
import {
|
|
109
|
-
import { _ as
|
|
105
|
+
import { _ as _76 } from "./chunks/LpToaster-Bo9Q4QBP.js";
|
|
106
|
+
import { _ as _77 } from "./chunks/LpTooltip-suFCM34F.js";
|
|
107
|
+
import { _ as _78 } from "./chunks/LpTour-D7m9ZxNk.js";
|
|
108
|
+
import { holeOf, openContextMenu, panelsAround } from "./components/tour.js";
|
|
109
|
+
import { _ as _79 } from "./chunks/LpHintLayer-B5-6FyEf.js";
|
|
110
|
+
import { _ as _80 } from "./chunks/LpHints-BqoZXHZk.js";
|
|
111
|
+
import { createHintSystem, hintKey, hintSummary, localHintStorage, provideHintSystem, useHintSystem } from "./composables/useHintSystem.js";
|
|
112
|
+
import { _ as _81 } from "./chunks/LpTooltipProvider-CftjV7Xc.js";
|
|
113
|
+
import { _ as _82 } from "./chunks/LpTopologyCanvas-6ozNrQKh.js";
|
|
114
|
+
import { _ as _83 } from "./chunks/LpUptimeBar-B4ltCfno.js";
|
|
110
115
|
import { deserializeLayout, serializeLayout } from "./layout/tree.js";
|
|
111
116
|
import { addLeaf, addTab, countBlocks, countLeaves, makeLayout, moveLeaf, removeBlock, removeLeaf, reorderTab, resizeAt, setActiveTab } from "./layout/tree.js";
|
|
112
117
|
import { blockTitle, defineBlocks } from "./layout/registry.js";
|
|
@@ -127,6 +132,9 @@ import { LP_FIELD, fieldMessageId, provideField, useField, useFieldControl } fro
|
|
|
127
132
|
import { FIELD_NOTICE_MS, useFieldNotice } from "./composables/useFieldNotice.js";
|
|
128
133
|
import { easeOut, easeTravel, easingToken, prefersReducedMotion } from "./composables/easing.js";
|
|
129
134
|
import { useReveal } from "./composables/useReveal.js";
|
|
135
|
+
import { hints, vHint } from "./composables/useHints.js";
|
|
136
|
+
import { scrollParent, scrollToElement } from "./composables/scroll.js";
|
|
137
|
+
import { useMediaQuery } from "./composables/useMediaQuery.js";
|
|
130
138
|
import { useAsyncTask } from "./composables/useAsyncTask.js";
|
|
131
139
|
import { useRovingFocus } from "./composables/useRovingFocus.js";
|
|
132
140
|
import { useFormDraft } from "./composables/useFormDraft.js";
|
|
@@ -137,7 +145,7 @@ import { useShift } from "./composables/useShift.js";
|
|
|
137
145
|
import { useTilt } from "./composables/useTilt.js";
|
|
138
146
|
import { useZoomPan } from "./composables/useZoomPan.js";
|
|
139
147
|
import { useToast } from "./composables/useToast.js";
|
|
140
|
-
import { _ as
|
|
148
|
+
import { _ as _84 } from "./chunks/LpThemeProvider-CQ2jC9TA.js";
|
|
141
149
|
import { isInternalHref, resolveLink } from "./components/link.js";
|
|
142
150
|
function defineTheme(base, overrides = {}) {
|
|
143
151
|
const src = typeof base === "string" ? presets[base] : base;
|
|
@@ -209,6 +217,8 @@ export {
|
|
|
209
217
|
_30 as LpFieldNotice,
|
|
210
218
|
_29 as LpFileTree,
|
|
211
219
|
_31 as LpFormField,
|
|
220
|
+
_79 as LpHintLayer,
|
|
221
|
+
_80 as LpHints,
|
|
212
222
|
_32 as LpIcon,
|
|
213
223
|
default10 as LpImageEditor,
|
|
214
224
|
_33 as LpInfraNode,
|
|
@@ -260,15 +270,16 @@ export {
|
|
|
260
270
|
_71 as LpTabs,
|
|
261
271
|
_72 as LpTagsInput,
|
|
262
272
|
_73 as LpTextarea,
|
|
263
|
-
|
|
273
|
+
_84 as LpThemeProvider,
|
|
264
274
|
_74 as LpThemeSwitcher,
|
|
265
275
|
_75 as LpTilt,
|
|
266
276
|
_43 as LpTimeField,
|
|
267
277
|
_76 as LpToaster,
|
|
268
278
|
_77 as LpTooltip,
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
279
|
+
_81 as LpTooltipProvider,
|
|
280
|
+
_82 as LpTopologyCanvas,
|
|
281
|
+
_78 as LpTour,
|
|
282
|
+
_83 as LpUptimeBar,
|
|
272
283
|
_65 as LpVideoBackdrop,
|
|
273
284
|
N as NO_BACKDROP_ATTR,
|
|
274
285
|
OSM_TILES,
|
|
@@ -306,6 +317,7 @@ export {
|
|
|
306
317
|
countBlocks,
|
|
307
318
|
countLeaves,
|
|
308
319
|
countLevels,
|
|
320
|
+
createHintSystem,
|
|
309
321
|
createNominatimProvider,
|
|
310
322
|
csvField,
|
|
311
323
|
g as dark,
|
|
@@ -336,6 +348,10 @@ export {
|
|
|
336
348
|
formatSize,
|
|
337
349
|
formatTick,
|
|
338
350
|
highlightParts,
|
|
351
|
+
hintKey,
|
|
352
|
+
hintSummary,
|
|
353
|
+
hints,
|
|
354
|
+
holeOf,
|
|
339
355
|
hotkeyConflicts,
|
|
340
356
|
hotkeySteps,
|
|
341
357
|
hsvToHsl,
|
|
@@ -351,6 +367,7 @@ export {
|
|
|
351
367
|
l as light,
|
|
352
368
|
j as lime,
|
|
353
369
|
loadCountries,
|
|
370
|
+
localHintStorage,
|
|
354
371
|
lpConfig,
|
|
355
372
|
makeLayout,
|
|
356
373
|
markerIndex,
|
|
@@ -370,6 +387,8 @@ export {
|
|
|
370
387
|
normalizeRange,
|
|
371
388
|
k as normalizeTheme,
|
|
372
389
|
opaqueCss,
|
|
390
|
+
openContextMenu,
|
|
391
|
+
panelsAround,
|
|
373
392
|
parseColor,
|
|
374
393
|
parseCommandQuery,
|
|
375
394
|
parseConfig,
|
|
@@ -385,6 +404,7 @@ export {
|
|
|
385
404
|
project,
|
|
386
405
|
provideField,
|
|
387
406
|
provideGlass,
|
|
407
|
+
provideHintSystem,
|
|
388
408
|
provideLpConfig,
|
|
389
409
|
pushRecent,
|
|
390
410
|
rankCommandItems,
|
|
@@ -405,6 +425,8 @@ export {
|
|
|
405
425
|
ringWindow,
|
|
406
426
|
o as rose,
|
|
407
427
|
sameRange,
|
|
428
|
+
scrollParent,
|
|
429
|
+
scrollToElement,
|
|
408
430
|
seamProgress,
|
|
409
431
|
seamReached,
|
|
410
432
|
sequenceProgress,
|
|
@@ -441,6 +463,7 @@ export {
|
|
|
441
463
|
useFormDraft,
|
|
442
464
|
useGamepadNav,
|
|
443
465
|
useGlass,
|
|
466
|
+
useHintSystem,
|
|
444
467
|
useHotkeys,
|
|
445
468
|
useInputFilter,
|
|
446
469
|
useInputMask,
|
|
@@ -448,6 +471,7 @@ export {
|
|
|
448
471
|
useLayout,
|
|
449
472
|
useLinkComponent,
|
|
450
473
|
useLpConfig,
|
|
474
|
+
useMediaQuery,
|
|
451
475
|
useMergedAttrs,
|
|
452
476
|
useMergedClass,
|
|
453
477
|
useModalLayer,
|
|
@@ -460,5 +484,6 @@ export {
|
|
|
460
484
|
useTilt,
|
|
461
485
|
useToast,
|
|
462
486
|
useZoomPan,
|
|
487
|
+
vHint,
|
|
463
488
|
y as violet
|
|
464
489
|
};
|
package/package.json
CHANGED
package/src/component-names.ts
CHANGED
|
@@ -33,6 +33,8 @@ export const COMPONENT_NAMES = [
|
|
|
33
33
|
"LpFieldNotice",
|
|
34
34
|
"LpFileTree",
|
|
35
35
|
"LpFormField",
|
|
36
|
+
"LpHintLayer",
|
|
37
|
+
"LpHints",
|
|
36
38
|
"LpIcon",
|
|
37
39
|
"LpImageEditor",
|
|
38
40
|
"LpInfraNode",
|
|
@@ -92,6 +94,7 @@ export const COMPONENT_NAMES = [
|
|
|
92
94
|
"LpTooltip",
|
|
93
95
|
"LpTooltipProvider",
|
|
94
96
|
"LpTopologyCanvas",
|
|
97
|
+
"LpTour",
|
|
95
98
|
"LpUptimeBar",
|
|
96
99
|
"LpVideoBackdrop"
|
|
97
100
|
] as const
|
|
@@ -10,11 +10,12 @@ export default { inheritAttrs: false }
|
|
|
10
10
|
* Two months sit side by side where there is room, one on a phone.
|
|
11
11
|
*/
|
|
12
12
|
import { PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger } from "reka-ui"
|
|
13
|
-
import { computed,
|
|
13
|
+
import { computed, ref, useAttrs } from "vue"
|
|
14
14
|
import { useFieldControl } from "../composables/useField"
|
|
15
15
|
import { useLocale } from "../composables/useLocale"
|
|
16
16
|
import { useLabels } from "../composables/useLpConfig"
|
|
17
17
|
import { mergeClass } from "../composables/useMergedClass"
|
|
18
|
+
import { useMediaQuery } from "../composables/useMediaQuery"
|
|
18
19
|
import {
|
|
19
20
|
clampRange,
|
|
20
21
|
type DateRange,
|
|
@@ -113,17 +114,7 @@ function presetFits(preset: DateRangePreset): boolean {
|
|
|
113
114
|
return !!clampRange(preset.range(), props.min, props.max)
|
|
114
115
|
}
|
|
115
116
|
|
|
116
|
-
const wide =
|
|
117
|
-
let query: MediaQueryList | undefined
|
|
118
|
-
const onQuery = () => {
|
|
119
|
-
wide.value = !!query?.matches
|
|
120
|
-
}
|
|
121
|
-
onMounted(() => {
|
|
122
|
-
query = window.matchMedia("(min-width: 640px)")
|
|
123
|
-
onQuery()
|
|
124
|
-
query.addEventListener("change", onQuery)
|
|
125
|
-
})
|
|
126
|
-
onBeforeUnmount(() => query?.removeEventListener("change", onQuery))
|
|
117
|
+
const wide = useMediaQuery("(min-width: 640px)")
|
|
127
118
|
|
|
128
119
|
const shellSize = {
|
|
129
120
|
sm: "h-(--size-control-sm) text-xs",
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
} from "vaul-vue"
|
|
35
35
|
import { computed, onBeforeUnmount, ref, useSlots, watch } from "vue"
|
|
36
36
|
import { CLOSE_ICON } from "./dropdown"
|
|
37
|
+
import { prefersReducedMotion } from "../composables/easing"
|
|
37
38
|
import { useGlass } from "../composables/useGlass"
|
|
38
39
|
import { useLabels } from "../composables/useLpConfig"
|
|
39
40
|
import LpIcon from "./LpIcon.vue"
|
|
@@ -328,10 +329,6 @@ function edgeEnabled(): boolean {
|
|
|
328
329
|
let track: { id: number; x: number; y: number; t: number; lastX: number; lastT: number; speed: number } | null = null
|
|
329
330
|
const owner = Symbol("edge-pull")
|
|
330
331
|
|
|
331
|
-
function reducedMotion(): boolean {
|
|
332
|
-
return typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches
|
|
333
|
-
}
|
|
334
|
-
|
|
335
332
|
// A horizontally scrollable ancestor that can still move the way the finger
|
|
336
333
|
// pulls (a carousel, a wide table) keeps the gesture: the pull only claims
|
|
337
334
|
// what nothing under the finger wants.
|
|
@@ -414,7 +411,7 @@ function settle() {
|
|
|
414
411
|
peek.value = 0
|
|
415
412
|
}, 60),
|
|
416
413
|
)
|
|
417
|
-
},
|
|
414
|
+
}, prefersReducedMotion() ? 0 : 180),
|
|
418
415
|
)
|
|
419
416
|
} else {
|
|
420
417
|
peek.value = 0
|
|
@@ -462,7 +459,7 @@ const previewStyle = computed(() => {
|
|
|
462
459
|
const axis = dir.value === "right" ? off : -off
|
|
463
460
|
return {
|
|
464
461
|
transform: `translateX(${axis}%)`,
|
|
465
|
-
transition: peeking.value ||
|
|
462
|
+
transition: peeking.value || prefersReducedMotion() ? "none" : "transform 0.18s cubic-bezier(0.32, 0.72, 0, 1)",
|
|
466
463
|
pointerEvents: "none" as const,
|
|
467
464
|
}
|
|
468
465
|
})
|
|
@@ -477,7 +474,7 @@ const previewStyle = computed(() => {
|
|
|
477
474
|
v-show="peeking || peek > 0"
|
|
478
475
|
class="lp-scrim pointer-events-none fixed inset-0"
|
|
479
476
|
:class="{ 'lp-scrim--light': frosted, 'lp-scrim--nested': layer.nested }"
|
|
480
|
-
:style="{ zIndex: layer.scrim, opacity: peek, transition: peeking ||
|
|
477
|
+
:style="{ zIndex: layer.scrim, opacity: peek, transition: peeking || prefersReducedMotion() ? 'none' : 'opacity 0.18s ease-out' }"
|
|
481
478
|
/>
|
|
482
479
|
<div
|
|
483
480
|
v-show="peeking || peek > 0"
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export interface HintNote {
|
|
3
|
+
title: string
|
|
4
|
+
text?: string
|
|
5
|
+
}
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<script setup lang="ts">
|
|
9
|
+
/*
|
|
10
|
+
* Quiet "new" markers over `v-hint` elements, with a short note when the user
|
|
11
|
+
* reaches for one. Nothing pops up by itself: a dot sits on the control, and
|
|
12
|
+
* the note opens only when the pointer or focus lands on it. Reading the note
|
|
13
|
+
* (or simply using the control) is the app's cue to stop marking it.
|
|
14
|
+
*
|
|
15
|
+
* The layer only draws. Which ids are new, and when a read counts, is decided
|
|
16
|
+
* by the app from the registry's seen/used events.
|
|
17
|
+
*/
|
|
18
|
+
import { PopoverAnchor, PopoverContent, PopoverPortal, PopoverRoot } from "reka-ui"
|
|
19
|
+
import { computed, onBeforeUnmount, onMounted, ref, shallowRef, watch } from "vue"
|
|
20
|
+
import { hints } from "../composables/useHints"
|
|
21
|
+
import { useLabels } from "../composables/useLpConfig"
|
|
22
|
+
import { PANEL_SURFACE, POPOVER_ANIM } from "./dropdown"
|
|
23
|
+
import LpButton from "./LpButton.vue"
|
|
24
|
+
|
|
25
|
+
const props = withDefaults(
|
|
26
|
+
defineProps<{
|
|
27
|
+
/** Ids to mark, most important first. */
|
|
28
|
+
fresh: string[]
|
|
29
|
+
notes: Record<string, HintNote>
|
|
30
|
+
/** At most this many dots at once, so a page full of news stays calm. */
|
|
31
|
+
limit?: number
|
|
32
|
+
labels?: Partial<typeof DEFAULT_LABELS>
|
|
33
|
+
}>(),
|
|
34
|
+
{ limit: 3 },
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
const emit = defineEmits<{ (e: "read", id: string): void }>()
|
|
38
|
+
|
|
39
|
+
const DEFAULT_LABELS = { gotIt: "Got it", badge: "New" }
|
|
40
|
+
const labels = useLabels("hintLayer", DEFAULT_LABELS, () => props.labels)
|
|
41
|
+
|
|
42
|
+
const OPEN_DELAY_MS = 350
|
|
43
|
+
|
|
44
|
+
const shown = computed(() => props.fresh.filter((id) => hints.present(id) && props.notes[id]).slice(0, props.limit))
|
|
45
|
+
const spots = ref<{ id: string; x: number; y: number }[]>([])
|
|
46
|
+
const openId = ref<string | null>(null)
|
|
47
|
+
const anchor = shallowRef<Element | null>(null)
|
|
48
|
+
let frame = 0
|
|
49
|
+
let timer: ReturnType<typeof setTimeout> | undefined
|
|
50
|
+
|
|
51
|
+
function place() {
|
|
52
|
+
spots.value = shown.value.flatMap((id) => {
|
|
53
|
+
const el = hints.element(id)
|
|
54
|
+
if (!el) return []
|
|
55
|
+
const r = el.getBoundingClientRect()
|
|
56
|
+
return r.width || r.height ? [{ id, x: r.right, y: r.top }] : []
|
|
57
|
+
})
|
|
58
|
+
frame = shown.value.length ? requestAnimationFrame(place) : 0
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
watch(
|
|
62
|
+
shown,
|
|
63
|
+
(ids) => {
|
|
64
|
+
if (ids.length && !frame) frame = requestAnimationFrame(place)
|
|
65
|
+
if (openId.value && !ids.includes(openId.value)) openId.value = null
|
|
66
|
+
},
|
|
67
|
+
{ immediate: true },
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
function reveal(id: string) {
|
|
71
|
+
clearTimeout(timer)
|
|
72
|
+
timer = setTimeout(() => {
|
|
73
|
+
if (!shown.value.includes(id)) return
|
|
74
|
+
anchor.value = hints.element(id)
|
|
75
|
+
openId.value = anchor.value ? id : null
|
|
76
|
+
}, OPEN_DELAY_MS)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function read() {
|
|
80
|
+
const id = openId.value
|
|
81
|
+
openId.value = null
|
|
82
|
+
if (id) emit("read", id)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let off: (() => void)[] = []
|
|
86
|
+
onMounted(() => {
|
|
87
|
+
off = [
|
|
88
|
+
hints.on("hover", (id) => {
|
|
89
|
+
if (shown.value.includes(id)) reveal(id)
|
|
90
|
+
}),
|
|
91
|
+
hints.on("used", (id) => {
|
|
92
|
+
if (!shown.value.includes(id)) return
|
|
93
|
+
clearTimeout(timer)
|
|
94
|
+
if (openId.value === id) openId.value = null
|
|
95
|
+
emit("read", id)
|
|
96
|
+
}),
|
|
97
|
+
]
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
onBeforeUnmount(() => {
|
|
101
|
+
cancelAnimationFrame(frame)
|
|
102
|
+
clearTimeout(timer)
|
|
103
|
+
for (const stop of off) stop()
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const note = computed(() => (openId.value ? props.notes[openId.value] : undefined))
|
|
107
|
+
</script>
|
|
108
|
+
|
|
109
|
+
<template>
|
|
110
|
+
<Teleport to="body">
|
|
111
|
+
<button
|
|
112
|
+
v-for="spot in spots"
|
|
113
|
+
:key="spot.id"
|
|
114
|
+
type="button"
|
|
115
|
+
class="fixed z-(--z-popover) -translate-x-1/2 -translate-y-1/2 rounded-full p-1"
|
|
116
|
+
:style="{ left: `${spot.x}px`, top: `${spot.y}px` }"
|
|
117
|
+
:aria-label="`${labels.badge}: ${notes[spot.id]?.title ?? ''}`"
|
|
118
|
+
@pointerenter="reveal(spot.id)"
|
|
119
|
+
@focus="reveal(spot.id)"
|
|
120
|
+
@click="reveal(spot.id)"
|
|
121
|
+
>
|
|
122
|
+
<span class="relative flex size-2">
|
|
123
|
+
<span class="absolute inline-flex size-full animate-ping rounded-full bg-brand opacity-60 motion-reduce:animate-none" />
|
|
124
|
+
<span class="relative inline-flex size-2 rounded-full bg-brand ring-2 ring-surface" />
|
|
125
|
+
</span>
|
|
126
|
+
</button>
|
|
127
|
+
<PopoverRoot :open="!!openId" @update:open="(value) => !value && (openId = null)">
|
|
128
|
+
<PopoverAnchor v-if="anchor" :reference="anchor" />
|
|
129
|
+
<PopoverPortal>
|
|
130
|
+
<PopoverContent
|
|
131
|
+
side="bottom"
|
|
132
|
+
:side-offset="8"
|
|
133
|
+
:collision-padding="8"
|
|
134
|
+
:class="[PANEL_SURFACE, POPOVER_ANIM, 'z-(--z-popover) w-72 rounded-card p-3 text-sm text-ink outline-none']"
|
|
135
|
+
>
|
|
136
|
+
<p class="flex items-center gap-2 font-medium">
|
|
137
|
+
<span class="rounded-full bg-brand/15 px-1.5 text-[11px] text-brand">{{ labels.badge }}</span>
|
|
138
|
+
{{ note?.title }}
|
|
139
|
+
</p>
|
|
140
|
+
<p v-if="note?.text" class="mt-1.5 text-muted">{{ note.text }}</p>
|
|
141
|
+
<div class="mt-3 flex justify-end">
|
|
142
|
+
<LpButton size="sm" @click="read">{{ labels.gotIt }}</LpButton>
|
|
143
|
+
</div>
|
|
144
|
+
</PopoverContent>
|
|
145
|
+
</PopoverPortal>
|
|
146
|
+
</PopoverRoot>
|
|
147
|
+
</Teleport>
|
|
148
|
+
</template>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/*
|
|
3
|
+
* Drop-in onboarding: put it once next to the app's root, hand it a hint
|
|
4
|
+
* system, and the tour offer, the "new" dots, "what changed" and nudges all
|
|
5
|
+
* work. Nothing to wire per page beyond `v-hint` on the elements.
|
|
6
|
+
*
|
|
7
|
+
* It must never cost the page itself. Any error thrown inside (a tour step's
|
|
8
|
+
* `enter`, a storage that rejects, a target that misbehaves) switches the layer
|
|
9
|
+
* off for the session and is logged once; the page under it keeps working.
|
|
10
|
+
*/
|
|
11
|
+
import { computed, onBeforeUnmount, onErrorCaptured, onMounted, ref, unref, watch } from "vue"
|
|
12
|
+
import { provideHintSystem, type HintSystem } from "../composables/useHintSystem"
|
|
13
|
+
import { useLabels } from "../composables/useLpConfig"
|
|
14
|
+
import LpActionBar, { type ActionBarAction } from "./LpActionBar.vue"
|
|
15
|
+
import LpHintLayer from "./LpHintLayer.vue"
|
|
16
|
+
import LpTour from "./LpTour.vue"
|
|
17
|
+
|
|
18
|
+
const props = defineProps<{
|
|
19
|
+
system: HintSystem
|
|
20
|
+
labels?: Partial<typeof DEFAULT_LABELS>
|
|
21
|
+
}>()
|
|
22
|
+
|
|
23
|
+
const DEFAULT_LABELS = {
|
|
24
|
+
tourTitle: "New to {page}?",
|
|
25
|
+
tourText: "A one-minute look at what you can do here.",
|
|
26
|
+
assignedTitle: "You were asked to look at {page}",
|
|
27
|
+
assignedText: "A short tour of this page, about a minute.",
|
|
28
|
+
newsTitle: "What changed: {page}",
|
|
29
|
+
show: "Show me",
|
|
30
|
+
notNow: "Not now",
|
|
31
|
+
never: "Don't offer again",
|
|
32
|
+
gotIt: "Got it",
|
|
33
|
+
noThanks: "No thanks",
|
|
34
|
+
}
|
|
35
|
+
const labels = useLabels("hints", DEFAULT_LABELS, () => props.labels)
|
|
36
|
+
|
|
37
|
+
provideHintSystem(props.system)
|
|
38
|
+
|
|
39
|
+
const broken = ref(false)
|
|
40
|
+
onErrorCaptured((error) => {
|
|
41
|
+
if (!broken.value) console.warn("[LpHints] disabled after an error:", error)
|
|
42
|
+
broken.value = true
|
|
43
|
+
props.system.stop()
|
|
44
|
+
return false
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
onMounted(() => {
|
|
48
|
+
try {
|
|
49
|
+
props.system.start()
|
|
50
|
+
if (!props.system.state.loaded) void props.system.load()
|
|
51
|
+
} catch (error) {
|
|
52
|
+
broken.value = true
|
|
53
|
+
console.warn("[LpHints] disabled after an error:", error)
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
onBeforeUnmount(() => props.system.stop())
|
|
57
|
+
|
|
58
|
+
const state = props.system.state
|
|
59
|
+
const fresh = computed(() => unref(props.system.fresh))
|
|
60
|
+
const notes = computed(() => unref(props.system.notes))
|
|
61
|
+
watch(() => [state.tour.open, state.tour.step] as const, ([open, step]) => open && props.system.tourShown(step))
|
|
62
|
+
|
|
63
|
+
const offer = computed(() => state.offer)
|
|
64
|
+
const page = computed(() => (offer.value ? props.system.pageTitle(offer.value.page) : ""))
|
|
65
|
+
const fill = (text: string) => text.replace("{page}", page.value)
|
|
66
|
+
|
|
67
|
+
const title = computed(() => {
|
|
68
|
+
const o = offer.value
|
|
69
|
+
if (!o) return ""
|
|
70
|
+
if (o.kind === "nudge") return notes.value[o.nudge.feature]?.title ?? ""
|
|
71
|
+
if (o.kind === "news") return fill(labels.value.newsTitle)
|
|
72
|
+
return fill(o.kind === "assigned" ? labels.value.assignedTitle : labels.value.tourTitle)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const description = computed(() => {
|
|
76
|
+
const o = offer.value
|
|
77
|
+
if (!o) return ""
|
|
78
|
+
if (o.kind === "nudge") return o.nudge.text
|
|
79
|
+
if (o.kind === "news") return o.items.map((n) => n.text).join(" ")
|
|
80
|
+
return o.kind === "assigned" ? labels.value.assignedText : labels.value.tourText
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const actions = computed<ActionBarAction[]>(() => {
|
|
84
|
+
const o = offer.value
|
|
85
|
+
if (!o) return []
|
|
86
|
+
const answer = (choice: "show" | "later" | "never") => () => props.system.answer(choice)
|
|
87
|
+
const show: ActionBarAction = { label: labels.value.show, icon: "lucide:sparkles", onClick: answer("show") }
|
|
88
|
+
if (o.kind === "nudge") return [{ label: labels.value.noThanks, variant: "ghost", onClick: answer("never") }, show]
|
|
89
|
+
if (o.kind === "news") return [{ label: labels.value.gotIt, variant: "ghost", onClick: answer("later") }, show]
|
|
90
|
+
return [
|
|
91
|
+
...(o.kind === "tour" ? [{ label: labels.value.never, variant: "ghost" as const, onClick: answer("never") }] : []),
|
|
92
|
+
{ label: labels.value.notNow, variant: "ghost", onClick: answer("later") },
|
|
93
|
+
show,
|
|
94
|
+
]
|
|
95
|
+
})
|
|
96
|
+
</script>
|
|
97
|
+
|
|
98
|
+
<template>
|
|
99
|
+
<template v-if="!broken">
|
|
100
|
+
<LpTour
|
|
101
|
+
v-model:open="state.tour.open"
|
|
102
|
+
v-model:step="state.tour.step"
|
|
103
|
+
:steps="state.tour.steps"
|
|
104
|
+
@finish="system.tourEnded(true)"
|
|
105
|
+
@dismiss="system.tourEnded(false)"
|
|
106
|
+
/>
|
|
107
|
+
<LpHintLayer :fresh="fresh" :notes="notes" @read="system.readFresh" />
|
|
108
|
+
<LpActionBar
|
|
109
|
+
:open="!!offer"
|
|
110
|
+
:title="title"
|
|
111
|
+
:description="description"
|
|
112
|
+
:icon="offer?.kind === 'news' ? 'lucide:gift' : 'lucide:compass'"
|
|
113
|
+
:actions="actions"
|
|
114
|
+
/>
|
|
115
|
+
</template>
|
|
116
|
+
</template>
|