chore: updated error pages ea048f2c
Steve · 2025-12-30 19:24 1 file(s) · +24 −115
Titan/Views/ErrorPageView.swift +24 −115
217 217
        }
218 218
    }
219 219
220 -
    var asciiArt: String {
220 +
    var icon: String {
221 221
        switch self {
222 222
        case .temporaryFailure(let code, _):
223 223
            if code == 44 {
224 -
                // Hourglass for "slow down"
225 -
                return """
226 -
                    ╭━━━━━━━╮
227 -
                    │░░░░░░░│
228 -
                    ╰┬─────┬╯
229 -
                     │░░░░░│
230 -
                     │░░░░░│
231 -
                    ╭┴─────┴╮
232 -
                    │       │
233 -
                    ╰━━━━━━━╯
234 -
                """
224 +
                return "hourglass"
235 225
            }
236 -
            // Clock for temporary issues
237 -
            return """
238 -
                  ╭───────╮
239 -
                 ╱    │    ╲
240 -
                │     │     │
241 -
                │     ╰──   │
242 -
                │           │
243 -
                 ╲         ╱
244 -
                  ╰───────╯
245 -
            """
226 +
            return "clock.badge.exclamationmark"
246 227
        case .permanentFailure(let code, _):
247 228
            if code == 51 {
248 -
                // Question mark for not found
249 -
                return """
250 -
                   ╭━━━━━╮
251 -
                   │ ??? │
252 -
                   ╰──┬──╯
253 -
254 -
                    ╭─┴─╮
255 -
                    │ ? │
256 -
                    ╰───╯
257 -
                """
229 +
                return "questionmark.folder"
258 230
            }
259 231
            if code == 52 {
260 -
                // Ghost for "gone"
261 -
                return """
262 -
                    ╭─────╮
263 -
                   ╱ ◠   ◠ ╲
264 -
                  │    ▽    │
265 -
                  │         │
266 -
                   ╲ ╱ ╲ ╱ ╱
267 -
                    ╵   ╵
268 -
                """
232 +
                return "trash"
269 233
            }
270 -
            // X mark for errors
271 -
            return """
272 -
                  ╲       ╱
273 -
                   ╲     ╱
274 -
                    ╲   ╱
275 -
                     ╲ ╱
276 -
                     ╱ ╲
277 -
                    ╱   ╲
278 -
                   ╱     ╲
279 -
                  ╱       ╲
280 -
            """
234 +
            return "xmark.circle"
281 235
        case .clientCertificate:
282 -
            // Lock icon
283 -
            return """
284 -
                   ╭─────╮
285 -
                   │     │
286 -
                 ╭─┴─────┴─╮
287 -
                 │  ┌───┐  │
288 -
                 │  │ ◉ │  │
289 -
                 │  └─┬─┘  │
290 -
                 ╰────┴────╯
291 -
            """
236 +
            return "lock.shield"
292 237
        case .tooManyRedirects:
293 -
            // Circular arrows
294 -
            return """
295 -
                  ╭──────╮
296 -
                 ╱   ──▶  ╲
297 -
                │ ▲       │
298 -
                │         ▼
299 -
                 ╲  ◀──   ╱
300 -
                  ╰──────╯
301 -
            """
238 +
            return "arrow.triangle.2.circlepath"
302 239
        case .networkError:
303 -
            // Disconnected plug
304 -
            return """
305 -
                 ╭───╮
306 -
                 │ ● │
307 -
                 │ ● │╶╶╶╮
308 -
                 ╰───╯   ┊
309 -
310 -
                 ╭───╮   ┊
311 -
                 │ ○ │╶╶╶╯
312 -
                 │ ○ │
313 -
                 ╰───╯
314 -
            """
240 +
            return "wifi.slash"
315 241
        case .invalidResponse:
316 -
            // Broken document
317 -
            return """
318 -
                 ╭───────╮
319 -
                 │ ≋≋≋≋≋ │
320 -
                 │ ≋≋≋ ╱─┤
321 -
                 ├───╱   │
322 -
                 │   ╲───┤
323 -
                 │ ≋≋ ╲  │
324 -
                 ╰───────╯
325 -
            """
242 +
            return "doc.badge.ellipsis"
326 243
        case .invalidURL:
327 -
            // Broken link
328 -
            return """
329 -
                 ╭───╮
330 -
                ╱    ╲────╮
331 -
                ╲    ╱    │
332 -
                 ╰─╳─╯    │
333 -
                     ╭─╳──╯
334 -
                     │╱    ╲
335 -
                     ╰────╱
336 -
            """
244 +
            return "link.badge.plus"
337 245
        }
338 246
    }
339 247
}
366 274
367 275
    var body: some View {
368 276
        VStack(spacing: 24) {
369 -
            // ASCII Art
370 -
            Text(errorType.asciiArt)
371 -
                .font(.system(size: 14, design: .monospaced))
277 +
            // Icon
278 +
            Image(systemName: errorType.icon)
279 +
                .font(.system(size: 60))
372 280
                .foregroundColor(errorColor)
373 -
                .multilineTextAlignment(.center)
374 281
375 282
            // Title and status code
376 283
            VStack(spacing: 4) {
377 284
                Text(errorType.title)
378 -
                    .font(.system(.title2, design: .rounded))
285 +
                    .font(.system(.title2, design: themeSettings.fontDesign.fontDesign))
379 286
                    .fontWeight(.bold)
380 287
                    .foregroundColor(themeSettings.textColor)
381 288
382 289
                if let code = errorType.statusCode {
383 290
                    Text(code)
384 -
                        .font(.system(.subheadline, design: .monospaced))
291 +
                        .font(.system(.subheadline, design: themeSettings.fontDesign.fontDesign))
385 292
                        .foregroundColor(.secondary)
386 293
                }
387 294
            }
388 295
389 -
            // Server message if present
390 -
            if let meta = errorType.meta {
296 +
            // Server message if present and different from title
297 +
            if let meta = errorType.meta,
298 +
               meta.lowercased() != errorType.title.lowercased() {
391 299
                Text(meta)
392 -
                    .font(.system(.caption, design: .monospaced))
300 +
                    .font(.system(.caption, design: themeSettings.fontDesign.fontDesign))
393 301
                    .foregroundColor(.secondary)
394 302
                    .padding(.horizontal, 16)
395 303
                    .padding(.vertical, 8)
401 309
402 310
            // Explanation
403 311
            Text(errorType.explanation)
404 -
                .font(.system(.body, design: .default))
312 +
                .font(.system(.body, design: themeSettings.fontDesign.fontDesign))
405 313
                .foregroundColor(themeSettings.textColor.opacity(0.8))
406 314
                .multilineTextAlignment(.center)
407 315
                .padding(.horizontal, 24)
413 321
                        Text("•")
414 322
                            .foregroundColor(errorColor)
415 323
                        Text(suggestion)
416 -
                            .font(.system(.callout))
324 +
                            .font(.system(.callout, design: themeSettings.fontDesign.fontDesign))
417 325
                            .foregroundColor(.secondary)
418 326
                    }
419 327
                }
427 335
                        Image(systemName: "arrow.clockwise")
428 336
                        Text("Try Again")
429 337
                    }
430 -
                    .font(.system(.body, weight: .medium))
338 +
                    .font(.system(.body, design: themeSettings.fontDesign.fontDesign))
339 +
                    .fontWeight(.medium)
431 340
                    .foregroundColor(.white)
432 341
                    .padding(.horizontal, 24)
433 342
                    .padding(.vertical, 12)