@mxtommy/kip 3.12.0 → 4.0.2
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/.github/copilot-instructions.md +102 -27
- package/.github/instructions/angular.instructions.md +1 -1
- package/CHANGELOG.md +26 -0
- package/README.md +94 -74
- package/docs/widget-schematic.md +102 -0
- package/images/ChartplotterMode.png +0 -0
- package/package.json +8 -3
- package/public/3rdpartylicenses.txt +67 -41
- package/public/assets/help-docs/chartplotter.md +122 -0
- package/public/assets/help-docs/community.md +1 -11
- package/public/assets/help-docs/kiosk.md +15 -15
- package/public/assets/help-docs/menu.json +1 -0
- package/public/assets/help-docs/welcome.md +3 -0
- package/public/assets/svg/icons.svg +4 -6
- package/public/chunk-52M2PJJL.js +4 -0
- package/public/{chunk-I454VRMK.js → chunk-AB255PKD.js} +1 -1
- package/public/chunk-B4SMHL7P.js +1 -0
- package/public/chunk-BEFXDBJY.js +3 -0
- package/public/{chunk-ZEV6YXHP.js → chunk-BMDGKBYM.js} +23 -23
- package/public/chunk-CA2BN4YV.js +9 -0
- package/public/chunk-D2CYLQZF.js +1 -0
- package/public/chunk-DKOFT6NI.js +52 -0
- package/public/{chunk-3LKIOGV7.js → chunk-E7MNINLP.js} +1 -1
- package/public/chunk-F75BVJPY.js +2 -0
- package/public/chunk-H3EFQCTE.js +5 -0
- package/public/{chunk-ZPCYFQPB.js → chunk-HIADZ4BV.js} +1 -1
- package/public/{chunk-IQG4DDQX.js → chunk-IJ22WXFB.js} +1 -1
- package/public/chunk-KI5CZR7P.js +1 -0
- package/public/{chunk-UTCRLFYC.js → chunk-NBMGYSW2.js} +1 -1
- package/public/chunk-OA5PBKO5.js +6 -0
- package/public/{chunk-YPUCOH35.js → chunk-OB3QLUH6.js} +12 -12
- package/public/{chunk-6MRJ4C55.js → chunk-OQULS6SV.js} +1 -1
- package/public/chunk-PPT35KWJ.js +8 -0
- package/public/{chunk-EPTIEPMQ.js → chunk-RYHOAWDD.js} +1 -1
- package/public/{chunk-NOLKBYOV.js → chunk-SZ2GUIT5.js} +1 -1
- package/public/chunk-TIWUK3AU.js +1 -0
- package/public/{chunk-RMLGKVWE.js → chunk-UIO7WC72.js} +1 -1
- package/public/{chunk-YVLZ2UAQ.js → chunk-V2FKRRBL.js} +2 -2
- package/public/chunk-WYPJEP5R.js +1 -0
- package/public/index.html +2 -2
- package/public/main-7RENLC7I.js +5 -0
- package/public/scripts-7HSGK5LZ.js +14 -0
- package/public/styles-MJ4EO4B4.css +1 -0
- package/tools/schematics/collection.json +9 -0
- package/tools/schematics/create-host2-widget/files/readme/README.md.template +109 -0
- package/tools/schematics/create-host2-widget/files/spec/widget-__name@dasherize__.component.spec.ts +38 -0
- package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.html +6 -0
- package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.scss +5 -0
- package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.ts.template +94 -0
- package/tools/schematics/create-host2-widget/index.js +138 -0
- package/tools/schematics/create-host2-widget/schema.json +89 -0
- package/tools/schematics/create-host2-widget/test/create-host2-widget.spec.ts +70 -0
- package/tools/schematics/create-host2-widget/utils/formatting.js +119 -0
- package/public/chunk-65TR3CWM.js +0 -6
- package/public/chunk-7S37JBY2.js +0 -2
- package/public/chunk-A5CYPNMD.js +0 -2
- package/public/chunk-BSAAN2EI.js +0 -2
- package/public/chunk-CDPHRRZR.js +0 -3
- package/public/chunk-D4DROTBC.js +0 -8
- package/public/chunk-D4MWDRNW.js +0 -5
- package/public/chunk-K5OOC3CF.js +0 -4
- package/public/chunk-QOXZFV6P.js +0 -47
- package/public/chunk-T6TC7KWG.js +0 -1
- package/public/chunk-UHKP2PC3.js +0 -1
- package/public/chunk-VEJNBHWJ.js +0 -5
- package/public/chunk-XLJT6YPP.js +0 -1
- package/public/chunk-YCW2UBVQ.js +0 -1
- package/public/chunk-Z5MCM3TT.js +0 -11
- package/public/main-7TSLA2U5.js +0 -5
- package/public/styles-PDNHT2L2.css +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@font-face{font-family:Material Icons;font-style:normal;font-weight:400;font-display:swap;src:local("Material Icons"),local("MaterialIcons-Regular"),url("./media/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ-CN2J7AYH.woff2") format("woff2")}.material-icons{font-family:Material Icons;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:"liga";font-feature-settings:"liga";-webkit-font-smoothing:antialiased}@font-face{font-family:Roboto;font-style:normal;font-weight:300;font-display:swap;src:local("Roboto Light"),local("Roboto-Light"),url("./media/KFOlCnqEu92Fr1MmSU5fCRc4AMP6lbBP-QPSNQEDD.woff2") format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Roboto;font-style:normal;font-weight:300;font-display:swap;src:local("Roboto Light"),local("Roboto-Light"),url("./media/KFOlCnqEu92Fr1MmSU5fABc4AMP6lbBP-XWLWMQVU.woff2") format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Roboto;font-style:normal;font-weight:300;font-display:swap;src:local("Roboto Light"),local("Roboto-Light"),url("./media/KFOlCnqEu92Fr1MmSU5fCBc4AMP6lbBP-32PLHKPQ.woff2") format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Roboto;font-style:normal;font-weight:300;font-display:swap;src:local("Roboto Light"),local("Roboto-Light"),url("./media/KFOlCnqEu92Fr1MmSU5fBxc4AMP6lbBP-ITB7NUJC.woff2") format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Roboto;font-style:normal;font-weight:300;font-display:swap;src:local("Roboto Light"),local("Roboto-Light"),url("./media/KFOlCnqEu92Fr1MmSU5fCxc4AMP6lbBP-OG5AHRIX.woff2") format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Roboto;font-style:normal;font-weight:300;font-display:swap;src:local("Roboto Light"),local("Roboto-Light"),url("./media/KFOlCnqEu92Fr1MmSU5fChc4AMP6lbBP-JKBSJZY3.woff2") format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Roboto;font-style:normal;font-weight:300;font-display:swap;src:local("Roboto Light"),local("Roboto-Light"),url("./media/KFOlCnqEu92Fr1MmSU5fBBc4AMP6lQ-PWGJWDFE.woff2") format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:local("Roboto"),local("Roboto-Regular"),url("./media/KFOmCnqEu92Fr1Mu72xKKTU1Kvnz-PRJ7OQMU.woff2") format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:local("Roboto"),local("Roboto-Regular"),url("./media/KFOmCnqEu92Fr1Mu5mxKKTU1Kvnz-DRL4U32S.woff2") format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:local("Roboto"),local("Roboto-Regular"),url("./media/KFOmCnqEu92Fr1Mu7mxKKTU1Kvnz-Z72STTMG.woff2") format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:local("Roboto"),local("Roboto-Regular"),url("./media/KFOmCnqEu92Fr1Mu4WxKKTU1Kvnz-PPTELUJT.woff2") format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:local("Roboto"),local("Roboto-Regular"),url("./media/KFOmCnqEu92Fr1Mu7WxKKTU1Kvnz-KZD6JQRT.woff2") format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:local("Roboto"),local("Roboto-Regular"),url("./media/KFOmCnqEu92Fr1Mu7GxKKTU1Kvnz-HW6RMPJ3.woff2") format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:local("Roboto"),local("Roboto-Regular"),url("./media/KFOmCnqEu92Fr1Mu4mxKKTU1Kg-SNGEW7FX.woff2") format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Roboto;font-style:normal;font-weight:500;font-display:swap;src:local("Roboto Medium"),local("Roboto-Medium"),url("./media/KFOlCnqEu92Fr1MmEU9fCRc4AMP6lbBP-36ULTGLY.woff2") format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Roboto;font-style:normal;font-weight:500;font-display:swap;src:local("Roboto Medium"),local("Roboto-Medium"),url("./media/KFOlCnqEu92Fr1MmEU9fABc4AMP6lbBP-ILKS6RVC.woff2") format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Roboto;font-style:normal;font-weight:500;font-display:swap;src:local("Roboto Medium"),local("Roboto-Medium"),url("./media/KFOlCnqEu92Fr1MmEU9fCBc4AMP6lbBP-U3JTBV4H.woff2") format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Roboto;font-style:normal;font-weight:500;font-display:swap;src:local("Roboto Medium"),local("Roboto-Medium"),url("./media/KFOlCnqEu92Fr1MmEU9fBxc4AMP6lbBP-UW3XWY7P.woff2") format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Roboto;font-style:normal;font-weight:500;font-display:swap;src:local("Roboto Medium"),local("Roboto-Medium"),url("./media/KFOlCnqEu92Fr1MmEU9fCxc4AMP6lbBP-2EL65J2O.woff2") format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Roboto;font-style:normal;font-weight:500;font-display:swap;src:local("Roboto Medium"),local("Roboto-Medium"),url("./media/KFOlCnqEu92Fr1MmEU9fChc4AMP6lbBP-5NJLO2HW.woff2") format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Roboto;font-style:normal;font-weight:500;font-display:swap;src:local("Roboto Medium"),local("Roboto-Medium"),url("./media/KFOlCnqEu92Fr1MmEU9fBBc4AMP6lQ-MJ3CERJ6.woff2") format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}.rounded-card-color{background-color:var(--kip-contrast-dimmer-color)}.rounded-card{margin-top:10px;border-radius:15px;padding:10px}.formActionFooter{width:100%;text-align:end;margin-top:10px}.formActionButton{margin:0 3px 10px 10px}.formActionDivider{padding-bottom:10px}.flex-container{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:center;align-content:flex-start;gap:10px}.flex-item-rounded-card{flex:1 1 29%;padding:10px 20px;border-radius:15px}.flex-checkbox-30{flex-grow:1;flex-basis:30%;padding-bottom:23px}.flex-field-30{flex-grow:1;flex-basis:30%}.flex-field-50{flex-grow:1;flex-basis:48%}.flex-field-65{flex-grow:1;flex-basis:65%}.flex-field-100{flex-grow:1;flex-basis:100%}.flex-field-to-100{flex-grow:1;flex-basis:60%}.flex-field-fixed{flex-grow:0;flex-shrink:0;flex-basis:auto}.filter-path{width:125px}.mat-mdc-radio-button~.mat-radio-button{margin-left:16px}.widget-options-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px}.options-grid-span2{grid-column:1/span 2}.radio-group{display:flex;flex-direction:column;margin:15px 0}.radio-button{margin-left:16px}.full-width{width:100%}.page-content-wrapper{padding:0 24px 14px}.grid-stack{position:relative}.grid-stack-rtl{direction:ltr}.grid-stack-rtl>.grid-stack-item{direction:rtl}.grid-stack-placeholder>.placeholder-content{background-color:#0000001a;margin:0;position:absolute;width:auto;z-index:0!important}.grid-stack>.grid-stack-item{position:absolute;padding:0;top:0;left:0;width:var(--gs-column-width);height:var(--gs-cell-height)}.grid-stack>.grid-stack-item>.grid-stack-item-content{margin:0;position:absolute;width:auto;overflow-x:hidden;overflow-y:auto}.grid-stack>.grid-stack-item.size-to-content:not(.size-to-content-max)>.grid-stack-item-content{overflow-y:hidden}.grid-stack>.grid-stack-item>.grid-stack-item-content,.grid-stack>.grid-stack-placeholder>.placeholder-content{top:var(--gs-item-margin-top);right:var(--gs-item-margin-right);bottom:var(--gs-item-margin-bottom);left:var(--gs-item-margin-left)}.grid-stack-item>.ui-resizable-handle{position:absolute;font-size:.1px;display:block;-ms-touch-action:none;touch-action:none}.grid-stack-item.ui-resizable-autohide>.ui-resizable-handle,.grid-stack-item.ui-resizable-disabled>.ui-resizable-handle{display:none}.grid-stack-item>.ui-resizable-ne,.grid-stack-item>.ui-resizable-nw,.grid-stack-item>.ui-resizable-se,.grid-stack-item>.ui-resizable-sw{background-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="%23666" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 20 20"><path d="m10 3 2 2H8l2-2v14l-2-2h4l-2 2"/></svg>');background-repeat:no-repeat;background-position:center}.grid-stack-item>.ui-resizable-ne{transform:rotate(45deg)}.grid-stack-item>.ui-resizable-sw{transform:rotate(45deg)}.grid-stack-item>.ui-resizable-nw{transform:rotate(-45deg)}.grid-stack-item>.ui-resizable-se{transform:rotate(-45deg)}.grid-stack-item>.ui-resizable-nw{cursor:nw-resize;width:20px;height:20px;top:var(--gs-item-margin-top);left:var(--gs-item-margin-left)}.grid-stack-item>.ui-resizable-n{cursor:n-resize;height:10px;top:var(--gs-item-margin-top);left:25px;right:25px}.grid-stack-item>.ui-resizable-ne{cursor:ne-resize;width:20px;height:20px;top:var(--gs-item-margin-top);right:var(--gs-item-margin-right)}.grid-stack-item>.ui-resizable-e{cursor:e-resize;width:10px;top:15px;bottom:15px;right:var(--gs-item-margin-right)}.grid-stack-item>.ui-resizable-se{cursor:se-resize;width:20px;height:20px;bottom:var(--gs-item-margin-bottom);right:var(--gs-item-margin-right)}.grid-stack-item>.ui-resizable-s{cursor:s-resize;height:10px;left:25px;bottom:var(--gs-item-margin-bottom);right:25px}.grid-stack-item>.ui-resizable-sw{cursor:sw-resize;width:20px;height:20px;bottom:var(--gs-item-margin-bottom);left:var(--gs-item-margin-left)}.grid-stack-item>.ui-resizable-w{cursor:w-resize;width:10px;top:15px;bottom:15px;left:var(--gs-item-margin-left)}.grid-stack-item.ui-draggable-dragging>.ui-resizable-handle{display:none!important}.grid-stack-item.ui-draggable-dragging{will-change:left,top}.grid-stack-item.ui-resizable-resizing{will-change:width,height}.ui-draggable-dragging,.ui-resizable-resizing{z-index:10000}.ui-draggable-dragging>.grid-stack-item-content,.ui-resizable-resizing>.grid-stack-item-content{box-shadow:1px 4px 6px #0003;opacity:.8}.grid-stack-animate,.grid-stack-animate .grid-stack-item{transition:left .3s,top .3s,height .3s,width .3s}.grid-stack-animate .grid-stack-item.grid-stack-placeholder,.grid-stack-animate .grid-stack-item.ui-draggable-dragging,.grid-stack-animate .grid-stack-item.ui-resizable-resizing{transition:left 0s,top 0s,height 0s,width 0s}.grid-stack>.grid-stack-item[gs-y="0"]{top:0}.grid-stack>.grid-stack-item[gs-x="0"]{left:0}:root{--mat-sys-background: #191c1d;--kip-nightModeBrightness: 1;--kip-widget-card-background-color: #000000;--kip-widget-card-border-color: #252525;--kip-widget-card-border-style: solid;--kip-widget-card-border-width: 2px;--kip-blue-color: #3298ff;--kip-blue-dim-color: rgba(53, 154, 255, .7764705882);--kip-blue-dimmer-color: rgba(6, 59, 113, .4705882353);--kip-green-color: #00d000;--kip-green-dim-color: rgba(0, 208, 0, .7137254902);--kip-green-dimmer-color: rgba(0, 104, 0, .4705882353);--kip-purple-color: #A020F0;--kip-purple-dim-color: rgba(160, 32, 240, .7137254902);--kip-purple-dimmer-color: rgba(74, 15, 110, .4705882353);--kip-yellow-color: #ffdf00;--kip-yellow-dim-color: rgba(255, 223, 0, .7137254902);--kip-yellow-dimmer-color: rgba(114, 110, 0, .4705882353);--kip-pink-color: #FC0FC0;--kip-pink-dim-color: rgba(252, 15, 192, .7137254902);--kip-pink-dimmer-color: rgba(109, 7, 83, .4705882353);--kip-orange-color: #ff9100;--kip-orange-dim-color: rgba(255, 145, 0, .7137254902);--kip-orange-dimmer-color: rgba(113, 74, 0, .4705882353);--kip-contrast-color: #FFFFFF;--kip-contrast-dim-color: rgba(255, 255, 255, .7137254902);--kip-contrast-dimmer-color: rgba(255, 255, 255, .1607843137);--kip-grey-color: #B5B5B5;--kip-grey-dim-color: rgba(181, 181, 181, .7137254902);--kip-grey-dimmer-color: #1a1a1a;--kip-port-color: #8F0000;--kip-starboard-color: #008700;--kip-zone-nominal-color: #0164FA;--kip-zone-alert-color: #ffff60;--kip-zone-warn-color: #ff8d41;--kip-zone-alarm-color: #E90000;--kip-zone-emergency-color: #760000}body.light-theme{--mat-sys-background: #e1e4ec;--kip-widget-card-background-color: #ffffff;--kip-widget-card-border-color: #252525;--kip-contrast-color: #000000;--kip-contrast-dim-color: rgba(0, 0, 0, .7137254902);--kip-contrast-dimmer-color: rgba(0, 0, 0, .1607843137);--kip-grey-color: #666666;--kip-grey-dim-color: rgba(102, 102, 102, .7137254902);--kip-grey-dimmer-color: rgba(102, 102, 102, .1607843137);--kip-blue-color: #005bb5;--kip-blue-dim-color: rgba(0, 91, 181, .7137254902);--kip-blue-dimmer-color: rgba(0, 91, 181, .4705882353);--kip-green-color: #007a00;--kip-green-dim-color: rgba(0, 122, 0, .7137254902);--kip-green-dimmer-color: rgba(0, 122, 0, .4705882353);--kip-purple-color: #6a00a8;--kip-purple-dim-color: rgba(106, 0, 168, .7137254902);--kip-purple-dimmer-color: rgba(106, 0, 168, .4705882353);--kip-yellow-color: #bfa800;--kip-yellow-dim-color: rgba(191, 168, 0, .7137254902);--kip-yellow-dimmer-color: rgba(191, 168, 0, .4705882353);--kip-pink-color: #b00070;--kip-pink-dim-color: rgba(176, 0, 112, .7137254902);--kip-pink-dimmer-color: rgba(176, 0, 112, .4705882353);--kip-orange-color: #c56200;--kip-orange-dim-color: rgba(197, 98, 0, .7137254902);--kip-orange-dimmer-color: rgba(197, 98, 0, .4705882353);--kip-port-color: #b70000;--kip-starboard-color: #008700;--kip-zone-nominal-color: #0182fa;--kip-zone-alert-color: #f0f032;--kip-zone-warn-color: #ff8534;--kip-zone-alarm-color: #ff0000;--kip-zone-emergency-color: #741e1e}body.night-theme{--mat-sys-background: #101415;--kip-widget-card-background-color: #000000;--kip-widget-card-border-color: #252525;--kip-contrast-color: #520000;--kip-contrast-dim-color: rgba(82, 0, 0, .7137254902);--kip-contrast-dimmer-color: rgba(38, 0, 0, .7725490196);--kip-grey-color: #520000;--kip-grey-dim-color: rgba(82, 0, 0, .7137254902);--kip-grey-dimmer-color: rgba(38, 0, 0, .7725490196);--kip-blue-color: #520000;--kip-blue-dim-color: rgba(82, 0, 0, .7137254902);--kip-blue-dimmer-color: rgba(38, 0, 0, .7725490196);--kip-green-color: #520000;--kip-green-dim-color: rgba(82, 0, 0, .7137254902);--kip-green-dimmer-color: rgba(38, 0, 0, .7725490196);--kip-purple-color: #520000;--kip-purple-dim-color: rgba(82, 0, 0, .7137254902);--kip-purple-dimmer-color: rgba(38, 0, 0, .7725490196);--kip-yellow-color: #520000;--kip-yellow-dim-color: rgba(82, 0, 0, .7137254902);--kip-yellow-dimmer-color: rgba(38, 0, 0, .7725490196);--kip-pink-color: #520000;--kip-pink-dim-color: rgba(82, 0, 0, .7137254902);--kip-pink-dimmer-color: rgba(38, 0, 0, .7725490196);--kip-orange-color: #520000;--kip-orange-dim-color: rgba(82, 0, 0, .7137254902);--kip-orange-dimmer-color: rgba(38, 0, 0, .7725490196);--kip-port-color: #800000;--kip-starboard-color: #005500;--kip-zone-nominal-color: #001d49;--kip-zone-alert-color: #2c2c00;--kip-zone-warn-color: #441e00;--kip-zone-alarm-color: #850000;--kip-zone-emergency-color: #bd0000}html{--mat-sys-background: #101415;--mat-sys-error: #ffb4ab;--mat-sys-error-container: #93000a;--mat-sys-inverse-on-surface: #2e3132;--mat-sys-inverse-primary: #0058c9;--mat-sys-inverse-surface: #e1e3e3;--mat-sys-on-background: #e1e3e3;--mat-sys-on-error: #690005;--mat-sys-on-error-container: #ffdad6;--mat-sys-on-primary: #002d6d;--mat-sys-on-primary-container: #d9e2ff;--mat-sys-on-primary-fixed: #001944;--mat-sys-on-primary-fixed-variant: #00429a;--mat-sys-on-secondary: #002e6b;--mat-sys-on-secondary-container: #d8e2ff;--mat-sys-on-secondary-fixed: #001a42;--mat-sys-on-secondary-fixed-variant: #13448f;--mat-sys-on-surface: #e1e3e3;--mat-sys-on-surface-variant: #dbe4e6;--mat-sys-on-tertiary: #3d2f00;--mat-sys-on-tertiary-container: #ffe08b;--mat-sys-on-tertiary-fixed: #241a00;--mat-sys-on-tertiary-fixed-variant: #584400;--mat-sys-outline: #899294;--mat-sys-outline-variant: #3f484a;--mat-sys-primary: #afc6ff;--mat-sys-primary-container: #00429a;--mat-sys-primary-fixed: #d9e2ff;--mat-sys-primary-fixed-dim: #afc6ff;--mat-sys-scrim: #000000;--mat-sys-secondary: #aec6ff;--mat-sys-secondary-container: #13448f;--mat-sys-secondary-fixed: #d8e2ff;--mat-sys-secondary-fixed-dim: #aec6ff;--mat-sys-shadow: #000000;--mat-sys-surface: #101415;--mat-sys-surface-bright: #363a3a;--mat-sys-surface-container: #1d2021;--mat-sys-surface-container-high: #272b2b;--mat-sys-surface-container-highest: #323536;--mat-sys-surface-container-low: #191c1d;--mat-sys-surface-container-lowest: #0b0f0f;--mat-sys-surface-dim: #101415;--mat-sys-surface-tint: #afc6ff;--mat-sys-surface-variant: #3f484a;--mat-sys-tertiary: #eec12c;--mat-sys-tertiary-container: #584400;--mat-sys-tertiary-fixed: #ffe08b;--mat-sys-tertiary-fixed-dim: #eec12c;--mat-sys-neutral-variant20: #293234;--mat-sys-neutral10: #191c1d;--mat-sys-level0: 0px 0px 0px 0px rgba(0, 0, 0, .2), 0px 0px 0px 0px rgba(0, 0, 0, .14), 0px 0px 0px 0px rgba(0, 0, 0, .12);--mat-sys-level1: 0px 2px 1px -1px rgba(0, 0, 0, .2), 0px 1px 1px 0px rgba(0, 0, 0, .14), 0px 1px 3px 0px rgba(0, 0, 0, .12);--mat-sys-level2: 0px 3px 3px -2px rgba(0, 0, 0, .2), 0px 3px 4px 0px rgba(0, 0, 0, .14), 0px 1px 8px 0px rgba(0, 0, 0, .12);--mat-sys-level3: 0px 3px 5px -1px rgba(0, 0, 0, .2), 0px 6px 10px 0px rgba(0, 0, 0, .14), 0px 1px 18px 0px rgba(0, 0, 0, .12);--mat-sys-level4: 0px 5px 5px -3px rgba(0, 0, 0, .2), 0px 8px 10px 1px rgba(0, 0, 0, .14), 0px 3px 14px 2px rgba(0, 0, 0, .12);--mat-sys-level5: 0px 7px 8px -4px rgba(0, 0, 0, .2), 0px 12px 17px 2px rgba(0, 0, 0, .14), 0px 5px 22px 4px rgba(0, 0, 0, .12);--mat-sys-body-large: 400 1rem / 1.5rem Roboto;--mat-sys-body-large-font: Roboto;--mat-sys-body-large-line-height: 1.5rem;--mat-sys-body-large-size: 1rem;--mat-sys-body-large-tracking: .031rem;--mat-sys-body-large-weight: 400;--mat-sys-body-medium: 400 .875rem / 1.25rem Roboto;--mat-sys-body-medium-font: Roboto;--mat-sys-body-medium-line-height: 1.25rem;--mat-sys-body-medium-size: .875rem;--mat-sys-body-medium-tracking: .016rem;--mat-sys-body-medium-weight: 400;--mat-sys-body-small: 400 .75rem / 1rem Roboto;--mat-sys-body-small-font: Roboto;--mat-sys-body-small-line-height: 1rem;--mat-sys-body-small-size: .75rem;--mat-sys-body-small-tracking: .025rem;--mat-sys-body-small-weight: 400;--mat-sys-display-large: 400 3.562rem / 4rem Roboto;--mat-sys-display-large-font: Roboto;--mat-sys-display-large-line-height: 4rem;--mat-sys-display-large-size: 3.562rem;--mat-sys-display-large-tracking: -.016rem;--mat-sys-display-large-weight: 400;--mat-sys-display-medium: 400 2.812rem / 3.25rem Roboto;--mat-sys-display-medium-font: Roboto;--mat-sys-display-medium-line-height: 3.25rem;--mat-sys-display-medium-size: 2.812rem;--mat-sys-display-medium-tracking: 0;--mat-sys-display-medium-weight: 400;--mat-sys-display-small: 400 2.25rem / 2.75rem Roboto;--mat-sys-display-small-font: Roboto;--mat-sys-display-small-line-height: 2.75rem;--mat-sys-display-small-size: 2.25rem;--mat-sys-display-small-tracking: 0;--mat-sys-display-small-weight: 400;--mat-sys-headline-large: 400 2rem / 2.5rem Roboto;--mat-sys-headline-large-font: Roboto;--mat-sys-headline-large-line-height: 2.5rem;--mat-sys-headline-large-size: 2rem;--mat-sys-headline-large-tracking: 0;--mat-sys-headline-large-weight: 400;--mat-sys-headline-medium: 400 1.75rem / 2.25rem Roboto;--mat-sys-headline-medium-font: Roboto;--mat-sys-headline-medium-line-height: 2.25rem;--mat-sys-headline-medium-size: 1.75rem;--mat-sys-headline-medium-tracking: 0;--mat-sys-headline-medium-weight: 400;--mat-sys-headline-small: 400 1.5rem / 2rem Roboto;--mat-sys-headline-small-font: Roboto;--mat-sys-headline-small-line-height: 2rem;--mat-sys-headline-small-size: 1.5rem;--mat-sys-headline-small-tracking: 0;--mat-sys-headline-small-weight: 400;--mat-sys-label-large: 500 .875rem / 1.25rem Roboto;--mat-sys-label-large-font: Roboto;--mat-sys-label-large-line-height: 1.25rem;--mat-sys-label-large-size: .875rem;--mat-sys-label-large-tracking: .006rem;--mat-sys-label-large-weight: 500;--mat-sys-label-large-weight-prominent: 700;--mat-sys-label-medium: 500 .75rem / 1rem Roboto;--mat-sys-label-medium-font: Roboto;--mat-sys-label-medium-line-height: 1rem;--mat-sys-label-medium-size: .75rem;--mat-sys-label-medium-tracking: .031rem;--mat-sys-label-medium-weight: 500;--mat-sys-label-medium-weight-prominent: 700;--mat-sys-label-small: 500 .688rem / 1rem Roboto;--mat-sys-label-small-font: Roboto;--mat-sys-label-small-line-height: 1rem;--mat-sys-label-small-size: .688rem;--mat-sys-label-small-tracking: .031rem;--mat-sys-label-small-weight: 500;--mat-sys-title-large: 400 1.375rem / 1.75rem Roboto;--mat-sys-title-large-font: Roboto;--mat-sys-title-large-line-height: 1.75rem;--mat-sys-title-large-size: 1.375rem;--mat-sys-title-large-tracking: 0;--mat-sys-title-large-weight: 400;--mat-sys-title-medium: 500 1rem / 1.5rem Roboto;--mat-sys-title-medium-font: Roboto;--mat-sys-title-medium-line-height: 1.5rem;--mat-sys-title-medium-size: 1rem;--mat-sys-title-medium-tracking: .009rem;--mat-sys-title-medium-weight: 500;--mat-sys-title-small: 500 .875rem / 1.25rem Roboto;--mat-sys-title-small-font: Roboto;--mat-sys-title-small-line-height: 1.25rem;--mat-sys-title-small-size: .875rem;--mat-sys-title-small-tracking: .006rem;--mat-sys-title-small-weight: 500;--mat-sys-corner-extra-large: 28px;--mat-sys-corner-extra-large-top: 28px 28px 0 0;--mat-sys-corner-extra-small: 4px;--mat-sys-corner-extra-small-top: 4px 4px 0 0;--mat-sys-corner-full: 9999px;--mat-sys-corner-large: 16px;--mat-sys-corner-large-end: 0 16px 16px 0;--mat-sys-corner-large-start: 16px 0 0 16px;--mat-sys-corner-large-top: 16px 16px 0 0;--mat-sys-corner-medium: 12px;--mat-sys-corner-none: 0;--mat-sys-corner-small: 8px;--mat-sys-dragged-state-layer-opacity: .16;--mat-sys-focus-state-layer-opacity: .12;--mat-sys-hover-state-layer-opacity: .08;--mat-sys-pressed-state-layer-opacity: .12}.light-theme{--mat-sys-background: #fcf8fd;--mat-sys-error: #ba1a1a;--mat-sys-error-container: #ffdad6;--mat-sys-inverse-on-surface: #f3eff4;--mat-sys-inverse-primary: #bec2ff;--mat-sys-inverse-surface: #303034;--mat-sys-on-background: #1b1b1f;--mat-sys-on-error: #ffffff;--mat-sys-on-error-container: #93000a;--mat-sys-on-primary: #ffffff;--mat-sys-on-primary-container: #0000ef;--mat-sys-on-primary-fixed: #00006e;--mat-sys-on-primary-fixed-variant: #0000ef;--mat-sys-on-secondary: #ffffff;--mat-sys-on-secondary-container: #444559;--mat-sys-on-secondary-fixed: #191a2c;--mat-sys-on-secondary-fixed-variant: #444559;--mat-sys-on-surface: #1b1b1f;--mat-sys-on-surface-variant: #46464f;--mat-sys-on-tertiary: #ffffff;--mat-sys-on-tertiary-container: #494900;--mat-sys-on-tertiary-fixed: #1d1d00;--mat-sys-on-tertiary-fixed-variant: #494900;--mat-sys-outline: #777680;--mat-sys-outline-variant: #c7c5d0;--mat-sys-primary: #343dff;--mat-sys-primary-container: #e0e0ff;--mat-sys-primary-fixed: #e0e0ff;--mat-sys-primary-fixed-dim: #bec2ff;--mat-sys-scrim: #000000;--mat-sys-secondary: #5c5d72;--mat-sys-secondary-container: #e1e0f9;--mat-sys-secondary-fixed: #e1e0f9;--mat-sys-secondary-fixed-dim: #c5c4dd;--mat-sys-shadow: #000000;--mat-sys-surface: #fcf8fd;--mat-sys-surface-bright: #fcf8fd;--mat-sys-surface-container: #f0edf1;--mat-sys-surface-container-high: #ebe7eb;--mat-sys-surface-container-highest: #e5e1e6;--mat-sys-surface-container-low: #f6f2f7;--mat-sys-surface-container-lowest: #ffffff;--mat-sys-surface-dim: #dcd9dd;--mat-sys-surface-tint: #343dff;--mat-sys-surface-variant: #e4e1ec;--mat-sys-tertiary: #626200;--mat-sys-tertiary-container: #eaea00;--mat-sys-tertiary-fixed: #eaea00;--mat-sys-tertiary-fixed-dim: #cdcd00;--mat-sys-neutral-variant20: #303038;--mat-sys-neutral10: #1b1b1f;--mat-sys-level0: 0px 0px 0px 0px rgba(0, 0, 0, .2), 0px 0px 0px 0px rgba(0, 0, 0, .14), 0px 0px 0px 0px rgba(0, 0, 0, .12);--mat-sys-level1: 0px 2px 1px -1px rgba(0, 0, 0, .2), 0px 1px 1px 0px rgba(0, 0, 0, .14), 0px 1px 3px 0px rgba(0, 0, 0, .12);--mat-sys-level2: 0px 3px 3px -2px rgba(0, 0, 0, .2), 0px 3px 4px 0px rgba(0, 0, 0, .14), 0px 1px 8px 0px rgba(0, 0, 0, .12);--mat-sys-level3: 0px 3px 5px -1px rgba(0, 0, 0, .2), 0px 6px 10px 0px rgba(0, 0, 0, .14), 0px 1px 18px 0px rgba(0, 0, 0, .12);--mat-sys-level4: 0px 5px 5px -3px rgba(0, 0, 0, .2), 0px 8px 10px 1px rgba(0, 0, 0, .14), 0px 3px 14px 2px rgba(0, 0, 0, .12);--mat-sys-level5: 0px 7px 8px -4px rgba(0, 0, 0, .2), 0px 12px 17px 2px rgba(0, 0, 0, .14), 0px 5px 22px 4px rgba(0, 0, 0, .12);--mat-sys-body-large: 400 1rem / 1.5rem Roboto;--mat-sys-body-large-font: Roboto;--mat-sys-body-large-line-height: 1.5rem;--mat-sys-body-large-size: 1rem;--mat-sys-body-large-tracking: .031rem;--mat-sys-body-large-weight: 400;--mat-sys-body-medium: 400 .875rem / 1.25rem Roboto;--mat-sys-body-medium-font: Roboto;--mat-sys-body-medium-line-height: 1.25rem;--mat-sys-body-medium-size: .875rem;--mat-sys-body-medium-tracking: .016rem;--mat-sys-body-medium-weight: 400;--mat-sys-body-small: 400 .75rem / 1rem Roboto;--mat-sys-body-small-font: Roboto;--mat-sys-body-small-line-height: 1rem;--mat-sys-body-small-size: .75rem;--mat-sys-body-small-tracking: .025rem;--mat-sys-body-small-weight: 400;--mat-sys-display-large: 400 3.562rem / 4rem Roboto;--mat-sys-display-large-font: Roboto;--mat-sys-display-large-line-height: 4rem;--mat-sys-display-large-size: 3.562rem;--mat-sys-display-large-tracking: -.016rem;--mat-sys-display-large-weight: 400;--mat-sys-display-medium: 400 2.812rem / 3.25rem Roboto;--mat-sys-display-medium-font: Roboto;--mat-sys-display-medium-line-height: 3.25rem;--mat-sys-display-medium-size: 2.812rem;--mat-sys-display-medium-tracking: 0;--mat-sys-display-medium-weight: 400;--mat-sys-display-small: 400 2.25rem / 2.75rem Roboto;--mat-sys-display-small-font: Roboto;--mat-sys-display-small-line-height: 2.75rem;--mat-sys-display-small-size: 2.25rem;--mat-sys-display-small-tracking: 0;--mat-sys-display-small-weight: 400;--mat-sys-headline-large: 400 2rem / 2.5rem Roboto;--mat-sys-headline-large-font: Roboto;--mat-sys-headline-large-line-height: 2.5rem;--mat-sys-headline-large-size: 2rem;--mat-sys-headline-large-tracking: 0;--mat-sys-headline-large-weight: 400;--mat-sys-headline-medium: 400 1.75rem / 2.25rem Roboto;--mat-sys-headline-medium-font: Roboto;--mat-sys-headline-medium-line-height: 2.25rem;--mat-sys-headline-medium-size: 1.75rem;--mat-sys-headline-medium-tracking: 0;--mat-sys-headline-medium-weight: 400;--mat-sys-headline-small: 400 1.5rem / 2rem Roboto;--mat-sys-headline-small-font: Roboto;--mat-sys-headline-small-line-height: 2rem;--mat-sys-headline-small-size: 1.5rem;--mat-sys-headline-small-tracking: 0;--mat-sys-headline-small-weight: 400;--mat-sys-label-large: 500 .875rem / 1.25rem Roboto;--mat-sys-label-large-font: Roboto;--mat-sys-label-large-line-height: 1.25rem;--mat-sys-label-large-size: .875rem;--mat-sys-label-large-tracking: .006rem;--mat-sys-label-large-weight: 500;--mat-sys-label-large-weight-prominent: 700;--mat-sys-label-medium: 500 .75rem / 1rem Roboto;--mat-sys-label-medium-font: Roboto;--mat-sys-label-medium-line-height: 1rem;--mat-sys-label-medium-size: .75rem;--mat-sys-label-medium-tracking: .031rem;--mat-sys-label-medium-weight: 500;--mat-sys-label-medium-weight-prominent: 700;--mat-sys-label-small: 500 .688rem / 1rem Roboto;--mat-sys-label-small-font: Roboto;--mat-sys-label-small-line-height: 1rem;--mat-sys-label-small-size: .688rem;--mat-sys-label-small-tracking: .031rem;--mat-sys-label-small-weight: 500;--mat-sys-title-large: 400 1.375rem / 1.75rem Roboto;--mat-sys-title-large-font: Roboto;--mat-sys-title-large-line-height: 1.75rem;--mat-sys-title-large-size: 1.375rem;--mat-sys-title-large-tracking: 0;--mat-sys-title-large-weight: 400;--mat-sys-title-medium: 500 1rem / 1.5rem Roboto;--mat-sys-title-medium-font: Roboto;--mat-sys-title-medium-line-height: 1.5rem;--mat-sys-title-medium-size: 1rem;--mat-sys-title-medium-tracking: .009rem;--mat-sys-title-medium-weight: 500;--mat-sys-title-small: 500 .875rem / 1.25rem Roboto;--mat-sys-title-small-font: Roboto;--mat-sys-title-small-line-height: 1.25rem;--mat-sys-title-small-size: .875rem;--mat-sys-title-small-tracking: .006rem;--mat-sys-title-small-weight: 500;--mat-sys-corner-extra-large: 28px;--mat-sys-corner-extra-large-top: 28px 28px 0 0;--mat-sys-corner-extra-small: 4px;--mat-sys-corner-extra-small-top: 4px 4px 0 0;--mat-sys-corner-full: 9999px;--mat-sys-corner-large: 16px;--mat-sys-corner-large-end: 0 16px 16px 0;--mat-sys-corner-large-start: 16px 0 0 16px;--mat-sys-corner-large-top: 16px 16px 0 0;--mat-sys-corner-medium: 12px;--mat-sys-corner-none: 0;--mat-sys-corner-small: 8px;--mat-sys-dragged-state-layer-opacity: .16;--mat-sys-focus-state-layer-opacity: .12;--mat-sys-hover-state-layer-opacity: .08;--mat-sys-pressed-state-layer-opacity: .12}.night-theme{--mat-sys-background: #1b110f;--mat-sys-error: #ffb4ab;--mat-sys-error-container: #93000a;--mat-sys-inverse-on-surface: #3a2e2c;--mat-sys-inverse-primary: #a33c2e;--mat-sys-inverse-surface: #f3dedb;--mat-sys-on-background: #f3dedb;--mat-sys-on-error: #690005;--mat-sys-on-error-container: #ffdad6;--mat-sys-on-primary: #640d06;--mat-sys-on-primary-container: #ffdad4;--mat-sys-on-primary-fixed: #410000;--mat-sys-on-primary-fixed-variant: #83251a;--mat-sys-on-secondary: #640d06;--mat-sys-on-secondary-container: #ffdad4;--mat-sys-on-secondary-fixed: #410000;--mat-sys-on-secondary-fixed-variant: #83251a;--mat-sys-on-surface: #f3dedb;--mat-sys-on-surface-variant: #fbdcd7;--mat-sys-on-tertiary: #640d06;--mat-sys-on-tertiary-container: #ffdad4;--mat-sys-on-tertiary-fixed: #410000;--mat-sys-on-tertiary-fixed-variant: #83251a;--mat-sys-outline: #a58b86;--mat-sys-outline-variant: #57423e;--mat-sys-primary: #ffb4a8;--mat-sys-primary-container: #83251a;--mat-sys-primary-fixed: #ffdad4;--mat-sys-primary-fixed-dim: #ffb4a8;--mat-sys-scrim: #000000;--mat-sys-secondary: #ffb4a8;--mat-sys-secondary-container: #83251a;--mat-sys-secondary-fixed: #ffdad4;--mat-sys-secondary-fixed-dim: #ffb4a8;--mat-sys-shadow: #000000;--mat-sys-surface: #1b110f;--mat-sys-surface-bright: #433634;--mat-sys-surface-container: #281d1b;--mat-sys-surface-container-high: #332725;--mat-sys-surface-container-highest: #3e3230;--mat-sys-surface-container-low: #241917;--mat-sys-surface-container-lowest: #150c0a;--mat-sys-surface-dim: #1b110f;--mat-sys-surface-tint: #ffb4a8;--mat-sys-surface-variant: #57423e;--mat-sys-tertiary: #ffb4a8;--mat-sys-tertiary-container: #83251a;--mat-sys-tertiary-fixed: #ffdad4;--mat-sys-tertiary-fixed-dim: #ffb4a8;--mat-sys-neutral-variant20: #3f2c29;--mat-sys-neutral10: #241917;--mat-sys-level0: 0px 0px 0px 0px rgba(0, 0, 0, .2), 0px 0px 0px 0px rgba(0, 0, 0, .14), 0px 0px 0px 0px rgba(0, 0, 0, .12);--mat-sys-level1: 0px 2px 1px -1px rgba(0, 0, 0, .2), 0px 1px 1px 0px rgba(0, 0, 0, .14), 0px 1px 3px 0px rgba(0, 0, 0, .12);--mat-sys-level2: 0px 3px 3px -2px rgba(0, 0, 0, .2), 0px 3px 4px 0px rgba(0, 0, 0, .14), 0px 1px 8px 0px rgba(0, 0, 0, .12);--mat-sys-level3: 0px 3px 5px -1px rgba(0, 0, 0, .2), 0px 6px 10px 0px rgba(0, 0, 0, .14), 0px 1px 18px 0px rgba(0, 0, 0, .12);--mat-sys-level4: 0px 5px 5px -3px rgba(0, 0, 0, .2), 0px 8px 10px 1px rgba(0, 0, 0, .14), 0px 3px 14px 2px rgba(0, 0, 0, .12);--mat-sys-level5: 0px 7px 8px -4px rgba(0, 0, 0, .2), 0px 12px 17px 2px rgba(0, 0, 0, .14), 0px 5px 22px 4px rgba(0, 0, 0, .12);--mat-sys-body-large: 400 1rem / 1.5rem Roboto;--mat-sys-body-large-font: Roboto;--mat-sys-body-large-line-height: 1.5rem;--mat-sys-body-large-size: 1rem;--mat-sys-body-large-tracking: .031rem;--mat-sys-body-large-weight: 400;--mat-sys-body-medium: 400 .875rem / 1.25rem Roboto;--mat-sys-body-medium-font: Roboto;--mat-sys-body-medium-line-height: 1.25rem;--mat-sys-body-medium-size: .875rem;--mat-sys-body-medium-tracking: .016rem;--mat-sys-body-medium-weight: 400;--mat-sys-body-small: 400 .75rem / 1rem Roboto;--mat-sys-body-small-font: Roboto;--mat-sys-body-small-line-height: 1rem;--mat-sys-body-small-size: .75rem;--mat-sys-body-small-tracking: .025rem;--mat-sys-body-small-weight: 400;--mat-sys-display-large: 400 3.562rem / 4rem Roboto;--mat-sys-display-large-font: Roboto;--mat-sys-display-large-line-height: 4rem;--mat-sys-display-large-size: 3.562rem;--mat-sys-display-large-tracking: -.016rem;--mat-sys-display-large-weight: 400;--mat-sys-display-medium: 400 2.812rem / 3.25rem Roboto;--mat-sys-display-medium-font: Roboto;--mat-sys-display-medium-line-height: 3.25rem;--mat-sys-display-medium-size: 2.812rem;--mat-sys-display-medium-tracking: 0;--mat-sys-display-medium-weight: 400;--mat-sys-display-small: 400 2.25rem / 2.75rem Roboto;--mat-sys-display-small-font: Roboto;--mat-sys-display-small-line-height: 2.75rem;--mat-sys-display-small-size: 2.25rem;--mat-sys-display-small-tracking: 0;--mat-sys-display-small-weight: 400;--mat-sys-headline-large: 400 2rem / 2.5rem Roboto;--mat-sys-headline-large-font: Roboto;--mat-sys-headline-large-line-height: 2.5rem;--mat-sys-headline-large-size: 2rem;--mat-sys-headline-large-tracking: 0;--mat-sys-headline-large-weight: 400;--mat-sys-headline-medium: 400 1.75rem / 2.25rem Roboto;--mat-sys-headline-medium-font: Roboto;--mat-sys-headline-medium-line-height: 2.25rem;--mat-sys-headline-medium-size: 1.75rem;--mat-sys-headline-medium-tracking: 0;--mat-sys-headline-medium-weight: 400;--mat-sys-headline-small: 400 1.5rem / 2rem Roboto;--mat-sys-headline-small-font: Roboto;--mat-sys-headline-small-line-height: 2rem;--mat-sys-headline-small-size: 1.5rem;--mat-sys-headline-small-tracking: 0;--mat-sys-headline-small-weight: 400;--mat-sys-label-large: 500 .875rem / 1.25rem Roboto;--mat-sys-label-large-font: Roboto;--mat-sys-label-large-line-height: 1.25rem;--mat-sys-label-large-size: .875rem;--mat-sys-label-large-tracking: .006rem;--mat-sys-label-large-weight: 500;--mat-sys-label-large-weight-prominent: 700;--mat-sys-label-medium: 500 .75rem / 1rem Roboto;--mat-sys-label-medium-font: Roboto;--mat-sys-label-medium-line-height: 1rem;--mat-sys-label-medium-size: .75rem;--mat-sys-label-medium-tracking: .031rem;--mat-sys-label-medium-weight: 500;--mat-sys-label-medium-weight-prominent: 700;--mat-sys-label-small: 500 .688rem / 1rem Roboto;--mat-sys-label-small-font: Roboto;--mat-sys-label-small-line-height: 1rem;--mat-sys-label-small-size: .688rem;--mat-sys-label-small-tracking: .031rem;--mat-sys-label-small-weight: 500;--mat-sys-title-large: 400 1.375rem / 1.75rem Roboto;--mat-sys-title-large-font: Roboto;--mat-sys-title-large-line-height: 1.75rem;--mat-sys-title-large-size: 1.375rem;--mat-sys-title-large-tracking: 0;--mat-sys-title-large-weight: 400;--mat-sys-title-medium: 500 1rem / 1.5rem Roboto;--mat-sys-title-medium-font: Roboto;--mat-sys-title-medium-line-height: 1.5rem;--mat-sys-title-medium-size: 1rem;--mat-sys-title-medium-tracking: .009rem;--mat-sys-title-medium-weight: 500;--mat-sys-title-small: 500 .875rem / 1.25rem Roboto;--mat-sys-title-small-font: Roboto;--mat-sys-title-small-line-height: 1.25rem;--mat-sys-title-small-size: .875rem;--mat-sys-title-small-tracking: .006rem;--mat-sys-title-small-weight: 500;--mat-sys-corner-extra-large: 28px;--mat-sys-corner-extra-large-top: 28px 28px 0 0;--mat-sys-corner-extra-small: 4px;--mat-sys-corner-extra-small-top: 4px 4px 0 0;--mat-sys-corner-full: 9999px;--mat-sys-corner-large: 16px;--mat-sys-corner-large-end: 0 16px 16px 0;--mat-sys-corner-large-start: 16px 0 0 16px;--mat-sys-corner-large-top: 16px 16px 0 0;--mat-sys-corner-medium: 12px;--mat-sys-corner-none: 0;--mat-sys-corner-small: 8px;--mat-sys-dragged-state-layer-opacity: .16;--mat-sys-focus-state-layer-opacity: .12;--mat-sys-hover-state-layer-opacity: .08;--mat-sys-pressed-state-layer-opacity: .12;--mat-button-filled-container-color: var(--kip-contrast-dim-color);--mat-button-outlined-outline-color: var(--kip-contrast-color);--mat-icon-color: var(--kip-contrast-color);--mat-sys-on-background: #831d1d;--mat-sys-on-surface: #831d1d;--mat-sys-on-surface-variant: #831d1d;--mat-sys-inverse-surface: #831d1d;--mat-sys-primary: #831d1d;--mat-sys-outline: #831d1d;--mat-sys-tertiary-fixed: var(--kip-contrast-color);--mat-sys-tertiary-fixed-dim: var(--kip-contrast-color)}html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}html,body{height:100%;overscroll-behavior-y:none;user-select:none;-webkit-user-select:none;-ms-user-select:none;overflow-x:hidden}input,textarea,[contenteditable=true]{user-select:text;-webkit-user-select:text;margin:0;overscroll-behavior-y:none}.app-shell{height:100%;overflow:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain}body{font-family:Roboto,Helvetica Neue,sans-serif;background:var(--mat-sys-surface);color:var(--mat-sys-on-surface);margin:0;touch-action:none}#app-filter-wrapper{filter:brightness(var(--kip-nightModeBrightness)) var(--kip-nightModeFilters);-webkit-backdrop-filter:brightness(var(--kip-nightModeBrightness));backdrop-filter:brightness(var(--kip-nightModeBrightness));transition:filter .3s ease;position:relative;z-index:1300}.dialogBackdrop{background-color:#000000bf}.ng-invalid:not(form){border-left:5px solid var(--kip-zone-alarm-color)}.ng-valid[required],.ng-valid.required{border-left:5px solid var(--kip-green-color)}.grid-stack .ui-resizable-se,.grid-stack .ui-resizable-sw,.grid-stack .ui-resizable-ne,.grid-stack .ui-resizable-nw{width:32px;height:32px}.grid-stack .ui-resizable-e,.grid-stack .ui-resizable-w{width:32px}.grid-stack .ui-resizable-n,.grid-stack .ui-resizable-s{height:32px}.loader-container{height:100%;width:100%;background-color:var(--mat-sys-background);display:flex;align-items:center;justify-content:center}#loader{height:175px;width:175px;position:relative}#loader .dot{height:100%;inset:0;margin:auto;position:absolute;width:87.5px}#loader .dot:before{border-radius:100%;content:"";height:87.5px;left:0;position:absolute;right:0;top:0;transform:scale(0);width:87.5px}#loader .dot:nth-child(7n+1){transform:rotate(45deg)}#loader .dot:nth-child(7n+1):before{animation:.8s linear .1s normal none infinite running load;background:#e5ab13 none repeat scroll 0 0}.notification-overlay-panel{position:fixed;bottom:20px;left:20px;z-index:1100!important;pointer-events:auto}.cdk-overlay-container .cdk-overlay-pane.notification-overlay-panel{z-index:1100!important}#loader .dot:nth-child(7n+2){transform:rotate(90deg)}#loader .dot:nth-child(7n+2):before{animation:.8s linear .2s normal none infinite running load;background:#f0ca31 none repeat scroll 0 0}#loader .dot:nth-child(7n+3){transform:rotate(135deg)}#loader .dot:nth-child(7n+3):before{animation:.8s linear .3s normal none infinite running load;background:#92c7e9 none repeat scroll 0 0}#loader .dot:nth-child(7n+4){transform:rotate(180deg)}#loader .dot:nth-child(7n+4):before{animation:.8s linear .4s normal none infinite running load;background:#63afdf none repeat scroll 0 0}#loader .dot:nth-child(7n+5){transform:rotate(225deg)}#loader .dot:nth-child(7n+5):before{animation:.8s linear .5s normal none infinite running load;background:#3586ca none repeat scroll 0 0}#loader .dot:nth-child(7n+6){transform:rotate(270deg)}#loader .dot:nth-child(7n+6):before{animation:.8s linear .6s normal none infinite running load;background:#d52626 none repeat scroll 0 0}#loader .dot:nth-child(7n+7){transform:rotate(315deg)}#loader .dot:nth-child(7n+7):before{animation:.8s linear .7s normal none infinite running load;background:#e26767 none repeat scroll 0 0}#loader .dot:nth-child(7n+8){transform:rotate(360deg)}#loader .dot:nth-child(7n+8):before{animation:.8s linear .8s normal none infinite running load;background:#f8e598 none repeat scroll 0 0}#loader .loading{background-position:50% 50%;background-repeat:no-repeat;bottom:-40px;height:20px;left:0;position:absolute;right:0;width:180px}@keyframes load{to{opacity:0;transform:scale(1)}}code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:none;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#272822}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.comment,.token.prolog,.token.doctype,.token.cdata{color:#8292a2}.token.punctuation{color:#f8f8f2}.token.namespace{opacity:.7}.token.property,.token.tag,.token.constant,.token.symbol,.token.deleted{color:#f92672}.token.boolean,.token.number{color:#ae81ff}.token.selector,.token.attr-name,.token.string,.token.char,.token.builtin,.token.inserted{color:#a6e22e}.token.operator,.token.entity,.token.url,.language-css .token.string,.style .token.string,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.function,.token.class-name{color:#e6db74}.token.keyword{color:#66d9ef}.token.regex,.token.important{color:#fd971f}.token.important,.token.bold{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# <%= title %> Widget
|
|
2
|
+
|
|
3
|
+
Generated by KIP create-host2-widget schematic.
|
|
4
|
+
|
|
5
|
+
Selector: `<%= selector %>`
|
|
6
|
+
|
|
7
|
+
## Default Config
|
|
8
|
+
```ts
|
|
9
|
+
<%= className %>.DEFAULT_CONFIG
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Path(s)
|
|
13
|
+
Primary path key: `signalKPath` (<%= pathType %>) unit: `<%= convertUnitTo %>` sampleTime: <%= sampleTime %>ms
|
|
14
|
+
|
|
15
|
+
<% if (zonesSupport) { %>
|
|
16
|
+
## Zones Support
|
|
17
|
+
This widget was generated with Zones support enabled. Zones scaffolding includes two integration points:
|
|
18
|
+
|
|
19
|
+
### Zones definitions
|
|
20
|
+
- `WidgetMetadataDirective` is imported and injected.
|
|
21
|
+
- A `this.metadata.zones()` signal placeholder is included to surface zones metadata information.
|
|
22
|
+
- A `highlights` computed signal that generates KIP widget compatible zones array is included. Modify to your needs.
|
|
23
|
+
- metadata.observe('signalKPath') call is added automating zone monitoring for the configured path.
|
|
24
|
+
- Remove or adapt these parts if your widget will not visualize Signal K Zones.
|
|
25
|
+
|
|
26
|
+
### Path Data State
|
|
27
|
+
The path data may also include a state (zone classification) emitted by the server. That state corresponds to the zone whose range the value falls into. This state is sent whether or not the widget enables zones metadata support. See `path.data.state` in the observed path payload.
|
|
28
|
+
<% } %>
|
|
29
|
+
|
|
30
|
+
## Core Concepts
|
|
31
|
+
This widget follows the Host2 architecture. The runtime merges persisted config
|
|
32
|
+
(Signal K server or local storage) with `DEFAULT_CONFIG` and feeds it through the
|
|
33
|
+
injected directives. All you need to do is set the DEFAULT_CONFIG and the directive
|
|
34
|
+
will handle merging and persisting user settings automatically.
|
|
35
|
+
|
|
36
|
+
### Adding More Paths
|
|
37
|
+
Add additional keys under `DEFAULT_CONFIG.paths` (each must include `pathType` and
|
|
38
|
+
typical options). Then register observers within the second `effect()` in the
|
|
39
|
+
component (group them in a single `untracked` block for performance).
|
|
40
|
+
|
|
41
|
+
### Optional vs Required Paths
|
|
42
|
+
Mark non-critical (optional) paths with `pathRequired: false` to allow empty configuration
|
|
43
|
+
without errors. Always guard before observing.
|
|
44
|
+
|
|
45
|
+
### Units & Conversion
|
|
46
|
+
Specify `convertUnitTo` for number paths in `DEFAULT_CONFIG` to let KIP auto-convert
|
|
47
|
+
via `UnitsService`. Do not manually convert unless you have a special case.
|
|
48
|
+
UnitsService supports most formatting and conversions. If one is missing, add the
|
|
49
|
+
unit to the service instead of hardcoding conversion math in a widget.
|
|
50
|
+
|
|
51
|
+
## Available Angular Services (Commonly Injected)
|
|
52
|
+
| Service | Purpose | Typical Use |
|
|
53
|
+
|---------|---------|-------------|
|
|
54
|
+
| `UnitsService` | Central unit conversion & formatting | Convert or format values when you must post-process derived numbers. |
|
|
55
|
+
| `DataSetService` | Historical / trend datasets (chart widgets) | Create/update/remove datasets for charts or statistics. |
|
|
56
|
+
| `NotificationsService` | User-visible toast/Snackbar/info/warn/error | Present message to user |
|
|
57
|
+
| `SignalKRequestsService` | PUT/Request operations to server | Implement interactive controls and set Signal K path value (e.g., set heading). |
|
|
58
|
+
| `DataService` | Low-level Signal K value + metadata access | Rarely needed directly; `WidgetStreamsDirective` wraps it. |
|
|
59
|
+
| `CanvasService` | High-DPI sizing, font readiness, offscreen/static layer caching, draw helpers | Register & auto-resize canvases, cache static bitmaps (titles/backgrounds), release GPU memory on destroy. |
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
Inject with Angular `inject(ServiceClass)` or constructor injection (signals style recommended in Host2 files).
|
|
63
|
+
|
|
64
|
+
## Directives Supplied to Widgets
|
|
65
|
+
| Directive | Role |
|
|
66
|
+
|-----------|------|
|
|
67
|
+
| `WidgetRuntimeDirective` | Provides merged config (`options()`), id, sizing. |
|
|
68
|
+
| `WidgetStreamsDirective` | Observe path data streams with sampling, unit conversion, timeout logic. |
|
|
69
|
+
| `WidgetMetadataDirective` | Access zones / metadata (call `observe` for updates, `zones()` for current list). |
|
|
70
|
+
|
|
71
|
+
## Useful Utility Functions
|
|
72
|
+
| Utility | Source | Purpose |
|
|
73
|
+
|---------|--------|---------|
|
|
74
|
+
| `getColors(themeKey, theme)` | `core/utils/themeColors.utils` | Returns palette variants (normal/dim/bright) for configured color key. |
|
|
75
|
+
| `svg-animate.util` helpers | `widgets/utils/svg-animate.util` | Smooth rAF animations (rotation, angle transitions, sectors). |
|
|
76
|
+
| `zones-highlight.utils` | `core/utils/zones-highlight.utils` | Build highlight arrays for gauge / chart overlays from zones metadata. |
|
|
77
|
+
|
|
78
|
+
## Integrating Zones (If Enabled)
|
|
79
|
+
When zones support is active, metadata-driven highlights can be computed and surfaced to the template. Use colors derived from the active theme for contrast and accessibility. Keep highlight computation outside change detection hot paths (use signals/computed as shown).
|
|
80
|
+
|
|
81
|
+
## Performance Tips
|
|
82
|
+
1. Batch all `streams.observe` calls in one `untracked` block inside a single `effect`.
|
|
83
|
+
2. Store transient UI state in signals, never mutate the merged config object.
|
|
84
|
+
3. Use SVG animation helpers for high-frequency visual updates; they run outside Angular via `NgZone`.
|
|
85
|
+
4. Keep sample times reasonable (>= 250ms) to avoid widget churn.
|
|
86
|
+
|
|
87
|
+
## Error / Edge Handling
|
|
88
|
+
| Scenario | Recommendation |
|
|
89
|
+
|----------|---------------|
|
|
90
|
+
| Missing path | Guard before observing; show placeholder or dim widget. |
|
|
91
|
+
| Stale data (timeout) | Enable `enableTimeout` and set `dataTimeout` seconds in config. UI can style on timeout state. |
|
|
92
|
+
| Unit mismatch | Rely on `convertUnitTo`; avoid manual conversions. |
|
|
93
|
+
| Zones absent | Treat highlights array as empty; avoid errors by null-guarding metadata. |
|
|
94
|
+
|
|
95
|
+
## Icon & Description
|
|
96
|
+
Update the icon and description in the `widget.service.ts` entry inserted by the schematic. Replace `placeholder-icon` and the long TODO description. Ensure the SVG symbol id exists in `src/assets/svg/icons.svg` or add a new symbol there.
|
|
97
|
+
|
|
98
|
+
## Testing
|
|
99
|
+
If `--add-spec` was used, a basic spec file is generated. Extend tests to:
|
|
100
|
+
1. Mock `WidgetStreamsDirective` emissions to verify signal updates.
|
|
101
|
+
2. Validate conditional rendering with and without path values.
|
|
102
|
+
3. (Optional) Provide fake zones metadata to exercise highlight logic.
|
|
103
|
+
|
|
104
|
+
## Deployment Checklist
|
|
105
|
+
- [ ] Replace placeholder icon & description
|
|
106
|
+
- [ ] Adjust DEFAULT_CONFIG displayName
|
|
107
|
+
- [ ] Remove unused TODO comments
|
|
108
|
+
- [ ] Remove all console.log() calls
|
|
109
|
+
- [ ] Add tests for edge cases (timeouts, no path, zones absent)
|
package/tools/schematics/create-host2-widget/files/spec/widget-__name@dasherize__.component.spec.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
|
3
|
+
import { signal } from '@angular/core';
|
|
4
|
+
import { <%= className %> } from './<%= selector %>.component';
|
|
5
|
+
import { WidgetRuntimeDirective } from '../../core/directives/widget-runtime.directive';
|
|
6
|
+
import { WidgetStreamsDirective } from '../../core/directives/widget-streams.directive';
|
|
7
|
+
import { WidgetMetadataDirective } from '../../core/directives/widget-metadata.directive';
|
|
8
|
+
|
|
9
|
+
@Component({
|
|
10
|
+
template: `<%= '<' + selector %> [id]="id()" [type]="type()" [theme]="theme()" />`,
|
|
11
|
+
imports: [<%= className %>, WidgetRuntimeDirective, WidgetStreamsDirective, WidgetMetadataDirective]
|
|
12
|
+
})
|
|
13
|
+
class HostTestComponent {
|
|
14
|
+
id = signal('test-id');
|
|
15
|
+
type = signal('<%= selector %>');
|
|
16
|
+
theme = signal<null>(null);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe('<%= className %> (Host2)', () => {
|
|
20
|
+
let fixture: ComponentFixture<HostTestComponent>;
|
|
21
|
+
let host: HostTestComponent;
|
|
22
|
+
|
|
23
|
+
beforeEach(waitForAsync(() => {
|
|
24
|
+
TestBed.configureTestingModule({
|
|
25
|
+
imports: [HostTestComponent]
|
|
26
|
+
}).compileComponents();
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
fixture = TestBed.createComponent(HostTestComponent);
|
|
31
|
+
host = fixture.componentInstance;
|
|
32
|
+
fixture.detectChanges();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should create', () => {
|
|
36
|
+
expect(host).toBeTruthy();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<%# keep ejs tags intact %>
|
|
2
|
+
import { AfterViewInit, Component, effect, inject, input, signal, untracked<% if (zonesSupport) { %>, computed<% } %> } from '@angular/core';
|
|
3
|
+
import { IWidgetSvcConfig<% if (zonesSupport) { %>, IDataHighlight<% } %> } from '../../core/interfaces/widgets-interface';
|
|
4
|
+
import { WidgetRuntimeDirective } from '../../core/directives/widget-runtime.directive';
|
|
5
|
+
import { WidgetStreamsDirective } from '../../core/directives/widget-streams.directive';<% if (zonesSupport) { %>
|
|
6
|
+
import { WidgetMetadataDirective } from '../../core/directives/widget-metadata.directive';
|
|
7
|
+
import { getHighlights } from '../../core/utils/zones-highlight.utils';
|
|
8
|
+
import { UnitsService } from '../../core/services/units.service';<% } %>
|
|
9
|
+
import { ITheme } from '../../core/services/app-service';
|
|
10
|
+
import { getColors } from '../../core/utils/themeColors.utils';
|
|
11
|
+
import { WidgetTitleComponent } from '../../core/components/widget-title/widget-title.component';
|
|
12
|
+
|
|
13
|
+
@Component({
|
|
14
|
+
selector: '<%= selector %>',
|
|
15
|
+
templateUrl: './<%= selector %>.component.html',
|
|
16
|
+
styleUrls: ['./<%= selector %>.component.scss'],
|
|
17
|
+
imports: [WidgetTitleComponent]
|
|
18
|
+
})
|
|
19
|
+
export class <%= className %> implements AfterViewInit {
|
|
20
|
+
public id = input.required<string>();
|
|
21
|
+
public type = input.required<string>();
|
|
22
|
+
public theme = input.required<ITheme | null>();
|
|
23
|
+
public static readonly DEFAULT_CONFIG: IWidgetSvcConfig = { <%= todoBlock ? "// TODO: Update default configuration values as required. See IWidgetSvcConfig interface for all options." : "" %>
|
|
24
|
+
displayName: "My New Widget Label",
|
|
25
|
+
color: "contrast",
|
|
26
|
+
paths: {
|
|
27
|
+
"signalKPath": {
|
|
28
|
+
description: "My new widget Options path description",
|
|
29
|
+
path: <%= pathDefault === null ? 'null' : `'${pathDefault}'` %>,
|
|
30
|
+
source: null,
|
|
31
|
+
pathType: '<%= pathType %>',
|
|
32
|
+
isPathConfigurable: true,
|
|
33
|
+
pathRequired: true,
|
|
34
|
+
convertUnitTo: null,
|
|
35
|
+
showPathSkUnitsFilter: false,
|
|
36
|
+
pathSkUnitsFilter: null,
|
|
37
|
+
sampleTime: 1000
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
filterSelfPaths: true,
|
|
41
|
+
enableTimeout: false,
|
|
42
|
+
dataTimeout: 5<% if (zonesSupport) { %>,
|
|
43
|
+
ignoreZones: false<%= todoBlock ? " // TODO: Signal K Zones support: delete if disabling zones should not be a widget Option users can configure." : "" %><% } %>
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
protected readonly runtime = inject(WidgetRuntimeDirective);
|
|
47
|
+
private readonly streams = inject(WidgetStreamsDirective);<% if (zonesSupport) { %>
|
|
48
|
+
private readonly metadata = inject(WidgetMetadataDirective);
|
|
49
|
+
private readonly unitsService = inject(UnitsService);<% } %>
|
|
50
|
+
|
|
51
|
+
protected titleColor = signal<string | undefined>(undefined);
|
|
52
|
+
protected pathValue = signal<number | null>(null);<% if (zonesSupport) { %>
|
|
53
|
+
|
|
54
|
+
protected highlights = computed<IDataHighlight[]>(() => {<%= todoBlock ? " // TODO: Signal K Zones support: Sample computed signal for zones highlights. Adjust depending on your widget needs." : "" %>
|
|
55
|
+
const zones = this.metadata.zones();
|
|
56
|
+
const cfg = this.runtime.options();
|
|
57
|
+
const theme = this.theme();
|
|
58
|
+
|
|
59
|
+
if (cfg?.ignoreZones || !zones?.length || !theme) return [];
|
|
60
|
+
const unit = cfg.paths['gaugePath'].convertUnitTo;
|
|
61
|
+
const min = cfg.displayScale.lower;
|
|
62
|
+
const max = cfg.displayScale.upper;
|
|
63
|
+
return getHighlights(zones, theme, unit, this.unitsService, min, max);
|
|
64
|
+
});<% } %>
|
|
65
|
+
|
|
66
|
+
constructor() {
|
|
67
|
+
effect(() => {
|
|
68
|
+
const theme = this.theme();
|
|
69
|
+
const cfg = this.runtime.options();
|
|
70
|
+
if (!theme || !cfg) return;
|
|
71
|
+
|
|
72
|
+
untracked(() => {
|
|
73
|
+
this.titleColor.set(getColors(this.runtime.options().color, theme).dim);<%= todoBlock ? " // TODO: Themes are either, Dark, Light or Red Night mode. Add signals to include more colors and variants in your template." : "" %>
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
effect(() => {<%= todoBlock ? " // React to widget Options configuration changes." : "" %>
|
|
78
|
+
const cfg = this.runtime.options();
|
|
79
|
+
untracked(() => {
|
|
80
|
+
const pathCfg = cfg.paths['signalKPath'];
|
|
81
|
+
if (pathCfg.path) {
|
|
82
|
+
this.streams.observe('signalKPath', path => {<%= todoBlock ? " // TODO: Update the signal with the latest path value and/or do more data processing as required." : "" %>
|
|
83
|
+
this.pathValue.set(path.data.value);
|
|
84
|
+
});<% if (zonesSupport) { %>
|
|
85
|
+
this.metadata.observe('signalKPath');<% } %>
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// eslint-disable-next-line @angular-eslint/no-empty-lifecycle-method
|
|
92
|
+
ngAfterViewInit() {<%= todoBlock ? " // TODO: Add additional widget logic here (canvas drawing, animations, etc.) here or remove if not needed." : "" %>
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
const { apply, url, template, move, mergeWith, chain, noop } = require('@angular-devkit/schematics');
|
|
2
|
+
const { strings } = require('@angular-devkit/core');
|
|
3
|
+
const { appendImport, updateComponentMap, insertDefinitionObject } = require('./utils/formatting');
|
|
4
|
+
|
|
5
|
+
const WIDGETS_DIR = 'src/app/widgets';
|
|
6
|
+
const WIDGET_SERVICE = 'src/app/core/services/widget.service.ts';
|
|
7
|
+
|
|
8
|
+
function createHost2Widget(options) {
|
|
9
|
+
return (tree, ctx) => {
|
|
10
|
+
const debug = !!options.debugLogging;
|
|
11
|
+
if (debug) ctx.logger.info('[widget-schematic] Raw options input: ' + JSON.stringify(options));
|
|
12
|
+
if (debug) ctx.logger.info('[widget-schematic] Using schema x-prompt only (no inquirer).');
|
|
13
|
+
// Normalize registerWidget (case-insensitive). 'no' => skip service update.
|
|
14
|
+
const rawReg = (options.registerWidget || '').trim();
|
|
15
|
+
const lower = rawReg.toLowerCase();
|
|
16
|
+
const skip = lower === 'no';
|
|
17
|
+
const normalizedCategory = skip ? 'no' : capitalizeCategory(lower);
|
|
18
|
+
if (debug) ctx.logger.info(`[widget-schematic] registerWidget raw='${rawReg}' lower='${lower}' => normalized='${normalizedCategory}' skip=${skip}`);
|
|
19
|
+
|
|
20
|
+
const nameDashed = strings.dasherize(options.name);
|
|
21
|
+
const selector = `widget-${nameDashed}`;
|
|
22
|
+
const className = `Widget${strings.classify(options.name)}Component`;
|
|
23
|
+
const widgetFolder = `${WIDGETS_DIR}/${selector}`;
|
|
24
|
+
if (tree.exists(`${widgetFolder}/${selector}.component.ts`)) {
|
|
25
|
+
throw new Error(`Widget already exists: ${selector}`);
|
|
26
|
+
}
|
|
27
|
+
const tplSource = apply(url('./files/widget'), [
|
|
28
|
+
template({
|
|
29
|
+
...strings,
|
|
30
|
+
...options,
|
|
31
|
+
nameDashed,
|
|
32
|
+
selector,
|
|
33
|
+
className,
|
|
34
|
+
zonesSupport: !!options.zonesSupport,
|
|
35
|
+
// Hidden defaults
|
|
36
|
+
convertUnitTo: null,
|
|
37
|
+
sampleTime: 1000,
|
|
38
|
+
icon: 'placeholder-icon',
|
|
39
|
+
description: 'TODO: Add description',
|
|
40
|
+
}),
|
|
41
|
+
move(widgetFolder)
|
|
42
|
+
]);
|
|
43
|
+
const commonTemplateCtx = { ...strings, ...options, nameDashed, selector, className, zonesSupport: !!options.zonesSupport };
|
|
44
|
+
const specSource = options.addSpec ? apply(url('./files/spec'), [
|
|
45
|
+
template(commonTemplateCtx), move(widgetFolder)
|
|
46
|
+
]) : null;
|
|
47
|
+
const readmeSource = options.readme ? apply(url('./files/readme'), [
|
|
48
|
+
template({
|
|
49
|
+
...commonTemplateCtx,
|
|
50
|
+
convertUnitTo: null,
|
|
51
|
+
sampleTime: 1000,
|
|
52
|
+
icon: 'placeholder-icon',
|
|
53
|
+
description: 'TODO: Add description'
|
|
54
|
+
}), move(widgetFolder)
|
|
55
|
+
]) : null;
|
|
56
|
+
|
|
57
|
+
return chain([
|
|
58
|
+
mergeWith(tplSource),
|
|
59
|
+
specSource ? mergeWith(specSource) : noop(),
|
|
60
|
+
readmeSource ? mergeWith(readmeSource) : noop(),
|
|
61
|
+
stripTemplateSuffixRule(widgetFolder),
|
|
62
|
+
!skip ? updateWidgetService(selector, className, { ...options, category: normalizedCategory, debugLogging: debug }) : noop(),
|
|
63
|
+
logSummary(selector, className, normalizedCategory)
|
|
64
|
+
])(tree, ctx);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function logSummary(selector, className, registerMode) {
|
|
69
|
+
return (_t, ctx) => {
|
|
70
|
+
ctx.logger.info(`✔ Created ${selector} (${className})`);
|
|
71
|
+
if (registerMode !== 'no') ctx.logger.info('✔ WidgetService updated');
|
|
72
|
+
else ctx.logger.info('ℹ Skipped WidgetService update (registerWidget=no)');
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function capitalizeCategory(lower) {
|
|
77
|
+
switch (lower) {
|
|
78
|
+
case 'core': return 'Core';
|
|
79
|
+
case 'gauge': return 'Gauge';
|
|
80
|
+
case 'component': return 'Component';
|
|
81
|
+
case 'racing': return 'Racing';
|
|
82
|
+
default: return lower; // includes 'no' or any unexpected value
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function updateWidgetService(selector, className, opts) {
|
|
87
|
+
return (tree, ctx) => {
|
|
88
|
+
if (!tree.exists(WIDGET_SERVICE)) {
|
|
89
|
+
ctx.logger.warn('WidgetService not found; skipping auto-registration');
|
|
90
|
+
return tree;
|
|
91
|
+
}
|
|
92
|
+
if (opts.debugLogging) ctx.logger.info('[widget-schematic] Updating WidgetService for ' + className);
|
|
93
|
+
let updated = tree.read(WIDGET_SERVICE).toString('utf-8');
|
|
94
|
+
const importStatement = `import { ${className} } from '../../widgets/${selector}/${selector}.component';`;
|
|
95
|
+
updated = appendImport(updated, importStatement);
|
|
96
|
+
if (opts.debugLogging) ctx.logger.info('[widget-schematic] After import insertion.');
|
|
97
|
+
updated = updateComponentMap(updated, className);
|
|
98
|
+
if (opts.debugLogging) ctx.logger.info('[widget-schematic] After component map update.');
|
|
99
|
+
updated = insertDefinitionObject(updated, selector, className, {
|
|
100
|
+
title: opts.title || opts.name || className,
|
|
101
|
+
description: "TODO: Add description. Description is found in the item related to your widget as an item in array _widgetDefinition, found in file src/app/core/services/widget.service.ts. In this file you can also set the widget icon and other properties.",
|
|
102
|
+
icon: 'placeholder-icon', // TODO: Replace with proper icon key when you add an icon. See file src/assets/svg/icons.svg
|
|
103
|
+
category: opts.category || 'Core',
|
|
104
|
+
minWidth: 1,
|
|
105
|
+
minHeight: 1,
|
|
106
|
+
defaultWidth: 4,
|
|
107
|
+
defaultHeight: 6,
|
|
108
|
+
});
|
|
109
|
+
if (opts.debugLogging) ctx.logger.info('[widget-schematic] After definition insertion.');
|
|
110
|
+
tree.overwrite(WIDGET_SERVICE, updated);
|
|
111
|
+
return tree;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function stripTemplateSuffixRule(widgetFolder) {
|
|
116
|
+
return (tree) => {
|
|
117
|
+
const visit = (dirPath) => {
|
|
118
|
+
const dir = tree.getDir(dirPath);
|
|
119
|
+
dir.subfiles.forEach(fileName => {
|
|
120
|
+
if (fileName.endsWith('.template')) {
|
|
121
|
+
const fullPath = `${dirPath}/${fileName}`;
|
|
122
|
+
const newPath = fullPath.replace(/\.template$/, '');
|
|
123
|
+
const content = tree.read(fullPath);
|
|
124
|
+
if (content) {
|
|
125
|
+
if (!tree.exists(newPath)) tree.create(newPath, content);
|
|
126
|
+
tree.delete(fullPath);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
dir.subdirs.forEach(sub => visit(`${dirPath}/${sub}`));
|
|
131
|
+
};
|
|
132
|
+
if (tree.getDir(widgetFolder)) visit(widgetFolder);
|
|
133
|
+
return tree;
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
exports.createHost2Widget = createHost2Widget;
|
|
138
|
+
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema",
|
|
3
|
+
"$id": "CreateHost2WidgetSchema",
|
|
4
|
+
"title": "Create Host2 Widget",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"name": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"description": "Widget machine name without widget- prefix (kebab-case). e.g. tides-chart",
|
|
10
|
+
"minLength": 3,
|
|
11
|
+
"x-prompt": "The widget base name is the Angular component machine name (kebab-case, without widget- prefix which will be added automatically). Using base name tides-chart will create a widget-tides-chart component.\nWidget base name:"
|
|
12
|
+
},
|
|
13
|
+
"title": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "The widget title is the descriptive title used in the Add Widget dialog",
|
|
16
|
+
"minLength": 3,
|
|
17
|
+
"default": "Widget Label",
|
|
18
|
+
"x-prompt": "The widget title is the descriptive title used in the Add Widget dialog.\nWidget title:"
|
|
19
|
+
},
|
|
20
|
+
"registerWidget": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"description": "Register widget and make it available in the widget Add Options dialog",
|
|
23
|
+
"enum": [
|
|
24
|
+
"No",
|
|
25
|
+
"Core",
|
|
26
|
+
"Gauge",
|
|
27
|
+
"Component",
|
|
28
|
+
"Racing"
|
|
29
|
+
],
|
|
30
|
+
"x-prompt": "Register widget and make it available in the widget Add Options dialog (choose category or 'no' to skip):"
|
|
31
|
+
},
|
|
32
|
+
"pathType": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"description": "The type of value the Signal K path provides (number|string|boolean|Date)",
|
|
35
|
+
"enum": [
|
|
36
|
+
"number",
|
|
37
|
+
"string",
|
|
38
|
+
"boolean",
|
|
39
|
+
"Date"
|
|
40
|
+
],
|
|
41
|
+
"default": "number",
|
|
42
|
+
"x-prompt": "Path value type (number|string|boolean|Date):"
|
|
43
|
+
},
|
|
44
|
+
"pathDefault": {
|
|
45
|
+
"type": [
|
|
46
|
+
"string",
|
|
47
|
+
"null"
|
|
48
|
+
],
|
|
49
|
+
"default": null,
|
|
50
|
+
"description": "The default Signal K path the widget should use (if any)",
|
|
51
|
+
"x-prompt": "Type the default Signal K path value for the widget (press enter for no default):"
|
|
52
|
+
},
|
|
53
|
+
"zonesSupport": {
|
|
54
|
+
"type": "boolean",
|
|
55
|
+
"default": false,
|
|
56
|
+
"description": "Enable Signal K Zones metadata support.",
|
|
57
|
+
"x-prompt": "Enable Signal K Zones metadata support?"
|
|
58
|
+
},
|
|
59
|
+
"addSpec": {
|
|
60
|
+
"type": "boolean",
|
|
61
|
+
"default": true,
|
|
62
|
+
"description": "Generate widget spec (test) file.",
|
|
63
|
+
"x-prompt": "Generate widget tests file?"
|
|
64
|
+
},
|
|
65
|
+
"todoBlock": {
|
|
66
|
+
"type": "boolean",
|
|
67
|
+
"default": true,
|
|
68
|
+
"description": "Include TODO guidance block in component.",
|
|
69
|
+
"x-prompt": "Include TODO guidance block in component?"
|
|
70
|
+
},
|
|
71
|
+
"readme": {
|
|
72
|
+
"type": "boolean",
|
|
73
|
+
"default": true,
|
|
74
|
+
"description": "Generate developer instruction README file in the widget's folder.",
|
|
75
|
+
"x-prompt": "Generate developer instruction README file in the widget's folder?"
|
|
76
|
+
},
|
|
77
|
+
"debugLogging": {
|
|
78
|
+
"type": "boolean",
|
|
79
|
+
"default": false,
|
|
80
|
+
"description": "Enable verbose debug logging for schematic execution (normalization, prompts, service update)."
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"required": [
|
|
84
|
+
"name",
|
|
85
|
+
"title",
|
|
86
|
+
"registerWidget"
|
|
87
|
+
],
|
|
88
|
+
"additionalProperties": false
|
|
89
|
+
}
|