11use axum:: extract:: Json ;
22use axum:: http:: Uri ;
3- use axum:: response:: IntoResponse ;
3+ use axum:: response:: { Html , IntoResponse } ;
44use axum:: {
55 Router ,
66 routing:: { get, post} ,
@@ -13,7 +13,136 @@ use vercel_runtime::Error;
1313use vercel_runtime:: axum:: { VercelLayer , stream_response} ;
1414
1515async fn home ( ) -> impl IntoResponse {
16- "Hello from Axum on Vercel"
16+ let html = r#"
17+ <!DOCTYPE html>
18+ <html lang="en">
19+ <head>
20+ <meta charset="UTF-8">
21+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
22+ <title>Vercel Axum</title>
23+ <style>
24+ * {
25+ margin: 0;
26+ padding: 0;
27+ box-sizing: border-box;
28+ }
29+ body {
30+ background-color: #000000;
31+ color: #ffffff;
32+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Inter', sans-serif;
33+ min-height: 100vh;
34+ display: flex;
35+ flex-direction: column;
36+ align-items: center;
37+ justify-content: center;
38+ padding: 2rem;
39+ }
40+ .container {
41+ width: 100%;
42+ max-width: 600px;
43+ }
44+ h1 {
45+ font-size: 2.25rem;
46+ font-weight: 500;
47+ margin-bottom: 2rem;
48+ text-align: left;
49+ letter-spacing: -0.025em;
50+ }
51+ button {
52+ background-color: #171717;
53+ color: #ffffff;
54+ border: 1px solid #333333;
55+ padding: 8px 16px;
56+ font-size: 0.875rem;
57+ font-weight: 500;
58+ border-radius: 4px;
59+ cursor: pointer;
60+ transition: all 0.15s ease;
61+ margin-bottom: 1.5rem;
62+ font-family: inherit;
63+ }
64+ button:hover {
65+ background-color: #262626;
66+ border-color: #404040;
67+ }
68+ button:disabled {
69+ background-color: #0a0a0a;
70+ color: #666666;
71+ border-color: #262626;
72+ cursor: not-allowed;
73+ }
74+ #stream-container {
75+ background-color: #0a0a0a;
76+ border: 1px solid #262626;
77+ border-radius: 4px;
78+ padding: 1rem;
79+ margin-top: 1rem;
80+ min-height: 200px;
81+ display: block;
82+ }
83+ #stream-content {
84+ white-space: pre-wrap;
85+ font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
86+ font-size: 0.8rem;
87+ line-height: 1.5;
88+ color: #e5e5e5;
89+ }
90+ .loading {
91+ color: #888888;
92+ font-style: italic;
93+ }
94+ </style>
95+ </head>
96+ <body>
97+ <div class="container">
98+ <h1>Vercel Axum <a href="https://github.com/vercel/examples/tree/main/rust/axum" style="color: #60a5fa; text-decoration: none; font-size: 0.875rem; margin-left: 1rem;">View on GitHub</a></h1>
99+ <button id="stream-btn">Start streaming</button>
100+ <div id="stream-container">
101+ <div id="stream-content"></div>
102+ </div>
103+ </div>
104+ <script>
105+ const streamBtn = document.getElementById('stream-btn');
106+ const streamContainer = document.getElementById('stream-container');
107+ const streamContent = document.getElementById('stream-content');
108+ let isStreaming = false;
109+ streamBtn.addEventListener('click', async () => {
110+ if (isStreaming) return;
111+ isStreaming = true;
112+ streamBtn.textContent = 'Streaming...';
113+ streamBtn.disabled = true;
114+ streamContent.innerHTML = '';
115+ streamContent.className = 'loading';
116+ streamContent.textContent = 'Starting stream...';
117+ try {
118+ const response = await fetch('/stream');
119+ const reader = response.body.getReader();
120+ const decoder = new TextDecoder();
121+ let firstChunk = true;
122+ while (true) {
123+ const { done, value } = await reader.read();
124+ if (done) break;
125+ const chunk = decoder.decode(value);
126+ if (firstChunk) {
127+ streamContent.className = '';
128+ streamContent.textContent = '';
129+ firstChunk = false;
130+ }
131+ streamContent.textContent += chunk;
132+ }
133+ } catch (error) {
134+ streamContent.textContent = 'Error: ' + error.message;
135+ } finally {
136+ isStreaming = false;
137+ streamBtn.textContent = 'Start streaming';
138+ streamBtn.disabled = false;
139+ }
140+ });
141+ </script>
142+ </body>
143+ </html>"# ;
144+
145+ Html ( html)
17146}
18147
19148async fn stream_example ( ) -> impl IntoResponse {
0 commit comments