Skip to content

Commit 4461289

Browse files
Add maintenance mode
1 parent 5ca0214 commit 4461289

2 files changed

Lines changed: 279 additions & 0 deletions

File tree

docker/nginx.conf

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,40 @@ server {
22
listen 80 default_server;
33
root /home/app/decidim-diba/public;
44

5+
# ---------------------------------------------------------------------------
6+
# MAINTENANCE MODE — file-based toggle (no nginx reload required)
7+
#
8+
# Enable: docker exec <container> touch /home/app/decidim-diba/public/maintenance.enable
9+
# Disable: docker exec <container> rm /home/app/decidim-diba/public/maintenance.enable
10+
#
11+
# nginx re-checks the sentinel file on every request automatically.
12+
# The 503 page is served from /usr/share/nginx/html so it works even
13+
# when the Rails app / Passenger is not running.
14+
#
15+
# location blocks for /assets/ and /uploads/ are matched before the
16+
# server-level `if`, so static files are always served — handy if your
17+
# maintenance page references assets from public/.
18+
#
19+
# Uncomment the remote_addr block below to whitelist an admin IP.
20+
# ---------------------------------------------------------------------------
21+
22+
set $maintenance 0;
23+
24+
if (-f $document_root/maintenance.enable) {
25+
set $maintenance 1;
26+
}
27+
28+
# if ($remote_addr = "YOUR.ADMIN.IP.HERE") {
29+
# set $maintenance 0;
30+
# }
31+
32+
if ($maintenance = 1) {
33+
# Returning 503 error seems to not work
34+
rewrite ^ /maintenance.html break;
35+
}
36+
37+
error_page 503 =503 /maintenance.html;
38+
539
passenger_enabled on;
640
passenger_user app;
741
passenger_ruby /usr/bin/ruby;

public/maintenance.html

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
<!DOCTYPE html>
2+
<html lang="ca">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Manteniment – Plataforma Participa311</title>
7+
<link rel="preconnect" href="https://fonts.googleapis.com" />
8+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9+
<link href="https://fonts.googleapis.com/css2?family=Source+Serif+4:ital,wght@0,300;0,400;0,600;1,300&family=Source+Sans+3:wght@300;400;600&display=swap" rel="stylesheet" />
10+
<style>
11+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
12+
13+
:root {
14+
--black: #1a1a2e;
15+
--red: #c0392b;
16+
--red-mid: #e74c3c;
17+
--white: #ffffff;
18+
--off: #f5f4f0;
19+
--grey: #6b7280;
20+
--border: #d1d5db;
21+
}
22+
23+
html, body {
24+
height: 100%;
25+
background: var(--off);
26+
font-family: 'Source Sans 3', sans-serif;
27+
color: var(--black);
28+
}
29+
30+
/* ── HEADER ── */
31+
header {
32+
background: var(--black);
33+
padding: 0 2rem;
34+
height: 64px;
35+
display: flex;
36+
align-items: center;
37+
justify-content: space-between;
38+
}
39+
40+
.header-brand {
41+
display: flex;
42+
align-items: center;
43+
gap: 0.75rem;
44+
text-decoration: none;
45+
}
46+
47+
.brand-pill {
48+
background: var(--red);
49+
color: var(--white);
50+
font-family: 'Source Sans 3', sans-serif;
51+
font-weight: 600;
52+
font-size: 1.15rem;
53+
letter-spacing: 0.04em;
54+
padding: 0.25rem 0.65rem 0.28rem;
55+
border-radius: 3px;
56+
}
57+
58+
.brand-name {
59+
color: var(--white);
60+
font-family: 'Source Sans 3', sans-serif;
61+
font-weight: 300;
62+
font-size: 1.05rem;
63+
letter-spacing: 0.06em;
64+
text-transform: uppercase;
65+
}
66+
67+
.header-diba {
68+
color: rgba(255,255,255,0.45);
69+
font-size: 0.72rem;
70+
letter-spacing: 0.08em;
71+
text-transform: uppercase;
72+
}
73+
74+
/* ── RED ACCENT BAR ── */
75+
.accent-bar {
76+
height: 4px;
77+
background: var(--red);
78+
}
79+
80+
/* ── MAIN ── */
81+
main {
82+
min-height: calc(100vh - 64px - 4px - 80px);
83+
display: flex;
84+
align-items: center;
85+
justify-content: center;
86+
padding: 4rem 1.5rem;
87+
}
88+
89+
.card {
90+
background: var(--white);
91+
border: 1px solid var(--border);
92+
border-top: 4px solid var(--red);
93+
max-width: 560px;
94+
width: 100%;
95+
padding: 3rem 3.5rem;
96+
box-shadow: 0 4px 32px rgba(26,26,46,0.07);
97+
animation: rise 0.55s cubic-bezier(.22,.68,0,1.2) both;
98+
}
99+
100+
@keyframes rise {
101+
from { opacity: 0; transform: translateY(18px); }
102+
to { opacity: 1; transform: translateY(0); }
103+
}
104+
105+
.icon-wrap {
106+
width: 52px;
107+
height: 52px;
108+
background: #fff0ef;
109+
border-radius: 50%;
110+
display: flex;
111+
align-items: center;
112+
justify-content: center;
113+
margin-bottom: 1.75rem;
114+
}
115+
116+
.icon-wrap svg {
117+
width: 26px;
118+
height: 26px;
119+
stroke: var(--red);
120+
}
121+
122+
.label {
123+
font-size: 0.72rem;
124+
font-weight: 600;
125+
letter-spacing: 0.14em;
126+
text-transform: uppercase;
127+
color: var(--red);
128+
margin-bottom: 0.6rem;
129+
}
130+
131+
h1 {
132+
font-family: 'Source Serif 4', Georgia, serif;
133+
font-weight: 600;
134+
font-size: 1.65rem;
135+
line-height: 1.25;
136+
color: var(--black);
137+
margin-bottom: 1.25rem;
138+
}
139+
140+
.divider {
141+
width: 36px;
142+
height: 2px;
143+
background: var(--red);
144+
margin-bottom: 1.25rem;
145+
}
146+
147+
p {
148+
font-size: 1rem;
149+
line-height: 1.7;
150+
color: #374151;
151+
font-weight: 300;
152+
}
153+
154+
.time-badge {
155+
display: inline-flex;
156+
align-items: center;
157+
gap: 0.4rem;
158+
margin-top: 1.75rem;
159+
background: var(--off);
160+
border: 1px solid var(--border);
161+
border-radius: 2px;
162+
padding: 0.45rem 0.85rem;
163+
font-size: 0.82rem;
164+
color: var(--grey);
165+
font-weight: 400;
166+
}
167+
168+
.time-badge svg {
169+
width: 14px;
170+
height: 14px;
171+
stroke: var(--grey);
172+
flex-shrink: 0;
173+
}
174+
175+
/* ── FOOTER ── */
176+
footer {
177+
height: 80px;
178+
background: var(--black);
179+
display: flex;
180+
align-items: center;
181+
justify-content: center;
182+
gap: 1.5rem;
183+
}
184+
185+
.footer-dot {
186+
width: 4px;
187+
height: 4px;
188+
border-radius: 50%;
189+
background: rgba(255,255,255,0.2);
190+
}
191+
192+
footer span {
193+
color: rgba(255,255,255,0.38);
194+
font-size: 0.72rem;
195+
letter-spacing: 0.06em;
196+
}
197+
198+
@media (max-width: 480px) {
199+
.card { padding: 2rem 1.5rem; }
200+
h1 { font-size: 1.35rem; }
201+
}
202+
</style>
203+
</head>
204+
<body>
205+
206+
<header>
207+
<div class="header-brand">
208+
</div>
209+
</header>
210+
<div class="accent-bar"></div>
211+
212+
<main>
213+
<div class="card">
214+
215+
<div class="icon-wrap">
216+
<!-- wrench / settings icon -->
217+
<svg viewBox="0 0 24 24" fill="none" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
218+
<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>
219+
</svg>
220+
</div>
221+
222+
<p class="label">Manteniment del sistema</p>
223+
224+
<h1>Plataforma Participa311<br>en manteniment</h1>
225+
226+
<div class="divider"></div>
227+
228+
<p>Estem actualitzant el programari de la Plataforma Participa311 per millorar-la. La pàgina estarà fora de servei dues hores aproximadament. Perdoneu les molèsties.</p>
229+
230+
<div class="time-badge">
231+
<!-- clock icon -->
232+
<svg viewBox="0 0 24 24" fill="none" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
233+
<circle cx="12" cy="12" r="10"/>
234+
<polyline points="12 6 12 12 16 14"/>
235+
</svg>
236+
Durada aproximada: 2 hores
237+
</div>
238+
239+
</div>
240+
</main>
241+
242+
<footer>
243+
</footer>
244+
</body>
245+
</html>

0 commit comments

Comments
 (0)