@metricinsights/pp-dev 1.5.0-beta.1 → 1.5.0-beta.11
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/README.md +11 -5
- package/dist/README.md +11 -5
- package/dist/cjs/cli.js +1 -1
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/index-DZYClNrq.js +2 -0
- package/dist/cjs/index-DZYClNrq.js.map +1 -0
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/{migrate-pmX6NEmP.js → migrate-CWaA9822.js} +2 -2
- package/dist/cjs/{migrate-pmX6NEmP.js.map → migrate-CWaA9822.js.map} +1 -1
- package/dist/cjs/package.json +8 -8
- package/dist/cjs/plugin-C9wKTJUJ.js +106 -0
- package/dist/cjs/plugin-C9wKTJUJ.js.map +1 -0
- package/dist/cjs/plugin.js +1 -1
- package/dist/cjs/{version-plugin-0EjcUgtP.js → version-plugin-BYlQIq9P.js} +2 -2
- package/dist/cjs/{version-plugin-0EjcUgtP.js.map → version-plugin-BYlQIq9P.js.map} +1 -1
- package/dist/client/client.css +1 -1
- package/dist/client/client.css.map +1 -1
- package/dist/client/client.js +208 -82
- package/dist/client/client.js.map +1 -1
- package/dist/esm/cli.js +1 -1
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/index-D-UQbBcq.js +2 -0
- package/dist/esm/index-D-UQbBcq.js.map +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/{migrate-Dsd7Aqx-.js → migrate-Brx9j28S.js} +2 -2
- package/dist/esm/{migrate-Dsd7Aqx-.js.map → migrate-Brx9j28S.js.map} +1 -1
- package/dist/esm/package.json +8 -8
- package/dist/esm/plugin-B936Mkft.js +106 -0
- package/dist/esm/plugin-B936Mkft.js.map +1 -0
- package/dist/esm/plugin.js +1 -1
- package/dist/esm/{version-plugin-pYbaqnAH.js → version-plugin-CA0tX4h3.js} +2 -2
- package/dist/esm/{version-plugin-pYbaqnAH.js.map → version-plugin-CA0tX4h3.js.map} +1 -1
- package/dist/types/index.d.ts +7 -0
- package/docs/features.md +9 -5
- package/package.json +16 -16
- package/dist/cjs/index-FgUi7Fqw.js +0 -2
- package/dist/cjs/index-FgUi7Fqw.js.map +0 -1
- package/dist/cjs/plugin-yWlSj5sK.js +0 -2
- package/dist/cjs/plugin-yWlSj5sK.js.map +0 -1
- package/dist/esm/index-BA9vecJD.js +0 -2
- package/dist/esm/index-BA9vecJD.js.map +0 -1
- package/dist/esm/plugin-CFtRWPwU.js +0 -2
- package/dist/esm/plugin-CFtRWPwU.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sourceRoot":"","sources":["client.scss"],"names":[],"mappings":"AA+FA,uBAtBI,sXA2BF,qDA3BE,sXA+BF,2CACE,eACA,SACA,WACA,YACA,6BACA,YACA,gDACA,uCACA,kBACA,aACA,sBACA,qBACA,QACA,aACA,gDACA,gBACA,eACA,uDACA,wBACA,UACA,sBACA,6DAEA,oDACE,wCACA,UAGF,mDACE,wCACA,UAGF,iDACE,aACA,uBACA,8BACA,QACA,UACA,aACA,WACA,sBACA,gBACA,cAEA,sDACE,aACA,mBACA,uBACA,WACA,YACA,cACA,sCAGF,sDACE,OACA,cACA,eACA,gBACA,iBACA,gBACA,sBAGF,uDACE,eACA,eACA,gBACA,aACA,mBACA,uBACA,UACA,SACA,gBACA,aACA,yBACA,kBACA,0BACA,cAEA,6DACE,oCAGF,qEACE,kDACA,mBAGF,2DACE,8BAKN,mDACE,iBACA,UACA,wBACA,gBACA,sBACA,YACA,+BACA,wBACA,eACA,gBACA,iBACA,gBACA,sBACA,qBAGF,oDACE,6DACA,mDAGF,mDACE,4DACA,kDAGF,iDACE,0DACA,gDAGF,oDACE,6DACA,mDAIF,iDACE,WACA,UACA,iBACA,uDAEA,mHAEE,yCAKN,yGAEE,eACA,QACA,eACA,aACA,mBACA,uBACA,iCACA,0BACA,kCAGF,6CACE,8BACA,kBACA,iCACA,gDACA,8CACA,gBAEA,mDACE,kBACA,eACA,gBACA,wCACA,oCACA,iCAGF,qDACE,aACA,qBACA,oCACA,eACA,gBAGF,qDACE,aACA,sBACA,QACA,oBAGF,iDACE,WACA,iBACA,kBACA,+BACA,eACA,gBACA,eACA,wBAEA,yDACE,oCACA,+BACA,4BAGF,0DACE,qCACA,kDAGF,uDACE,WAKN,uEAEE,eACA,eACA,mBACA,kBACA,OAxUY,KAyUZ,kBACA,YACA,QACA,gDACA,oCACA,sBACA,aACA,mBACA,gDACA,iBACA,0BACA,kCAMA,2EACE,oCACA,+BACA,eACA,gBACA,iBACA,iBACA,qBACA,uBACA,uBACA,sBACA,SACA,UACA,SACA,UACA,eACA,gBACA,mCACA,kCAGF,yFACE,aACA,mBACA,QAGF,yFACE,aACA,mBACA,kBACA,cAEA,yIACE,WACA,kBACA,QACA,QACA,2BACA,YACA,UACA,oCAEA,mMACE,sCAGF,+CAdF,yIAeI,sCAEA,qMACE,qCAKN,iHACE,eAGF,+GACE,gBAIJ,mFACE,aACA,mBACA,QACA,eACA,gBACA,iBAGF,qFACE,yCACA,gBAGF,qFACE,gBAGF,mFACE,uCACA,qBACA,0BACA,aACA,mBACA,QAEA,+FACE,uCACA,0BAQJ,yFACE,kDAGF,yFACE,kDAGF,mFACE,+CAGF,yFACE,kDAGF,uFACE,iDAGF,2EACE,uCACA,qBACA,sBACA,iBAEA,uFACE,qBAGF,gLAEE,UAIJ,qFACE,YACA,YACA,gBACA,eACA,aAGF,oLA/CE,gBAoDF,iGACE,aACA,mBACA,uBACA,cACA,WACA,YACA,YACA,kBACA,kBACA,yCACA,YACA,WACE,2CAGF,yGACE,oBACA,kBAGF,6GACE,UACA,oCAIJ,mGACE,aACA,mBACA,uBACA,WACA,YACA,YACA,kBACA,eACA,yCACA,wBAEA,2GACE,WACA,YACA,UACA,8BAGF,+GACE,uCACA,oCAEA,uHACE,wBAKN,2FACE,kBACA,gBACA,aACA,aACA,sBACA,SACA,gDACA,oCACA,kBACA,wCACA,eACA,eACA,mBACA,gBAEA,qJACE,eACA,gBACA,yCACA,yBACA,oBAGF,iJACE,aACA,mBACA,8BACA,SAGF,uJACE,gBACA,4BACA,WACA,YACA,8CACA,eACA,cAGF,+IACE,aACA,sCACA,QAGF,6IACE,WACA,YACA,oCACA,kBACA,eACA,kBACA,yBACA,iCAEA,2JACE,WACA,kBACA,WACA,WACA,kBACA,oDACA,qCAGF,+KACE,QACA,SAGF,iLACE,QACA,UAGF,qLACE,WACA,SAGF,uLACE,WACA,UAGF,yJACE,8CAGF,2JACE,8CAEA,yKACE,kDAKN,6IACE,aACA,QAGF,2IACE,gBACA,oCACA,kBACA,eACA,yBACA,eACA,iBACA,yCACA,WACE,+DAIF,uJACE,8CACA,uCAGF,yJACE,8CACA,kDACA,qCAGF,uKACE,mDACA,mBAIJ,2JACE,WACA,iBACA,mCACA,kBACA,eACA,gBACA,sCACA,qCAEA,uKACE,qCAIJ,qJACE,aACA,sBACA,QACA,iBACA,wCAGF,iJACE,aACA,sBACA,QAGF,yIACE,WACA,iBACA,kBACA,eACA,gBACA,kBACA,uCACA,mCACA,mCACA,WACE,gDAGF,qJACE,oCACA,+BAGF,qKACE,mDACA,mBAIJ,mJACE,eACA,iBACA,yCAEA,6JACE,sBACA,eAIJ,qJACE,sBACA,eACA,uCACA,eAEA,iKACE,0BAMN,6FACE,aACA,mBACA,uBACA,WACA,YACA,YACA,kBACA,eACA,yCACA,wBAEA,qGACE,WACA,YACA,cAGF,yGACE,uCACA,oCAKJ,mKACE,WACA,yBAEA,+KACE,yBAIJ,iIACE,YACA,6BACA,sBAEA,iLACE,eACA,iBACA,oCAEA,2LACE,cACA,eACA,yCAIJ,mLACE,aACA,sBACA,QACA,iBACA,gBAGF,iLACE,aACA,mBACA,QACA,gBACA,kBACA,oCAEA,uMACE,0BACA,sCAIJ,yLACE,gBACA,yBACA,WACA,YACA,SACA,cACA,8CACA,eAEA,2MACE,mBAIJ,iLACE,aACA,sBACA,YACA,OAGF,mLACE,eACA,gBACA,oCACA,gBACA,uBAGF,mLACE,eACA,iBACA,yCACA,gBACA,uBAGF,6MACE,sCAGF,uLACE,cACA,gBACA,oCACA,kBACA,yBACA,eACA,eACA,iBACA,uCAEA,mMACE,8CAGF,uMACE,8CACA,kDACA,qCAIJ,uLACE,cACA,WACA,YACA,UACA,YACA,kBACA,yBACA,eACA,eACA,iBACA,yCAEA,mMACE,sCACA,qCAIJ,qLACE,WACA,sBACA,gBACA,oCACA,kBACA,yBACA,eACA,oCAEA,iMACE,aACA,8CAIJ,sXAEE,eACA,iBACA,sCAGF,iMACE,yCAGF,mJACE,wBAIJ,2FACE,sBACA,aACA,mBACA,uBACA,WACA,YACA,YACA,eACA,kBACA,qCAEA,uGACE,oCACA,yCAGF,uGACE,WACA,YACA,oCACA,UACA,8BAIJ,qFACE,eAGE,+IACE,0CASJ,mHACE,MACA,OACA,wBACA,4CACA,2CAEA,iKACE,qBACA,OA6BA,iKACE,SAEA,6KACE,yBAIJ,iIACE,yCAEA,2LACE,uBAIJ,uOACE,wCACA,WACE,mFAGF,qPACE,WACA,kBACA,SACA,YACA,WACA,UAlER,qHACE,MACA,QACA,wBACA,6CACA,2CAEA,mKACE,qBACA,QAIA,mIACE,wCAEA,6LACE,yBAIJ,yOACE,uCACA,WACE,mFAIF,uPACE,WACA,kBACA,SACA,YACA,UACA,UAlCR,yHACE,SACA,OACA,wBACA,6CACA,wCAEA,uKACE,wBACA,OA6BA,uKACE,SAEA,mLACE,yBAIJ,uIACE,yCAEA,iMACE,uBAIJ,6OACE,wCACA,WACE,oFAGF,2PACE,WACA,kBACA,SACA,YACA,WACA,UAlER,2HACE,SACA,QACA,wBACA,8CACA,wCAEA,yKACE,wBACA,QAIA,yIACE,wCAEA,mMACE,yBAIJ,+OACE,uCACA,WACE,oFAIF,6PACE,WACA,kBACA,SACA,YACA,UACA,UAuCV,qHACE,eAGF,+FACE,gBACA,iBACA,gBAEA,mJACE,gBAIJ,+GACE,aAGF,iGACE,aACA,mBACA,uBACA,WACA,YACA,YACA,+BACA,kBACA,eACA,uCACA,wBACA,kBACA,gBAEA,iHACE,WACA,kBACA,MACA,OACA,WACA,YACA,8BACA,UACA,4BACA,kBAGF,yGACE,WACA,YACA,kBACA,UACA,8BAGF,2IACE,uCACA,oCAEA,mJACE,mCACA,8BAKF,qJACE,mCAIJ,mHACE,WACA,mBACA,oBACA,yCAIA,yHACE,sCAKN,iFACE,oBACA,cACA,UACA,YACA,oCAEA,2IACE,sCAGF,+CAXF,iFAYI,sCAEA,6IACE,qCAKN,kBACE,KACE,uBAEF,GACE,0BAIJ,2FACE,iBAGF,6FACE,kBAGF,iGACE,+BACA,eACA,gBACA,sBACA,iBACA,oCAEA,yIACE,kDAIJ,oBACE,GACE,uBAEF,KACE,0BAIJ,sBACE,GACE,0BAEF,IACE,2BAEF,KACE,2BAOJ,iIAloCA,yXAOF,+KACE,sCACA,kCAEA,2LACE,sCACA,kCAIJ,2LACE,uCAunCA,+CA94BF,uEA3PE,yXAOF,qHACE,sCACA,kCAEA,iIACE,sCACA,kCAIJ,iIACE,wCA6nCF,uCACE,gKAIE","file":"client.css","sourcesContent":["@use 'sass:map';\n\n$pp-dev-height: 32px;\n$pp-dev-peek: 4px;\n\n// Corner map: v/h — anchored edges; sx — horizontal slide direction for minimize/auto-hide\n// (1 → slides right, -1 → slides left); radius/shadow face the viewport center;\n// edge — hairline border on the exposed horizontal edge.\n$pp-dev-corners: (\n 'top-left': (\n v: top,\n h: left,\n sx: -1,\n radius: 0 0 4px 0,\n shadow: 2px 2px 8px 0 rgba(34, 34, 34, 0.08),\n edge: border-bottom,\n ),\n 'top-right': (\n v: top,\n h: right,\n sx: 1,\n radius: 0 0 0 4px,\n shadow: -2px 2px 8px 0 rgba(34, 34, 34, 0.08),\n edge: border-bottom,\n ),\n 'bottom-left': (\n v: bottom,\n h: left,\n sx: -1,\n radius: 0 4px 0 0,\n shadow: 2px -2px 8px 0 rgba(34, 34, 34, 0.08),\n edge: border-top,\n ),\n 'bottom-right': (\n v: bottom,\n h: right,\n sx: 1,\n radius: 4px 0 0 0,\n shadow: -2px -2px 8px 0 rgba(34, 34, 34, 0.08),\n edge: border-top,\n ),\n);\n\n// Light/dark color maps, shared by the default (light) rules, the prefers-color-scheme:dark\n// media query (Auto), and the explicit data-pp-dev-theme override (Dark/Light picked in the\n// panel's settings popover — see src/client/theme.ts). One place to edit either palette.\n$pp-dev-light-colors: (\n primary: #075b7e,\n secondary: rgba(34, 34, 34, 0.64),\n success: #077e45,\n info: #17a2b8,\n warning: #ffb000,\n danger: #ac2b2b,\n light: #f8f9fa,\n dark: #343a40,\n 'white': #ffffff,\n 'black': #000000,\n);\n$pp-dev-dark-colors: (\n primary: #2a8db5,\n secondary: rgba(220, 220, 220, 0.64),\n success: #0fad5e,\n info: #2dccff,\n warning: #ffb302,\n danger: #e05252,\n light: #343a40,\n dark: #f8f9fa,\n 'white': #000000,\n 'black': #ffffff,\n);\n\n@mixin pp-dev-theme-colors($colors) {\n @each $name, $value in $colors {\n --pp-dev-info-color-#{$name}: #{$value};\n }\n}\n\n// rgba() literals don't follow the --pp-dev-info-color-primary reassignment above,\n// so the button fill/border are re-tinted here to match the dark-mode primary.\n@mixin pp-dev-dark-tints {\n .pp-dev-info__vars-btn {\n background-color: rgba(42, 141, 181, 0.14);\n border-color: rgba(42, 141, 181, 0.45);\n\n &:hover {\n background-color: rgba(42, 141, 181, 0.24);\n border-color: rgba(42, 141, 181, 0.65);\n }\n }\n\n .pp-dev-info__settings-group {\n border-top-color: rgba(255, 255, 255, 0.15);\n }\n}\n\n.pp-dev-info-namespace {\n // Define theme colors — light by default; overridden for Auto (media query, below) or an\n // explicit Dark/Light pick (html[data-pp-dev-theme], below — always wins on specificity).\n @include pp-dev-theme-colors($pp-dev-light-colors);\n\n html[data-pp-dev-theme='light'] & {\n @include pp-dev-theme-colors($pp-dev-light-colors);\n }\n\n .pp-dev-info__popup {\n position: fixed;\n top: 10px;\n right: 10px;\n width: 280px;\n max-width: calc(100vw - 20px);\n height: auto;\n background-color: var(--pp-dev-info-color-white);\n box-shadow: 0 2px 4px rgba(34, 34, 34, 0.2);\n border-radius: 2px;\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: 4px;\n padding: 12px;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n z-index: 100001;\n border-left: 2px solid var(--pp-dev-info-color-primary);\n transform: translateX(0);\n opacity: 1;\n box-sizing: border-box;\n --pp-dev-info-popup-accent: var(--pp-dev-info-color-primary);\n\n &.entering {\n transform: translateX(calc(100% + 10px));\n opacity: 0;\n }\n\n &.exiting {\n transform: translateX(calc(100% + 10px));\n opacity: 0;\n }\n\n &-title {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 8px;\n padding: 0;\n min-height: 0;\n width: 100%;\n box-sizing: border-box;\n border-bottom: 0;\n color: #040404;\n\n &-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n flex-shrink: 0;\n color: var(--pp-dev-info-popup-accent);\n }\n\n &-text {\n flex: 1;\n color: #040404;\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n text-align: left;\n word-break: break-word;\n }\n\n &-close {\n cursor: pointer;\n min-width: 24px;\n min-height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 0;\n background: none;\n font: inherit;\n color: rgba(34, 34, 34, 0.64);\n border-radius: 2px;\n transition: color 0.2s ease;\n flex-shrink: 0;\n\n &:hover {\n color: var(--pp-dev-info-color-dark);\n }\n\n &:focus-visible {\n outline: 2px solid var(--pp-dev-info-popup-accent);\n outline-offset: 1px;\n }\n\n svg {\n transition: transform 0.2s ease;\n }\n }\n }\n\n &-content {\n margin-left: 24px;\n padding: 0;\n width: calc(100% - 24px);\n overflow-y: auto;\n box-sizing: border-box;\n flex-grow: 0;\n background-color: transparent;\n color: rgba(34, 34, 34, 0.8);\n font-size: 12px;\n font-weight: 400;\n line-height: 18px;\n text-align: left;\n word-break: break-word;\n white-space: pre-line;\n }\n\n &--success {\n --pp-dev-info-popup-accent: var(--pp-dev-info-color-success);\n border-left-color: var(--pp-dev-info-color-success);\n }\n\n &--danger {\n --pp-dev-info-popup-accent: var(--pp-dev-info-color-danger);\n border-left-color: var(--pp-dev-info-color-danger);\n }\n\n &--info {\n --pp-dev-info-popup-accent: var(--pp-dev-info-color-info);\n border-left-color: var(--pp-dev-info-color-info);\n }\n\n &--warning {\n --pp-dev-info-popup-accent: var(--pp-dev-info-color-warning);\n border-left-color: var(--pp-dev-info-color-warning);\n }\n\n // Popups anchored to the left screen edge (panel in a left corner)\n &--left {\n right: auto;\n left: 10px;\n border-left: none;\n border-right: 2px solid var(--pp-dev-info-popup-accent);\n\n &.entering,\n &.exiting {\n transform: translateX(calc(-100% - 10px));\n }\n }\n }\n\n &.pp-dev-info__confirm-overlay,\n .pp-dev-info__confirm-overlay {\n position: fixed;\n inset: 0;\n z-index: 100003;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(0, 0, 0, 0.35);\n backdrop-filter: blur(2px);\n -webkit-backdrop-filter: blur(2px);\n }\n\n .pp-dev-info__confirm {\n width: min(408px, calc(100vw - 32px));\n border-radius: 3px;\n border: 1px solid rgba(0, 0, 0, 0.15);\n background-color: var(--pp-dev-info-color-white);\n box-shadow: 0px 8px 32px 0px rgba(34, 34, 34, 0.4);\n overflow: hidden;\n\n &-title {\n padding: 14px 16px;\n font-size: 15px;\n font-weight: 600;\n border-bottom: 1px solid rgba(0, 0, 0, 0.08);\n color: var(--pp-dev-info-color-dark);\n background-color: rgba(0, 0, 0, 0.03);\n }\n\n &-content {\n padding: 16px;\n white-space: pre-wrap;\n color: var(--pp-dev-info-color-dark);\n font-size: 13px;\n line-height: 1.5;\n }\n\n &-actions {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 0 16px 16px;\n }\n\n &-btn {\n width: 100%;\n padding: 8px 12px;\n border-radius: 6px;\n border: 1px solid transparent;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n\n &--cancel {\n color: var(--pp-dev-info-color-dark);\n background-color: transparent;\n border-color: rgba(0, 0, 0, 0.2);\n }\n\n &--confirm {\n color: var(--pp-dev-info-color-white);\n background-color: var(--pp-dev-info-color-primary);\n }\n\n &:hover {\n opacity: 0.9;\n }\n }\n }\n\n &.pp-dev-info,\n .pp-dev-info {\n position: fixed;\n z-index: 100000;\n white-space: nowrap;\n width: fit-content;\n height: $pp-dev-height;\n text-align: center;\n padding: 2px;\n gap: 8px;\n background-color: var(--pp-dev-info-color-white);\n color: var(--pp-dev-info-color-dark);\n box-sizing: border-box;\n display: flex;\n align-items: center;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: visible;\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n\n // Setup default values for styles that can be overlapped by other page styles\n // (e.g. color, font-family, font-size etc.)\n // This is needed to make sure that the extension styles are not overlapped by the page styles\n // and the extension is still usable\n * {\n color: var(--pp-dev-info-color-dark);\n font-family: 'Inter', sans-serif;\n font-size: 12px;\n font-weight: 400;\n line-height: 18px;\n letter-spacing: 0;\n text-decoration: none;\n text-transform: inherit;\n vertical-align: inherit;\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n border: 0;\n outline: 0;\n background: 0 0;\n list-style: none;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n &__content {\n display: flex;\n align-items: center;\n gap: 0px;\n }\n\n &__section {\n display: flex;\n align-items: center;\n position: relative;\n padding: 0 8px;\n\n &:not(:last-child)::after {\n content: '';\n position: absolute;\n right: 0;\n top: 50%;\n transform: translateY(-50%);\n height: 16px;\n width: 1px;\n background-color: rgba(34, 34, 34, 0.24);\n\n html[data-pp-dev-theme='dark'] & {\n background-color: rgba(255, 255, 255, 0.2);\n }\n\n @media screen and (prefers-color-scheme: dark) {\n background-color: rgba(255, 255, 255, 0.2);\n\n html[data-pp-dev-theme='light'] & {\n background-color: rgba(34, 34, 34, 0.24);\n }\n }\n }\n\n &:first-child {\n padding-left: 0;\n }\n\n &:last-child {\n padding-right: 0;\n }\n }\n\n &__item {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n font-weight: 400;\n line-height: 18px;\n }\n\n &__label {\n color: var(--pp-dev-info-color-secondary);\n font-weight: 400;\n }\n\n &__value {\n font-weight: 600;\n }\n\n &__link {\n color: var(--pp-dev-info-color-primary);\n text-decoration: none;\n transition: color 0.2s ease;\n display: flex;\n align-items: center;\n gap: 8px;\n\n &:hover {\n color: var(--pp-dev-info-color-primary);\n text-decoration: underline;\n }\n }\n\n @mixin bold {\n font-weight: 700;\n }\n\n .primary {\n color: var(--pp-dev-info-color-primary) !important;\n }\n\n .success {\n color: var(--pp-dev-info-color-success) !important;\n }\n\n .info {\n color: var(--pp-dev-info-color-info) !important;\n }\n\n .warning {\n color: var(--pp-dev-info-color-warning) !important;\n }\n\n .danger {\n color: var(--pp-dev-info-color-danger) !important;\n }\n\n a {\n color: var(--pp-dev-info-color-primary);\n text-decoration: none;\n vertical-align: middle;\n line-height: 18px;\n\n &:hover {\n text-decoration: none;\n }\n\n &:active,\n &:hover {\n outline: 0;\n }\n }\n\n button {\n padding: 1px;\n border: none;\n background: none;\n cursor: pointer;\n outline: none;\n }\n\n .bold,\n .status-text {\n @include bold;\n }\n\n &__drag-handle {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 14px;\n height: 28px;\n cursor: grab;\n touch-action: none;\n border-radius: 3px;\n color: var(--pp-dev-info-color-secondary);\n opacity: 0.55;\n transition:\n opacity 0.2s ease,\n background-color 0.2s ease;\n\n svg {\n pointer-events: none;\n fill: currentColor;\n }\n\n &:hover {\n opacity: 1;\n background-color: rgba(7, 91, 126, 0.06);\n }\n }\n\n &__settings-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 6px;\n border-radius: 3px;\n cursor: pointer;\n color: var(--pp-dev-info-color-secondary);\n transition: all 0.2s ease;\n\n svg {\n width: 16px;\n height: 16px;\n fill: none;\n transition: transform 0.3s ease;\n }\n\n &:hover {\n color: var(--pp-dev-info-color-primary);\n background-color: rgba(7, 91, 126, 0.06);\n\n svg {\n transform: rotate(45deg);\n }\n }\n }\n\n &__settings {\n position: absolute;\n min-width: 216px;\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n background-color: var(--pp-dev-info-color-white);\n border: 1px solid rgba(34, 34, 34, 0.15);\n border-radius: 3px;\n box-shadow: 0 4px 16px rgba(34, 34, 34, 0.2);\n z-index: 100002;\n cursor: default;\n white-space: normal;\n text-align: left;\n\n .pp-dev-info__settings-title {\n font-size: 10px;\n font-weight: 600;\n color: var(--pp-dev-info-color-secondary);\n text-transform: uppercase;\n letter-spacing: 0.4px;\n }\n\n .pp-dev-info__settings-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n }\n\n .pp-dev-info__settings-toggle {\n appearance: auto;\n -webkit-appearance: checkbox;\n width: 14px;\n height: 14px;\n accent-color: var(--pp-dev-info-color-primary);\n cursor: pointer;\n flex-shrink: 0;\n }\n\n .pp-dev-info__corner-grid {\n display: grid;\n grid-template-columns: repeat(2, 30px);\n gap: 4px;\n }\n\n .pp-dev-info__corner-btn {\n width: 30px;\n height: 22px;\n border: 1px solid rgba(34, 34, 34, 0.25);\n border-radius: 3px;\n cursor: pointer;\n position: relative;\n background: transparent;\n transition: border-color 0.2s ease;\n\n &::after {\n content: '';\n position: absolute;\n width: 10px;\n height: 6px;\n border-radius: 1px;\n background-color: var(--pp-dev-info-color-secondary);\n transition: background-color 0.2s ease;\n }\n\n &--top-left::after {\n top: 2px;\n left: 2px;\n }\n\n &--top-right::after {\n top: 2px;\n right: 2px;\n }\n\n &--bottom-left::after {\n bottom: 2px;\n left: 2px;\n }\n\n &--bottom-right::after {\n bottom: 2px;\n right: 2px;\n }\n\n &:hover {\n border-color: var(--pp-dev-info-color-primary);\n }\n\n &.active {\n border-color: var(--pp-dev-info-color-primary);\n\n &::after {\n background-color: var(--pp-dev-info-color-primary);\n }\n }\n }\n\n .pp-dev-info__theme-grid {\n display: flex;\n gap: 4px;\n }\n\n .pp-dev-info__theme-btn {\n padding: 3px 8px;\n border: 1px solid rgba(34, 34, 34, 0.25);\n border-radius: 3px;\n cursor: pointer;\n background: transparent;\n font-size: 11px;\n line-height: 16px;\n color: var(--pp-dev-info-color-secondary);\n transition:\n border-color 0.2s ease,\n color 0.2s ease,\n background-color 0.2s ease;\n\n &:hover {\n border-color: var(--pp-dev-info-color-primary);\n color: var(--pp-dev-info-color-primary);\n }\n\n &.active {\n border-color: var(--pp-dev-info-color-primary);\n background-color: var(--pp-dev-info-color-primary);\n color: var(--pp-dev-info-color-white);\n }\n\n &:focus-visible {\n outline: 2px solid var(--pp-dev-info-color-primary);\n outline-offset: 1px;\n }\n }\n\n .pp-dev-info__settings-hide-btn {\n width: 100%;\n padding: 6px 10px;\n border: 1px solid rgba(34, 34, 34, 0.2);\n border-radius: 4px;\n cursor: pointer;\n font-weight: 600;\n color: var(--pp-dev-info-color-danger);\n transition: background-color 0.2s ease;\n\n &:hover {\n background-color: rgba(172, 43, 43, 0.06);\n }\n }\n\n .pp-dev-info__settings-group {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding-top: 10px;\n border-top: 1px solid rgba(34, 34, 34, 0.12);\n }\n\n .pp-dev-info__vars-buttons {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .pp-dev-info__vars-btn {\n width: 100%;\n padding: 6px 10px;\n border-radius: 4px;\n cursor: pointer;\n font-weight: 600;\n text-align: center;\n color: var(--pp-dev-info-color-primary);\n background-color: rgba(7, 91, 126, 0.1);\n border: 1px solid rgba(7, 91, 126, 0.4);\n transition:\n background-color 0.2s ease,\n border-color 0.2s ease;\n\n &:hover {\n background-color: rgba(7, 91, 126, 0.18);\n border-color: rgba(7, 91, 126, 0.6);\n }\n\n &:focus-visible {\n outline: 2px solid var(--pp-dev-info-color-primary);\n outline-offset: 1px;\n }\n }\n\n .pp-dev-info__settings-hint {\n font-size: 10px;\n line-height: 14px;\n color: var(--pp-dev-info-color-secondary);\n\n code {\n font-family: monospace;\n font-size: 10px;\n }\n }\n\n .pp-dev-info__settings-reset {\n align-self: flex-start;\n font-size: 11px;\n color: var(--pp-dev-info-color-primary);\n cursor: pointer;\n\n &:hover {\n text-decoration: underline;\n }\n }\n }\n\n // ── Users (PP-4597) ──────────────────────────────────────────────────────\n &__users-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 6px;\n border-radius: 3px;\n cursor: pointer;\n color: var(--pp-dev-info-color-secondary);\n transition: all 0.2s ease;\n\n svg {\n width: 16px;\n height: 16px;\n flex-shrink: 0;\n }\n\n &:hover {\n color: var(--pp-dev-info-color-primary);\n background-color: rgba(7, 91, 126, 0.06);\n }\n }\n\n // A saved user's tab: the button stands out, so the tab is never taken for your own.\n &.pp-dev-info--user-tab .pp-dev-info__users-btn {\n color: #ffffff;\n background-color: #7a3fb8;\n\n &:hover {\n background-color: #8d52cc;\n }\n }\n\n &__users.pp-dev-info__settings {\n width: 320px;\n max-width: calc(100vw - 16px);\n box-sizing: border-box;\n\n .pp-dev-info__users-tab {\n font-size: 12px;\n line-height: 16px;\n color: var(--pp-dev-info-color-dark);\n\n span {\n display: block;\n font-size: 10px;\n color: var(--pp-dev-info-color-secondary);\n }\n }\n\n .pp-dev-info__users-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n max-height: 240px;\n overflow-y: auto;\n }\n\n .pp-dev-info__users-row {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 5px 6px;\n border-radius: 3px;\n border-left: 2px solid transparent;\n\n &.is-current {\n border-left-color: #7a3fb8;\n background-color: rgba(122, 63, 184, 0.08);\n }\n }\n\n .pp-dev-info__users-default {\n appearance: auto;\n -webkit-appearance: radio;\n width: 13px;\n height: 13px;\n margin: 0;\n flex-shrink: 0;\n accent-color: var(--pp-dev-info-color-primary);\n cursor: pointer;\n\n &:disabled {\n cursor: not-allowed;\n }\n }\n\n .pp-dev-info__users-who {\n display: flex;\n flex-direction: column;\n min-width: 0;\n flex: 1;\n }\n\n .pp-dev-info__users-name {\n font-size: 12px;\n font-weight: 600;\n color: var(--pp-dev-info-color-dark);\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .pp-dev-info__users-meta {\n font-size: 10px;\n line-height: 13px;\n color: var(--pp-dev-info-color-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .needs-login .pp-dev-info__users-meta {\n color: var(--pp-dev-info-color-danger);\n }\n\n .pp-dev-info__users-action {\n flex-shrink: 0;\n padding: 2px 7px;\n border: 1px solid rgba(34, 34, 34, 0.25);\n border-radius: 3px;\n background: transparent;\n cursor: pointer;\n font-size: 11px;\n line-height: 16px;\n color: var(--pp-dev-info-color-primary);\n\n &:hover {\n border-color: var(--pp-dev-info-color-primary);\n }\n\n &--accent {\n border-color: var(--pp-dev-info-color-primary);\n background-color: var(--pp-dev-info-color-primary);\n color: var(--pp-dev-info-color-white);\n }\n }\n\n .pp-dev-info__users-remove {\n flex-shrink: 0;\n width: 20px;\n height: 20px;\n padding: 0;\n border: none;\n border-radius: 3px;\n background: transparent;\n cursor: pointer;\n font-size: 15px;\n line-height: 20px;\n color: var(--pp-dev-info-color-secondary);\n\n &:hover {\n color: var(--pp-dev-info-color-danger);\n background-color: rgba(172, 43, 43, 0.08);\n }\n }\n\n .pp-dev-info__users-input {\n width: 100%;\n box-sizing: border-box;\n padding: 5px 8px;\n border: 1px solid rgba(34, 34, 34, 0.25);\n border-radius: 3px;\n background: transparent;\n font-size: 12px;\n color: var(--pp-dev-info-color-dark);\n\n &:focus {\n outline: none;\n border-color: var(--pp-dev-info-color-primary);\n }\n }\n\n .pp-dev-info__users-error,\n .pp-dev-info__users-unavailable {\n font-size: 11px;\n line-height: 15px;\n color: var(--pp-dev-info-color-danger);\n }\n\n .pp-dev-info__users-unavailable {\n color: var(--pp-dev-info-color-secondary);\n }\n\n [hidden] {\n display: none !important;\n }\n }\n\n &__wrap-btn {\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 6px;\n cursor: pointer;\n border-radius: 3px;\n transition: background-color 0.2s ease;\n\n &:hover {\n background-color: rgba(7, 91, 126, 0.06);\n animation: arrowHover 0.8s linear infinite;\n }\n\n &-arrow {\n width: 16px;\n height: 16px;\n color: var(--pp-dev-info-color-dark);\n fill: none;\n transition: transform 0.2s ease;\n }\n }\n\n &.closed {\n z-index: 100002;\n\n & .pp-dev-info__wrap-btn {\n &:hover {\n animation: arrowHover 1.2s linear infinite;\n }\n }\n }\n\n // Corner variants: placement, center-facing radius/shadow, direction-aware\n // minimize (.closed) and auto-hide slides. The corner class is always rendered\n // on the panel root (server default: bottom-right).\n @each $name, $c in $pp-dev-corners {\n &.pp-dev-info--#{$name} {\n #{map.get($c, v)}: 0;\n #{map.get($c, h)}: 0;\n border-radius: map.get($c, radius);\n box-shadow: map.get($c, shadow);\n #{map.get($c, edge)}: 1px solid rgba(34, 34, 34, 0.08);\n\n .pp-dev-info__settings {\n #{map.get($c, v)}: calc(100% + 8px);\n #{map.get($c, h)}: 0;\n }\n\n @if map.get($c, sx) == 1 {\n &.closed {\n transform: translateX(calc(100% - $pp-dev-height));\n\n .pp-dev-info__wrap-btn-arrow {\n transform: rotate(180deg);\n }\n }\n\n &.pp-dev-info--auto-hide:not(.is-peeking):not(.is-dragging) {\n transform: translateX(calc(100% - $pp-dev-peek));\n box-shadow:\n map.get($c, shadow),\n inset $pp-dev-peek 0 0 0 var(--pp-dev-info-color-primary);\n\n // Extended invisible hover zone on the inner side of the 4px strip\n &::after {\n content: '';\n position: absolute;\n top: -6px;\n bottom: -6px;\n left: -8px;\n width: 8px;\n }\n }\n } @else {\n .pp-dev-info__wrap-btn {\n order: 99;\n\n &-arrow {\n transform: rotate(180deg);\n }\n }\n\n &.closed {\n transform: translateX(calc(-100% + $pp-dev-height));\n\n .pp-dev-info__wrap-btn-arrow {\n transform: rotate(0deg);\n }\n }\n\n &.pp-dev-info--auto-hide:not(.is-peeking):not(.is-dragging) {\n transform: translateX(calc(-100% + $pp-dev-peek));\n box-shadow:\n map.get($c, shadow),\n inset (-$pp-dev-peek) 0 0 0 var(--pp-dev-info-color-primary);\n\n &::after {\n content: '';\n position: absolute;\n top: -6px;\n bottom: -6px;\n right: -8px;\n width: 8px;\n }\n }\n }\n }\n }\n\n &.pp-dev-info--auto-hide {\n z-index: 100002;\n }\n\n &.is-dragging {\n transition: none;\n user-select: none;\n cursor: grabbing;\n\n .pp-dev-info__drag-handle {\n cursor: grabbing;\n }\n }\n\n &.pp-dev-info--hidden {\n display: none;\n }\n\n .sync-button {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 6px;\n background-color: transparent;\n border-radius: 3px;\n cursor: pointer;\n color: var(--pp-dev-info-color-primary);\n transition: all 0.2s ease;\n position: relative;\n overflow: hidden;\n\n &::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: currentColor;\n opacity: 0;\n transition: opacity 0.2s ease;\n border-radius: 3px;\n }\n\n svg {\n width: 16px;\n height: 16px;\n position: relative;\n z-index: 1;\n transition: transform 0.3s ease;\n }\n\n &:hover:not(.disabled) {\n color: var(--pp-dev-info-color-primary);\n background-color: rgba(7, 91, 126, 0.06);\n\n svg {\n transform: scale(1.1) rotate(45deg);\n transition: transform 0.2s ease;\n }\n }\n\n &:active:not(.disabled) {\n svg {\n transform: scale(0.9) rotate(45deg);\n }\n }\n\n &.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n color: var(--pp-dev-info-color-secondary);\n }\n\n &.syncing {\n svg {\n animation: rotate 1.5s linear infinite;\n }\n }\n }\n\n &__sep {\n display: inline-flex;\n flex-shrink: 0;\n width: 1px;\n height: 16px;\n background-color: rgba(34, 34, 34, 0.24);\n\n html[data-pp-dev-theme='dark'] & {\n background-color: rgba(255, 255, 255, 0.2);\n }\n\n @media screen and (prefers-color-scheme: dark) {\n background-color: rgba(255, 255, 255, 0.2);\n\n html[data-pp-dev-theme='light'] & {\n background-color: rgba(34, 34, 34, 0.24);\n }\n }\n }\n\n @keyframes rotate {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n }\n\n .margin-5 {\n margin-right: 5px;\n }\n\n .margin-10 {\n margin-right: 10px;\n }\n\n .custom-font {\n font-family: 'Inter', sans-serif;\n font-size: 13px;\n font-weight: 400;\n vertical-align: middle;\n line-height: 18px;\n color: var(--pp-dev-info-color-dark);\n\n &:not(.not-colored) a {\n color: var(--pp-dev-info-color-primary) !important;\n }\n }\n\n @keyframes rotation {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n }\n\n @keyframes arrowHover {\n 0% {\n transform: translateX(2px);\n }\n 50% {\n transform: translateX(-2px);\n }\n 100% {\n transform: translateX(2px);\n }\n }\n\n // Explicit Dark pick (html[data-pp-dev-theme='dark'], set via the settings popover's Theme\n // row — see src/client/theme.ts) — always wins over both the light default above and the\n // Auto media query below, on selector specificity alone.\n html[data-pp-dev-theme='dark'] & {\n @include pp-dev-theme-colors($pp-dev-dark-colors);\n @include pp-dev-dark-tints;\n }\n\n // Auto (OS/browser preference) — same values, only takes effect when no explicit\n // html[data-pp-dev-theme] override is set (those always outrank a plain :root/& selector).\n @media screen and (prefers-color-scheme: dark) {\n @include pp-dev-theme-colors($pp-dev-dark-colors);\n @include pp-dev-dark-tints;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n &.pp-dev-info,\n .pp-dev-info,\n .pp-dev-info__popup,\n .pp-dev-info__settings {\n transition: none;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sourceRoot":"","sources":["client.scss"],"names":[],"mappings":"AAqGA,uBAtBI,wcA2BF,qDA3BE,wcA+BF,2CACE,eACA,SACA,WACA,YACA,6BACA,YACA,gDACA,uCACA,kBACA,aACA,sBACA,qBACA,QACA,aACA,gDACA,gBACA,eACA,uDACA,wBACA,UACA,sBACA,6DAEA,oDACE,wCACA,UAGF,mDACE,wCACA,UAGF,iDACE,aACA,uBACA,8BACA,QACA,UACA,aACA,WACA,sBACA,gBACA,cAEA,sDACE,aACA,mBACA,uBACA,WACA,YACA,cACA,sCAGF,sDACE,OACA,cACA,eACA,gBACA,iBACA,gBACA,sBAGF,uDACE,eACA,eACA,gBACA,aACA,mBACA,uBACA,UACA,SACA,gBACA,aACA,yBACA,kBACA,0BACA,cAEA,6DACE,oCAGF,qEACE,kDACA,mBAGF,2DACE,8BAKN,mDACE,iBACA,UACA,wBACA,gBACA,sBACA,YACA,+BACA,wBACA,eACA,gBACA,iBACA,gBACA,sBACA,qBAGF,oDACE,6DACA,mDAGF,mDACE,4DACA,kDAGF,iDACE,0DACA,gDAGF,oDACE,6DACA,mDAIF,iDACE,WACA,UACA,iBACA,uDAEA,mHAEE,yCAKN,yGAEE,eACA,QACA,eACA,aACA,mBACA,uBACA,iCACA,0BACA,kCAGF,6CACE,8BACA,kBACA,iCACA,gDACA,8CACA,gBAEA,mDACE,kBACA,eACA,gBACA,wCACA,oCACA,iCAGF,qDACE,aACA,qBACA,oCACA,eACA,gBAGF,qDACE,aACA,sBACA,QACA,oBAGF,iDACE,WACA,iBACA,kBACA,+BACA,eACA,gBACA,eACA,wBAEA,yDACE,oCACA,+BACA,4BAGF,0DACE,qCACA,kDAGF,uDACE,WAKN,uEAEE,eACA,eACA,mBACA,kBACA,OA9UY,KA+UZ,kBACA,YACA,QACA,gDACA,oCACA,sBACA,aACA,mBACA,gDACA,iBACA,0BACA,kCAMA,2EACE,oCACA,+BACA,eACA,gBACA,iBACA,iBACA,qBACA,uBACA,uBACA,sBACA,SACA,UACA,SACA,UACA,eACA,gBACA,mCACA,kCAGF,yFACE,aACA,mBACA,QAGF,yFACE,aACA,mBACA,kBACA,cAEA,yIACE,WACA,kBACA,QACA,QACA,2BACA,YACA,UACA,oCAEA,mMACE,sCAGF,+CAdF,yIAeI,sCAEA,qMACE,qCAKN,iHACE,eAGF,+GACE,gBAIJ,mFACE,aACA,mBACA,QACA,eACA,gBACA,iBAGF,qFACE,yCACA,gBAGF,qFACE,gBAGF,mFACE,uCACA,qBACA,0BACA,aACA,mBACA,QAEA,+FACE,uCACA,0BAQJ,yFACE,kDAGF,yFACE,kDAGF,mFACE,+CAGF,yFACE,kDAGF,uFACE,iDAGF,2EACE,uCACA,qBACA,sBACA,iBAEA,uFACE,qBAGF,gLAEE,UAIJ,qFACE,YACA,YACA,gBACA,eACA,aAGF,oLA/CE,gBAoDF,iGACE,aACA,mBACA,uBACA,cACA,WACA,YACA,YACA,kBACA,kBACA,yCACA,YACA,WACE,2CAGF,yGACE,oBACA,kBAGF,6GACE,UACA,oCAIJ,mGACE,aACA,mBACA,uBACA,WACA,YACA,YACA,kBACA,eACA,yCACA,wBAEA,2GACE,WACA,YACA,UACA,8BAGF,+GACE,uCACA,oCAEA,uHACE,wBAKN,2FACE,kBACA,gBACA,aACA,aACA,sBACA,SACA,gDACA,oCACA,kBACA,wCACA,eACA,eACA,mBACA,gBAEA,qJACE,eACA,gBACA,yCACA,yBACA,oBAGF,iJACE,aACA,mBACA,8BACA,SAGF,uJACE,gBACA,4BACA,WACA,YACA,8CACA,eACA,cAGF,+IACE,aACA,sCACA,QAGF,6IACE,WACA,YACA,+CACA,kBACA,eACA,kBACA,yBACA,iCAEA,2JACE,WACA,kBACA,WACA,WACA,kBACA,oDACA,qCAGF,+KACE,QACA,SAGF,iLACE,QACA,UAGF,qLACE,WACA,SAGF,uLACE,WACA,UAGF,yJACE,8CAGF,2JACE,8CAEA,yKACE,kDAKN,6IACE,aACA,QAGF,2IACE,gBACA,+CACA,kBACA,eACA,yBACA,eACA,iBACA,yCACA,WACE,+DAIF,uJACE,8CACA,uCAGF,yJACE,8CACA,kDACA,qCAGF,uKACE,mDACA,mBAIJ,2JACE,WACA,iBACA,mCACA,kBACA,eACA,gBACA,sCACA,qCAEA,uKACE,qCAIJ,qJACE,aACA,sBACA,QACA,iBACA,wCAGF,iJACE,aACA,sBACA,QAGF,yIACE,WACA,iBACA,kBACA,eACA,gBACA,kBACA,uCACA,mCACA,mCACA,WACE,gDAGF,qJACE,oCACA,+BAGF,qKACE,mDACA,mBAIJ,mJACE,eACA,iBACA,yCAEA,6JACE,sBACA,eAIJ,qJACE,sBACA,eACA,uCACA,eAEA,iKACE,0BAMN,6FACE,aACA,mBACA,uBACA,WACA,YACA,YACA,kBACA,eACA,yCACA,wBAEA,qGACE,WACA,YACA,cAGF,yGACE,uCACA,oCAKJ,mKACE,WACA,yBAEA,+KACE,yBAIJ,iIACE,YACA,6BACA,sBAEA,iLACE,eACA,iBACA,oCAIF,6LACE,mBACA,iBACA,cACA,qBACA,yBACA,yCAGF,qLACE,gBACA,cACA,8BACA,kBACA,cACA,gBACA,iBACA,mBACA,mCAGF,mLACE,aACA,sBACA,QACA,iBACA,gBAGF,iLACE,aACA,mBACA,QACA,gBACA,kBACA,oCAEA,uMACE,0BACA,sCAIJ,yLACE,gBACA,yBACA,WACA,YACA,SACA,cACA,8CACA,eAEA,2MACE,mBAIJ,iLACE,aACA,sBACA,YACA,OAGF,mLACE,eACA,gBACA,oCACA,gBACA,uBAGF,mLACE,eACA,iBACA,yCACA,gBACA,uBAGF,6MACE,sCAGF,uLACE,cACA,gBACA,+CACA,kBACA,yBACA,eACA,eACA,iBACA,uCAEA,mMACE,8CAGF,uMACE,8CACA,kDACA,qCAKJ,mLACE,sBACA,oBACA,QACA,SAGF,mMACE,aACA,yBACA,QAGF,uLACE,cACA,WACA,YACA,UACA,YACA,kBACA,yBACA,eACA,eACA,iBACA,yCAEA,mMACE,sCACA,qCAIJ,qLACE,WACA,sBACA,gBACA,+CACA,kBACA,yBACA,eACA,oCAEA,iMACE,aACA,8CAIJ,sXAEE,eACA,iBACA,sCAGF,iMACE,yCAGF,mJACE,wBAIJ,2FACE,sBACA,aACA,mBACA,uBACA,WACA,YACA,YACA,eACA,kBACA,qCAEA,uGACE,oCACA,yCAGF,uGACE,WACA,YACA,oCACA,UACA,8BAIJ,qFACE,eAGE,+IACE,0CASJ,mHACE,MACA,OACA,wBACA,4CACA,2CAEA,iKACE,qBACA,OA6BA,iKACE,SAEA,6KACE,yBAIJ,iIACE,yCAEA,2LACE,uBAIJ,uOACE,wCACA,WACE,mFAGF,qPACE,WACA,kBACA,SACA,YACA,WACA,UAlER,qHACE,MACA,QACA,wBACA,6CACA,2CAEA,mKACE,qBACA,QAIA,mIACE,wCAEA,6LACE,yBAIJ,yOACE,uCACA,WACE,mFAIF,uPACE,WACA,kBACA,SACA,YACA,UACA,UAlCR,yHACE,SACA,OACA,wBACA,6CACA,wCAEA,uKACE,wBACA,OA6BA,uKACE,SAEA,mLACE,yBAIJ,uIACE,yCAEA,iMACE,uBAIJ,6OACE,wCACA,WACE,oFAGF,2PACE,WACA,kBACA,SACA,YACA,WACA,UAlER,2HACE,SACA,QACA,wBACA,8CACA,wCAEA,yKACE,wBACA,QAIA,yIACE,wCAEA,mMACE,yBAIJ,+OACE,uCACA,WACE,oFAIF,6PACE,WACA,kBACA,SACA,YACA,UACA,UAuCV,qHACE,eAGF,+FACE,gBACA,iBACA,gBAEA,mJACE,gBAIJ,+GACE,aAGF,iGACE,aACA,mBACA,uBACA,WACA,YACA,YACA,+BACA,kBACA,eACA,uCACA,wBACA,kBACA,gBAEA,iHACE,WACA,kBACA,MACA,OACA,WACA,YACA,8BACA,UACA,4BACA,kBAGF,yGACE,WACA,YACA,kBACA,UACA,8BAGF,2IACE,uCACA,oCAEA,mJACE,mCACA,8BAKF,qJACE,mCAIJ,mHACE,WACA,mBACA,oBACA,yCAIA,yHACE,sCAKN,iFACE,oBACA,cACA,UACA,YACA,oCAEA,2IACE,sCAGF,+CAXF,iFAYI,sCAEA,6IACE,qCAKN,kBACE,KACE,uBAEF,GACE,0BAIJ,2FACE,iBAGF,6FACE,kBAGF,iGACE,+BACA,eACA,gBACA,sBACA,iBACA,oCAEA,yIACE,kDAIJ,oBACE,GACE,uBAEF,KACE,0BAIJ,sBACE,GACE,0BAEF,IACE,2BAEF,KACE,2BAOJ,iIAhqCA,6cAOF,+KACE,sCACA,kCAEA,2LACE,sCACA,kCAIJ,2LACE,uCAqpCA,+CA56BF,uEA3PE,6cAOF,qHACE,sCACA,kCAEA,iIACE,sCACA,kCAIJ,iIACE,wCA2pCF,uCACE,gKAIE","file":"client.css","sourcesContent":["@use 'sass:map';\n\n$pp-dev-height: 32px;\n$pp-dev-peek: 4px;\n\n// Corner map: v/h — anchored edges; sx — horizontal slide direction for minimize/auto-hide\n// (1 → slides right, -1 → slides left); radius/shadow face the viewport center;\n// edge — hairline border on the exposed horizontal edge.\n$pp-dev-corners: (\n 'top-left': (\n v: top,\n h: left,\n sx: -1,\n radius: 0 0 4px 0,\n shadow: 2px 2px 8px 0 rgba(34, 34, 34, 0.08),\n edge: border-bottom,\n ),\n 'top-right': (\n v: top,\n h: right,\n sx: 1,\n radius: 0 0 0 4px,\n shadow: -2px 2px 8px 0 rgba(34, 34, 34, 0.08),\n edge: border-bottom,\n ),\n 'bottom-left': (\n v: bottom,\n h: left,\n sx: -1,\n radius: 0 4px 0 0,\n shadow: 2px -2px 8px 0 rgba(34, 34, 34, 0.08),\n edge: border-top,\n ),\n 'bottom-right': (\n v: bottom,\n h: right,\n sx: 1,\n radius: 4px 0 0 0,\n shadow: -2px -2px 8px 0 rgba(34, 34, 34, 0.08),\n edge: border-top,\n ),\n);\n\n// Light/dark color maps, shared by the default (light) rules, the prefers-color-scheme:dark\n// media query (Auto), and the explicit data-pp-dev-theme override (Dark/Light picked in the\n// panel's settings popover — see src/client/theme.ts). One place to edit either palette.\n$pp-dev-light-colors: (\n primary: #075b7e,\n secondary: rgba(34, 34, 34, 0.64),\n success: #077e45,\n info: #17a2b8,\n warning: #ffb000,\n danger: #ac2b2b,\n light: #f8f9fa,\n dark: #343a40,\n 'white': #ffffff,\n 'black': #000000,\n // Outline of inputs and outlined buttons.\n line: rgba(34, 34, 34, 0.25),\n // The \"this tab\" badge in the Users popover.\n tab: #7a3fb8,\n);\n$pp-dev-dark-colors: (\n primary: #2a8db5,\n secondary: rgba(220, 220, 220, 0.64),\n success: #0fad5e,\n info: #2dccff,\n warning: #ffb302,\n danger: #e05252,\n light: #343a40,\n dark: #f8f9fa,\n 'white': #000000,\n 'black': #ffffff,\n line: rgba(220, 220, 220, 0.3),\n tab: #b48ae6,\n);\n\n@mixin pp-dev-theme-colors($colors) {\n @each $name, $value in $colors {\n --pp-dev-info-color-#{$name}: #{$value};\n }\n}\n\n// rgba() literals don't follow the --pp-dev-info-color-primary reassignment above,\n// so the button fill/border are re-tinted here to match the dark-mode primary.\n@mixin pp-dev-dark-tints {\n .pp-dev-info__vars-btn {\n background-color: rgba(42, 141, 181, 0.14);\n border-color: rgba(42, 141, 181, 0.45);\n\n &:hover {\n background-color: rgba(42, 141, 181, 0.24);\n border-color: rgba(42, 141, 181, 0.65);\n }\n }\n\n .pp-dev-info__settings-group {\n border-top-color: rgba(255, 255, 255, 0.15);\n }\n}\n\n.pp-dev-info-namespace {\n // Define theme colors — light by default; overridden for Auto (media query, below) or an\n // explicit Dark/Light pick (html[data-pp-dev-theme], below — always wins on specificity).\n @include pp-dev-theme-colors($pp-dev-light-colors);\n\n html[data-pp-dev-theme='light'] & {\n @include pp-dev-theme-colors($pp-dev-light-colors);\n }\n\n .pp-dev-info__popup {\n position: fixed;\n top: 10px;\n right: 10px;\n width: 280px;\n max-width: calc(100vw - 20px);\n height: auto;\n background-color: var(--pp-dev-info-color-white);\n box-shadow: 0 2px 4px rgba(34, 34, 34, 0.2);\n border-radius: 2px;\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: 4px;\n padding: 12px;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n z-index: 100001;\n border-left: 2px solid var(--pp-dev-info-color-primary);\n transform: translateX(0);\n opacity: 1;\n box-sizing: border-box;\n --pp-dev-info-popup-accent: var(--pp-dev-info-color-primary);\n\n &.entering {\n transform: translateX(calc(100% + 10px));\n opacity: 0;\n }\n\n &.exiting {\n transform: translateX(calc(100% + 10px));\n opacity: 0;\n }\n\n &-title {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 8px;\n padding: 0;\n min-height: 0;\n width: 100%;\n box-sizing: border-box;\n border-bottom: 0;\n color: #040404;\n\n &-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n flex-shrink: 0;\n color: var(--pp-dev-info-popup-accent);\n }\n\n &-text {\n flex: 1;\n color: #040404;\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n text-align: left;\n word-break: break-word;\n }\n\n &-close {\n cursor: pointer;\n min-width: 24px;\n min-height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 0;\n background: none;\n font: inherit;\n color: rgba(34, 34, 34, 0.64);\n border-radius: 2px;\n transition: color 0.2s ease;\n flex-shrink: 0;\n\n &:hover {\n color: var(--pp-dev-info-color-dark);\n }\n\n &:focus-visible {\n outline: 2px solid var(--pp-dev-info-popup-accent);\n outline-offset: 1px;\n }\n\n svg {\n transition: transform 0.2s ease;\n }\n }\n }\n\n &-content {\n margin-left: 24px;\n padding: 0;\n width: calc(100% - 24px);\n overflow-y: auto;\n box-sizing: border-box;\n flex-grow: 0;\n background-color: transparent;\n color: rgba(34, 34, 34, 0.8);\n font-size: 12px;\n font-weight: 400;\n line-height: 18px;\n text-align: left;\n word-break: break-word;\n white-space: pre-line;\n }\n\n &--success {\n --pp-dev-info-popup-accent: var(--pp-dev-info-color-success);\n border-left-color: var(--pp-dev-info-color-success);\n }\n\n &--danger {\n --pp-dev-info-popup-accent: var(--pp-dev-info-color-danger);\n border-left-color: var(--pp-dev-info-color-danger);\n }\n\n &--info {\n --pp-dev-info-popup-accent: var(--pp-dev-info-color-info);\n border-left-color: var(--pp-dev-info-color-info);\n }\n\n &--warning {\n --pp-dev-info-popup-accent: var(--pp-dev-info-color-warning);\n border-left-color: var(--pp-dev-info-color-warning);\n }\n\n // Popups anchored to the left screen edge (panel in a left corner)\n &--left {\n right: auto;\n left: 10px;\n border-left: none;\n border-right: 2px solid var(--pp-dev-info-popup-accent);\n\n &.entering,\n &.exiting {\n transform: translateX(calc(-100% - 10px));\n }\n }\n }\n\n &.pp-dev-info__confirm-overlay,\n .pp-dev-info__confirm-overlay {\n position: fixed;\n inset: 0;\n z-index: 100003;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(0, 0, 0, 0.35);\n backdrop-filter: blur(2px);\n -webkit-backdrop-filter: blur(2px);\n }\n\n .pp-dev-info__confirm {\n width: min(408px, calc(100vw - 32px));\n border-radius: 3px;\n border: 1px solid rgba(0, 0, 0, 0.15);\n background-color: var(--pp-dev-info-color-white);\n box-shadow: 0px 8px 32px 0px rgba(34, 34, 34, 0.4);\n overflow: hidden;\n\n &-title {\n padding: 14px 16px;\n font-size: 15px;\n font-weight: 600;\n border-bottom: 1px solid rgba(0, 0, 0, 0.08);\n color: var(--pp-dev-info-color-dark);\n background-color: rgba(0, 0, 0, 0.03);\n }\n\n &-content {\n padding: 16px;\n white-space: pre-wrap;\n color: var(--pp-dev-info-color-dark);\n font-size: 13px;\n line-height: 1.5;\n }\n\n &-actions {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 0 16px 16px;\n }\n\n &-btn {\n width: 100%;\n padding: 8px 12px;\n border-radius: 6px;\n border: 1px solid transparent;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n\n &--cancel {\n color: var(--pp-dev-info-color-dark);\n background-color: transparent;\n border-color: rgba(0, 0, 0, 0.2);\n }\n\n &--confirm {\n color: var(--pp-dev-info-color-white);\n background-color: var(--pp-dev-info-color-primary);\n }\n\n &:hover {\n opacity: 0.9;\n }\n }\n }\n\n &.pp-dev-info,\n .pp-dev-info {\n position: fixed;\n z-index: 100000;\n white-space: nowrap;\n width: fit-content;\n height: $pp-dev-height;\n text-align: center;\n padding: 2px;\n gap: 8px;\n background-color: var(--pp-dev-info-color-white);\n color: var(--pp-dev-info-color-dark);\n box-sizing: border-box;\n display: flex;\n align-items: center;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: visible;\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n\n // Setup default values for styles that can be overlapped by other page styles\n // (e.g. color, font-family, font-size etc.)\n // This is needed to make sure that the extension styles are not overlapped by the page styles\n // and the extension is still usable\n * {\n color: var(--pp-dev-info-color-dark);\n font-family: 'Inter', sans-serif;\n font-size: 12px;\n font-weight: 400;\n line-height: 18px;\n letter-spacing: 0;\n text-decoration: none;\n text-transform: inherit;\n vertical-align: inherit;\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n border: 0;\n outline: 0;\n background: 0 0;\n list-style: none;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n &__content {\n display: flex;\n align-items: center;\n gap: 0px;\n }\n\n &__section {\n display: flex;\n align-items: center;\n position: relative;\n padding: 0 8px;\n\n &:not(:last-child)::after {\n content: '';\n position: absolute;\n right: 0;\n top: 50%;\n transform: translateY(-50%);\n height: 16px;\n width: 1px;\n background-color: rgba(34, 34, 34, 0.24);\n\n html[data-pp-dev-theme='dark'] & {\n background-color: rgba(255, 255, 255, 0.2);\n }\n\n @media screen and (prefers-color-scheme: dark) {\n background-color: rgba(255, 255, 255, 0.2);\n\n html[data-pp-dev-theme='light'] & {\n background-color: rgba(34, 34, 34, 0.24);\n }\n }\n }\n\n &:first-child {\n padding-left: 0;\n }\n\n &:last-child {\n padding-right: 0;\n }\n }\n\n &__item {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n font-weight: 400;\n line-height: 18px;\n }\n\n &__label {\n color: var(--pp-dev-info-color-secondary);\n font-weight: 400;\n }\n\n &__value {\n font-weight: 600;\n }\n\n &__link {\n color: var(--pp-dev-info-color-primary);\n text-decoration: none;\n transition: color 0.2s ease;\n display: flex;\n align-items: center;\n gap: 8px;\n\n &:hover {\n color: var(--pp-dev-info-color-primary);\n text-decoration: underline;\n }\n }\n\n @mixin bold {\n font-weight: 700;\n }\n\n .primary {\n color: var(--pp-dev-info-color-primary) !important;\n }\n\n .success {\n color: var(--pp-dev-info-color-success) !important;\n }\n\n .info {\n color: var(--pp-dev-info-color-info) !important;\n }\n\n .warning {\n color: var(--pp-dev-info-color-warning) !important;\n }\n\n .danger {\n color: var(--pp-dev-info-color-danger) !important;\n }\n\n a {\n color: var(--pp-dev-info-color-primary);\n text-decoration: none;\n vertical-align: middle;\n line-height: 18px;\n\n &:hover {\n text-decoration: none;\n }\n\n &:active,\n &:hover {\n outline: 0;\n }\n }\n\n button {\n padding: 1px;\n border: none;\n background: none;\n cursor: pointer;\n outline: none;\n }\n\n .bold,\n .status-text {\n @include bold;\n }\n\n &__drag-handle {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 14px;\n height: 28px;\n cursor: grab;\n touch-action: none;\n border-radius: 3px;\n color: var(--pp-dev-info-color-secondary);\n opacity: 0.55;\n transition:\n opacity 0.2s ease,\n background-color 0.2s ease;\n\n svg {\n pointer-events: none;\n fill: currentColor;\n }\n\n &:hover {\n opacity: 1;\n background-color: rgba(7, 91, 126, 0.06);\n }\n }\n\n &__settings-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 6px;\n border-radius: 3px;\n cursor: pointer;\n color: var(--pp-dev-info-color-secondary);\n transition: all 0.2s ease;\n\n svg {\n width: 16px;\n height: 16px;\n fill: none;\n transition: transform 0.3s ease;\n }\n\n &:hover {\n color: var(--pp-dev-info-color-primary);\n background-color: rgba(7, 91, 126, 0.06);\n\n svg {\n transform: rotate(45deg);\n }\n }\n }\n\n &__settings {\n position: absolute;\n min-width: 216px;\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n background-color: var(--pp-dev-info-color-white);\n border: 1px solid rgba(34, 34, 34, 0.15);\n border-radius: 3px;\n box-shadow: 0 4px 16px rgba(34, 34, 34, 0.2);\n z-index: 100002;\n cursor: default;\n white-space: normal;\n text-align: left;\n\n .pp-dev-info__settings-title {\n font-size: 10px;\n font-weight: 600;\n color: var(--pp-dev-info-color-secondary);\n text-transform: uppercase;\n letter-spacing: 0.4px;\n }\n\n .pp-dev-info__settings-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n }\n\n .pp-dev-info__settings-toggle {\n appearance: auto;\n -webkit-appearance: checkbox;\n width: 14px;\n height: 14px;\n accent-color: var(--pp-dev-info-color-primary);\n cursor: pointer;\n flex-shrink: 0;\n }\n\n .pp-dev-info__corner-grid {\n display: grid;\n grid-template-columns: repeat(2, 30px);\n gap: 4px;\n }\n\n .pp-dev-info__corner-btn {\n width: 30px;\n height: 22px;\n border: 1px solid var(--pp-dev-info-color-line);\n border-radius: 3px;\n cursor: pointer;\n position: relative;\n background: transparent;\n transition: border-color 0.2s ease;\n\n &::after {\n content: '';\n position: absolute;\n width: 10px;\n height: 6px;\n border-radius: 1px;\n background-color: var(--pp-dev-info-color-secondary);\n transition: background-color 0.2s ease;\n }\n\n &--top-left::after {\n top: 2px;\n left: 2px;\n }\n\n &--top-right::after {\n top: 2px;\n right: 2px;\n }\n\n &--bottom-left::after {\n bottom: 2px;\n left: 2px;\n }\n\n &--bottom-right::after {\n bottom: 2px;\n right: 2px;\n }\n\n &:hover {\n border-color: var(--pp-dev-info-color-primary);\n }\n\n &.active {\n border-color: var(--pp-dev-info-color-primary);\n\n &::after {\n background-color: var(--pp-dev-info-color-primary);\n }\n }\n }\n\n .pp-dev-info__theme-grid {\n display: flex;\n gap: 4px;\n }\n\n .pp-dev-info__theme-btn {\n padding: 3px 8px;\n border: 1px solid var(--pp-dev-info-color-line);\n border-radius: 3px;\n cursor: pointer;\n background: transparent;\n font-size: 11px;\n line-height: 16px;\n color: var(--pp-dev-info-color-secondary);\n transition:\n border-color 0.2s ease,\n color 0.2s ease,\n background-color 0.2s ease;\n\n &:hover {\n border-color: var(--pp-dev-info-color-primary);\n color: var(--pp-dev-info-color-primary);\n }\n\n &.active {\n border-color: var(--pp-dev-info-color-primary);\n background-color: var(--pp-dev-info-color-primary);\n color: var(--pp-dev-info-color-white);\n }\n\n &:focus-visible {\n outline: 2px solid var(--pp-dev-info-color-primary);\n outline-offset: 1px;\n }\n }\n\n .pp-dev-info__settings-hide-btn {\n width: 100%;\n padding: 6px 10px;\n border: 1px solid rgba(34, 34, 34, 0.2);\n border-radius: 4px;\n cursor: pointer;\n font-weight: 600;\n color: var(--pp-dev-info-color-danger);\n transition: background-color 0.2s ease;\n\n &:hover {\n background-color: rgba(172, 43, 43, 0.06);\n }\n }\n\n .pp-dev-info__settings-group {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding-top: 10px;\n border-top: 1px solid rgba(34, 34, 34, 0.12);\n }\n\n .pp-dev-info__vars-buttons {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .pp-dev-info__vars-btn {\n width: 100%;\n padding: 6px 10px;\n border-radius: 4px;\n cursor: pointer;\n font-weight: 600;\n text-align: center;\n color: var(--pp-dev-info-color-primary);\n background-color: rgba(7, 91, 126, 0.1);\n border: 1px solid rgba(7, 91, 126, 0.4);\n transition:\n background-color 0.2s ease,\n border-color 0.2s ease;\n\n &:hover {\n background-color: rgba(7, 91, 126, 0.18);\n border-color: rgba(7, 91, 126, 0.6);\n }\n\n &:focus-visible {\n outline: 2px solid var(--pp-dev-info-color-primary);\n outline-offset: 1px;\n }\n }\n\n .pp-dev-info__settings-hint {\n font-size: 10px;\n line-height: 14px;\n color: var(--pp-dev-info-color-secondary);\n\n code {\n font-family: monospace;\n font-size: 10px;\n }\n }\n\n .pp-dev-info__settings-reset {\n align-self: flex-start;\n font-size: 11px;\n color: var(--pp-dev-info-color-primary);\n cursor: pointer;\n\n &:hover {\n text-decoration: underline;\n }\n }\n }\n\n // ── Users (PP-4597) ──────────────────────────────────────────────────────\n &__users-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 6px;\n border-radius: 3px;\n cursor: pointer;\n color: var(--pp-dev-info-color-secondary);\n transition: all 0.2s ease;\n\n svg {\n width: 16px;\n height: 16px;\n flex-shrink: 0;\n }\n\n &:hover {\n color: var(--pp-dev-info-color-primary);\n background-color: rgba(7, 91, 126, 0.06);\n }\n }\n\n // A saved user's tab: the button stands out, so the tab is never taken for your own.\n &.pp-dev-info--user-tab .pp-dev-info__users-btn {\n color: #ffffff;\n background-color: #7a3fb8;\n\n &:hover {\n background-color: #8d52cc;\n }\n }\n\n &__users.pp-dev-info__settings {\n width: 320px;\n max-width: calc(100vw - 16px);\n box-sizing: border-box;\n\n .pp-dev-info__users-tab {\n font-size: 12px;\n line-height: 16px;\n color: var(--pp-dev-info-color-dark);\n }\n\n // Over the radios: they pick who localhost works as, not this tab.\n .pp-dev-info__users-list-head {\n margin-bottom: -4px;\n padding-left: 4px;\n font-size: 9px;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--pp-dev-info-color-secondary);\n }\n\n .pp-dev-info__users-badge {\n margin-left: 6px;\n padding: 0 5px;\n border: 1px solid currentColor;\n border-radius: 3px;\n font-size: 9px;\n font-weight: 400;\n line-height: 13px;\n vertical-align: 1px;\n color: var(--pp-dev-info-color-tab);\n }\n\n .pp-dev-info__users-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n max-height: 240px;\n overflow-y: auto;\n }\n\n .pp-dev-info__users-row {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 5px 6px;\n border-radius: 3px;\n border-left: 2px solid transparent;\n\n &.is-current {\n border-left-color: #7a3fb8;\n background-color: rgba(122, 63, 184, 0.08);\n }\n }\n\n .pp-dev-info__users-default {\n appearance: auto;\n -webkit-appearance: radio;\n width: 13px;\n height: 13px;\n margin: 0;\n flex-shrink: 0;\n accent-color: var(--pp-dev-info-color-primary);\n cursor: pointer;\n\n &:disabled {\n cursor: not-allowed;\n }\n }\n\n .pp-dev-info__users-who {\n display: flex;\n flex-direction: column;\n min-width: 0;\n flex: 1;\n }\n\n .pp-dev-info__users-name {\n font-size: 12px;\n font-weight: 600;\n color: var(--pp-dev-info-color-dark);\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .pp-dev-info__users-meta {\n font-size: 10px;\n line-height: 13px;\n color: var(--pp-dev-info-color-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .needs-login .pp-dev-info__users-meta {\n color: var(--pp-dev-info-color-danger);\n }\n\n .pp-dev-info__users-action {\n flex-shrink: 0;\n padding: 2px 7px;\n border: 1px solid var(--pp-dev-info-color-line);\n border-radius: 3px;\n background: transparent;\n cursor: pointer;\n font-size: 11px;\n line-height: 16px;\n color: var(--pp-dev-info-color-primary);\n\n &:hover {\n border-color: var(--pp-dev-info-color-primary);\n }\n\n &--accent {\n border-color: var(--pp-dev-info-color-primary);\n background-color: var(--pp-dev-info-color-primary);\n color: var(--pp-dev-info-color-white);\n }\n }\n\n // A token user's row while it is being edited: name, new token, Save and Cancel.\n .pp-dev-info__users-edit {\n flex-direction: column;\n align-items: stretch;\n gap: 6px;\n margin: 0;\n }\n\n .pp-dev-info__users-edit-actions {\n display: flex;\n justify-content: flex-end;\n gap: 6px;\n }\n\n .pp-dev-info__users-remove {\n flex-shrink: 0;\n width: 20px;\n height: 20px;\n padding: 0;\n border: none;\n border-radius: 3px;\n background: transparent;\n cursor: pointer;\n font-size: 15px;\n line-height: 20px;\n color: var(--pp-dev-info-color-secondary);\n\n &:hover {\n color: var(--pp-dev-info-color-danger);\n background-color: rgba(172, 43, 43, 0.08);\n }\n }\n\n .pp-dev-info__users-input {\n width: 100%;\n box-sizing: border-box;\n padding: 5px 8px;\n border: 1px solid var(--pp-dev-info-color-line);\n border-radius: 3px;\n background: transparent;\n font-size: 12px;\n color: var(--pp-dev-info-color-dark);\n\n &:focus {\n outline: none;\n border-color: var(--pp-dev-info-color-primary);\n }\n }\n\n .pp-dev-info__users-error,\n .pp-dev-info__users-unavailable {\n font-size: 11px;\n line-height: 15px;\n color: var(--pp-dev-info-color-danger);\n }\n\n .pp-dev-info__users-unavailable {\n color: var(--pp-dev-info-color-secondary);\n }\n\n [hidden] {\n display: none !important;\n }\n }\n\n &__wrap-btn {\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 6px;\n cursor: pointer;\n border-radius: 3px;\n transition: background-color 0.2s ease;\n\n &:hover {\n background-color: rgba(7, 91, 126, 0.06);\n animation: arrowHover 0.8s linear infinite;\n }\n\n &-arrow {\n width: 16px;\n height: 16px;\n color: var(--pp-dev-info-color-dark);\n fill: none;\n transition: transform 0.2s ease;\n }\n }\n\n &.closed {\n z-index: 100002;\n\n & .pp-dev-info__wrap-btn {\n &:hover {\n animation: arrowHover 1.2s linear infinite;\n }\n }\n }\n\n // Corner variants: placement, center-facing radius/shadow, direction-aware\n // minimize (.closed) and auto-hide slides. The corner class is always rendered\n // on the panel root (server default: bottom-right).\n @each $name, $c in $pp-dev-corners {\n &.pp-dev-info--#{$name} {\n #{map.get($c, v)}: 0;\n #{map.get($c, h)}: 0;\n border-radius: map.get($c, radius);\n box-shadow: map.get($c, shadow);\n #{map.get($c, edge)}: 1px solid rgba(34, 34, 34, 0.08);\n\n .pp-dev-info__settings {\n #{map.get($c, v)}: calc(100% + 8px);\n #{map.get($c, h)}: 0;\n }\n\n @if map.get($c, sx) == 1 {\n &.closed {\n transform: translateX(calc(100% - $pp-dev-height));\n\n .pp-dev-info__wrap-btn-arrow {\n transform: rotate(180deg);\n }\n }\n\n &.pp-dev-info--auto-hide:not(.is-peeking):not(.is-dragging) {\n transform: translateX(calc(100% - $pp-dev-peek));\n box-shadow:\n map.get($c, shadow),\n inset $pp-dev-peek 0 0 0 var(--pp-dev-info-color-primary);\n\n // Extended invisible hover zone on the inner side of the 4px strip\n &::after {\n content: '';\n position: absolute;\n top: -6px;\n bottom: -6px;\n left: -8px;\n width: 8px;\n }\n }\n } @else {\n .pp-dev-info__wrap-btn {\n order: 99;\n\n &-arrow {\n transform: rotate(180deg);\n }\n }\n\n &.closed {\n transform: translateX(calc(-100% + $pp-dev-height));\n\n .pp-dev-info__wrap-btn-arrow {\n transform: rotate(0deg);\n }\n }\n\n &.pp-dev-info--auto-hide:not(.is-peeking):not(.is-dragging) {\n transform: translateX(calc(-100% + $pp-dev-peek));\n box-shadow:\n map.get($c, shadow),\n inset (-$pp-dev-peek) 0 0 0 var(--pp-dev-info-color-primary);\n\n &::after {\n content: '';\n position: absolute;\n top: -6px;\n bottom: -6px;\n right: -8px;\n width: 8px;\n }\n }\n }\n }\n }\n\n &.pp-dev-info--auto-hide {\n z-index: 100002;\n }\n\n &.is-dragging {\n transition: none;\n user-select: none;\n cursor: grabbing;\n\n .pp-dev-info__drag-handle {\n cursor: grabbing;\n }\n }\n\n &.pp-dev-info--hidden {\n display: none;\n }\n\n .sync-button {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 6px;\n background-color: transparent;\n border-radius: 3px;\n cursor: pointer;\n color: var(--pp-dev-info-color-primary);\n transition: all 0.2s ease;\n position: relative;\n overflow: hidden;\n\n &::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: currentColor;\n opacity: 0;\n transition: opacity 0.2s ease;\n border-radius: 3px;\n }\n\n svg {\n width: 16px;\n height: 16px;\n position: relative;\n z-index: 1;\n transition: transform 0.3s ease;\n }\n\n &:hover:not(.disabled) {\n color: var(--pp-dev-info-color-primary);\n background-color: rgba(7, 91, 126, 0.06);\n\n svg {\n transform: scale(1.1) rotate(45deg);\n transition: transform 0.2s ease;\n }\n }\n\n &:active:not(.disabled) {\n svg {\n transform: scale(0.9) rotate(45deg);\n }\n }\n\n &.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n color: var(--pp-dev-info-color-secondary);\n }\n\n &.syncing {\n svg {\n animation: rotate 1.5s linear infinite;\n }\n }\n }\n\n &__sep {\n display: inline-flex;\n flex-shrink: 0;\n width: 1px;\n height: 16px;\n background-color: rgba(34, 34, 34, 0.24);\n\n html[data-pp-dev-theme='dark'] & {\n background-color: rgba(255, 255, 255, 0.2);\n }\n\n @media screen and (prefers-color-scheme: dark) {\n background-color: rgba(255, 255, 255, 0.2);\n\n html[data-pp-dev-theme='light'] & {\n background-color: rgba(34, 34, 34, 0.24);\n }\n }\n }\n\n @keyframes rotate {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n }\n\n .margin-5 {\n margin-right: 5px;\n }\n\n .margin-10 {\n margin-right: 10px;\n }\n\n .custom-font {\n font-family: 'Inter', sans-serif;\n font-size: 13px;\n font-weight: 400;\n vertical-align: middle;\n line-height: 18px;\n color: var(--pp-dev-info-color-dark);\n\n &:not(.not-colored) a {\n color: var(--pp-dev-info-color-primary) !important;\n }\n }\n\n @keyframes rotation {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n }\n\n @keyframes arrowHover {\n 0% {\n transform: translateX(2px);\n }\n 50% {\n transform: translateX(-2px);\n }\n 100% {\n transform: translateX(2px);\n }\n }\n\n // Explicit Dark pick (html[data-pp-dev-theme='dark'], set via the settings popover's Theme\n // row — see src/client/theme.ts) — always wins over both the light default above and the\n // Auto media query below, on selector specificity alone.\n html[data-pp-dev-theme='dark'] & {\n @include pp-dev-theme-colors($pp-dev-dark-colors);\n @include pp-dev-dark-tints;\n }\n\n // Auto (OS/browser preference) — same values, only takes effect when no explicit\n // html[data-pp-dev-theme] override is set (those always outrank a plain :root/& selector).\n @media screen and (prefers-color-scheme: dark) {\n @include pp-dev-theme-colors($pp-dev-dark-colors);\n @include pp-dev-dark-tints;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n &.pp-dev-info,\n .pp-dev-info,\n .pp-dev-info__popup,\n .pp-dev-info__settings {\n transition: none;\n }\n }\n}\n"]}
|
package/dist/client/client.js
CHANGED
|
@@ -58,8 +58,11 @@ function createPPDevHotContext() {
|
|
|
58
58
|
scheduleReconnect();
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
|
+
let opened = false;
|
|
61
62
|
socket.addEventListener('open', () => {
|
|
63
|
+
opened = true;
|
|
62
64
|
reconnectDelay = 1_000;
|
|
65
|
+
dispatch('vite:ws:connect', {});
|
|
63
66
|
flushOutbox();
|
|
64
67
|
});
|
|
65
68
|
socket.addEventListener('message', (ev) => {
|
|
@@ -76,6 +79,12 @@ function createPPDevHotContext() {
|
|
|
76
79
|
});
|
|
77
80
|
socket.addEventListener('close', () => {
|
|
78
81
|
socket = null;
|
|
82
|
+
// Same events as Vite's own HMR client, so the panel can tell a lost connection apart
|
|
83
|
+
// (e.g. a sync whose response will never arrive). Only for a socket that was open: a
|
|
84
|
+
// failed reconnect attempt is not a new disconnect.
|
|
85
|
+
if (opened) {
|
|
86
|
+
dispatch('vite:ws:disconnect', {});
|
|
87
|
+
}
|
|
79
88
|
scheduleReconnect();
|
|
80
89
|
});
|
|
81
90
|
socket.addEventListener('error', () => {
|
|
@@ -652,6 +661,8 @@ function initPanelSettings($panel, controller, hooks) {
|
|
|
652
661
|
const USERS_API = '/@api/users';
|
|
653
662
|
const REFRESH_INTERVAL = 3000;
|
|
654
663
|
const USER_HOST_REGEXP = /^([a-z](?:[a-z0-9-]*[a-z0-9])?)\.localhost$/;
|
|
664
|
+
/** Marks the user this tab works as, apart from the radio, which picks localhost's user. */
|
|
665
|
+
const THIS_TAB_BADGE = '<span class="pp-dev-info__users-badge">this tab</span>';
|
|
655
666
|
const STATE_LABELS = {
|
|
656
667
|
pending: 'not logged in yet',
|
|
657
668
|
active: 'logged in',
|
|
@@ -714,6 +725,8 @@ function initUsersPanel($panel, hooks) {
|
|
|
714
725
|
let data = null;
|
|
715
726
|
// What the list shows now, so a refresh with the same data leaves it (and the focus) alone.
|
|
716
727
|
let renderedData = '';
|
|
728
|
+
// The token user being edited, whose row shows the edit form instead.
|
|
729
|
+
let editing = null;
|
|
717
730
|
const onDocClick = (ev) => {
|
|
718
731
|
const target = ev.target;
|
|
719
732
|
if ($popover && !$popover.contains(target) && !$btn.contains(target)) {
|
|
@@ -729,6 +742,7 @@ function initUsersPanel($panel, hooks) {
|
|
|
729
742
|
if (!$popover) {
|
|
730
743
|
return;
|
|
731
744
|
}
|
|
745
|
+
editing = null;
|
|
732
746
|
window.clearInterval(refreshTimer);
|
|
733
747
|
$popover.remove();
|
|
734
748
|
$popover = null;
|
|
@@ -762,11 +776,25 @@ function initUsersPanel($panel, hooks) {
|
|
|
762
776
|
return null;
|
|
763
777
|
}
|
|
764
778
|
};
|
|
779
|
+
/**
|
|
780
|
+
* Who this tab works as: on a user's host that user, on localhost the default user, and on an IP
|
|
781
|
+
* address or a custom domain you (`undefined`). Before the users are loaded, a user's host only.
|
|
782
|
+
*/
|
|
783
|
+
const getCurrentUser = () => tabUser ?? (window.location.hostname === 'localhost' ? data?.defaultUser : null) ?? undefined;
|
|
765
784
|
const renderList = () => {
|
|
766
785
|
const $list = $popover?.querySelector('.pp-dev-info__users-list');
|
|
767
786
|
if (!$popover || !$list || !data) {
|
|
768
787
|
return;
|
|
769
788
|
}
|
|
789
|
+
// The user being edited is gone (removed, logged out): nothing to edit any more.
|
|
790
|
+
if (editing && !data.users.some((user) => user.name === editing && user.kind === 'token')) {
|
|
791
|
+
editing = null;
|
|
792
|
+
}
|
|
793
|
+
else if (editing && $list.querySelector('.pp-dev-info__users-edit')?.dataset.user === editing) {
|
|
794
|
+
// A refresh must not wipe what is being typed into the edit form. (Edit on another user
|
|
795
|
+
// redraws it for that one.)
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
770
798
|
const snapshot = JSON.stringify(data);
|
|
771
799
|
if (snapshot === renderedData) {
|
|
772
800
|
return;
|
|
@@ -777,9 +805,7 @@ function initUsersPanel($panel, hooks) {
|
|
|
777
805
|
? document.activeElement.dataset.focusKey
|
|
778
806
|
: undefined;
|
|
779
807
|
const defaultUser = data.defaultUser;
|
|
780
|
-
|
|
781
|
-
// address or a custom domain as you.
|
|
782
|
-
const currentUser = tabUser ?? (window.location.hostname === 'localhost' ? defaultUser : null) ?? undefined;
|
|
808
|
+
const currentUser = getCurrentUser();
|
|
783
809
|
const $tab = $popover.querySelector('.pp-dev-info__users-tab strong');
|
|
784
810
|
if ($tab) {
|
|
785
811
|
$tab.textContent = currentUser ?? 'you';
|
|
@@ -789,7 +815,7 @@ function initUsersPanel($panel, hooks) {
|
|
|
789
815
|
<input type="radio" name="pp-dev-default-user" class="pp-dev-info__users-default" value="" data-focus-key=":default"
|
|
790
816
|
title="Make the main host (localhost) work as you" ${defaultUser ? '' : 'checked'} />
|
|
791
817
|
<div class="pp-dev-info__users-who">
|
|
792
|
-
<span class="pp-dev-info__users-name">You</span>
|
|
818
|
+
<span class="pp-dev-info__users-name">You${currentUser ? '' : THIS_TAB_BADGE}</span>
|
|
793
819
|
<span class="pp-dev-info__users-meta">original user · the dev panel always works as you</span>
|
|
794
820
|
</div>
|
|
795
821
|
${
|
|
@@ -804,6 +830,19 @@ function initUsersPanel($panel, hooks) {
|
|
|
804
830
|
const needsLogin = user.kind === 'session' && user.state !== 'active';
|
|
805
831
|
const needsAttention = needsLogin || user.state === 'expired';
|
|
806
832
|
const name = escapeHtml(user.name);
|
|
833
|
+
if (user.kind === 'token' && user.name === editing) {
|
|
834
|
+
return `<form class="pp-dev-info__users-row pp-dev-info__users-edit" data-user="${name}">
|
|
835
|
+
<input class="pp-dev-info__users-input pp-dev-info__users-edit-name" value="${name}" maxlength="32"
|
|
836
|
+
autocomplete="off" spellcheck="false" aria-label="Name" data-focus-key="${name}:edit-name"
|
|
837
|
+
title="Lowercase latin letters, digits and -, starting with a letter. The user opens on <name>.localhost." />
|
|
838
|
+
<input class="pp-dev-info__users-input pp-dev-info__users-edit-token" type="password" autocomplete="off"
|
|
839
|
+
placeholder="New API token (empty keeps the current one)" aria-label="New API token" data-focus-key="${name}:edit-token" />
|
|
840
|
+
<div class="pp-dev-info__users-edit-actions">
|
|
841
|
+
<button type="submit" class="pp-dev-info__users-action pp-dev-info__users-action--accent" data-focus-key="${name}:save">Save</button>
|
|
842
|
+
<button type="button" class="pp-dev-info__users-action" data-cancel-edit data-focus-key="${name}:cancel">Cancel</button>
|
|
843
|
+
</div>
|
|
844
|
+
</form>`;
|
|
845
|
+
}
|
|
807
846
|
let defaultTitle = `Make the main host (localhost) work as ${name}`;
|
|
808
847
|
if (!canBeDefault) {
|
|
809
848
|
defaultTitle =
|
|
@@ -814,12 +853,15 @@ function initUsersPanel($panel, hooks) {
|
|
|
814
853
|
title="${defaultTitle}"
|
|
815
854
|
${user.name === defaultUser ? 'checked' : ''} ${canBeDefault ? '' : 'disabled'} />
|
|
816
855
|
<div class="pp-dev-info__users-who">
|
|
817
|
-
<span class="pp-dev-info__users-name">${name}</span>
|
|
856
|
+
<span class="pp-dev-info__users-name">${name}${user.name === currentUser ? THIS_TAB_BADGE : ''}</span>
|
|
818
857
|
<span class="pp-dev-info__users-meta">${escapeHtml(describeUser(user))}</span>
|
|
819
858
|
</div>
|
|
820
859
|
${needsLogin && user.loginUrl
|
|
821
860
|
? `<button type="button" class="pp-dev-info__users-action pp-dev-info__users-action--accent" data-open="${escapeHtml(user.loginUrl)}" data-raw="true" data-focus-key="${name}:login">Log in</button>`
|
|
822
861
|
: ''}
|
|
862
|
+
${user.kind === 'token'
|
|
863
|
+
? `<button type="button" class="pp-dev-info__users-action" data-edit="${name}" data-focus-key="${name}:edit" title="Rename ${name} or replace its API token">Edit</button>`
|
|
864
|
+
: ''}
|
|
823
865
|
<button type="button" class="pp-dev-info__users-action" data-open="${escapeHtml(user.origin)}" data-focus-key="${name}:open" title="Open this page as ${name}">Open</button>
|
|
824
866
|
<button type="button" class="pp-dev-info__users-remove" data-remove="${name}" data-focus-key="${name}:remove" title="Remove ${name}" aria-label="Remove ${name}">×</button>
|
|
825
867
|
</div>`;
|
|
@@ -838,6 +880,46 @@ function initUsersPanel($panel, hooks) {
|
|
|
838
880
|
window.open($open.dataset.raw ? target : samePageOn(target), '_blank');
|
|
839
881
|
});
|
|
840
882
|
});
|
|
883
|
+
const startEditing = (name) => {
|
|
884
|
+
editing = name;
|
|
885
|
+
renderedData = '';
|
|
886
|
+
renderList();
|
|
887
|
+
$list.querySelector('.pp-dev-info__users-edit-name')?.focus();
|
|
888
|
+
};
|
|
889
|
+
$list.querySelectorAll('[data-edit]').forEach(($edit) => {
|
|
890
|
+
$edit.addEventListener('click', (ev) => {
|
|
891
|
+
ev.preventDefault();
|
|
892
|
+
startEditing($edit.dataset.edit);
|
|
893
|
+
});
|
|
894
|
+
});
|
|
895
|
+
$list.querySelector('[data-cancel-edit]')?.addEventListener('click', (ev) => {
|
|
896
|
+
ev.preventDefault();
|
|
897
|
+
setError('');
|
|
898
|
+
startEditing(null);
|
|
899
|
+
});
|
|
900
|
+
$list.querySelector('.pp-dev-info__users-edit')?.addEventListener('submit', async (ev) => {
|
|
901
|
+
ev.preventDefault();
|
|
902
|
+
const name = editing;
|
|
903
|
+
const $form = ev.currentTarget;
|
|
904
|
+
const newName = $form.querySelector('.pp-dev-info__users-edit-name').value.trim();
|
|
905
|
+
const token = $form.querySelector('.pp-dev-info__users-edit-token').value.trim();
|
|
906
|
+
const response = await request('PATCH', `${USERS_API}/${encodeURIComponent(name)}`, {
|
|
907
|
+
name: newName,
|
|
908
|
+
...(token ? { token } : {}),
|
|
909
|
+
});
|
|
910
|
+
if (!response) {
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
const { user } = (await response.json());
|
|
914
|
+
// This tab's own user got a new host: go on there (the old one would only send it on).
|
|
915
|
+
if (tabUser === name && user.name !== name) {
|
|
916
|
+
window.location.href = samePageOn(user.origin);
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
editing = null;
|
|
920
|
+
renderedData = '';
|
|
921
|
+
await refresh();
|
|
922
|
+
});
|
|
841
923
|
$list.querySelectorAll('[data-remove]').forEach(($remove) => {
|
|
842
924
|
$remove.addEventListener('click', async (ev) => {
|
|
843
925
|
ev.preventDefault();
|
|
@@ -946,10 +1028,13 @@ function initUsersPanel($panel, hooks) {
|
|
|
946
1028
|
$popover.innerHTML = `
|
|
947
1029
|
<div class="pp-dev-info__settings-title">Users</div>
|
|
948
1030
|
<div class="pp-dev-info__users-tab">
|
|
949
|
-
This tab works as <strong>${escapeHtml(
|
|
950
|
-
|
|
1031
|
+
This tab works as <strong>${escapeHtml(getCurrentUser() ?? 'you')}</strong>.
|
|
1032
|
+
</div>
|
|
1033
|
+
<div class="pp-dev-info__users-list-head" aria-hidden="true">localhost</div>
|
|
1034
|
+
<div class="pp-dev-info__users-list" role="radiogroup" aria-label="Who localhost works as">
|
|
1035
|
+
<span class="pp-dev-info__users-meta">Loading users…</span>
|
|
951
1036
|
</div>
|
|
952
|
-
<div class="pp-dev-
|
|
1037
|
+
<div class="pp-dev-info__settings-hint">The radio picks who localhost works as; each user's own host always works as that user.</div>
|
|
953
1038
|
<div class="pp-dev-info__users-unavailable" hidden></div>
|
|
954
1039
|
<form class="pp-dev-info__settings-group pp-dev-info__users-add" hidden>
|
|
955
1040
|
<span class="pp-dev-info__settings-label">Add user</span>
|
|
@@ -983,10 +1068,15 @@ function initUsersPanel($panel, hooks) {
|
|
|
983
1068
|
document.addEventListener('click', onDocClick, true);
|
|
984
1069
|
document.addEventListener('keydown', onKeyDown, true);
|
|
985
1070
|
hooks?.onOpenChange?.(true);
|
|
1071
|
+
// Shown right away from what was loaded with the panel, then brought up to date.
|
|
1072
|
+
renderList();
|
|
1073
|
+
renderAvailability();
|
|
986
1074
|
refresh();
|
|
987
1075
|
// Picks up logins and expired sessions while the popover is open.
|
|
988
1076
|
refreshTimer = window.setInterval(refresh, REFRESH_INTERVAL);
|
|
989
1077
|
};
|
|
1078
|
+
// Loaded with the panel, so the popover opens with its list.
|
|
1079
|
+
refresh();
|
|
990
1080
|
$btn.addEventListener('click', (ev) => {
|
|
991
1081
|
ev.preventDefault();
|
|
992
1082
|
if ($popover) {
|
|
@@ -1059,6 +1149,115 @@ function createPopupElement(opts) {
|
|
|
1059
1149
|
return $popup;
|
|
1060
1150
|
}
|
|
1061
1151
|
|
|
1152
|
+
/**
|
|
1153
|
+
* `template:sync:response` code for a sync requested while another one runs. Kept in sync with
|
|
1154
|
+
* `SYNC_IN_PROGRESS_CODE` in `src/lib/client.service.ts` (server side, not importable here).
|
|
1155
|
+
*/
|
|
1156
|
+
const SYNC_IN_PROGRESS_CODE = 'SYNC_IN_PROGRESS';
|
|
1157
|
+
const TITLE_AVAILABLE = 'Sync template';
|
|
1158
|
+
const TITLE_UNAVAILABLE = 'Sync is unavailable on this instance';
|
|
1159
|
+
/**
|
|
1160
|
+
* Wires the dev panel's "Sync template" button to the dev server.
|
|
1161
|
+
*
|
|
1162
|
+
* The button is disabled while a sync runs, so a double click can't start a second build, and is
|
|
1163
|
+
* enabled again by whatever ends the sync: its response, or a lost connection. It stays disabled
|
|
1164
|
+
* only when the server says sync is unavailable on this instance (`config.canSync === false`);
|
|
1165
|
+
* a failed sync (MI unreachable, a build error) can simply be retried.
|
|
1166
|
+
*/
|
|
1167
|
+
function initSyncButton(hot, $button, deps) {
|
|
1168
|
+
const reload = deps.reload ?? (() => window.location.reload());
|
|
1169
|
+
let available = !$button.disabled && !$button.classList.contains('disabled');
|
|
1170
|
+
let syncing = false;
|
|
1171
|
+
const applyState = () => {
|
|
1172
|
+
$button.disabled = syncing || !available;
|
|
1173
|
+
$button.classList.toggle('syncing', syncing);
|
|
1174
|
+
$button.classList.toggle('disabled', !available);
|
|
1175
|
+
$button.title = available ? TITLE_AVAILABLE : TITLE_UNAVAILABLE;
|
|
1176
|
+
if (syncing) {
|
|
1177
|
+
$button.setAttribute('aria-busy', 'true');
|
|
1178
|
+
}
|
|
1179
|
+
else {
|
|
1180
|
+
$button.removeAttribute('aria-busy');
|
|
1181
|
+
}
|
|
1182
|
+
};
|
|
1183
|
+
const endSync = () => {
|
|
1184
|
+
syncing = false;
|
|
1185
|
+
applyState();
|
|
1186
|
+
};
|
|
1187
|
+
hot.on('client:config:update', (data) => {
|
|
1188
|
+
if (typeof data?.config?.canSync !== 'boolean') {
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
// The server sends `canSync: true` at the start of every sync: it must not enable the
|
|
1192
|
+
// button while that sync runs, which `applyState` takes care of.
|
|
1193
|
+
available = data.config.canSync;
|
|
1194
|
+
applyState();
|
|
1195
|
+
});
|
|
1196
|
+
hot.on('template:sync:action-required', async (payload) => {
|
|
1197
|
+
// The spinner keeps running while a confirmation modal is shown: the sync is still in
|
|
1198
|
+
// progress and only ends on `template:sync:response`.
|
|
1199
|
+
const approved = await deps.confirmModal({
|
|
1200
|
+
title: payload.title,
|
|
1201
|
+
content: payload.content,
|
|
1202
|
+
confirmText: payload.confirmText,
|
|
1203
|
+
cancelText: payload.cancelText,
|
|
1204
|
+
});
|
|
1205
|
+
hot.send('template:sync:action-response', { requestId: payload.requestId, approved });
|
|
1206
|
+
});
|
|
1207
|
+
hot.on('template:sync:response', (payload) => {
|
|
1208
|
+
deps.closeAllConfirmModals();
|
|
1209
|
+
if ('error' in payload && payload.config?.canSync === false) {
|
|
1210
|
+
available = false;
|
|
1211
|
+
}
|
|
1212
|
+
endSync();
|
|
1213
|
+
if ('cancelled' in payload && payload.cancelled) {
|
|
1214
|
+
deps.infoPopup({ title: 'Sync cancelled', content: payload.message, type: 'warning' });
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
if ('error' in payload && typeof payload.error !== 'undefined') {
|
|
1218
|
+
if (payload.code === SYNC_IN_PROGRESS_CODE) {
|
|
1219
|
+
deps.infoPopup({ title: 'Sync already running', content: payload.error, type: 'warning' });
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1222
|
+
deps.infoPopup({ title: 'Sync error', content: payload.error, type: 'danger' });
|
|
1223
|
+
if (payload.refresh) {
|
|
1224
|
+
setTimeout(reload);
|
|
1225
|
+
}
|
|
1226
|
+
return;
|
|
1227
|
+
}
|
|
1228
|
+
if ('syncedAt' in payload && typeof payload.syncedAt !== 'undefined') {
|
|
1229
|
+
deps.infoPopup({
|
|
1230
|
+
title: 'Sync success',
|
|
1231
|
+
content: `Synced at ${new Date(payload.syncedAt).toLocaleString()}.\nBackup filename: ${payload.backupFilename}`,
|
|
1232
|
+
type: 'success',
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1235
|
+
});
|
|
1236
|
+
// A response sent to a socket that has closed never arrives. Without this, the button would
|
|
1237
|
+
// spin, disabled, until the page is reloaded.
|
|
1238
|
+
hot.on('vite:ws:disconnect', () => {
|
|
1239
|
+
if (!syncing) {
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
deps.closeAllConfirmModals();
|
|
1243
|
+
endSync();
|
|
1244
|
+
deps.infoPopup({
|
|
1245
|
+
title: 'Sync result unknown',
|
|
1246
|
+
content: 'The connection to the dev server was lost during the sync. Check its terminal for the result before syncing again.',
|
|
1247
|
+
type: 'warning',
|
|
1248
|
+
});
|
|
1249
|
+
});
|
|
1250
|
+
$button.addEventListener('click', (ev) => {
|
|
1251
|
+
ev.preventDefault();
|
|
1252
|
+
if (syncing || !available) {
|
|
1253
|
+
return;
|
|
1254
|
+
}
|
|
1255
|
+
syncing = true;
|
|
1256
|
+
applyState();
|
|
1257
|
+
hot.send('template:sync', {});
|
|
1258
|
+
});
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1062
1261
|
/// <reference types="vite/client" />
|
|
1063
1262
|
// Applied unconditionally (even if the panel itself is hidden) — this is what makes the
|
|
1064
1263
|
// override affect the whole injected panel, not just its own markup.
|
|
@@ -1291,82 +1490,9 @@ if (hot) {
|
|
|
1291
1490
|
hot.on('redirect', (data) => {
|
|
1292
1491
|
window.location.href = data.url;
|
|
1293
1492
|
});
|
|
1294
|
-
hot.on('client:config:update', (data) => {
|
|
1295
|
-
if (typeof data.config?.canSync === 'boolean') {
|
|
1296
|
-
if (data.config.canSync) {
|
|
1297
|
-
const $syncButton = document.getElementById('sync-template');
|
|
1298
|
-
if ($syncButton) {
|
|
1299
|
-
$syncButton.disabled = false;
|
|
1300
|
-
$syncButton.classList.remove('disabled');
|
|
1301
|
-
$syncButton.title = 'Sync template';
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
else {
|
|
1305
|
-
const $syncButton = document.getElementById('sync-template');
|
|
1306
|
-
if ($syncButton) {
|
|
1307
|
-
$syncButton.disabled = true;
|
|
1308
|
-
$syncButton.classList.add('disabled');
|
|
1309
|
-
$syncButton.title = 'Sync is unavailable on this instance';
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
}
|
|
1313
|
-
});
|
|
1314
1493
|
const $syncButton = document.getElementById('sync-template');
|
|
1315
1494
|
if ($syncButton) {
|
|
1316
|
-
hot
|
|
1317
|
-
// Keep the sync spinner running while a confirmation modal is shown — the sync
|
|
1318
|
-
// process is still in progress and only ends on `template:sync:response`.
|
|
1319
|
-
const approved = await confirmModal({
|
|
1320
|
-
title: payload.title,
|
|
1321
|
-
content: payload.content,
|
|
1322
|
-
confirmText: payload.confirmText,
|
|
1323
|
-
cancelText: payload.cancelText,
|
|
1324
|
-
});
|
|
1325
|
-
hot.send('template:sync:action-response', {
|
|
1326
|
-
requestId: payload.requestId,
|
|
1327
|
-
approved,
|
|
1328
|
-
});
|
|
1329
|
-
});
|
|
1330
|
-
hot.on('template:sync:response', (payload) => {
|
|
1331
|
-
closeAllConfirmModals();
|
|
1332
|
-
$syncButton.classList.remove('syncing');
|
|
1333
|
-
if ('cancelled' in payload && payload.cancelled) {
|
|
1334
|
-
infoPopup({
|
|
1335
|
-
title: 'Sync cancelled',
|
|
1336
|
-
content: payload.message,
|
|
1337
|
-
type: 'warning',
|
|
1338
|
-
});
|
|
1339
|
-
}
|
|
1340
|
-
else if ('error' in payload && typeof payload.error !== 'undefined') {
|
|
1341
|
-
infoPopup({
|
|
1342
|
-
title: 'Sync error',
|
|
1343
|
-
content: payload.error,
|
|
1344
|
-
type: 'danger',
|
|
1345
|
-
});
|
|
1346
|
-
if (payload.refresh) {
|
|
1347
|
-
setTimeout(() => {
|
|
1348
|
-
window.location.reload();
|
|
1349
|
-
});
|
|
1350
|
-
}
|
|
1351
|
-
else {
|
|
1352
|
-
$syncButton.disabled = true;
|
|
1353
|
-
$syncButton.classList.add('disabled');
|
|
1354
|
-
$syncButton.title = 'Sync is unavailable on this instance';
|
|
1355
|
-
}
|
|
1356
|
-
}
|
|
1357
|
-
else if ('syncedAt' in payload && typeof payload.syncedAt !== 'undefined') {
|
|
1358
|
-
infoPopup({
|
|
1359
|
-
title: 'Sync success',
|
|
1360
|
-
content: `Synced at ${new Date(payload.syncedAt).toLocaleString()}.\nBackup filename: ${payload.backupFilename}`,
|
|
1361
|
-
type: 'success',
|
|
1362
|
-
});
|
|
1363
|
-
}
|
|
1364
|
-
});
|
|
1365
|
-
$syncButton.addEventListener('click', (ev) => {
|
|
1366
|
-
ev.preventDefault();
|
|
1367
|
-
$syncButton.classList.add('syncing');
|
|
1368
|
-
hot.send('template:sync', {});
|
|
1369
|
-
});
|
|
1495
|
+
initSyncButton(hot, $syncButton, { infoPopup, confirmModal, closeAllConfirmModals });
|
|
1370
1496
|
}
|
|
1371
1497
|
hot.on('page-variables:reload:response', (payload) => {
|
|
1372
1498
|
pendingReloadVariablesPopup?.close();
|