Skip to main content

DEFAULT_404_HTML

Constant DEFAULT_404_HTML 

Source
pub const DEFAULT_404_HTML: &str = "<!doctype html>\n<html lang=\"en\">\n    <head>\n        <meta charset=\"UTF-8\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n        <title>404 \u{2014} Page Not Found</title>\n        <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n        <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n        <link\n            href=\"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap\"\n            rel=\"stylesheet\"\n        />\n        <script>\n            // Tailwind config must run BEFORE the CDN script loads.\n            // Extends the default theme: Inter as the default sans family\n            // (so `font-sans` / body text picks it up), and JetBrains Mono\n            // as the default mono family (so `font-mono` / `.mono` works).\n            window.tailwind = window.tailwind || {};\n            window.tailwind.config = {\n                theme: {\n                    extend: {\n                        fontFamily: {\n                            sans: [\n                                \"Inter\",\n                                \"ui-sans-serif\",\n                                \"system-ui\",\n                                \"-apple-system\",\n                                \"Segoe UI\",\n                                \"Roboto\",\n                                \"sans-serif\",\n                            ],\n                            mono: [\n                                \"JetBrains Mono\",\n                                \"ui-monospace\",\n                                \"SFMono-Regular\",\n                                \"Menlo\",\n                                \"Consolas\",\n                                \"monospace\",\n                            ],\n                        },\n                    },\n                },\n            };\n        </script>\n        <script src=\"https://cdn.tailwindcss.com?plugins=forms,container-queries\"></script>\n        <style>\n            /* Apply the body font to the page (Tailwind\'s preflight\n               already sets ui-sans-serif on body; we override it here\n               so Inter wins once it has loaded). */\n            body {\n                font-family: \"Inter\", ui-sans-serif, system-ui, -apple-system,\n                    \"Segoe UI\", Roboto, sans-serif;\n            }\n            /* `.mono` is the shorthand class used throughout the page\n               for monospace text. Tailwind\'s `font-mono` utility also\n               resolves to the same stack via the config above. */\n            .mono {\n                font-family: \"JetBrains Mono\", ui-monospace, SFMono-Regular,\n                    Menlo, Consolas, monospace;\n            }\n        </style>\n    </head>\n    <body\n        class=\"min-h-screen bg-slate-950 text-slate-300 antialiased flex flex-col\"\n    >\n        <!-- Wordmark. Natural document flow so the footer never\n             overlaps the route list when it grows tall. -->\n        <header\n            class=\"relative z-10 px-6 py-5 flex items-center justify-between\"\n        >\n            <a\n                href=\"/\"\n                class=\"mono text-xs tracking-widest text-slate-500 hover:text-slate-300 transition-colors\"\n            >\n                umbral\n            </a>\n            <span\n                class=\"mono text-[10px] tracking-widest text-slate-600 uppercase\"\n            >\n                error // not_found\n            </span>\n        </header>\n\n        <!-- Subtle grid background -->\n        <div\n            class=\"absolute inset-0 -z-10 bg-[linear-gradient(to_right,#0f172a_1px,transparent_1px),linear-gradient(to_bottom,#0f172a_1px,transparent_1px)] bg-[size:4rem_4rem] [mask-image:radial-gradient(ellipse_60%_50%_at_50%_40%,#000_30%,transparent_100%)] opacity-40\"\n        ></div>\n        <div\n            class=\"absolute inset-0 -z-10 bg-[radial-gradient(circle_at_50%_30%,rgba(99,102,241,0.08),transparent_60%)]\"\n        ></div>\n\n        <!-- Main content. `flex-1` makes it absorb the spare\n             viewport so the footer hugs the bottom when the page is\n             short; when the dev-mode route panel makes it tall, the\n             whole body grows and the footer simply follows. -->\n        <main\n            class=\"relative flex-1 flex items-center justify-center px-6 py-16\"\n        >\n            <div class=\"w-full max-w-2xl mx-auto text-center\">\n                <!-- Status label -->\n                <p\n                    class=\"mono text-xs tracking-[0.25em] text-slate-500 uppercase\"\n                >\n                    Error // Not_Found\n                </p>\n\n                <!-- Hero code -->\n                <h1\n                    class=\"mono mt-6 text-7xl sm:text-8xl md:text-9xl font-bold tracking-tighter text-slate-200 leading-none\"\n                >\n                    404\n                </h1>\n\n                <!-- Headline -->\n                <h2\n                    class=\"mt-8 text-2xl sm:text-3xl font-semibold text-slate-100 tracking-tight\"\n                >\n                    Page not found\n                </h2>\n\n                <!-- Sub-copy -->\n                <p\n                    class=\"mt-4 text-base text-slate-400 max-w-md mx-auto leading-relaxed\"\n                >\n                    The path you requested doesn\'t match any registered route on\n                    this server.\n                </p>\n\n                <!-- URL strip -->\n                {% if path %}\n                <div class=\"mt-8 mx-auto max-w-xl\">\n                    <div\n                        class=\"flex items-center gap-2 rounded-md border border-slate-800 bg-slate-900/60 px-3 py-2.5 backdrop-blur-sm\"\n                    >\n                        <span\n                            class=\"mono text-[10px] tracking-widest text-slate-600 uppercase shrink-0\"\n                            >GET</span\n                        >\n                        <code\n                            class=\"mono text-sm text-slate-300 truncate flex-1 text-left\"\n                            title=\"{{ path }}\"\n                            >{{ path }}</code\n                        >\n                        <button\n                            type=\"button\"\n                            onclick=\"navigator.clipboard?.writeText(\'{{ path }}\'); this.textContent=\'Copied\'; setTimeout(()=>this.textContent=\'Copy\',1200);\"\n                            class=\"mono text-[10px] tracking-widest uppercase text-slate-500 hover:text-slate-200 transition-colors shrink-0 px-2 py-1 rounded focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-400\"\n                        >\n                            Copy\n                        </button>\n                    </div>\n                </div>\n                {% endif %}\n\n                <!-- Actions -->\n                <div\n                    class=\"mt-10 flex flex-col sm:flex-row items-center justify-center gap-3\"\n                >\n                    <a\n                        href=\"/\"\n                        class=\"inline-flex items-center justify-center gap-2 rounded-md bg-indigo-500 px-5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-400 transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-400 w-full sm:w-auto\"\n                    >\n                        <span aria-hidden=\"true\">\u{2190}</span>\n                        <span>Go home</span>\n                    </a>\n                    <button\n                        type=\"button\"\n                        onclick=\"\n                            if (history.length > 1) {\n                                history.back();\n                            } else {\n                                window.location.href = \'/\';\n                            }\n                        \"\n                        class=\"inline-flex items-center justify-center gap-2 rounded-md border border-slate-800 bg-slate-900/40 px-5 py-2.5 text-sm font-semibold text-slate-200 hover:bg-slate-900 hover:border-slate-700 transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-400 w-full sm:w-auto\"\n                    >\n                        Go back\n                    </button>\n                </div>\n\n                {# Dev-mode aid: list every registered route, grouped\n                   by plugin. Production responses set `dev_mode =\n                   false` so this whole block collapses to nothing. The\n                   list is a declared snapshot, not a live introspection\n                   of axum\'s routing table \u{2014} see\n                   `crates/umbral-core/src/routes.rs`. #}\n                {% if dev_mode and routes_by_plugin %}\n                <div\n                    class=\"mt-12 mx-auto max-w-2xl text-left rounded-md border border-slate-800 bg-slate-900/40 backdrop-blur-sm\"\n                >\n                    <div\n                        class=\"flex items-center justify-between gap-3 px-4 py-2.5 border-b border-slate-800\"\n                    >\n                        <span\n                            class=\"mono text-[10px] tracking-widest text-slate-400 uppercase\"\n                        >\n                            Dev only // registered routes\n                        </span>\n                        <span class=\"mono text-[10px] text-slate-600\">\n                            {{ routes_by_plugin | length }} plugin{% if routes_by_plugin | length != 1 %}s{% endif %}\n                        </span>\n                    </div>\n                    <div class=\"divide-y divide-slate-800\">\n                        {% for group in routes_by_plugin %}\n                        <details class=\"group\">\n                            <summary\n                                class=\"flex items-center justify-between gap-3 px-4 py-2.5 cursor-pointer hover:bg-slate-900/60 transition-colors\"\n                            >\n                                <span\n                                    class=\"mono text-xs text-slate-300\"\n                                    >{{ group.plugin }}</span\n                                >\n                                <span\n                                    class=\"mono text-[10px] text-slate-500\"\n                                    >{{ group.routes | length }} route{% if group.routes | length != 1 %}s{% endif %}</span\n                                >\n                            </summary>\n                            <ul\n                                class=\"px-4 py-2 space-y-1.5 bg-slate-950/40 border-t border-slate-800\"\n                            >\n                                {% for route in group.routes %}\n                                <li class=\"flex items-baseline gap-2\">\n                                    {# Method badge: tinted by verb so\n                                       the eye can scan a list of mixed\n                                       GET/POST/DELETE entries without\n                                       reading every label. The single\n                                       `method_label` (joined with `\u{b7}`)\n                                       keeps the badge narrow even for\n                                       composite routes like\n                                       `GET\u{b7}PUT`. #}\n                                    {% set ml = route.method_label %}\n                                    <span class=\"mono text-[10px] tracking-wider uppercase px-1.5 py-0.5 rounded shrink-0\n                                        {% if \'POST\' in route.methods or \'PUT\' in route.methods or \'PATCH\' in route.methods %}bg-amber-500/10 text-amber-300 ring-1 ring-amber-500/30\n                                        {% elif \'DELETE\' in route.methods %}bg-rose-500/10 text-rose-300 ring-1 ring-rose-500/30\n                                        {% elif \'GET\' in route.methods or \'HEAD\' in route.methods %}bg-emerald-500/10 text-emerald-300 ring-1 ring-emerald-500/30\n                                        {% else %}bg-slate-700/30 text-slate-400 ring-1 ring-slate-700{% endif %}\"\n                                        >{{ ml }}</span>\n                                    <code\n                                        class=\"mono text-xs text-slate-400 break-all\"\n                                        >{{ route.path }}</code\n                                    >\n                                </li>\n                                {% endfor %}\n                            </ul>\n                        </details>\n                        {% endfor %}\n                    </div>\n                </div>\n                {% endif %}\n            </div>\n        </main>\n\n        <!-- Footer links. Sits in normal flow at the bottom of the\n             flex column body \u{2014} no `absolute` positioning so it never\n             overlaps the route panel when it grows tall. -->\n        <footer\n            class=\"relative z-10 px-6 py-5 flex items-center justify-center gap-6\"\n        >\n            <a\n                href=\"/docs\"\n                class=\"text-xs text-slate-500 hover:text-slate-300 transition-colors\"\n                >Docs</a\n            >\n            <span class=\"text-slate-800\" aria-hidden=\"true\">\u{b7}</span>\n            <a\n                href=\"/status\"\n                class=\"text-xs text-slate-500 hover:text-slate-300 transition-colors\"\n                >Status</a\n            >\n            <span class=\"text-slate-800\" aria-hidden=\"true\">\u{b7}</span>\n            <a\n                href=\"https://github.com/umbral/umbral\"\n                class=\"text-xs text-slate-500 hover:text-slate-300 transition-colors\"\n                >GitHub</a\n            >\n        </footer>\n    </body>\n</html>\n";
Expand description

Default 404 page: centered, inline Tailwind utility classes. Degrades gracefully without Tailwind loaded — the page is functional even as unstyled HTML.