diff --git a/frontend/index.html b/frontend/index.html
index f6bc449..b87e23f 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -7,8 +7,8 @@
-
-
MiroFish Offline - Predict Everything
+
+ The Pin Factory - Predict Everything
diff --git a/frontend/public/home-styles.css b/frontend/public/home-styles.css
index c1590c1..4096a11 100644
--- a/frontend/public/home-styles.css
+++ b/frontend/public/home-styles.css
@@ -80,7 +80,7 @@
}
.orange-tag {
- background: #FF4500;
+ background: #5BA4F5;
color: #FFFFFF;
padding: 4px 10px;
font-weight: 700;
@@ -104,7 +104,7 @@
}
.gradient-text {
- background: linear-gradient(90deg, #000000 0%, #444444 100%);
+ background: linear-gradient(90deg, #1565C0 0%, #5BA4F5 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
display: inline-block;
@@ -130,7 +130,7 @@
}
.highlight-orange {
- color: #FF4500;
+ color: #5BA4F5;
font-weight: 700;
font-family: 'JetBrains Mono', monospace;
}
@@ -150,13 +150,13 @@
font-weight: 520;
color: #000000;
letter-spacing: 1px;
- border-left: 3px solid #FF4500;
+ border-left: 3px solid #5BA4F5;
padding-left: 15px;
margin-top: 20px;
}
.blinking-cursor {
- color: #FF4500;
+ color: #5BA4F5;
animation: blink 1s step-end infinite;
font-weight: 700;
}
@@ -169,7 +169,7 @@
.decoration-square {
width: 16px;
height: 16px;
- background: #FF4500;
+ background: #5BA4F5;
}
.hero-right {
@@ -201,13 +201,13 @@
align-items: center;
justify-content: center;
cursor: pointer;
- color: #FF4500;
+ color: #5BA4F5;
font-size: 1.2rem;
transition: all 0.2s;
}
.scroll-down-btn:hover {
- border-color: #FF4500;
+ border-color: #5BA4F5;
}
/* Dashboard Two-Column Layout */
@@ -241,7 +241,7 @@
}
.status-dot {
- color: #FF4500;
+ color: #5BA4F5;
font-size: 0.8rem;
}
@@ -520,8 +520,8 @@
}
.start-engine-btn:hover:not(:disabled) {
- background: #FF4500;
- border-color: #FF4500;
+ background: #5BA4F5;
+ border-color: #5BA4F5;
transform: translateY(-2px);
}
@@ -539,9 +539,9 @@
/* Pulse animation for border */
@keyframes pulse-border {
- 0% { box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.2); }
- 70% { box-shadow: 0 0 0 6px rgba(0, 0, 0, 0); }
- 100% { box-shadow: 0 0 0 0 rgba(0, 0, 0, 0); }
+ 0% { box-shadow: 0 0 0 0 rgba(91, 164, 245, 0.4); }
+ 70% { box-shadow: 0 0 0 6px rgba(91, 164, 245, 0); }
+ 100% { box-shadow: 0 0 0 0 rgba(91, 164, 245, 0); }
}
/* Responsive */
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index 702be81..2df1814 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -122,7 +122,7 @@ button {
}
.orange-tag {
- background: #FF4500;
+ background: #5BA4F5;
color: #FFFFFF;
padding: 4px 10px;
font-weight: 700;
@@ -146,7 +146,7 @@ button {
}
.gradient-text {
- background: linear-gradient(90deg, #000000 0%, #444444 100%);
+ background: linear-gradient(90deg, #1565C0 0%, #5BA4F5 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
display: inline-block;
@@ -172,7 +172,7 @@ button {
}
.highlight-orange {
- color: #FF4500;
+ color: #5BA4F5;
font-weight: 700;
font-family: 'JetBrains Mono', monospace;
}
@@ -192,13 +192,13 @@ button {
font-weight: 520;
color: #000000;
letter-spacing: 1px;
- border-left: 3px solid #FF4500;
+ border-left: 3px solid #5BA4F5;
padding-left: 15px;
margin-top: 20px;
}
.blinking-cursor {
- color: #FF4500;
+ color: #5BA4F5;
animation: blink 1s step-end infinite;
font-weight: 700;
}
@@ -211,7 +211,7 @@ button {
.decoration-square {
width: 16px;
height: 16px;
- background: #FF4500;
+ background: #5BA4F5;
}
.hero-right {
@@ -243,13 +243,13 @@ button {
align-items: center;
justify-content: center;
cursor: pointer;
- color: #FF4500;
+ color: #5BA4F5;
font-size: 1.2rem;
transition: all 0.2s;
}
.scroll-down-btn:hover {
- border-color: #FF4500;
+ border-color: #5BA4F5;
}
.dashboard-section {
@@ -281,7 +281,7 @@ button {
}
.status-dot {
- color: #FF4500;
+ color: #5BA4F5;
font-size: 0.8rem;
}
@@ -557,8 +557,8 @@ button {
}
.start-engine-btn:hover:not(:disabled) {
- background: #FF4500;
- border-color: #FF4500;
+ background: #5BA4F5;
+ border-color: #5BA4F5;
transform: translateY(-2px);
}
@@ -575,9 +575,9 @@ button {
}
@keyframes pulse-border {
- 0% { box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.2); }
- 70% { box-shadow: 0 0 0 6px rgba(0, 0, 0, 0); }
- 100% { box-shadow: 0 0 0 0 rgba(0, 0, 0, 0); }
+ 0% { box-shadow: 0 0 0 0 rgba(91, 164, 245, 0.4); }
+ 70% { box-shadow: 0 0 0 6px rgba(91, 164, 245, 0); }
+ 100% { box-shadow: 0 0 0 0 rgba(91, 164, 245, 0); }
}
@media (max-width: 1024px) {
diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js
index fe51e53..4baa13c 100644
--- a/frontend/src/api/index.js
+++ b/frontend/src/api/index.js
@@ -33,9 +33,11 @@ service.interceptors.response.use(
return res
},
- error => {
+ async error => {
console.error('Response error:', error)
+ const config = error.config
+
// Handle timeout
if (error.code === 'ECONNABORTED' && error.message.includes('timeout')) {
console.error('Request timeout')
@@ -46,6 +48,25 @@ service.interceptors.response.use(
console.error('Network error - please check your connection')
}
+ // Retry logic for transient failures (network errors, timeouts, 5xx server errors)
+ if (config) {
+ config.__retryCount = config.__retryCount || 0
+ const maxRetries = config.__maxRetries !== undefined ? config.__maxRetries : 3
+ const retryDelay = config.__retryDelay || 1000
+
+ const isTimeout = error.code === 'ECONNABORTED' && error.message.includes('timeout')
+ const isNetworkError = error.message === 'Network Error'
+ const isServerError = error.response && error.response.status >= 500
+
+ if ((isTimeout || isNetworkError || isServerError) && config.__retryCount < maxRetries) {
+ config.__retryCount += 1
+ const delay = retryDelay * Math.pow(2, config.__retryCount - 1)
+ console.warn(`Request failed, retrying (${config.__retryCount}/${maxRetries}) after ${delay}ms...`)
+ await new Promise(resolve => setTimeout(resolve, delay))
+ return service(config)
+ }
+ }
+
return Promise.reject(error)
}
)
diff --git a/frontend/src/components/Step2EnvSetup.vue b/frontend/src/components/Step2EnvSetup.vue
index 67a4f1d..66cc7ff 100644
--- a/frontend/src/components/Step2EnvSetup.vue
+++ b/frontend/src/components/Step2EnvSetup.vue
@@ -440,7 +440,7 @@