@stfrigerio/sito-template 0.1.96 → 0.1.98
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/components/organisms/charts/MoodChart/MoodChart.d.ts.map +1 -1
- package/dist/components/organisms/charts/QuantifiableHabitsChart/QuantifiableHabitsChart.d.ts.map +1 -1
- package/dist/index.esm.js +540 -176
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +539 -175
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
- package/storybook-static/assets/{ASCIIText.stories-BNQcc9gv.js → ASCIIText.stories-DSI7g-mB.js} +1 -1
- package/storybook-static/assets/{AllAtoms.stories-DBpk-rB8.js → AllAtoms.stories-JflUIS5e.js} +1 -1
- package/storybook-static/assets/{AnimatedContent.stories-CCnlHD5Y.js → AnimatedContent.stories-YR7SgIxb.js} +1 -1
- package/storybook-static/assets/{AnimatedList.stories-DNI1W5-A.js → AnimatedList.stories-GR75O93H.js} +1 -1
- package/storybook-static/assets/{Antigravity.stories-BQw1Zvk9.js → Antigravity.stories-B2MVCdRl.js} +1 -1
- package/storybook-static/assets/{ArrayInput.stories-HQd6ODME.js → ArrayInput.stories-BI_3D81-.js} +1 -1
- package/storybook-static/assets/{Aurora.stories-xI4i4wH4.js → Aurora.stories-C_w705rr.js} +1 -1
- package/storybook-static/assets/{Beams.stories-DxSqefhF.js → Beams.stories-D1L26zBi.js} +1 -1
- package/storybook-static/assets/{BlobCursor.stories-DNk0BeNz.js → BlobCursor.stories-BjywoQ5q.js} +1 -1
- package/storybook-static/assets/{BlurText.stories-DBsRktVj.js → BlurText.stories-CSpGTebR.js} +1 -1
- package/storybook-static/assets/{BooleansHeatmap.stories-dsUQfyWg.js → BooleansHeatmap.stories-CKYZW8W5.js} +1 -1
- package/storybook-static/assets/{BorderGlow.stories-lgvEGRVA.js → BorderGlow.stories-BadihHiQ.js} +1 -1
- package/storybook-static/assets/{BubbleMenu.stories-CXvB9JdY.js → BubbleMenu.stories-Up_UUIWc.js} +1 -1
- package/storybook-static/assets/{Button-6nmyMGc3.js → Button-DtiJJxMy.js} +1 -1
- package/storybook-static/assets/{Button.stories-DD3HQBXg.js → Button.stories-BG9uxBwH.js} +1 -1
- package/storybook-static/assets/{Calendar.stories-_ZDa4YfS.js → Calendar.stories-CUZikQRy.js} +2 -2
- package/storybook-static/assets/{Card-B7F8cu_z.js → Card-BrvmNtM2.js} +1 -1
- package/storybook-static/assets/{Card.stories-BLbuUq_5.js → Card.stories-Bf_EtMxA.js} +1 -1
- package/storybook-static/assets/{CardNav.stories-CiJ_bFt8.js → CardNav.stories-OiwfVEn3.js} +1 -1
- package/storybook-static/assets/{Carousel.stories-BYGW6P4X.js → Carousel.stories-Gw1aPaNl.js} +1 -1
- package/storybook-static/assets/{Checkbox-xrie0yDX.js → Checkbox-CJhut6rk.js} +1 -1
- package/storybook-static/assets/{Checkbox.stories-D-NYqhCG.js → Checkbox.stories-tIqU6B-y.js} +1 -1
- package/storybook-static/assets/{ChromaGrid.stories-yYkbcq2a.js → ChromaGrid.stories-DbsrxAuC.js} +1 -1
- package/storybook-static/assets/{CircularGallery.stories-Ci3GTUgX.js → CircularGallery.stories-0ffqgfyn.js} +1 -1
- package/storybook-static/assets/{CircularText.stories-7QMPmTLn.js → CircularText.stories-o46bAR53.js} +1 -1
- package/storybook-static/assets/{ClickSpark.stories-Dz9M-gEC.js → ClickSpark.stories-Ci-BtpH_.js} +1 -1
- package/storybook-static/assets/{ColorBends.stories-Dfa0YMsf.js → ColorBends.stories-CAiI7Gmw.js} +1 -1
- package/storybook-static/assets/{CountUp.stories-DrdYM8-J.js → CountUp.stories-CFiYranp.js} +1 -1
- package/storybook-static/assets/{Counter.stories-3m6ldyes.js → Counter.stories-BfaVu_y6.js} +1 -1
- package/storybook-static/assets/{Crosshair.stories-DfRqBfZC.js → Crosshair.stories-_Hh1nKQp.js} +1 -1
- package/storybook-static/assets/{Cubes.stories-D1sZRgvG.js → Cubes.stories-DXBS_f8J.js} +1 -1
- package/storybook-static/assets/{CurvedLoop.stories-D6jowEDF.js → CurvedLoop.stories-jcgMeMsw.js} +1 -1
- package/storybook-static/assets/{DarkVeil.stories-DLCrll-I.js → DarkVeil.stories-BwtU9vKO.js} +1 -1
- package/storybook-static/assets/{DateInput-D4MHyeLk.js → DateInput-6Jn_FyvO.js} +1 -1
- package/storybook-static/assets/{DateInput.stories-BRfVBcf6.js → DateInput.stories-C_XBRwB3.js} +1 -1
- package/storybook-static/assets/{DecayCard.stories-DX1ak6pd.js → DecayCard.stories-D6kTH79t.js} +1 -1
- package/storybook-static/assets/{DecryptedText.stories-BcCQ2Tby.js → DecryptedText.stories-B4xWEvyF.js} +1 -1
- package/storybook-static/assets/{Dither.stories-BPqBpmFI.js → Dither.stories-DmAOxBWe.js} +1 -1
- package/storybook-static/assets/{Dock.stories-CKD_TOGP.js → Dock.stories-AHZywNVf.js} +1 -1
- package/storybook-static/assets/{EditFAB.stories-DGVMpMOL.js → EditFAB.stories-BJ5P85ZN.js} +1 -1
- package/storybook-static/assets/{EvilEye.stories-DNoB6FG0.js → EvilEye.stories-D0CBPfm1.js} +1 -1
- package/storybook-static/assets/{FadeContent.stories-C8ppDaXi.js → FadeContent.stories-D1capsBJ.js} +1 -1
- package/storybook-static/assets/{FaultyTerminal.stories-Y8ME_yze.js → FaultyTerminal.stories-BxqqRf0S.js} +1 -1
- package/storybook-static/assets/{Fbo-Bkb1mqiu.js → Fbo-DvyLCJ1Y.js} +1 -1
- package/storybook-static/assets/{FloatingLines.stories-ZByyesqH.js → FloatingLines.stories-7ze9ddpl.js} +1 -1
- package/storybook-static/assets/{FlowingMenu.stories-CTWLtqhL.js → FlowingMenu.stories-BX9PD8x2.js} +1 -1
- package/storybook-static/assets/{FluidGlass.stories--PsLBBhn.js → FluidGlass.stories-DynD7GVO.js} +1 -1
- package/storybook-static/assets/{Folder.stories-JNXotEML.js → Folder.stories-DDktLoEO.js} +1 -1
- package/storybook-static/assets/{FuzzyText.stories-o6wySpRq.js → FuzzyText.stories-D9tRARUX.js} +1 -1
- package/storybook-static/assets/{Galaxy.stories-DTZantrp.js → Galaxy.stories-aSApGekp.js} +1 -1
- package/storybook-static/assets/{GhostCursor.stories-DXF-m9YM.js → GhostCursor.stories-5l0di532.js} +1 -1
- package/storybook-static/assets/{GlareHover.stories-Bb4_dcLV.js → GlareHover.stories-Dc69-LbU.js} +1 -1
- package/storybook-static/assets/{GlassSurface.stories-yZ4K521K.js → GlassSurface.stories-DETLyc0H.js} +1 -1
- package/storybook-static/assets/{GlitchText.stories-B4Eqkyri.js → GlitchText.stories-Bzb3ZMSY.js} +1 -1
- package/storybook-static/assets/{GooeyNav.stories-CqUOrJR-.js → GooeyNav.stories-rxdxJjAy.js} +1 -1
- package/storybook-static/assets/{GradientBlinds.stories-DZ6bTCGp.js → GradientBlinds.stories-03LkBbo8.js} +1 -1
- package/storybook-static/assets/{GradientText.stories-DyDht-TI.js → GradientText.stories-CGo9FyNH.js} +1 -1
- package/storybook-static/assets/{Grainient.stories-C1PtR90_.js → Grainient.stories-CzGAEJr-.js} +1 -1
- package/storybook-static/assets/{GridMotion.stories-BRbD6MZr.js → GridMotion.stories-BzeBDaK8.js} +1 -1
- package/storybook-static/assets/{HabitTimeOfDayChart.stories-D3gqeKpl.js → HabitTimeOfDayChart.stories-CbMqUfq0.js} +1 -1
- package/storybook-static/assets/{ImageSlideshow.stories-BileVQYy.js → ImageSlideshow.stories-hoGOc1Gf.js} +1 -1
- package/storybook-static/assets/{Iridescence.stories-BIhFVHOn.js → Iridescence.stories-CQTjQ1lh.js} +1 -1
- package/storybook-static/assets/{LaserFlow.stories-BSnwH5Mv.js → LaserFlow.stories-DzkVWskc.js} +1 -1
- package/storybook-static/assets/{LetterGlitch.stories-CfGaNSmi.js → LetterGlitch.stories-0wcxCpnJ.js} +1 -1
- package/storybook-static/assets/{LightPillar.stories-CNtpoF6N.js → LightPillar.stories-C3jRtdg9.js} +1 -1
- package/storybook-static/assets/{LightRays.stories-DRKVWqXb.js → LightRays.stories-C52kBsnd.js} +1 -1
- package/storybook-static/assets/{Lightning.stories-DJOW6kK7.js → Lightning.stories-BFVGqmMh.js} +1 -1
- package/storybook-static/assets/{LineWaves.stories-17nqJpH2.js → LineWaves.stories-DNdwRrSd.js} +1 -1
- package/storybook-static/assets/{LiquidChrome.stories-CgmsyPLg.js → LiquidChrome.stories-DFTBXxI6.js} +1 -1
- package/storybook-static/assets/{LiquidEther.stories-CKvaP6zm.js → LiquidEther.stories-BGYmyfDI.js} +1 -1
- package/storybook-static/assets/{LoadingSpinner-LXRJXAO4.js → LoadingSpinner-D3Kx-V7J.js} +1 -1
- package/storybook-static/assets/{LoadingSpinner.stories-C0tbgfV3.js → LoadingSpinner.stories-CP70BGAb.js} +1 -1
- package/storybook-static/assets/{MagicRings.stories-qzHi78-J.js → MagicRings.stories-BA9xv5mB.js} +1 -1
- package/storybook-static/assets/{Magnet.stories-QWTKtI1e.js → Magnet.stories-cqBYCb-D.js} +1 -1
- package/storybook-static/assets/{MagnetLines.stories-BOaR4PZi.js → MagnetLines.stories-QkoPnGKj.js} +1 -1
- package/storybook-static/assets/{Masonry.stories-DLz9dA8U.js → Masonry.stories-CiGXRf3O.js} +1 -1
- package/storybook-static/assets/{MetaBalls.stories-DcleGPI8.js → MetaBalls.stories-3l0pQiKn.js} +1 -1
- package/storybook-static/assets/{MetallicPaint.stories-Dqit7nFj.js → MetallicPaint.stories-DgZJfMr5.js} +1 -1
- package/storybook-static/assets/MoodChart-Cu7ntVIE.css +1 -0
- package/storybook-static/assets/MoodChart.stories-UXaQU4EG.js +40 -0
- package/storybook-static/assets/{MotionConfigContext-HXxMOMJo.js → MotionConfigContext-BWFxZgdN.js} +1 -1
- package/storybook-static/assets/{Navbar.stories-BPE4RMdc.js → Navbar.stories-C_Zyfhqr.js} +1 -1
- package/storybook-static/assets/{Noise.stories-BktPkK5a.js → Noise.stories-Cg7CucgT.js} +1 -1
- package/storybook-static/assets/{NumberStepper-D1to6bpi.js → NumberStepper-DpOu7xmF.js} +1 -1
- package/storybook-static/assets/{NumberStepper.stories-WnrisOam.js → NumberStepper.stories-CvG9oY5Q.js} +1 -1
- package/storybook-static/assets/{Orb.stories-BtZmx5Sy.js → Orb.stories-BR92tgyW.js} +1 -1
- package/storybook-static/assets/{OrbitImages.stories-DSTSVc16.js → OrbitImages.stories-D_-2HcAd.js} +1 -1
- package/storybook-static/assets/{PieChart.stories-L1NRhd_j.js → PieChart.stories-CjtEiSJY.js} +1 -1
- package/storybook-static/assets/{PixelBlast.stories-CfT09XYZ.js → PixelBlast.stories-B6FXuNf4.js} +1 -1
- package/storybook-static/assets/{PixelCard.stories-B2LTanjI.js → PixelCard.stories-Dq4CP2Qj.js} +1 -1
- package/storybook-static/assets/{PixelSnow.stories-Kg0VE4Bc.js → PixelSnow.stories-BoQSOear.js} +1 -1
- package/storybook-static/assets/{PixelTransition.stories-CeanWE2-.js → PixelTransition.stories-CtQQ070z.js} +1 -1
- package/storybook-static/assets/{Plasma.stories-DujATB5Q.js → Plasma.stories-D-421jzZ.js} +1 -1
- package/storybook-static/assets/{Prism.stories-Dxke5JPk.js → Prism.stories-BuibpwdU.js} +1 -1
- package/storybook-static/assets/{PrismaticBurst.stories-xc5NSeNp.js → PrismaticBurst.stories-CwYzdBlM.js} +1 -1
- package/storybook-static/assets/{ProfileCard.stories-Cnb3pxki.js → ProfileCard.stories-Dj4oJCxw.js} +1 -1
- package/storybook-static/assets/QuantifiableHabitsChart-DK3Cp5zY.css +1 -0
- package/storybook-static/assets/QuantifiableHabitsChart.stories-ZY1-WQ1g.js +125 -0
- package/storybook-static/assets/{Radar.stories-CrJcMxjq.js → Radar.stories-DxNmoYV3.js} +1 -1
- package/storybook-static/assets/{RecurrencePicker.stories-vkallG9D.js → RecurrencePicker.stories-BAicSNhQ.js} +1 -1
- package/storybook-static/assets/{Ribbons.stories-LT5RgvPo.js → Ribbons.stories-usN1kCyI.js} +1 -1
- package/storybook-static/assets/{RippleGrid.stories-Bwsl-Ueq.js → RippleGrid.stories-nTLGHPV6.js} +1 -1
- package/storybook-static/assets/{RotatingText.stories-CNDJn3v6.js → RotatingText.stories-8CShs_WJ.js} +1 -1
- package/storybook-static/assets/{ScrollFloat.stories-B0qUJggd.js → ScrollFloat.stories-Dp9YyvHK.js} +1 -1
- package/storybook-static/assets/{ScrollReveal.stories-BBVRW0fh.js → ScrollReveal.stories-Dy4JUrqi.js} +1 -1
- package/storybook-static/assets/{ScrollVelocity.stories-DfKnOsGa.js → ScrollVelocity.stories-CUf-OHNp.js} +1 -1
- package/storybook-static/assets/{SearchBar.stories-Coshf_t6.js → SearchBar.stories-BKfuRnlK.js} +1 -1
- package/storybook-static/assets/{SearchableDropdown-CC1-QlKh.js → SearchableDropdown-Ctnh_PVq.js} +1 -1
- package/storybook-static/assets/{SearchableDropdown.stories-DydVUjWf.js → SearchableDropdown.stories-1d-goy0G.js} +1 -1
- package/storybook-static/assets/{SelectInput-BqVWIQmb.js → SelectInput-C94OHQIl.js} +1 -1
- package/storybook-static/assets/{SelectInput.stories-I0azAt7k.js → SelectInput.stories-DPV5iKcs.js} +1 -1
- package/storybook-static/assets/{ShapeBlur.stories-BWBp8nEd.js → ShapeBlur.stories-CdASN24B.js} +1 -1
- package/storybook-static/assets/{ShapeGrid.stories-DJmnW7fN.js → ShapeGrid.stories-Duzq6qpW.js} +1 -1
- package/storybook-static/assets/{ShinyText.stories-7vHIqa03.js → ShinyText.stories-Dgqps29_.js} +1 -1
- package/storybook-static/assets/{Silk.stories-CXiaINFD.js → Silk.stories-DWnaBFZp.js} +1 -1
- package/storybook-static/assets/{SleepChart.stories-BmAtNTJP.js → SleepChart.stories-C1n9aK7B.js} +1 -1
- package/storybook-static/assets/{Slider-BmG0iCoC.js → Slider-C69QbwVa.js} +1 -1
- package/storybook-static/assets/{Slider.stories-DZciYzwU.js → Slider.stories-DDhTLU2g.js} +1 -1
- package/storybook-static/assets/{SoftAurora.stories-BubrO6U4.js → SoftAurora.stories-C5OSOqjj.js} +1 -1
- package/storybook-static/assets/{SoundDemo.stories-CDXr3mFW.js → SoundDemo.stories-sb4V9P8H.js} +1 -1
- package/storybook-static/assets/{SplashCursor.stories-DgMm9xv3.js → SplashCursor.stories-PeC0-y78.js} +1 -1
- package/storybook-static/assets/{SpotlightCard.stories-ChPn0jeh.js → SpotlightCard.stories-BCCdQhIJ.js} +1 -1
- package/storybook-static/assets/{Stack.stories-DzzqOEhy.js → Stack.stories-DJekNsdu.js} +1 -1
- package/storybook-static/assets/{StaggeredMenu.stories-BNHc0PM6.js → StaggeredMenu.stories-BU-AxZRv.js} +1 -1
- package/storybook-static/assets/{StarBorder.stories-DBGelRYw.js → StarBorder.stories-Dw9LDvMk.js} +1 -1
- package/storybook-static/assets/{SunburstChart.stories-KPCIjiOk.js → SunburstChart.stories-CE4d4r8-.js} +1 -1
- package/storybook-static/assets/{Table.stories-Bz2NsPvR.js → Table.stories-IhtnLV5J.js} +1 -1
- package/storybook-static/assets/{Tabs.stories-DH8uIATQ.js → Tabs.stories-F_Q4-xiR.js} +1 -1
- package/storybook-static/assets/{TargetCursor.stories-BUrQiofc.js → TargetCursor.stories-B-Tl1DdA.js} +1 -1
- package/storybook-static/assets/{TextArea-DVqzGhY3.js → TextArea-Bb148SaD.js} +1 -1
- package/storybook-static/assets/{TextArea.stories-A0YRdcwk.js → TextArea.stories-5-dHoUPL.js} +1 -1
- package/storybook-static/assets/{TextCursor.stories-B_UinRXa.js → TextCursor.stories-O-EIx7Nu.js} +1 -1
- package/storybook-static/assets/{TextInput-46C4j_hq.js → TextInput-BQ78htqq.js} +1 -1
- package/storybook-static/assets/{TextInput.stories-C7ZC_8wE.js → TextInput.stories-Bjjfu_5O.js} +1 -1
- package/storybook-static/assets/{TextPressure.stories-Wwlb-VgV.js → TextPressure.stories-BvXWcayn.js} +1 -1
- package/storybook-static/assets/{TextType.stories-DYLMktJi.js → TextType.stories-DL92625c.js} +1 -1
- package/storybook-static/assets/{ThemeSwitcher.stories-8FTV9MJW.js → ThemeSwitcher.stories-BUUyb12v.js} +1 -1
- package/storybook-static/assets/{Threads.stories-BDwauY1I.js → Threads.stories-C_LDNe0R.js} +1 -1
- package/storybook-static/assets/{TimeInput.stories-Bk2lwEyd.js → TimeInput.stories-Tj2LrCtN.js} +1 -1
- package/storybook-static/assets/{Toggle-BbWuVStR.js → Toggle-BgFXbOVy.js} +1 -1
- package/storybook-static/assets/{Toggle.stories-Bb7-wtRn.js → Toggle.stories-voNeGmVh.js} +1 -1
- package/storybook-static/assets/{ToggleButton-BaLN5DsF.js → ToggleButton-CQLM9369.js} +1 -1
- package/storybook-static/assets/{ToggleButton.stories-Cdx8eTPI.js → ToggleButton.stories-CLdG94qe.js} +1 -1
- package/storybook-static/assets/{TrueFocus.stories-B_pN3J3c.js → TrueFocus.stories-CEC_mKz7.js} +1 -1
- package/storybook-static/assets/{VariableProximity.stories-BTLVRXWD.js → VariableProximity.stories-CoB68xuF.js} +1 -1
- package/storybook-static/assets/{Waves.stories-_NtAqm6K.js → Waves.stories-Cpn9tv6C.js} +1 -1
- package/storybook-static/assets/{band-BYy0bT_S.js → band-Cq25-Mh7.js} +1 -1
- package/storybook-static/assets/{calendar-jGMMZsgE.js → calendar-B90N4a5g.js} +1 -1
- package/storybook-static/assets/{chart-column-jT4jlZWv.js → chart-column-Qn3KVlVm.js} +1 -1
- package/storybook-static/assets/{check-D_NpTUYB.js → check-BdgefYk0.js} +1 -1
- package/storybook-static/assets/{chevron-down-C40D1TRM.js → chevron-down-rAxqUK0f.js} +1 -1
- package/storybook-static/assets/{chevron-right-pJjQoHt-.js → chevron-right-BQYLOSGD.js} +1 -1
- package/storybook-static/assets/client-Chg03P_H.js +1 -0
- package/storybook-static/assets/{createLucideIcon-DhNY7W9i.js → createLucideIcon-CanksmPJ.js} +1 -1
- package/storybook-static/assets/{download-DDadr76l.js → download-BoPCl2gy.js} +1 -1
- package/storybook-static/assets/{folder-Dt06LOrp.js → folder-B0zTnOfo.js} +1 -1
- package/storybook-static/assets/{iconBase-HFPlWF3A.js → iconBase-jWAd7fUM.js} +1 -1
- package/storybook-static/assets/{iframe-rPhsLpUF.js → iframe-BTbLpgFM.js} +3 -3
- package/storybook-static/assets/{index-Ctb6PtgV.js → index-8orVvKs3.js} +1 -1
- package/storybook-static/assets/{index-DVywRwbF.js → index-D9A3yXPP.js} +1 -1
- package/storybook-static/assets/{index-B9UM6a_o.js → index-Dnnp7mc9.js} +1 -1
- package/storybook-static/assets/{linear-DhrdWH9x.js → linear-9syG7RFK.js} +1 -1
- package/storybook-static/assets/monotone-B6BFTqpP.js +1 -0
- package/storybook-static/assets/{proxy-uJ8evSzT.js → proxy-DHiOkbBq.js} +1 -1
- package/storybook-static/assets/{react-18-CYoR46z3.js → react-18-RyhzFaVZ.js} +1 -1
- package/storybook-static/assets/{react-three-fiber.esm-A61ChP7H.js → react-three-fiber.esm-DyDueq1t.js} +1 -1
- package/storybook-static/assets/{search-CIAI1CyG.js → search-C2F8ucQI.js} +1 -1
- package/storybook-static/assets/{settings-en9EIxHx.js → settings-B4F4kfld.js} +1 -1
- package/storybook-static/assets/{sun-D_CSzOJ1.js → sun-CbGl2Vwt.js} +1 -1
- package/storybook-static/assets/{transform-QOf3tDlt.js → transform-v7fcW145.js} +1 -1
- package/storybook-static/assets/{trash-2-C2s-nRjQ.js → trash-2-CNCXZ0wH.js} +1 -1
- package/storybook-static/assets/{use-animation-frame-B62vi9Ct.js → use-animation-frame-DY1VsI4g.js} +1 -1
- package/storybook-static/assets/{use-in-view-BHudJAGG.js → use-in-view-Cawxv_UZ.js} +1 -1
- package/storybook-static/assets/{use-motion-value-jBEsDEvG.js → use-motion-value-BKT0PPfP.js} +1 -1
- package/storybook-static/assets/{use-spring-Bf02nu3H.js → use-spring-CDH8BIpQ.js} +1 -1
- package/storybook-static/assets/{use-transform-Cfp6qWZw.js → use-transform-Bj0aHFrd.js} +1 -1
- package/storybook-static/assets/{useSound-CISJumm6.js → useSound-OlKqgJtL.js} +1 -1
- package/storybook-static/assets/{users-Bm-CUW6N.js → users-Oy8C2tFC.js} +1 -1
- package/storybook-static/assets/{x-Bb1g_3HM.js → x-CR0CkM0G.js} +1 -1
- package/storybook-static/iframe.html +1 -1
- package/storybook-static/project.json +1 -1
- package/storybook-static/assets/MoodChart-ba3aY_qF.css +0 -1
- package/storybook-static/assets/MoodChart.stories-1otFXWFu.js +0 -40
- package/storybook-static/assets/QuantifiableHabitsChart-JSu1fVKW.css +0 -1
- package/storybook-static/assets/QuantifiableHabitsChart.stories-BMxWoQO4.js +0 -125
- package/storybook-static/assets/client-BAyDOFGI.js +0 -1
- package/storybook-static/assets/monotone-DouxdRGd.js +0 -1
package/dist/index.js
CHANGED
|
@@ -3800,7 +3800,7 @@ function Calendar({ events, onEventClick, onDateClick, onEventClickByView, onDat
|
|
|
3800
3800
|
ease: "easeOut"
|
|
3801
3801
|
}, onClick: () => handleDateClick(day), children: [jsxRuntime.jsx("div", { className: styles$b.dayNumber, children: day.getDate() }), dayEvents.length > 0 && compact && currentViewMode === 'month' ? (jsxRuntime.jsxs("div", { className: styles$b.dots, children: [dayEvents.slice(0, maxEventsPerDay).map((event) => (jsxRuntime.jsx("span", { className: styles$b.dot, style: {
|
|
3802
3802
|
backgroundColor: event.status === 'completed'
|
|
3803
|
-
? '#
|
|
3803
|
+
? '#047857'
|
|
3804
3804
|
: getEventColor(event),
|
|
3805
3805
|
} }, event.id))), dayEvents.length > maxEventsPerDay && (jsxRuntime.jsxs("span", { className: styles$b.dotMore, children: ["+", dayEvents.length - maxEventsPerDay] }))] })) : dayEvents.length > 0 ? (jsxRuntime.jsxs("div", { className: styles$b.events, children: [dayEvents.slice(0, maxEventsPerDay).map((event, eventIndex) => (jsxRuntime.jsxs(framerMotion.motion.div, { className: `${styles$b.event} ${event.status === 'completed' ? styles$b.completed : ''}`, style: {
|
|
3806
3806
|
backgroundColor: getEventColor(event),
|
|
@@ -3957,22 +3957,27 @@ const Navbar = ({ items, logo, onItemClick, variant = 'sidebar', isMobile = fals
|
|
|
3957
3957
|
return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(framerMotion.motion.nav, { className: `${styles.navbar} ${styles[`navbar${variant.charAt(0).toUpperCase() + variant.slice(1)}`]} ${className}`, "data-colored-icons": coloredIconsAttr, initial: variant === 'sidebar' ? { x: -300 } : { opacity: 0 }, animate: variant === 'sidebar' ? { x: 0 } : { opacity: 1 }, transition: { type: 'spring', stiffness: 300, damping: 30 }, children: navContent }) }));
|
|
3958
3958
|
};
|
|
3959
3959
|
|
|
3960
|
-
var styles$9 = {"container":"MoodChart-module_container__MB1Vr","chart":"MoodChart-module_chart__4-spu","gridLine":"MoodChart-module_gridLine__YJpZ8","line":"MoodChart-module_line__LfeUX","xAxis":"MoodChart-module_xAxis__SeIWG","yAxis":"MoodChart-module_yAxis__sRjjE","dataPoint":"MoodChart-module_dataPoint__112P1","tooltip":"MoodChart-module_tooltip__vW59y","tooltipHeader":"MoodChart-module_tooltipHeader__U7yvN","tooltipDate":"MoodChart-module_tooltipDate__6Jjeu","tooltipRating":"MoodChart-module_tooltipRating__5A2Yx","ratingValue":"MoodChart-module_ratingValue__7Gpfx","ratingMax":"MoodChart-module_ratingMax__10WcJ","tooltipTags":"MoodChart-module_tooltipTags__FUQrU","tag":"MoodChart-module_tag__QhCh5","tooltipComment":"MoodChart-module_tooltipComment__6driJ"};
|
|
3960
|
+
var styles$9 = {"container":"MoodChart-module_container__MB1Vr","chart":"MoodChart-module_chart__4-spu","gridLine":"MoodChart-module_gridLine__YJpZ8","line":"MoodChart-module_line__LfeUX","area":"MoodChart-module_area__a4BFM","areaStopTop":"MoodChart-module_areaStopTop__KEp49","areaStopBottom":"MoodChart-module_areaStopBottom__cp7Gn","crosshair":"MoodChart-module_crosshair__PHLfW","halo":"MoodChart-module_halo__YQB-7","overlay":"MoodChart-module_overlay__ZwuHi","xAxis":"MoodChart-module_xAxis__SeIWG","yAxis":"MoodChart-module_yAxis__sRjjE","dataPoint":"MoodChart-module_dataPoint__112P1","tooltip":"MoodChart-module_tooltip__vW59y","tooltipHeader":"MoodChart-module_tooltipHeader__U7yvN","tooltipDate":"MoodChart-module_tooltipDate__6Jjeu","tooltipRating":"MoodChart-module_tooltipRating__5A2Yx","ratingValue":"MoodChart-module_ratingValue__7Gpfx","ratingMax":"MoodChart-module_ratingMax__10WcJ","tooltipTags":"MoodChart-module_tooltipTags__FUQrU","tag":"MoodChart-module_tag__QhCh5","tooltipComment":"MoodChart-module_tooltipComment__6driJ"};
|
|
3961
3961
|
|
|
3962
3962
|
const MoodChart = ({ moodData, width = 800, height = 400 }) => {
|
|
3963
3963
|
const svgRef = React.useRef(null);
|
|
3964
3964
|
const containerRef = React.useRef(null);
|
|
3965
3965
|
const tooltipRef = React.useRef(null);
|
|
3966
|
+
const isHoveringTooltipRef = React.useRef(false);
|
|
3967
|
+
const rawId = React.useId();
|
|
3968
|
+
const gradientId = React.useMemo(() => `mood-area-${rawId.replace(/[^a-zA-Z0-9]/g, '_')}`, [rawId]);
|
|
3966
3969
|
const [selectedMood, setSelectedMood] = React.useState(null);
|
|
3967
3970
|
const [tooltipPosition, setTooltipPosition] = React.useState({ x: 0, y: 0 });
|
|
3968
3971
|
const [isHoveringTooltip, setIsHoveringTooltip] = React.useState(false);
|
|
3972
|
+
React.useEffect(() => {
|
|
3973
|
+
isHoveringTooltipRef.current = isHoveringTooltip;
|
|
3974
|
+
}, [isHoveringTooltip]);
|
|
3969
3975
|
const margin = React.useMemo(() => ({ top: 20, right: 20, bottom: 50, left: 40 }), []);
|
|
3970
3976
|
const chartWidth = width - margin.left - margin.right;
|
|
3971
3977
|
const chartHeight = height - margin.top - margin.bottom;
|
|
3972
3978
|
const processedData = React.useMemo(() => {
|
|
3973
3979
|
return moodData
|
|
3974
3980
|
.map(mood => {
|
|
3975
|
-
// Parse comma-separated tags
|
|
3976
3981
|
const tags = mood.tag
|
|
3977
3982
|
? mood.tag.split(',').map(t => t.trim()).filter(t => t)
|
|
3978
3983
|
: [];
|
|
@@ -3984,7 +3989,8 @@ const MoodChart = ({ moodData, width = 800, height = 400 }) => {
|
|
|
3984
3989
|
};
|
|
3985
3990
|
})
|
|
3986
3991
|
.filter(mood => !isNaN(mood.date.getTime()) &&
|
|
3987
|
-
isFinite(mood.rating))
|
|
3992
|
+
isFinite(mood.rating))
|
|
3993
|
+
.sort((a, b) => a.date.getTime() - b.date.getTime());
|
|
3988
3994
|
}, [moodData]);
|
|
3989
3995
|
const colorScale = React.useMemo(() => {
|
|
3990
3996
|
return d3__namespace.scaleLinear()
|
|
@@ -3997,6 +4003,13 @@ const MoodChart = ({ moodData, width = 800, height = 400 }) => {
|
|
|
3997
4003
|
return;
|
|
3998
4004
|
const svg = d3__namespace.select(svgRef.current);
|
|
3999
4005
|
svg.selectAll('*').remove();
|
|
4006
|
+
const defs = svg.append('defs');
|
|
4007
|
+
const gradient = defs.append('linearGradient')
|
|
4008
|
+
.attr('id', gradientId)
|
|
4009
|
+
.attr('x1', '0%').attr('y1', '0%')
|
|
4010
|
+
.attr('x2', '0%').attr('y2', '100%');
|
|
4011
|
+
gradient.append('stop').attr('offset', '0%').attr('class', styles$9.areaStopTop);
|
|
4012
|
+
gradient.append('stop').attr('offset', '100%').attr('class', styles$9.areaStopBottom);
|
|
4000
4013
|
const g = svg.append('g')
|
|
4001
4014
|
.attr('transform', `translate(${margin.left},${margin.top})`);
|
|
4002
4015
|
const extentDates = d3__namespace.extent(processedData, d => d.date);
|
|
@@ -4012,6 +4025,12 @@ const MoodChart = ({ moodData, width = 800, height = 400 }) => {
|
|
|
4012
4025
|
.x(d => xScale(d.date))
|
|
4013
4026
|
.y(d => yScale(d.rating))
|
|
4014
4027
|
.curve(d3__namespace.curveMonotoneX);
|
|
4028
|
+
const area = d3__namespace.area()
|
|
4029
|
+
.x(d => xScale(d.date))
|
|
4030
|
+
.y0(chartHeight)
|
|
4031
|
+
.y1(d => yScale(d.rating))
|
|
4032
|
+
.curve(d3__namespace.curveMonotoneX);
|
|
4033
|
+
// Grid lines (fade in)
|
|
4015
4034
|
g.selectAll('.grid-line-y')
|
|
4016
4035
|
.data(yScale.ticks(5))
|
|
4017
4036
|
.enter().append('line')
|
|
@@ -4019,70 +4038,210 @@ const MoodChart = ({ moodData, width = 800, height = 400 }) => {
|
|
|
4019
4038
|
.attr('x1', 0)
|
|
4020
4039
|
.attr('y1', d => yScale(d))
|
|
4021
4040
|
.attr('x2', chartWidth)
|
|
4022
|
-
.attr('y2', d => yScale(d))
|
|
4023
|
-
|
|
4024
|
-
.
|
|
4025
|
-
.
|
|
4026
|
-
.
|
|
4041
|
+
.attr('y2', d => yScale(d))
|
|
4042
|
+
.style('opacity', 0)
|
|
4043
|
+
.transition()
|
|
4044
|
+
.duration(500)
|
|
4045
|
+
.ease(d3__namespace.easeCubicOut)
|
|
4046
|
+
.style('opacity', 1);
|
|
4047
|
+
// Axes (fade in)
|
|
4027
4048
|
g.append('g')
|
|
4028
4049
|
.attr('class', styles$9.xAxis)
|
|
4029
4050
|
.attr('transform', `translate(0,${chartHeight})`)
|
|
4051
|
+
.style('opacity', 0)
|
|
4030
4052
|
.call(d3__namespace.axisBottom(xScale)
|
|
4031
|
-
.tickFormat(d => d3__namespace.timeFormat('%m/%d')(d)))
|
|
4053
|
+
.tickFormat(d => d3__namespace.timeFormat('%m/%d')(d)))
|
|
4054
|
+
.transition()
|
|
4055
|
+
.duration(600)
|
|
4056
|
+
.delay(100)
|
|
4057
|
+
.style('opacity', 1);
|
|
4032
4058
|
g.append('g')
|
|
4033
4059
|
.attr('class', styles$9.yAxis)
|
|
4034
|
-
.
|
|
4035
|
-
|
|
4060
|
+
.style('opacity', 0)
|
|
4061
|
+
.call(d3__namespace.axisLeft(yScale))
|
|
4062
|
+
.transition()
|
|
4063
|
+
.duration(600)
|
|
4064
|
+
.delay(100)
|
|
4065
|
+
.style('opacity', 1);
|
|
4066
|
+
// Area fill (fades in after line draws past it)
|
|
4067
|
+
const areaPath = g.append('path')
|
|
4068
|
+
.datum(processedData)
|
|
4069
|
+
.attr('class', styles$9.area)
|
|
4070
|
+
.attr('fill', `url(#${gradientId})`)
|
|
4071
|
+
.attr('d', area)
|
|
4072
|
+
.style('opacity', 0);
|
|
4073
|
+
// Line (draw-in animation via stroke-dasharray)
|
|
4074
|
+
const linePath = g.append('path')
|
|
4075
|
+
.datum(processedData)
|
|
4076
|
+
.attr('class', styles$9.line)
|
|
4077
|
+
.attr('d', line);
|
|
4078
|
+
const lineNode = linePath.node();
|
|
4079
|
+
const totalLength = lineNode && typeof lineNode.getTotalLength === 'function'
|
|
4080
|
+
? lineNode.getTotalLength()
|
|
4081
|
+
: 0;
|
|
4082
|
+
const lineDuration = 1200;
|
|
4083
|
+
if (totalLength > 0) {
|
|
4084
|
+
linePath
|
|
4085
|
+
.attr('stroke-dasharray', `${totalLength} ${totalLength}`)
|
|
4086
|
+
.attr('stroke-dashoffset', totalLength)
|
|
4087
|
+
.transition()
|
|
4088
|
+
.duration(lineDuration)
|
|
4089
|
+
.ease(d3__namespace.easeCubicOut)
|
|
4090
|
+
.attr('stroke-dashoffset', 0)
|
|
4091
|
+
.on('end', () => {
|
|
4092
|
+
linePath.attr('stroke-dasharray', null);
|
|
4093
|
+
});
|
|
4094
|
+
}
|
|
4095
|
+
areaPath
|
|
4096
|
+
.transition()
|
|
4097
|
+
.delay(lineDuration * 0.4)
|
|
4098
|
+
.duration(800)
|
|
4099
|
+
.ease(d3__namespace.easeCubicOut)
|
|
4100
|
+
.style('opacity', 1);
|
|
4101
|
+
// Crosshair (vertical guide on hover)
|
|
4102
|
+
const crosshair = g.append('line')
|
|
4103
|
+
.attr('class', styles$9.crosshair)
|
|
4104
|
+
.attr('y1', 0)
|
|
4105
|
+
.attr('y2', chartHeight)
|
|
4106
|
+
.style('opacity', 0)
|
|
4107
|
+
.style('pointer-events', 'none');
|
|
4108
|
+
// Pulsing halo behind active point
|
|
4109
|
+
const halo = g.append('circle')
|
|
4110
|
+
.attr('class', styles$9.halo)
|
|
4111
|
+
.attr('r', 0)
|
|
4112
|
+
.style('opacity', 0)
|
|
4113
|
+
.style('pointer-events', 'none');
|
|
4114
|
+
// Data points (staggered entrance keyed to line draw)
|
|
4115
|
+
const minX = xScale(extentDates[0]);
|
|
4116
|
+
const maxX = xScale(extentDates[1]);
|
|
4117
|
+
const xRange = Math.max(1, maxX - minX);
|
|
4118
|
+
const pointSel = g.selectAll('.mood-circle')
|
|
4036
4119
|
.data(processedData)
|
|
4037
4120
|
.enter().append('circle')
|
|
4038
4121
|
.attr('class', styles$9.dataPoint)
|
|
4039
4122
|
.attr('cx', d => xScale(d.date))
|
|
4040
4123
|
.attr('cy', d => yScale(d.rating))
|
|
4041
|
-
.attr('r',
|
|
4124
|
+
.attr('r', 0)
|
|
4042
4125
|
.attr('fill', d => colorScale(d.rating))
|
|
4043
|
-
.style('
|
|
4044
|
-
.
|
|
4126
|
+
.style('opacity', 0)
|
|
4127
|
+
.style('pointer-events', 'none');
|
|
4128
|
+
pointSel.transition()
|
|
4129
|
+
.delay(d => 100 + lineDuration * ((xScale(d.date) - minX) / xRange))
|
|
4130
|
+
.duration(380)
|
|
4131
|
+
.ease(d3__namespace.easeBackOut.overshoot(2))
|
|
4132
|
+
.attr('r', 5)
|
|
4133
|
+
.style('opacity', 1);
|
|
4134
|
+
const pointNodes = pointSel.nodes();
|
|
4135
|
+
// Active state lives in mutable refs (closure over redraw)
|
|
4136
|
+
let activeIndex = null;
|
|
4137
|
+
const startHaloPulse = (cx, cy, fill) => {
|
|
4138
|
+
halo
|
|
4139
|
+
.interrupt('halo-pulse')
|
|
4140
|
+
.interrupt('halo-out')
|
|
4141
|
+
.attr('cx', cx)
|
|
4142
|
+
.attr('cy', cy)
|
|
4143
|
+
.attr('fill', fill);
|
|
4144
|
+
const pulseOnce = () => {
|
|
4145
|
+
halo
|
|
4146
|
+
.attr('r', 5)
|
|
4147
|
+
.style('opacity', 0.55)
|
|
4148
|
+
.transition('halo-pulse')
|
|
4149
|
+
.duration(900)
|
|
4150
|
+
.ease(d3__namespace.easeCubicOut)
|
|
4151
|
+
.attr('r', 20)
|
|
4152
|
+
.style('opacity', 0)
|
|
4153
|
+
.on('end', pulseOnce);
|
|
4154
|
+
};
|
|
4155
|
+
pulseOnce();
|
|
4156
|
+
};
|
|
4157
|
+
const stopHaloPulse = () => {
|
|
4158
|
+
halo
|
|
4159
|
+
.interrupt('halo-pulse')
|
|
4160
|
+
.transition('halo-out')
|
|
4161
|
+
.duration(180)
|
|
4162
|
+
.style('opacity', 0)
|
|
4163
|
+
.attr('r', 0);
|
|
4164
|
+
};
|
|
4165
|
+
const setActive = (idx, clientX, clientY) => {
|
|
4166
|
+
const d = processedData[idx];
|
|
4167
|
+
if (!d)
|
|
4168
|
+
return;
|
|
4169
|
+
const cx = xScale(d.date);
|
|
4170
|
+
const cy = yScale(d.rating);
|
|
4045
4171
|
const rect = svgRef.current?.getBoundingClientRect();
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
let
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
if (x + estimatedTooltipWidth > chartWidth + margin.left - rightEdgeBuffer) {
|
|
4054
|
-
// Position tooltip to the left of the cursor, but keep it close
|
|
4055
|
-
x = event.clientX - rect.left - estimatedTooltipWidth - 10;
|
|
4056
|
-
// Ensure it doesn't go off the left edge
|
|
4057
|
-
if (x < 0) {
|
|
4172
|
+
if (rect) {
|
|
4173
|
+
let x = clientX - rect.left + 12;
|
|
4174
|
+
let y = clientY - rect.top - 12;
|
|
4175
|
+
const estW = 280;
|
|
4176
|
+
if (x + estW > chartWidth + margin.left - 20) {
|
|
4177
|
+
x = clientX - rect.left - estW - 12;
|
|
4178
|
+
if (x < 0)
|
|
4058
4179
|
x = 10;
|
|
4059
|
-
}
|
|
4060
4180
|
}
|
|
4061
|
-
|
|
4062
|
-
if (y < 0) {
|
|
4181
|
+
if (y < 0)
|
|
4063
4182
|
y = 10;
|
|
4064
|
-
}
|
|
4065
4183
|
setTooltipPosition({ x, y });
|
|
4066
4184
|
}
|
|
4067
4185
|
setSelectedMood(d);
|
|
4068
|
-
|
|
4069
|
-
.
|
|
4070
|
-
.
|
|
4071
|
-
.
|
|
4186
|
+
crosshair
|
|
4187
|
+
.attr('x1', cx).attr('x2', cx)
|
|
4188
|
+
.interrupt('crosshair-fade')
|
|
4189
|
+
.transition('crosshair-fade')
|
|
4190
|
+
.duration(120)
|
|
4191
|
+
.style('opacity', 1);
|
|
4192
|
+
if (activeIndex !== idx) {
|
|
4193
|
+
if (activeIndex !== null) {
|
|
4194
|
+
d3__namespace.select(pointNodes[activeIndex])
|
|
4195
|
+
.transition('point-scale')
|
|
4196
|
+
.duration(180)
|
|
4197
|
+
.ease(d3__namespace.easeCubicOut)
|
|
4198
|
+
.attr('r', 5);
|
|
4199
|
+
}
|
|
4200
|
+
d3__namespace.select(pointNodes[idx])
|
|
4201
|
+
.transition('point-scale')
|
|
4202
|
+
.duration(180)
|
|
4203
|
+
.ease(d3__namespace.easeBackOut.overshoot(2))
|
|
4204
|
+
.attr('r', 8);
|
|
4205
|
+
startHaloPulse(cx, cy, colorScale(d.rating));
|
|
4206
|
+
activeIndex = idx;
|
|
4207
|
+
}
|
|
4208
|
+
};
|
|
4209
|
+
const clearActive = () => {
|
|
4210
|
+
crosshair
|
|
4211
|
+
.interrupt('crosshair-fade')
|
|
4212
|
+
.transition('crosshair-fade')
|
|
4213
|
+
.duration(180)
|
|
4214
|
+
.style('opacity', 0);
|
|
4215
|
+
if (activeIndex !== null) {
|
|
4216
|
+
d3__namespace.select(pointNodes[activeIndex])
|
|
4217
|
+
.transition('point-scale')
|
|
4218
|
+
.duration(180)
|
|
4219
|
+
.attr('r', 5);
|
|
4220
|
+
activeIndex = null;
|
|
4221
|
+
}
|
|
4222
|
+
stopHaloPulse();
|
|
4223
|
+
setSelectedMood(null);
|
|
4224
|
+
};
|
|
4225
|
+
// Overlay captures mouse for nearest-point lookup (rendered last so it sits on top)
|
|
4226
|
+
const bisect = d3__namespace.bisector(d => d.date).center;
|
|
4227
|
+
g.append('rect')
|
|
4228
|
+
.attr('class', styles$9.overlay)
|
|
4229
|
+
.attr('width', chartWidth)
|
|
4230
|
+
.attr('height', chartHeight)
|
|
4231
|
+
.on('mousemove', function (event) {
|
|
4232
|
+
const [mx] = d3__namespace.pointer(event, this);
|
|
4233
|
+
const xDate = xScale.invert(mx);
|
|
4234
|
+
const idx = Math.max(0, Math.min(processedData.length - 1, bisect(processedData, xDate)));
|
|
4235
|
+
setActive(idx, event.clientX, event.clientY);
|
|
4072
4236
|
})
|
|
4073
|
-
.on('mouseleave', (
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
setSelectedMood(null);
|
|
4237
|
+
.on('mouseleave', () => {
|
|
4238
|
+
window.setTimeout(() => {
|
|
4239
|
+
if (!isHoveringTooltipRef.current) {
|
|
4240
|
+
clearActive();
|
|
4078
4241
|
}
|
|
4079
|
-
},
|
|
4080
|
-
d3__namespace.select(event.currentTarget)
|
|
4081
|
-
.transition()
|
|
4082
|
-
.duration(200)
|
|
4083
|
-
.attr('r', 5);
|
|
4242
|
+
}, 220);
|
|
4084
4243
|
});
|
|
4085
|
-
}, [processedData, chartWidth, chartHeight, colorScale, margin,
|
|
4244
|
+
}, [processedData, chartWidth, chartHeight, colorScale, margin, gradientId]);
|
|
4086
4245
|
// Clean up tooltip on unmount
|
|
4087
4246
|
React.useEffect(() => {
|
|
4088
4247
|
return () => {
|
|
@@ -4101,9 +4260,8 @@ const MoodChart = ({ moodData, width = 800, height = 400 }) => {
|
|
|
4101
4260
|
}, children: [jsxRuntime.jsxs("div", { className: styles$9.tooltipHeader, children: [jsxRuntime.jsx("div", { className: styles$9.tooltipDate, children: selectedMood.date.toLocaleDateString() }), jsxRuntime.jsxs("div", { className: styles$9.tooltipRating, children: [jsxRuntime.jsx("span", { className: styles$9.ratingValue, children: selectedMood.rating }), jsxRuntime.jsx("span", { className: styles$9.ratingMax, children: "/10" })] })] }), selectedMood.tags.length > 0 && (jsxRuntime.jsx("div", { className: styles$9.tooltipTags, children: selectedMood.tags.map((tag, index) => (jsxRuntime.jsx("span", { className: styles$9.tag, children: tag }, index))) })), selectedMood.comment && (jsxRuntime.jsx("div", { className: styles$9.tooltipComment, children: selectedMood.comment }))] }))] }));
|
|
4102
4261
|
};
|
|
4103
4262
|
|
|
4104
|
-
var styles$8 = {"container":"QuantifiableHabitsChart-module_container__X5SBp","controls":"QuantifiableHabitsChart-module_controls__O-ObQ","viewToggle":"QuantifiableHabitsChart-module_viewToggle__24hKA","viewButton":"QuantifiableHabitsChart-module_viewButton__WFU6j","active":"QuantifiableHabitsChart-module_active__Pjqy9","viewIcon":"QuantifiableHabitsChart-module_viewIcon__b2mfk","viewLabel":"QuantifiableHabitsChart-module_viewLabel__9MjCU","aggregationToggle":"QuantifiableHabitsChart-module_aggregationToggle__WnxwB","aggregationButton":"QuantifiableHabitsChart-module_aggregationButton__sGCxX","aggregationIcon":"QuantifiableHabitsChart-module_aggregationIcon__HIaEf","aggregationLabel":"QuantifiableHabitsChart-module_aggregationLabel__Yc-S-","legend":"QuantifiableHabitsChart-module_legend__3Ki7c","compactLegend":"QuantifiableHabitsChart-module_compactLegend__jMpLB","legendItem":"QuantifiableHabitsChart-module_legendItem__Zl7fz","legendEmoji":"QuantifiableHabitsChart-module_legendEmoji__HG9CZ","legendLabel":"QuantifiableHabitsChart-module_legendLabel__H3oFL","inactive":"QuantifiableHabitsChart-module_inactive__TzZC-","legendColor":"QuantifiableHabitsChart-module_legendColor__zbPoV","chart":"QuantifiableHabitsChart-module_chart__FMeA-","gridLine":"QuantifiableHabitsChart-module_gridLine__CTNIq","line":"QuantifiableHabitsChart-module_line__CpYip","xAxis":"QuantifiableHabitsChart-module_xAxis__lbgBG","yAxis":"QuantifiableHabitsChart-module_yAxis__Y6WeV","dataPoint":"QuantifiableHabitsChart-module_dataPoint__s8UMX","tooltip":"QuantifiableHabitsChart-module_tooltip__Fay8N","visible":"QuantifiableHabitsChart-module_visible__-KSJq","tooltipHeader":"QuantifiableHabitsChart-module_tooltipHeader__7Q2up","tooltipEmoji":"QuantifiableHabitsChart-module_tooltipEmoji__atV3T","tooltipDot":"QuantifiableHabitsChart-module_tooltipDot__YbdFh","tooltipInfo":"QuantifiableHabitsChart-module_tooltipInfo__XC7WF","tooltipDate":"QuantifiableHabitsChart-module_tooltipDate__6V6Xi","tooltipValue":"QuantifiableHabitsChart-module_tooltipValue__ldASB"};
|
|
4263
|
+
var styles$8 = {"container":"QuantifiableHabitsChart-module_container__X5SBp","controls":"QuantifiableHabitsChart-module_controls__O-ObQ","viewToggle":"QuantifiableHabitsChart-module_viewToggle__24hKA","viewButton":"QuantifiableHabitsChart-module_viewButton__WFU6j","active":"QuantifiableHabitsChart-module_active__Pjqy9","viewIcon":"QuantifiableHabitsChart-module_viewIcon__b2mfk","viewLabel":"QuantifiableHabitsChart-module_viewLabel__9MjCU","aggregationToggle":"QuantifiableHabitsChart-module_aggregationToggle__WnxwB","aggregationButton":"QuantifiableHabitsChart-module_aggregationButton__sGCxX","aggregationIcon":"QuantifiableHabitsChart-module_aggregationIcon__HIaEf","aggregationLabel":"QuantifiableHabitsChart-module_aggregationLabel__Yc-S-","legend":"QuantifiableHabitsChart-module_legend__3Ki7c","compactLegend":"QuantifiableHabitsChart-module_compactLegend__jMpLB","legendItem":"QuantifiableHabitsChart-module_legendItem__Zl7fz","legendEmoji":"QuantifiableHabitsChart-module_legendEmoji__HG9CZ","legendLabel":"QuantifiableHabitsChart-module_legendLabel__H3oFL","inactive":"QuantifiableHabitsChart-module_inactive__TzZC-","legendColor":"QuantifiableHabitsChart-module_legendColor__zbPoV","chart":"QuantifiableHabitsChart-module_chart__FMeA-","gridLine":"QuantifiableHabitsChart-module_gridLine__CTNIq","line":"QuantifiableHabitsChart-module_line__CpYip","crosshair":"QuantifiableHabitsChart-module_crosshair__7hoFL","halo":"QuantifiableHabitsChart-module_halo__YlkOF","overlay":"QuantifiableHabitsChart-module_overlay__ffeNz","xAxis":"QuantifiableHabitsChart-module_xAxis__lbgBG","yAxis":"QuantifiableHabitsChart-module_yAxis__Y6WeV","dataPoint":"QuantifiableHabitsChart-module_dataPoint__s8UMX","tooltip":"QuantifiableHabitsChart-module_tooltip__Fay8N","visible":"QuantifiableHabitsChart-module_visible__-KSJq","tooltipHeader":"QuantifiableHabitsChart-module_tooltipHeader__7Q2up","tooltipEmoji":"QuantifiableHabitsChart-module_tooltipEmoji__atV3T","tooltipDot":"QuantifiableHabitsChart-module_tooltipDot__YbdFh","tooltipInfo":"QuantifiableHabitsChart-module_tooltipInfo__XC7WF","tooltipDate":"QuantifiableHabitsChart-module_tooltipDate__6V6Xi","tooltipValue":"QuantifiableHabitsChart-module_tooltipValue__ldASB"};
|
|
4105
4264
|
|
|
4106
|
-
// Default colors as fallback
|
|
4107
4265
|
const DEFAULT_HABIT_COLORS$1 = {
|
|
4108
4266
|
'Exercise': '#6BCB77',
|
|
4109
4267
|
'Meditation': '#4D96FF',
|
|
@@ -4114,14 +4272,53 @@ const DEFAULT_HABIT_COLORS$1 = {
|
|
|
4114
4272
|
'Calories': '#FF9F1C',
|
|
4115
4273
|
'Study': '#C774E8'
|
|
4116
4274
|
};
|
|
4275
|
+
// Smoothly interpolate between two SVG path strings by resampling both
|
|
4276
|
+
// at evenly-spaced arc-length positions and tweening corresponding points.
|
|
4277
|
+
const SVG_NS = 'http://www.w3.org/2000/svg';
|
|
4278
|
+
const pathTween = (oldD, newD, samples = 80) => {
|
|
4279
|
+
const safeOld = oldD && oldD.length > 0 ? oldD : 'M0,0';
|
|
4280
|
+
const safeNew = newD && newD.length > 0 ? newD : 'M0,0';
|
|
4281
|
+
const oldNode = document.createElementNS(SVG_NS, 'path');
|
|
4282
|
+
const newNode = document.createElementNS(SVG_NS, 'path');
|
|
4283
|
+
oldNode.setAttribute('d', safeOld);
|
|
4284
|
+
newNode.setAttribute('d', safeNew);
|
|
4285
|
+
const oldLen = typeof oldNode.getTotalLength === 'function' ? oldNode.getTotalLength() : 0;
|
|
4286
|
+
const newLen = typeof newNode.getTotalLength === 'function' ? newNode.getTotalLength() : 0;
|
|
4287
|
+
if (oldLen === 0 || newLen === 0) {
|
|
4288
|
+
return () => safeNew;
|
|
4289
|
+
}
|
|
4290
|
+
const old = [];
|
|
4291
|
+
const next = [];
|
|
4292
|
+
for (let i = 0; i < samples; i++) {
|
|
4293
|
+
const u = samples === 1 ? 0 : i / (samples - 1);
|
|
4294
|
+
const op = oldNode.getPointAtLength(u * oldLen);
|
|
4295
|
+
const np = newNode.getPointAtLength(u * newLen);
|
|
4296
|
+
old.push([op.x, op.y]);
|
|
4297
|
+
next.push([np.x, np.y]);
|
|
4298
|
+
}
|
|
4299
|
+
return (t) => {
|
|
4300
|
+
let s = '';
|
|
4301
|
+
for (let i = 0; i < samples; i++) {
|
|
4302
|
+
const x = old[i][0] + (next[i][0] - old[i][0]) * t;
|
|
4303
|
+
const y = old[i][1] + (next[i][1] - old[i][1]) * t;
|
|
4304
|
+
s += (i === 0 ? 'M' : 'L') + x + ',' + y;
|
|
4305
|
+
}
|
|
4306
|
+
return s;
|
|
4307
|
+
};
|
|
4308
|
+
};
|
|
4117
4309
|
const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewType = 'daily', periodType = 'month', habitColors: customHabitColors = {}, habitEmojis: customHabitEmojis = {}, onDataPointClick, hideControls = false, compactLegend = false }) => {
|
|
4118
4310
|
const svgRef = React.useRef(null);
|
|
4119
4311
|
const tooltipRef = React.useRef(null);
|
|
4312
|
+
const onClickRef = React.useRef(onDataPointClick);
|
|
4313
|
+
const hasMountedRef = React.useRef(false);
|
|
4120
4314
|
const [viewType, setViewType] = React.useState(defaultViewType);
|
|
4121
4315
|
const [activeHabits, setActiveHabits] = React.useState([]);
|
|
4122
4316
|
const [hoveredHabit, setHoveredHabit] = React.useState(null);
|
|
4123
4317
|
const [tooltipData, setTooltipData] = React.useState(null);
|
|
4124
4318
|
const [aggregationMode, setAggregationMode] = React.useState('average');
|
|
4319
|
+
React.useEffect(() => {
|
|
4320
|
+
onClickRef.current = onDataPointClick;
|
|
4321
|
+
}, [onDataPointClick]);
|
|
4125
4322
|
const margin = React.useMemo(() => ({ top: 20, right: 20, bottom: 50, left: 50 }), []);
|
|
4126
4323
|
const chartWidth = width - margin.left - margin.right;
|
|
4127
4324
|
const chartHeight = height - margin.top - margin.bottom;
|
|
@@ -4129,7 +4326,6 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
|
|
|
4129
4326
|
React.useEffect(() => {
|
|
4130
4327
|
setActiveHabits(habits);
|
|
4131
4328
|
}, [habits]);
|
|
4132
|
-
// Hide tooltip on scroll
|
|
4133
4329
|
React.useEffect(() => {
|
|
4134
4330
|
const handleScroll = () => {
|
|
4135
4331
|
setTooltipData(null);
|
|
@@ -4156,39 +4352,32 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
|
|
|
4156
4352
|
}
|
|
4157
4353
|
}, [periodType]);
|
|
4158
4354
|
const getColor = React.useCallback((habit) => {
|
|
4159
|
-
// First check custom colors, then defaults, then generate deterministic color
|
|
4160
4355
|
return customHabitColors[habit] || DEFAULT_HABIT_COLORS$1[habit] || `hsl(${Math.abs(habit.split('').reduce((a, b) => a + b.charCodeAt(0), 0)) % 360}, 70%, 50%)`;
|
|
4161
4356
|
}, [customHabitColors]);
|
|
4162
|
-
// Aggregate data based on view type
|
|
4163
4357
|
const aggregateData = React.useMemo(() => {
|
|
4164
4358
|
if (viewType === 'daily' || !data.dates.length) {
|
|
4165
4359
|
return data;
|
|
4166
4360
|
}
|
|
4167
4361
|
const aggregated = { dates: [] };
|
|
4168
4362
|
const dateGroups = new Map();
|
|
4169
|
-
// Group dates by period
|
|
4170
4363
|
data.dates.forEach((dateStr, index) => {
|
|
4171
4364
|
const date = new Date(dateStr);
|
|
4172
4365
|
let groupKey;
|
|
4173
4366
|
switch (viewType) {
|
|
4174
4367
|
case 'weekly': {
|
|
4175
|
-
// Get ISO week start (Monday)
|
|
4176
4368
|
const weekStart = new Date(date);
|
|
4177
4369
|
const day = weekStart.getDay();
|
|
4178
4370
|
const diff = weekStart.getDate() - day + (day === 0 ? -6 : 1);
|
|
4179
4371
|
weekStart.setDate(diff);
|
|
4180
|
-
// Use the Monday date as the group key to ensure proper sorting
|
|
4181
4372
|
groupKey = weekStart.toISOString().split('T')[0];
|
|
4182
4373
|
break;
|
|
4183
4374
|
}
|
|
4184
4375
|
case 'monthly':
|
|
4185
|
-
// Use first day of month for consistent sorting
|
|
4186
4376
|
groupKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-01`;
|
|
4187
4377
|
break;
|
|
4188
4378
|
case 'quarterly': {
|
|
4189
4379
|
const quarter = Math.floor(date.getMonth() / 3) + 1;
|
|
4190
4380
|
const quarterStartMonth = (quarter - 1) * 3;
|
|
4191
|
-
// Use first day of quarter for consistent sorting and grouping
|
|
4192
4381
|
const quarterStart = new Date(date.getFullYear(), quarterStartMonth, 1);
|
|
4193
4382
|
groupKey = quarterStart.toISOString().split('T')[0];
|
|
4194
4383
|
break;
|
|
@@ -4201,7 +4390,6 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
|
|
|
4201
4390
|
}
|
|
4202
4391
|
dateGroups.get(groupKey).push(index);
|
|
4203
4392
|
});
|
|
4204
|
-
// Calculate aggregated values - sort dates for proper chronological order
|
|
4205
4393
|
aggregated.dates = Array.from(dateGroups.keys()).sort();
|
|
4206
4394
|
habits.forEach(habit => {
|
|
4207
4395
|
aggregated[habit] = aggregated.dates.map(groupKey => {
|
|
@@ -4211,11 +4399,10 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
|
|
|
4211
4399
|
.filter(v => typeof v === 'number' && !isNaN(v));
|
|
4212
4400
|
if (values.length === 0)
|
|
4213
4401
|
return 0;
|
|
4214
|
-
// Calculate aggregation based on mode
|
|
4215
4402
|
if (aggregationMode === 'sum') {
|
|
4216
4403
|
return Math.round(values.reduce((sum, v) => sum + v, 0));
|
|
4217
4404
|
}
|
|
4218
|
-
else {
|
|
4405
|
+
else {
|
|
4219
4406
|
return Math.round(values.reduce((sum, v) => sum + v, 0) / values.length);
|
|
4220
4407
|
}
|
|
4221
4408
|
});
|
|
@@ -4231,98 +4418,53 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
|
|
|
4231
4418
|
if (!svgRef.current || aggregateData.dates.length === 0)
|
|
4232
4419
|
return;
|
|
4233
4420
|
const svg = d3__namespace.select(svgRef.current);
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
.attr('
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4421
|
+
const isFirstRender = !hasMountedRef.current;
|
|
4422
|
+
hasMountedRef.current = true;
|
|
4423
|
+
// Acquire/create persistent root group + sub-groups
|
|
4424
|
+
let root = svg.select('g.qhc-root');
|
|
4425
|
+
if (root.empty()) {
|
|
4426
|
+
root = svg.append('g').attr('class', 'qhc-root');
|
|
4427
|
+
}
|
|
4428
|
+
root.attr('transform', `translate(${margin.left},${margin.top})`);
|
|
4429
|
+
const ensureGroup = (cls) => {
|
|
4430
|
+
let s = root.select(`g.${cls}`);
|
|
4431
|
+
if (s.empty())
|
|
4432
|
+
s = root.append('g').attr('class', cls);
|
|
4433
|
+
return s;
|
|
4434
|
+
};
|
|
4435
|
+
const gridGroup = ensureGroup('qhc-grid');
|
|
4436
|
+
const linesGroup = ensureGroup('qhc-lines');
|
|
4437
|
+
const pointsGroup = ensureGroup('qhc-points');
|
|
4438
|
+
const axesGroup = ensureGroup('qhc-axes');
|
|
4439
|
+
const uiGroup = ensureGroup('qhc-ui');
|
|
4246
4440
|
const dates = aggregateData.dates.map(d => new Date(d));
|
|
4247
4441
|
const xScale = d3__namespace.scaleTime()
|
|
4248
4442
|
.domain(d3__namespace.extent(dates))
|
|
4249
4443
|
.range([0, chartWidth]);
|
|
4250
|
-
const maxValue = Math.max(...activeHabits.flatMap(habit => aggregateData[habit].filter(v => typeof v === 'number')));
|
|
4444
|
+
const maxValue = Math.max(1, ...activeHabits.flatMap(habit => aggregateData[habit].filter(v => typeof v === 'number')));
|
|
4251
4445
|
const yScale = d3__namespace.scaleLinear()
|
|
4252
4446
|
.domain([0, maxValue * 1.1])
|
|
4253
4447
|
.range([chartHeight, 0]);
|
|
4254
|
-
|
|
4255
|
-
.data(yScale.ticks(5))
|
|
4256
|
-
.enter().append('line')
|
|
4257
|
-
.attr('class', styles$8.gridLine)
|
|
4258
|
-
.attr('x1', 0)
|
|
4259
|
-
.attr('y1', d => yScale(d))
|
|
4260
|
-
.attr('x2', chartWidth)
|
|
4261
|
-
.attr('y2', d => yScale(d));
|
|
4262
|
-
const line = d3__namespace.line()
|
|
4448
|
+
const lineGen = d3__namespace.line()
|
|
4263
4449
|
.x(d => xScale(d[0]))
|
|
4264
4450
|
.y(d => yScale(d[1]))
|
|
4265
4451
|
.curve(d3__namespace.curveMonotoneX);
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
.style('cursor', 'pointer')
|
|
4283
|
-
.on('mouseenter', function (_event, d) {
|
|
4284
|
-
const [date, value] = d;
|
|
4285
|
-
const rect = svgRef.current?.getBoundingClientRect();
|
|
4286
|
-
if (rect) {
|
|
4287
|
-
setTooltipData({
|
|
4288
|
-
habit,
|
|
4289
|
-
date: date.toISOString().split('T')[0],
|
|
4290
|
-
value,
|
|
4291
|
-
x: xScale(date) + margin.left + rect.left,
|
|
4292
|
-
y: yScale(value) + margin.top + rect.top
|
|
4293
|
-
});
|
|
4294
|
-
}
|
|
4295
|
-
// Find and enlarge the visible circle
|
|
4296
|
-
d3__namespace.select(g.node())
|
|
4297
|
-
.selectAll(`.circle-${habit}-${dates.indexOf(date)}`)
|
|
4298
|
-
.attr('r', 6);
|
|
4299
|
-
})
|
|
4300
|
-
.on('mouseleave', function (_event, _d) {
|
|
4301
|
-
setTooltipData(null);
|
|
4302
|
-
// Reset all circles for this habit
|
|
4303
|
-
d3__namespace.select(g.node())
|
|
4304
|
-
.selectAll('[class*="circle-' + habit + '"]')
|
|
4305
|
-
.attr('r', 4);
|
|
4306
|
-
})
|
|
4307
|
-
.on('click', function (_event, d) {
|
|
4308
|
-
const [date, value] = d;
|
|
4309
|
-
if (onDataPointClick) {
|
|
4310
|
-
onDataPointClick(habit, date.toISOString().split('T')[0], value);
|
|
4311
|
-
}
|
|
4312
|
-
});
|
|
4313
|
-
// Add visible circles
|
|
4314
|
-
g.selectAll(`.circle-${habit}`)
|
|
4315
|
-
.data(habitData)
|
|
4316
|
-
.enter().append('circle')
|
|
4317
|
-
.attr('class', (_d, i) => `${styles$8.dataPoint} circle-${habit}-${i}`)
|
|
4318
|
-
.attr('cx', d => xScale(d[0]))
|
|
4319
|
-
.attr('cy', d => yScale(d[1]))
|
|
4320
|
-
.attr('r', 4)
|
|
4321
|
-
.attr('fill', getColor(habit))
|
|
4322
|
-
.attr('opacity', hoveredHabit && hoveredHabit !== habit ? 0.3 : 1)
|
|
4323
|
-
.style('pointer-events', 'none'); // Let the invisible circle handle events
|
|
4324
|
-
});
|
|
4325
|
-
// Helper function to get ISO week number
|
|
4452
|
+
// -------- Grid --------
|
|
4453
|
+
const gridSel = gridGroup.selectAll('line.qhc-grid-line')
|
|
4454
|
+
.data(yScale.ticks(5), d => String(d));
|
|
4455
|
+
gridSel.exit().remove();
|
|
4456
|
+
const gridEnter = gridSel.enter().append('line')
|
|
4457
|
+
.attr('class', `${styles$8.gridLine} qhc-grid-line`)
|
|
4458
|
+
.style('opacity', 0);
|
|
4459
|
+
gridEnter.merge(gridSel)
|
|
4460
|
+
.attr('x1', 0)
|
|
4461
|
+
.attr('x2', chartWidth)
|
|
4462
|
+
.attr('y1', d => yScale(d))
|
|
4463
|
+
.attr('y2', d => yScale(d))
|
|
4464
|
+
.transition()
|
|
4465
|
+
.duration(400)
|
|
4466
|
+
.style('opacity', 1);
|
|
4467
|
+
// -------- Axes --------
|
|
4326
4468
|
const getISOWeek = (date) => {
|
|
4327
4469
|
const d = new Date(date);
|
|
4328
4470
|
d.setHours(0, 0, 0, 0);
|
|
@@ -4330,28 +4472,20 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
|
|
|
4330
4472
|
const week1 = new Date(d.getFullYear(), 0, 4);
|
|
4331
4473
|
return 1 + Math.round(((d.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7);
|
|
4332
4474
|
};
|
|
4333
|
-
// Format x-axis based on view type
|
|
4334
4475
|
const xAxisFormat = (() => {
|
|
4335
4476
|
switch (viewType) {
|
|
4336
4477
|
case 'daily':
|
|
4337
4478
|
return d3__namespace.timeFormat('%m-%d');
|
|
4338
4479
|
case 'weekly':
|
|
4339
|
-
return (d) => {
|
|
4340
|
-
const weekNum = getISOWeek(d);
|
|
4341
|
-
return `W${weekNum.toString().padStart(2, '0')}`;
|
|
4342
|
-
};
|
|
4480
|
+
return (d) => `W${getISOWeek(d).toString().padStart(2, '0')}`;
|
|
4343
4481
|
case 'monthly':
|
|
4344
4482
|
return d3__namespace.timeFormat('%b');
|
|
4345
4483
|
case 'quarterly':
|
|
4346
|
-
return (d) => {
|
|
4347
|
-
const quarter = Math.floor(d.getMonth() / 3) + 1;
|
|
4348
|
-
return `Q${quarter}`;
|
|
4349
|
-
};
|
|
4484
|
+
return (d) => `Q${Math.floor(d.getMonth() / 3) + 1}`;
|
|
4350
4485
|
default:
|
|
4351
4486
|
return d3__namespace.timeFormat('%m-%d');
|
|
4352
4487
|
}
|
|
4353
4488
|
})();
|
|
4354
|
-
// Determine number of ticks based on view type and data
|
|
4355
4489
|
const tickCount = (() => {
|
|
4356
4490
|
switch (viewType) {
|
|
4357
4491
|
case 'daily':
|
|
@@ -4361,47 +4495,278 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
|
|
|
4361
4495
|
case 'monthly':
|
|
4362
4496
|
return Math.min(12, aggregateData.dates.length);
|
|
4363
4497
|
case 'quarterly':
|
|
4364
|
-
return aggregateData.dates.length;
|
|
4498
|
+
return aggregateData.dates.length;
|
|
4365
4499
|
default:
|
|
4366
4500
|
return undefined;
|
|
4367
4501
|
}
|
|
4368
4502
|
})();
|
|
4369
4503
|
const xAxisGenerator = d3__namespace.axisBottom(xScale)
|
|
4370
4504
|
.tickFormat(d => xAxisFormat(d));
|
|
4371
|
-
// Set tick values for quarterly to avoid duplicates
|
|
4372
4505
|
if (viewType === 'quarterly') {
|
|
4373
4506
|
xAxisGenerator.tickValues(dates);
|
|
4374
4507
|
}
|
|
4375
4508
|
else if (tickCount) {
|
|
4376
4509
|
xAxisGenerator.ticks(tickCount);
|
|
4377
4510
|
}
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
.attr('
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4511
|
+
let xAxis = axesGroup.select('g.qhc-x-axis');
|
|
4512
|
+
if (xAxis.empty()) {
|
|
4513
|
+
xAxis = axesGroup.append('g').attr('class', `${styles$8.xAxis} qhc-x-axis`);
|
|
4514
|
+
}
|
|
4515
|
+
xAxis.attr('transform', `translate(0,${chartHeight})`).call(xAxisGenerator);
|
|
4516
|
+
xAxis.selectAll('text')
|
|
4517
|
+
.style('text-anchor', viewType === 'daily' || viewType === 'weekly' ? 'end' : 'middle')
|
|
4518
|
+
.attr('dx', viewType === 'daily' || viewType === 'weekly' ? '-.8em' : '0')
|
|
4519
|
+
.attr('dy', viewType === 'daily' || viewType === 'weekly' ? '.15em' : '.71em')
|
|
4520
|
+
.attr('transform', viewType === 'daily' || viewType === 'weekly' ? 'rotate(-45)' : null);
|
|
4521
|
+
let yAxis = axesGroup.select('g.qhc-y-axis');
|
|
4522
|
+
if (yAxis.empty()) {
|
|
4523
|
+
yAxis = axesGroup.append('g').attr('class', `${styles$8.yAxis} qhc-y-axis`);
|
|
4524
|
+
}
|
|
4525
|
+
yAxis.call(d3__namespace.axisLeft(yScale));
|
|
4526
|
+
if (isFirstRender) {
|
|
4527
|
+
xAxis.style('opacity', 0).transition().duration(500).delay(80).style('opacity', 1);
|
|
4528
|
+
yAxis.style('opacity', 0).transition().duration(500).delay(80).style('opacity', 1);
|
|
4529
|
+
}
|
|
4530
|
+
// -------- Lines (data join, morph on update) --------
|
|
4531
|
+
const lineData = activeHabits.map(habit => {
|
|
4532
|
+
const points = dates
|
|
4533
|
+
.map((date, i) => [date, aggregateData[habit][i]])
|
|
4534
|
+
.filter(d => typeof d[1] === 'number');
|
|
4535
|
+
return { habit, color: getColor(habit), points };
|
|
4536
|
+
});
|
|
4537
|
+
const lineSel = linesGroup.selectAll('path.qhc-line')
|
|
4538
|
+
.data(lineData, (d) => d.habit);
|
|
4539
|
+
lineSel.exit()
|
|
4540
|
+
.transition('line-exit')
|
|
4541
|
+
.duration(300)
|
|
4542
|
+
.style('opacity', 0)
|
|
4543
|
+
.remove();
|
|
4544
|
+
const lineEnter = lineSel.enter().append('path')
|
|
4545
|
+
.attr('class', `${styles$8.line} qhc-line`)
|
|
4546
|
+
.attr('data-habit', d => d.habit)
|
|
4547
|
+
.attr('fill', 'none')
|
|
4548
|
+
.attr('stroke', d => d.color)
|
|
4549
|
+
.attr('opacity', 0)
|
|
4550
|
+
.attr('d', d => lineGen(d.points) || '')
|
|
4551
|
+
.each(function () {
|
|
4552
|
+
const node = this;
|
|
4553
|
+
const len = typeof node.getTotalLength === 'function' ? node.getTotalLength() : 0;
|
|
4554
|
+
if (len > 0) {
|
|
4555
|
+
d3__namespace.select(node)
|
|
4556
|
+
.attr('stroke-dasharray', `${len} ${len}`)
|
|
4557
|
+
.attr('stroke-dashoffset', len);
|
|
4558
|
+
}
|
|
4559
|
+
});
|
|
4560
|
+
lineEnter.transition('line-enter')
|
|
4561
|
+
.duration(900)
|
|
4562
|
+
.ease(d3__namespace.easeCubicOut)
|
|
4563
|
+
.attr('opacity', 1)
|
|
4564
|
+
.attr('stroke-dashoffset', 0)
|
|
4565
|
+
.on('end', function () {
|
|
4566
|
+
d3__namespace.select(this).attr('stroke-dasharray', null);
|
|
4567
|
+
});
|
|
4568
|
+
lineSel.transition('line-update')
|
|
4569
|
+
.duration(700)
|
|
4570
|
+
.ease(d3__namespace.easeCubicInOut)
|
|
4571
|
+
.attr('stroke', d => d.color)
|
|
4572
|
+
.attrTween('d', function (d) {
|
|
4573
|
+
const oldD = d3__namespace.select(this).attr('d') || '';
|
|
4574
|
+
const newD = lineGen(d.points) || '';
|
|
4575
|
+
return pathTween(oldD, newD, 90);
|
|
4576
|
+
})
|
|
4577
|
+
.on('end', function (d) {
|
|
4578
|
+
d3__namespace.select(this).attr('d', lineGen(d.points) || '');
|
|
4579
|
+
});
|
|
4580
|
+
// -------- Points --------
|
|
4581
|
+
// Clear and re-add (simpler than join when both habit set + count change).
|
|
4582
|
+
// Hide them during line morph, then spring up from baseline.
|
|
4583
|
+
pointsGroup.selectAll('*').remove();
|
|
4584
|
+
const allPoints = [];
|
|
4585
|
+
activeHabits.forEach(habit => {
|
|
4586
|
+
const color = getColor(habit);
|
|
4587
|
+
dates.forEach((date, i) => {
|
|
4588
|
+
const v = aggregateData[habit][i];
|
|
4589
|
+
if (typeof v === 'number' && !isNaN(v)) {
|
|
4590
|
+
allPoints.push({ habit, color, date, value: v });
|
|
4591
|
+
}
|
|
4592
|
+
});
|
|
4593
|
+
});
|
|
4594
|
+
const minX = xScale(dates[0]);
|
|
4595
|
+
const maxX = xScale(dates[dates.length - 1]);
|
|
4596
|
+
const xRange = Math.max(1, maxX - minX);
|
|
4597
|
+
const pointAppearDelay = isFirstRender ? 100 : 350;
|
|
4598
|
+
const pointAppearTotal = isFirstRender ? 1100 : 600;
|
|
4599
|
+
pointsGroup.selectAll('circle.qhc-point')
|
|
4600
|
+
.data(allPoints)
|
|
4601
|
+
.enter().append('circle')
|
|
4602
|
+
.attr('class', `${styles$8.dataPoint} qhc-point`)
|
|
4603
|
+
.attr('data-habit', d => d.habit)
|
|
4604
|
+
.attr('cx', d => xScale(d.date))
|
|
4605
|
+
.attr('cy', chartHeight)
|
|
4606
|
+
.attr('r', 0)
|
|
4607
|
+
.attr('fill', d => d.color)
|
|
4608
|
+
.style('opacity', 0)
|
|
4609
|
+
.transition('point-enter')
|
|
4610
|
+
.delay(d => pointAppearDelay + pointAppearTotal * ((xScale(d.date) - minX) / xRange))
|
|
4611
|
+
.duration(420)
|
|
4612
|
+
.ease(d3__namespace.easeBackOut.overshoot(2))
|
|
4613
|
+
.attr('cy', d => yScale(d.value))
|
|
4614
|
+
.attr('r', 4)
|
|
4615
|
+
.style('opacity', 1);
|
|
4616
|
+
// -------- UI layer (crosshair, halo, overlay) --------
|
|
4617
|
+
uiGroup.selectAll('*').remove();
|
|
4618
|
+
const crosshair = uiGroup.append('line')
|
|
4619
|
+
.attr('class', styles$8.crosshair)
|
|
4620
|
+
.attr('y1', 0)
|
|
4621
|
+
.attr('y2', chartHeight)
|
|
4622
|
+
.style('opacity', 0)
|
|
4623
|
+
.style('pointer-events', 'none');
|
|
4624
|
+
const halo = uiGroup.append('circle')
|
|
4625
|
+
.attr('class', styles$8.halo)
|
|
4626
|
+
.attr('r', 0)
|
|
4627
|
+
.style('opacity', 0)
|
|
4628
|
+
.style('pointer-events', 'none');
|
|
4629
|
+
let activeKey = null;
|
|
4630
|
+
const startHaloPulse = (cx, cy, fill) => {
|
|
4631
|
+
halo.interrupt('halo-pulse').interrupt('halo-out')
|
|
4632
|
+
.attr('cx', cx).attr('cy', cy).attr('fill', fill);
|
|
4633
|
+
const pulseOnce = () => {
|
|
4634
|
+
halo.attr('r', 4).style('opacity', 0.55)
|
|
4635
|
+
.transition('halo-pulse').duration(900).ease(d3__namespace.easeCubicOut)
|
|
4636
|
+
.attr('r', 18).style('opacity', 0)
|
|
4637
|
+
.on('end', pulseOnce);
|
|
4638
|
+
};
|
|
4639
|
+
pulseOnce();
|
|
4640
|
+
};
|
|
4641
|
+
const stopHaloPulse = () => {
|
|
4642
|
+
halo.interrupt('halo-pulse')
|
|
4643
|
+
.transition('halo-out').duration(180)
|
|
4644
|
+
.style('opacity', 0).attr('r', 0);
|
|
4645
|
+
};
|
|
4646
|
+
const activeAll = allPoints.map(p => ({
|
|
4647
|
+
habit: p.habit,
|
|
4648
|
+
date: p.date,
|
|
4649
|
+
value: p.value,
|
|
4650
|
+
x: xScale(p.date),
|
|
4651
|
+
y: yScale(p.value)
|
|
4652
|
+
}));
|
|
4653
|
+
const setActive = (pt, clientX, clientY) => {
|
|
4654
|
+
const key = `${pt.habit}|${pt.date.toISOString()}`;
|
|
4655
|
+
const color = getColor(pt.habit);
|
|
4656
|
+
crosshair.attr('x1', pt.x).attr('x2', pt.x)
|
|
4657
|
+
.interrupt('crosshair-fade')
|
|
4658
|
+
.transition('crosshair-fade').duration(120).style('opacity', 1);
|
|
4659
|
+
if (activeKey !== key) {
|
|
4660
|
+
pointsGroup.selectAll('circle.qhc-point')
|
|
4661
|
+
.filter(function () { return d3__namespace.select(this).attr('data-active') === 'true'; })
|
|
4662
|
+
.attr('data-active', null)
|
|
4663
|
+
.transition('point-scale').duration(150).attr('r', 4);
|
|
4664
|
+
pointsGroup.selectAll('circle.qhc-point')
|
|
4665
|
+
.filter(function () {
|
|
4666
|
+
const cx = +d3__namespace.select(this).attr('cx');
|
|
4667
|
+
const cy = +d3__namespace.select(this).attr('cy');
|
|
4668
|
+
const habit = d3__namespace.select(this).attr('data-habit');
|
|
4669
|
+
return habit === pt.habit && Math.abs(cx - pt.x) < 0.5 && Math.abs(cy - pt.y) < 0.5;
|
|
4670
|
+
})
|
|
4671
|
+
.attr('data-active', 'true')
|
|
4672
|
+
.transition('point-scale').duration(180).ease(d3__namespace.easeBackOut.overshoot(2))
|
|
4673
|
+
.attr('r', 7);
|
|
4674
|
+
startHaloPulse(pt.x, pt.y, color);
|
|
4675
|
+
activeKey = key;
|
|
4676
|
+
}
|
|
4677
|
+
setTooltipData({
|
|
4678
|
+
habit: pt.habit,
|
|
4679
|
+
date: pt.date.toISOString().split('T')[0],
|
|
4680
|
+
value: pt.value,
|
|
4681
|
+
x: clientX,
|
|
4682
|
+
y: clientY
|
|
4683
|
+
});
|
|
4684
|
+
};
|
|
4685
|
+
const clearActive = () => {
|
|
4686
|
+
crosshair.interrupt('crosshair-fade')
|
|
4687
|
+
.transition('crosshair-fade').duration(180).style('opacity', 0);
|
|
4688
|
+
pointsGroup.selectAll('circle.qhc-point')
|
|
4689
|
+
.filter(function () { return d3__namespace.select(this).attr('data-active') === 'true'; })
|
|
4690
|
+
.attr('data-active', null)
|
|
4691
|
+
.transition('point-scale').duration(180).attr('r', 4);
|
|
4692
|
+
stopHaloPulse();
|
|
4693
|
+
activeKey = null;
|
|
4694
|
+
setTooltipData(null);
|
|
4695
|
+
};
|
|
4696
|
+
uiGroup.append('rect')
|
|
4697
|
+
.attr('class', styles$8.overlay)
|
|
4698
|
+
.attr('width', chartWidth)
|
|
4699
|
+
.attr('height', chartHeight)
|
|
4700
|
+
.on('mousemove', function (event) {
|
|
4701
|
+
if (activeAll.length === 0)
|
|
4702
|
+
return;
|
|
4703
|
+
const [mx, my] = d3__namespace.pointer(event, this);
|
|
4704
|
+
let nearest = activeAll[0];
|
|
4705
|
+
let nearestDist = Infinity;
|
|
4706
|
+
for (const p of activeAll) {
|
|
4707
|
+
const dx = p.x - mx;
|
|
4708
|
+
const dy = p.y - my;
|
|
4709
|
+
const dist = dx * dx + dy * dy;
|
|
4710
|
+
if (dist < nearestDist) {
|
|
4711
|
+
nearestDist = dist;
|
|
4712
|
+
nearest = p;
|
|
4713
|
+
}
|
|
4714
|
+
}
|
|
4715
|
+
setActive(nearest, event.clientX, event.clientY);
|
|
4716
|
+
})
|
|
4717
|
+
.on('mouseleave', () => {
|
|
4718
|
+
clearActive();
|
|
4719
|
+
})
|
|
4720
|
+
.on('click', function (event) {
|
|
4721
|
+
if (activeAll.length === 0 || !onClickRef.current)
|
|
4722
|
+
return;
|
|
4723
|
+
const [mx, my] = d3__namespace.pointer(event, this);
|
|
4724
|
+
let nearest = activeAll[0];
|
|
4725
|
+
let nearestDist = Infinity;
|
|
4726
|
+
for (const p of activeAll) {
|
|
4727
|
+
const dx = p.x - mx;
|
|
4728
|
+
const dy = p.y - my;
|
|
4729
|
+
const dist = dx * dx + dy * dy;
|
|
4730
|
+
if (dist < nearestDist) {
|
|
4731
|
+
nearestDist = dist;
|
|
4732
|
+
nearest = p;
|
|
4733
|
+
}
|
|
4734
|
+
}
|
|
4735
|
+
onClickRef.current(nearest.habit, nearest.date.toISOString().split('T')[0], nearest.value);
|
|
4736
|
+
});
|
|
4737
|
+
uiGroup.raise();
|
|
4738
|
+
}, [aggregateData, activeHabits, chartWidth, chartHeight, margin, getColor, viewType, width, height]);
|
|
4739
|
+
// Hover dimming: update opacity on existing elements without redrawing.
|
|
4740
|
+
React.useEffect(() => {
|
|
4741
|
+
if (!svgRef.current)
|
|
4742
|
+
return;
|
|
4743
|
+
const svg = d3__namespace.select(svgRef.current);
|
|
4744
|
+
svg.selectAll('path.qhc-line')
|
|
4745
|
+
.each(function () {
|
|
4746
|
+
const habit = this.getAttribute('data-habit');
|
|
4747
|
+
const dim = hoveredHabit && hoveredHabit !== habit;
|
|
4748
|
+
d3__namespace.select(this)
|
|
4749
|
+
.transition('hover-dim')
|
|
4750
|
+
.duration(180)
|
|
4751
|
+
.attr('opacity', dim ? 0.25 : 1);
|
|
4752
|
+
});
|
|
4753
|
+
svg.selectAll('circle.qhc-point')
|
|
4754
|
+
.each(function () {
|
|
4755
|
+
const habit = this.getAttribute('data-habit');
|
|
4756
|
+
const dim = hoveredHabit && hoveredHabit !== habit;
|
|
4757
|
+
d3__namespace.select(this)
|
|
4758
|
+
.transition('hover-dim')
|
|
4759
|
+
.duration(180)
|
|
4760
|
+
.attr('opacity', dim ? 0.25 : 1);
|
|
4761
|
+
});
|
|
4762
|
+
}, [hoveredHabit]);
|
|
4395
4763
|
const formatTooltipDate = (dateStr, viewType) => {
|
|
4396
4764
|
const date = new Date(dateStr);
|
|
4397
4765
|
switch (viewType) {
|
|
4398
4766
|
case 'daily':
|
|
4399
4767
|
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
|
|
4400
|
-
case 'weekly':
|
|
4401
|
-
const weekEnd = new Date(date);
|
|
4402
|
-
weekEnd.setDate(date.getDate() + 6);
|
|
4768
|
+
case 'weekly':
|
|
4403
4769
|
return `Week of ${date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}`;
|
|
4404
|
-
}
|
|
4405
4770
|
case 'monthly':
|
|
4406
4771
|
return date.toLocaleDateString('en-US', { month: 'long', year: 'numeric' });
|
|
4407
4772
|
case 'quarterly': {
|
|
@@ -4412,7 +4777,6 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
|
|
|
4412
4777
|
return dateStr;
|
|
4413
4778
|
}
|
|
4414
4779
|
};
|
|
4415
|
-
// View type icons and labels
|
|
4416
4780
|
const viewTypeConfig = {
|
|
4417
4781
|
daily: { Icon: lucideReact.Calendar, label: 'Daily' },
|
|
4418
4782
|
weekly: { Icon: lucideReact.CalendarDays, label: 'Weekly' },
|