Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
emiMobile
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Mac Stephens
emiMobile
Commits
b47e6601
Commit
b47e6601
authored
Sep 05, 2026
by
Mac Stephens
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve mobile reliability, map controls, and WebSocket recovery
parent
ab0baace
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
505 additions
and
70 deletions
+505
-70
Main.dfm
emiMobileServer/Source/Main.dfm
+1
-1
WebSocket.Manager.pas
emiMobileServer/Source/WebSocket.Manager.pas
+169
-29
emiMobileServer.ini
emiMobileServer/bin/emiMobileServer.ini
+1
-1
Module.Websocket.pas
webEMIMobile/Module.Websocket.pas
+0
-0
View.Complaints.pas
webEMIMobile/View.Complaints.pas
+27
-0
View.Main.html
webEMIMobile/View.Main.html
+23
-4
View.Main.pas
webEMIMobile/View.Main.pas
+156
-13
View.Map.dfm
webEMIMobile/View.Map.dfm
+0
-1
View.Map.html
webEMIMobile/View.Map.html
+7
-6
View.Map.pas
webEMIMobile/View.Map.pas
+30
-15
View.Units.pas
webEMIMobile/View.Units.pas
+27
-0
app.css
webEMIMobile/css/app.css
+64
-0
No files found.
emiMobileServer/Source/Main.dfm
View file @
b47e6601
...
...
@@ -87,7 +87,7 @@ object FMain: TFMain
Top = 18
Width = 141
Height = 25
Caption = '
Disconnect Selected
Client'
Caption = '
Refresh
Client'
TabOrder = 0
OnClick = btnDisconnectClientClick
end
...
...
emiMobileServer/Source/WebSocket.Manager.pas
View file @
b47e6601
This diff is collapsed.
Click to expand it.
emiMobileServer/bin/emiMobileServer.ini
View file @
b47e6601
[Settings]
LogFileNum
=
15
3
LogFileNum
=
15
5
webClientVersion
=
0.9.4.1
[Database]
...
...
webEMIMobile/Module.Websocket.pas
View file @
b47e6601
This diff is collapsed.
Click to expand it.
webEMIMobile/View.Complaints.pas
View file @
b47e6601
...
...
@@ -39,6 +39,8 @@ type
FSelectProc
:
TSelectProc
;
FLoading
:
Boolean
;
FFirstLoad
:
Boolean
;
FRefreshPending
:
Boolean
;
FPendingWsData
:
TJSObject
;
[
async
]
procedure
GetComplaints
;
procedure
HandleListClick
(
e
:
TJSMouseEvent
);
procedure
ShowHideBusinessRows
;
...
...
@@ -59,6 +61,8 @@ procedure TFViewComplaints.WebFormCreate(Sender: TObject);
begin
Document
.
addEventListener
(
'click'
,
@
HandleListClick
);
FFirstLoad
:=
True
;
FRefreshPending
:=
False
;
FPendingWsData
:=
nil
;
GetComplaints
;
asm
if
(!
window
.
showComplaintDetails
)
{
...
...
@@ -178,12 +182,32 @@ begin
HideSpinner
(
'spinner'
);
FFirstLoad
:=
False
;
end
;
if
Assigned
(
FPendingWsData
)
then
begin
respObj
:=
FPendingWsData
;
FPendingWsData
:=
nil
;
ApplyWsData
(
respObj
);
end
;
if
FRefreshPending
then
begin
FRefreshPending
:=
False
;
GetComplaints
;
end
;
end
;
end
;
procedure
TFViewComplaints
.
RefreshData
;
begin
Console
.
Log
(
'Complaints.RefreshData'
);
if
FLoading
then
begin
FRefreshPending
:=
True
;
Exit
;
end
;
GetComplaints
;
end
;
...
...
@@ -192,7 +216,10 @@ var
complaintsCount
:
Integer
;
begin
if
FLoading
then
begin
FPendingWsData
:=
aRespObj
;
Exit
;
end
;
xdwdsComplaints
.
Close
;
xdwdsComplaints
.
SetJsonData
(
aRespObj
[
'data'
]);
...
...
webEMIMobile/View.Main.html
View file @
b47e6601
...
...
@@ -11,12 +11,31 @@
<span
id=
"lbl_main_title"
class=
"navbar-brand text-light mb-0 ms-1"
></span>
</div>
<!-- Right: Connection /
Logout
-->
<!-- Right: Connection /
Menu
-->
<div
class=
"d-flex align-items-center gap-2 ms-auto"
>
<span
id=
"view.main.lblconnection"
class=
"navbar-text text-light small"
></span>
<span
id=
"view.main.version"
class=
"navbar-text text-light small opacity-75"
></span>
<button
id=
"btn_logout"
type=
"button"
class=
"btn btn-outline-light btn-sm"
>
Logout
</button>
<span
id=
"view.main.lblconnection"
class=
"connection-status connection-status-connecting"
role=
"status"
aria-live=
"polite"
aria-atomic=
"true"
aria-label=
"Live updates: Connecting"
title=
"Live updates: Connecting"
>
<span
class=
"connection-status-dot"
aria-hidden=
"true"
></span>
<span
id=
"view.main.lblconnectiontext"
class=
"connection-status-text"
>
Connecting
</span>
</span>
<div
class=
"dropdown"
>
<button
type=
"button"
class=
"btn btn-outline-light btn-sm"
data-bs-toggle=
"dropdown"
aria-expanded=
"false"
aria-label=
"Menu"
>
<i
class=
"fas fa-bars"
aria-hidden=
"true"
></i>
</button>
<ul
class=
"dropdown-menu dropdown-menu-end"
>
<li><button
id=
"btn_logout"
type=
"button"
class=
"dropdown-item"
>
Logout
</button></li>
</ul>
</div>
</div>
</div>
</nav>
...
...
webEMIMobile/View.Main.pas
View file @
b47e6601
...
...
@@ -54,7 +54,11 @@ type
FDetailsForm
:
TWebForm
;
FArchiveForm
:
TWebForm
;
FLogoutProc
:
TLogoutProc
;
FBadgeRefreshInProgress
:
Boolean
;
FBadgeRefreshPending
:
Boolean
;
FPendingWsBadgeCounts
:
TJSObject
;
[
async
]
procedure
RefreshBadgesAsync
;
procedure
ApplyBadgeCounts
(
aData
:
TJSObject
);
procedure
ShowUnitDetails
(
UnitId
:
string
);
procedure
SetHeaderTitle
(
const
title
:
string
);
procedure
HideDetailsModal
;
...
...
@@ -68,6 +72,10 @@ type
procedure
HandleWsComplaintMap
(
aData
:
TJSObject
);
procedure
HandleWsUnitList
(
aData
:
TJSObject
);
procedure
HandleWsComplaintList
(
aData
:
TJSObject
);
procedure
HandleWsConnectionState
(
AState
:
TWsConnectionState
);
procedure
HandleWsRecoveryRequired
;
procedure
HandleWsAuthenticationExpired
;
procedure
ResyncLiveData
;
type
TActivePanel
=
(
apNone
,
apMap
,
apUnits
,
apComplaints
);
var
...
...
@@ -84,6 +92,7 @@ type
public
{ Public declarations }
destructor
Destroy
;
override
;
class
procedure
Display
(
LogoutProc
:
TLogoutProc
);
procedure
ShowForm
(
AFormClass
:
TWebFormClass
);
procedure
ShowComplaintDetails
(
ComplaintId
:
string
);
...
...
@@ -121,15 +130,10 @@ const
procedure
TFViewMain
.
WebFormCreate
(
Sender
:
TObject
);
var
userName
:
string
;
el
:
TJSElement
;
begin
userName
:=
JS
.
toString
(
AuthService
.
TokenPayload
.
Properties
[
'user_name'
]);
lblUsername
.
Caption
:=
' '
+
userName
.
ToLower
+
' '
;
el
:=
Document
.
getElementById
(
'view.main.version'
);
if
Assigned
(
el
)
then
TJSHtmlElement
(
el
).
innerText
:=
'v'
+
TDMConnection
.
clientVersion
;
FChildForm
:=
nil
;
FDetailsForm
:=
nil
;
FArchiveForm
:=
nil
;
...
...
@@ -139,6 +143,9 @@ begin
FMapRefreshTick
:=
0
;
FUnitsRefreshTick
:=
0
;
FComplaintsRefreshTick
:=
0
;
FBadgeRefreshInProgress
:=
False
;
FBadgeRefreshPending
:=
False
;
FPendingWsBadgeCounts
:=
nil
;
if
(
not
(
JS
.
toBoolean
(
AuthService
.
TokenPayload
.
Properties
[
'user_admin'
])))
then
lblUsers
.
Visible
:=
false
;
...
...
@@ -175,9 +182,27 @@ begin
dmWebsocket
.
OnComplaintMap
:=
HandleWsComplaintMap
;
dmWebsocket
.
OnUnitList
:=
HandleWsUnitList
;
dmWebsocket
.
OnComplaintList
:=
HandleWsComplaintList
;
dmWebsocket
.
OnStateChanged
:=
HandleWsConnectionState
;
dmWebsocket
.
OnRecoveryRequired
:=
HandleWsRecoveryRequired
;
dmWebsocket
.
OnAuthenticationExpired
:=
HandleWsAuthenticationExpired
;
dmWebsocket
.
Connect
(
DMConnection
.
WsUrl
);
end
;
destructor
TFViewMain
.
Destroy
;
begin
if
Assigned
(
dmWebsocket
)
and
(
dmWebsocket
.
Owner
=
Self
)
then
begin
dmWebsocket
.
Stop
;
dmWebsocket
.
Free
;
dmWebsocket
:=
nil
;
end
;
if
FViewMain
=
Self
then
FViewMain
:=
nil
;
inherited
;
end
;
procedure
TFViewMain
.
SetActivePanel
(
panel
:
TActivePanel
);
begin
FActivePanel
:=
panel
;
...
...
@@ -468,10 +493,13 @@ end;
// WebSocket push handlers
// ---------------------------------------------------------------------------
procedure
TFViewMain
.
HandleWs
BadgeCounts
(
aData
:
TJSObject
);
procedure
TFViewMain
.
Apply
BadgeCounts
(
aData
:
TJSObject
);
var
el
:
TJSElement
;
begin
if
not
Assigned
(
aData
)
then
Exit
;
el
:=
Document
.
getElementById
(
'view.main.badgecomplaints'
);
if
Assigned
(
el
)
then
TJSHtmlElement
(
el
).
innerText
:=
string
(
aData
[
'BadgeComplaints'
]);
...
...
@@ -481,6 +509,17 @@ begin
TJSHtmlElement
(
el
).
innerText
:=
string
(
aData
[
'BadgeUnits'
]);
end
;
procedure
TFViewMain
.
HandleWsBadgeCounts
(
aData
:
TJSObject
);
begin
if
FBadgeRefreshInProgress
then
begin
FPendingWsBadgeCounts
:=
aData
;
Exit
;
end
;
ApplyBadgeCounts
(
aData
);
end
;
procedure
TFViewMain
.
HandleWsUnitMap
(
aData
:
TJSObject
);
begin
if
Assigned
(
FMapForm
)
then
...
...
@@ -505,6 +544,83 @@ begin
FComplaintsForm
.
ApplyWsData
(
aData
);
end
;
procedure
TFViewMain
.
HandleWsConnectionState
(
AState
:
TWsConnectionState
);
var
statusElement
:
TJSHTMLElement
;
textElement
:
TJSHTMLElement
;
statusText
:
string
;
statusClass
:
string
;
begin
case
AState
of
wcsConnecting
:
begin
statusText
:=
'Connecting'
;
statusClass
:=
'connecting'
;
end
;
wcsConnected
:
begin
statusText
:=
'Connected'
;
statusClass
:=
'connected'
;
end
;
wcsReconnecting
:
begin
statusText
:=
'Reconnecting'
;
statusClass
:=
'reconnecting'
;
end
;
wcsOffline
:
begin
statusText
:=
'Offline'
;
statusClass
:=
'offline'
;
end
;
else
begin
statusText
:=
'Disconnected'
;
statusClass
:=
'stopped'
;
end
;
end
;
statusElement
:=
TJSHTMLElement
(
Document
.
getElementById
(
'view.main.lblconnection'
));
if
Assigned
(
statusElement
)
then
begin
statusElement
.
setAttribute
(
'class'
,
'connection-status connection-status-'
+
statusClass
);
statusElement
.
setAttribute
(
'aria-label'
,
'Live updates: '
+
statusText
);
statusElement
.
setAttribute
(
'title'
,
'Live updates: '
+
statusText
);
end
;
textElement
:=
TJSHTMLElement
(
Document
.
getElementById
(
'view.main.lblconnectiontext'
));
if
Assigned
(
textElement
)
then
textElement
.
innerText
:=
statusText
;
end
;
procedure
TFViewMain
.
HandleWsRecoveryRequired
;
begin
ResyncLiveData
;
end
;
procedure
TFViewMain
.
HandleWsAuthenticationExpired
;
begin
if
Assigned
(
dmWebsocket
)
then
dmWebsocket
.
Stop
;
if
Assigned
(
FLogoutProc
)
then
FLogoutProc
(
'Your session has expired. Please sign in again.'
);
end
;
procedure
TFViewMain
.
ResyncLiveData
;
begin
if
(
not
AuthService
.
Authenticated
)
or
AuthService
.
TokenExpired
then
begin
HandleWsAuthenticationExpired
;
Exit
;
end
;
Console
.
Log
(
'WS: resynchronizing live data'
);
RefreshBadgesAsync
;
Inc
(
FGlobalRefreshTick
);
RefreshActivePanelFromTimer
;
end
;
// ---------------------------------------------------------------------------
procedure
TFViewMain
.
tmrBadgeCountsTimer
(
Sender
:
TObject
);
...
...
@@ -528,27 +644,54 @@ var
badgeObj
:
TJSObject
;
el
:
TJSElement
;
begin
if
FBadgeRefreshInProgress
then
begin
FBadgeRefreshPending
:=
True
;
Exit
;
end
;
FBadgeRefreshInProgress
:=
True
;
try
try
resp
:=
await
(
xdwcBadgeCounts
.
RawInvokeAsync
(
'IApiService.GetBadgeCounts'
,
[]));
badgeObj
:=
TJSObject
(
resp
.
Result
);
el
:=
Document
.
getElementById
(
'view.main.badgecomplaints'
);
if
Assigned
(
el
)
the
n
TJSHtmlElement
(
el
).
innerText
:=
string
(
badgeObj
[
'BadgeComplaints'
]
);
el
:=
Document
.
getElementById
(
'view.main.badgeunits'
);
if
Assigned
(
el
)
then
TJSHtmlElement
(
el
).
innerText
:=
string
(
badgeObj
[
'BadgeUnits'
]
);
if
Assigned
(
FPendingWsBadgeCounts
)
then
begi
n
ApplyBadgeCounts
(
FPendingWsBadgeCounts
);
FPendingWsBadgeCounts
:=
nil
;
end
else
ApplyBadgeCounts
(
badgeObj
);
except
on
E
:
Exception
do
begin
if
Assigned
(
FPendingWsBadgeCounts
)
then
begin
ApplyBadgeCounts
(
FPendingWsBadgeCounts
);
FPendingWsBadgeCounts
:=
nil
;
end
else
begin
el
:=
Document
.
getElementById
(
'view.main.badgecomplaints'
);
if
Assigned
(
el
)
then
TJSHtmlElement
(
el
).
innerText
:=
'�'
;
el
:=
Document
.
getElementById
(
'view.main.badgeunits'
);
if
Assigned
(
el
)
then
TJSHtmlElement
(
el
).
innerText
:=
'�'
;
end
;
Console
.
Log
(
'Badge refresh error: '
+
E
.
Message
);
end
;
end
;
finally
FBadgeRefreshInProgress
:=
False
;
if
FBadgeRefreshPending
then
begin
FBadgeRefreshPending
:=
False
;
RefreshBadgesAsync
;
end
;
end
;
end
;
...
...
webEMIMobile/View.Map.dfm
View file @
b47e6601
...
...
@@ -62,7 +62,6 @@ object FViewMap: TFViewMap
end
object httpReqGeoJson: TWebHttpRequest
ResponseType = rtText
URL = 'assets/orleanscounty.geojson'
OnResponse = httpReqGeoJsonResponse
Left = 116
Top = 698
...
...
webEMIMobile/View.Map.html
View file @
b47e6601
...
...
@@ -52,16 +52,17 @@
<i
class=
"fa fa-crosshairs"
></i>
</button>
<!-- Filters (
top-right
) -->
<!-- Filters (
bottom-right, above recenter
) -->
<button
id=
"btn_map_filters"
type=
"button"
class=
"btn btn-primary position-absolute
top-0 end-0 m
-2 shadow"
style=
"z-index:1000;"
class=
"btn btn-primary position-absolute
end-0 me
-2 shadow"
style=
"z-index:1000;
bottom:4.5rem;
"
data-bs-toggle=
"offcanvas"
data-bs-target=
"#map_filters_offcanvas"
aria-controls=
"map_filters_offcanvas"
>
<i
class=
"fa fa-sliders-h"
></i>
<span
class=
"d-none d-sm-inline"
>
Filters
</span>
aria-controls=
"map_filters_offcanvas"
aria-label=
"Map filters"
title=
"Map filters"
>
<i
class=
"fa fa-sliders-h"
aria-hidden=
"true"
></i>
</button>
</div>
</div>
...
...
webEMIMobile/View.Map.pas
View file @
b47e6601
...
...
@@ -31,6 +31,7 @@ type
FUnitsLoaded
:
Boolean
;
FComplaintsLoaded
:
Boolean
;
FLoadingPoints
:
Boolean
;
FRefreshPending
:
Boolean
;
mapFilters
:
TMapFilters
;
FPendingUnitId
:
string
;
FPendingComplaintId
:
string
;
...
...
@@ -293,10 +294,12 @@ begin
resp
:=
await
(
xdwcMap
.
RawInvokeAsync
(
'IApiService.GetUnitMap'
,
[]));
root
:=
TJSObject
(
resp
.
Result
);
unitsData
:=
TJSArray
(
root
[
'data'
]);
FUnitsLoaded
:=
True
;
FUnitsLoaded
:=
Assigned
(
unitsData
)
;
except
on
E
:
EXDataClientRequestException
do
Console
.
Log
(
'Units XData error: '
+
E
.
ErrorResult
.
ErrorMessage
);
on
E
:
Exception
do
Console
.
Log
(
'Units error: '
+
E
.
Message
);
end
;
// --- Fetch Complaints ----------------------------------------------------
...
...
@@ -304,10 +307,12 @@ begin
resp
:=
await
(
xdwcMap
.
RawInvokeAsync
(
'IApiService.GetComplaintMap'
,
[]));
root
:=
TJSObject
(
resp
.
Result
);
complaintsData
:=
TJSArray
(
root
[
'data'
]);
FComplaintsLoaded
:=
True
;
FComplaintsLoaded
:=
Assigned
(
complaintsData
)
;
except
on
E
:
EXDataClientRequestException
do
Console
.
Log
(
'Complaints XData error: '
+
E
.
ErrorResult
.
ErrorMessage
);
on
E
:
Exception
do
Console
.
Log
(
'Complaints error: '
+
E
.
Message
);
end
;
// A WebSocket snapshot received while the HTTP requests were in flight is
...
...
@@ -329,7 +334,9 @@ begin
// --- Place markers (BeginUpdate wraps both so the map redraws once) ------
lfMap
.
BeginUpdate
;
try
if
FUnitsLoaded
then
PlaceUnitMarkers
(
unitsData
);
if
FComplaintsLoaded
then
PlaceComplaintMarkers
(
complaintsData
);
finally
lfMap
.
EndUpdate
;
...
...
@@ -344,6 +351,12 @@ begin
if
showBusy
then
HideSpinner
(
'spinner'
);
FLoadingPoints
:=
False
;
if
FRefreshPending
then
begin
FRefreshPending
:=
False
;
LoadPointsAsync
(
False
);
end
;
end
;
end
;
...
...
@@ -716,22 +729,17 @@ begin
end
;
procedure
TFViewMap
.
btnFindLocationClick
(
Sender
:
TObject
);
var
coord
:
TTMSFNCMapsCoordinateRec
;
begin
if
userLocationMarker
=
nil
then
Exit
;
coord
:=
CreateCoordinate
(
userLocationMarker
.
Latitude
,
userLocationMarker
.
Longitude
);
lfMap
.
SetCenterCoordinate
(
coord
);
FPendingFocusCoord
:=
coord
;
FPendingFocusZoom
:=
17
;
FDoFocusZoom
:=
True
;
tmrLocate
.
Enabled
:=
False
;
FDoFocusZoom
:=
False
;
FPendingFocusMarkerData
:=
''
;
FPendingUnitId
:=
''
;
FPendingComplaintId
:=
''
;
tmrLocate
.
Interval
:=
250
;
tmrLocate
.
Enabled
:=
True
;
if
lfMap
.
Polygons
.
Count
=
0
then
Exit
;
lfMap
.
ZoomToBounds
(
lfMap
.
Polygons
.
ToCoordinateArray
);
end
;
...
...
@@ -855,6 +863,13 @@ end;
procedure
TFViewMap
.
RefreshData
;
begin
Console
.
Log
(
'Map.RefreshData'
);
if
FLoadingPoints
then
begin
FRefreshPending
:=
True
;
Exit
;
end
;
LoadPointsAsync
(
False
);
end
;
...
...
webEMIMobile/View.Units.pas
View file @
b47e6601
...
...
@@ -37,6 +37,8 @@ type
private
FLoading
:
Boolean
;
FFirstLoad
:
Boolean
;
FRefreshPending
:
Boolean
;
FPendingWsData
:
TJSObject
;
[
async
]
procedure
GetUnits
;
procedure
HandleListClick
(
e
:
TJSMouseEvent
);
public
...
...
@@ -57,6 +59,8 @@ begin
DMConnection
.
ApiConnection
.
Connected
:=
True
;
Document
.
addEventListener
(
'click'
,
@
HandleListClick
);
FFirstLoad
:=
True
;
FRefreshPending
:=
False
;
FPendingWsData
:=
nil
;
GetUnits
;
asm
...
...
@@ -158,12 +162,32 @@ begin
FFirstLoad
:=
False
;
FLoading
:=
False
;
if
Assigned
(
FPendingWsData
)
then
begin
respObj
:=
FPendingWsData
;
FPendingWsData
:=
nil
;
ApplyWsData
(
respObj
);
end
;
if
FRefreshPending
then
begin
FRefreshPending
:=
False
;
GetUnits
;
end
;
end
;
end
;
procedure
TFViewUnits
.
RefreshData
;
begin
Console
.
Log
(
'Units.RefreshData'
);
if
FLoading
then
begin
FRefreshPending
:=
True
;
Exit
;
end
;
GetUnits
;
end
;
...
...
@@ -172,7 +196,10 @@ var
unitCount
:
Integer
;
begin
if
FLoading
then
begin
FPendingWsData
:=
aRespObj
;
Exit
;
end
;
xdwdsUnits
.
Close
;
xdwdsUnits
.
SetJsonData
(
aRespObj
[
'data'
]);
...
...
webEMIMobile/css/app.css
View file @
b47e6601
...
...
@@ -82,6 +82,70 @@ html, body {
.tab-hidden
{
display
:
none
!important
;
}
.connection-status
{
display
:
inline-flex
;
align-items
:
center
;
gap
:
0.35rem
;
min-height
:
1.75rem
;
padding
:
0.2rem
0.55rem
;
border
:
1px
solid
rgba
(
255
,
255
,
255
,
0.35
);
border-radius
:
999px
;
color
:
#fff
;
font-size
:
0.75rem
;
font-weight
:
600
;
line-height
:
1
;
white-space
:
nowrap
;
}
.connection-status-dot
{
width
:
0.55rem
;
height
:
0.55rem
;
flex
:
0
0
auto
;
border-radius
:
50%
;
background-color
:
#adb5bd
;
}
.connection-status-connected
.connection-status-dot
{
background-color
:
#75d995
;
box-shadow
:
0
0
0
0.14rem
rgba
(
117
,
217
,
149
,
0.2
);
}
.connection-status-connecting
.connection-status-dot
,
.connection-status-reconnecting
.connection-status-dot
{
background-color
:
#ffd166
;
animation
:
connection-status-pulse
1.4s
ease-in-out
infinite
;
}
.connection-status-offline
.connection-status-dot
,
.connection-status-stopped
.connection-status-dot
{
background-color
:
#ff8b94
;
}
@keyframes
connection-status-pulse
{
0
%,
100
%
{
opacity
:
0.45
;
}
50
%
{
opacity
:
1
;
}
}
@media
(
max-width
:
430px
)
{
.connection-status
{
width
:
1.75rem
;
justify-content
:
center
;
padding-right
:
0
;
padding-left
:
0
;
}
.connection-status-text
{
display
:
none
;
}
}
@media
(
prefers-reduced-motion
:
reduce
)
{
.connection-status-connecting
.connection-status-dot
,
.connection-status-reconnecting
.connection-status-dot
{
animation
:
none
;
}
}
.summary-chevron-icon
{
width
:
1rem
;
height
:
1rem
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment