Skip to content

Commit c7276ae

Browse files
committed
Add ReconnectModal to the BlazorWeb-CSharp project template
1 parent 00893da commit c7276ae

File tree

5 files changed

+217
-0
lines changed

5 files changed

+217
-0
lines changed

src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/.template.config/template.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,14 @@
9393
"BlazorWeb-CSharp/Components/Pages/Counter.razor"
9494
]
9595
},
96+
{
97+
"condition": "(!UseServer)",
98+
"exclude": [
99+
"BlazorWeb-CSharp/Components/Layout/ReconnectModal.razor",
100+
"BlazorWeb-CSharp/Components/Layout/ReconnectModal.razor.css",
101+
"BlazorWeb-CSharp/Components/Layout/ReconnectModal.razor.js"
102+
]
103+
},
96104
{
97105
"condition": "(ExcludeLaunchSettings)",
98106
"exclude": [

src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Layout/MainLayout.razor

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,6 @@
2828
<span class="dismiss">🗙</span>
2929
</div>
3030
##endif*@
31+
@*#if (UseServer) -->
32+
<ReconnectModal />
33+
##endif*@
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<script type="module" src="@Assets["Shared/ReconnectModal.razor.js"]"></script>
2+
3+
<dialog id="components-reconnect-modal" data-nosnippet>
4+
<div class="components-reconnect-container">
5+
<div class="components-rejoining-animation" aria-hidden="true">
6+
<div></div>
7+
<div></div>
8+
</div>
9+
<p class="components-reconnect-first-attempt-visible">
10+
Rejoining the server...
11+
</p>
12+
<p class="components-reconnect-repeated-attempt-visible">
13+
Rejoin failed... trying again in <span id="components-seconds-to-next-attempt"></span> seconds.
14+
</p>
15+
<p class="components-reconnect-failed-visible">
16+
Failed to rejoin.<br />Please retry or reload the page.
17+
</p>
18+
<button id="components-reconnect-button" class="components-reconnect-failed-visible">
19+
Retry
20+
</button>
21+
</div>
22+
</dialog>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
.components-reconnect-first-attempt-s,
2+
.components-reconnect-repeated-attempt-visible,
3+
.components-reconnect-failed-visible,
4+
.components-rejoining-animation {
5+
display: none;
6+
}
7+
8+
#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible,
9+
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation,
10+
#components-reconnect-modal.components-reconnect-retrying,
11+
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible,
12+
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation,
13+
#components-reconnect-modal.components-reconnect-failed,
14+
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible {
15+
display: block;
16+
}
17+
18+
19+
#components-reconnect-modal {
20+
background-color: white;
21+
width: 20rem;
22+
margin: 20vh auto;
23+
padding: 2rem;
24+
border: 0;
25+
border-radius: 0.5rem;
26+
box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3);
27+
opacity: 0;
28+
transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
29+
animation: components-reconnect-modal-fadeOutOpacity 0.5s both;
30+
&[open]
31+
32+
{
33+
animation: components-reconnect-modal-slideUp 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity 0.5s ease-in-out 0.3s;
34+
animation-fill-mode: both;
35+
}
36+
37+
}
38+
39+
#components-reconnect-modal::backdrop {
40+
background-color: rgba(0, 0, 0, 0.4);
41+
animation: components-reconnect-modal-fadeInOpacity 0.5s ease-in-out;
42+
opacity: 1;
43+
}
44+
45+
@keyframes components-reconnect-modal-slideUp {
46+
0% {
47+
transform: translateY(30px) scale(0.95);
48+
}
49+
50+
100% {
51+
transform: translateY(0);
52+
}
53+
}
54+
55+
@keyframes components-reconnect-modal-fadeInOpacity {
56+
0% {
57+
opacity: 0;
58+
}
59+
60+
100% {
61+
opacity: 1;
62+
}
63+
}
64+
65+
@keyframes components-reconnect-modal-fadeOutOpacity {
66+
0% {
67+
opacity: 1;
68+
}
69+
70+
100% {
71+
opacity: 0;
72+
}
73+
}
74+
75+
.components-reconnect-container {
76+
display: flex;
77+
flex-direction: column;
78+
align-items: center;
79+
gap: 1rem;
80+
}
81+
82+
#components-reconnect-modal p {
83+
margin: 0;
84+
text-align: center;
85+
}
86+
87+
#components-reconnect-modal button {
88+
border: 0;
89+
background-color: #6b9ed2;
90+
color: white;
91+
padding: 4px 24px;
92+
border-radius: 4px;
93+
}
94+
95+
#components-reconnect-modal button:hover {
96+
background-color: #3b6ea2;
97+
}
98+
99+
#components-reconnect-modal button:active {
100+
background-color: #6b9ed2;
101+
}
102+
103+
.components-rejoining-animation {
104+
display: block;
105+
position: relative;
106+
width: 80px;
107+
height: 80px;
108+
}
109+
110+
.components-rejoining-animation div {
111+
position: absolute;
112+
border: 3px solid #0087ff;
113+
opacity: 1;
114+
border-radius: 50%;
115+
animation: components-rejoining-animation 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
116+
}
117+
118+
.components-rejoining-animation div:nth-child(2) {
119+
animation-delay: -0.5s;
120+
}
121+
122+
@keyframes components-rejoining-animation {
123+
0% {
124+
top: 40px;
125+
left: 40px;
126+
width: 0;
127+
height: 0;
128+
opacity: 0;
129+
}
130+
131+
4.9% {
132+
top: 40px;
133+
left: 40px;
134+
width: 0;
135+
height: 0;
136+
opacity: 0;
137+
}
138+
139+
5% {
140+
top: 40px;
141+
left: 40px;
142+
width: 0;
143+
height: 0;
144+
opacity: 1;
145+
}
146+
147+
100% {
148+
top: 0px;
149+
left: 0px;
150+
width: 80px;
151+
height: 80px;
152+
opacity: 0;
153+
}
154+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Set up event handlers
2+
const retryButton = document.getElementById("components-reconnect-button");
3+
4+
retryButton.addEventListener('click', retry);
5+
6+
async function retry() {
7+
document.removeEventListener('visibilitychange', retryWhenDocumentBecomesVisible);
8+
9+
try {
10+
// Reconnect will asynchronously return:
11+
// - true to mean success
12+
// - false to mean we reached the server, but it rejected the connection (e.g., unknown circuit ID)
13+
// - exception to mean we didn't reach the server (this can be sync or async)
14+
const successful = await Blazor.reconnect();
15+
if (!successful) {
16+
// We have been able to reach the server, but the circuit is no longer available.
17+
// We'll reload the page so the user can continue using the app as quickly as possible.
18+
location.reload();
19+
}
20+
} catch (err) {
21+
// We got an exception, server is currently unavailable
22+
document.addEventListener('visibilitychange', retryWhenDocumentBecomesVisible);
23+
}
24+
}
25+
26+
async function retryWhenDocumentBecomesVisible() {
27+
if (document.visibilityState === 'visible') {
28+
await retry();
29+
}
30+
}

0 commit comments

Comments
 (0)