diff --git a/frontend/app/globals.css b/frontend/app/globals.css
index a2868cf4..d5389cba 100644
--- a/frontend/app/globals.css
+++ b/frontend/app/globals.css
@@ -348,8 +348,9 @@
/* Gradient Page Backgrounds - Enhanced visibility */
.gradient-page-bg {
- background: linear-gradient(135deg,
- rgba(102, 126, 234, 0.12) 0%,
+ background: linear-gradient(
+ 135deg,
+ rgba(102, 126, 234, 0.12) 0%,
rgba(240, 242, 255, 0.8) 25%,
rgba(255, 240, 245, 0.8) 50%,
rgba(245, 240, 255, 0.8) 75%,
@@ -359,8 +360,9 @@
}
.dark .gradient-page-bg {
- background: linear-gradient(135deg,
- rgba(76, 81, 191, 0.25) 0%,
+ background: linear-gradient(
+ 135deg,
+ rgba(76, 81, 191, 0.25) 0%,
rgba(30, 30, 45, 0.95) 25%,
rgba(40, 30, 45, 0.95) 50%,
rgba(35, 30, 50, 0.95) 75%,
@@ -531,3 +533,183 @@
border-color: rgba(76, 81, 191, 0.5);
box-shadow: 0 10px 40px rgba(76, 81, 191, 0.3);
}
+
+/* ========================================
+ DATE PICKER CUSTOM STYLING
+ ======================================== */
+
+/* Modern Date Input Styling */
+input[type="date"] {
+ position: relative;
+ padding: 0.75rem 1rem;
+ font-size: 1rem;
+ font-weight: 500;
+ line-height: 1.5;
+ color: var(--foreground);
+ background: linear-gradient(
+ 135deg,
+ rgba(102, 126, 234, 0.05) 0%,
+ rgba(118, 75, 162, 0.05) 100%
+ );
+ border: 2px solid rgba(102, 126, 234, 0.3);
+ border-radius: 0.75rem;
+ transition: all 0.3s ease;
+ cursor: pointer;
+ backdrop-filter: blur(10px);
+ -webkit-backdrop-filter: blur(10px);
+}
+
+input[type="date"]:hover {
+ background: linear-gradient(
+ 135deg,
+ rgba(102, 126, 234, 0.1) 0%,
+ rgba(118, 75, 162, 0.1) 100%
+ );
+ border-color: rgba(102, 126, 234, 0.5);
+ box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2);
+ transform: translateY(-2px);
+}
+
+input[type="date"]:focus {
+ outline: none;
+ background: linear-gradient(
+ 135deg,
+ rgba(102, 126, 234, 0.15) 0%,
+ rgba(118, 75, 162, 0.15) 100%
+ );
+ border-color: rgba(102, 126, 234, 0.6);
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1),
+ 0 8px 16px rgba(102, 126, 234, 0.25);
+ transform: translateY(-2px);
+}
+
+/* Dark mode date input */
+.dark input[type="date"] {
+ background: linear-gradient(
+ 135deg,
+ rgba(76, 81, 191, 0.15) 0%,
+ rgba(85, 60, 154, 0.15) 100%
+ );
+ border-color: rgba(76, 81, 191, 0.4);
+}
+
+.dark input[type="date"]:hover {
+ background: linear-gradient(
+ 135deg,
+ rgba(76, 81, 191, 0.2) 0%,
+ rgba(85, 60, 154, 0.2) 100%
+ );
+ border-color: rgba(76, 81, 191, 0.6);
+ box-shadow: 0 4px 12px rgba(76, 81, 191, 0.3);
+}
+
+.dark input[type="date"]:focus {
+ background: linear-gradient(
+ 135deg,
+ rgba(76, 81, 191, 0.25) 0%,
+ rgba(85, 60, 154, 0.25) 100%
+ );
+ border-color: rgba(76, 81, 191, 0.7);
+ box-shadow: 0 0 0 3px rgba(76, 81, 191, 0.15),
+ 0 8px 16px rgba(76, 81, 191, 0.35);
+}
+
+/* Calendar icon styling */
+input[type="date"]::-webkit-calendar-picker-indicator {
+ cursor: pointer;
+ opacity: 0.8;
+ padding: 0.25rem;
+ border-radius: 0.375rem;
+ transition: all 0.2s ease;
+ filter: brightness(0.9);
+}
+
+input[type="date"]::-webkit-calendar-picker-indicator:hover {
+ opacity: 1;
+ background: rgba(102, 126, 234, 0.15);
+ transform: scale(1.1);
+ filter: brightness(1.1);
+}
+
+.dark input[type="date"]::-webkit-calendar-picker-indicator {
+ filter: invert(1) brightness(0.9);
+}
+
+.dark input[type="date"]::-webkit-calendar-picker-indicator:hover {
+ background: rgba(76, 81, 191, 0.25);
+ filter: invert(1) brightness(1.1);
+}
+
+/* Date input inner elements (webkit) */
+input[type="date"]::-webkit-datetime-edit-fields-wrapper {
+ padding: 0;
+}
+
+input[type="date"]::-webkit-datetime-edit-text {
+ padding: 0 0.25rem;
+ opacity: 0.7;
+}
+
+input[type="date"]::-webkit-datetime-edit-month-field,
+input[type="date"]::-webkit-datetime-edit-day-field,
+input[type="date"]::-webkit-datetime-edit-year-field {
+ padding: 0.25rem 0.5rem;
+ border-radius: 0.375rem;
+ transition: all 0.2s ease;
+}
+
+input[type="date"]::-webkit-datetime-edit-month-field:hover,
+input[type="date"]::-webkit-datetime-edit-day-field:hover,
+input[type="date"]::-webkit-datetime-edit-year-field:hover {
+ background: rgba(102, 126, 234, 0.2);
+ color: var(--foreground);
+}
+
+input[type="date"]::-webkit-datetime-edit-month-field:focus,
+input[type="date"]::-webkit-datetime-edit-day-field:focus,
+input[type="date"]::-webkit-datetime-edit-year-field:focus {
+ background: rgba(102, 126, 234, 0.25);
+ color: var(--foreground);
+ outline: none;
+}
+
+.dark input[type="date"]::-webkit-datetime-edit-month-field:hover,
+.dark input[type="date"]::-webkit-datetime-edit-day-field:hover,
+.dark input[type="date"]::-webkit-datetime-edit-year-field:hover {
+ background: rgba(76, 81, 191, 0.3);
+}
+
+.dark input[type="date"]::-webkit-datetime-edit-month-field:focus,
+.dark input[type="date"]::-webkit-datetime-edit-day-field:focus,
+.dark input[type="date"]::-webkit-datetime-edit-year-field:focus {
+ background: rgba(76, 81, 191, 0.35);
+}
+
+/* Placeholder styling when empty */
+input[type="date"]:invalid::-webkit-datetime-edit {
+ color: var(--muted-foreground);
+}
+
+/* Animation for date picker open */
+@keyframes datePickerSlide {
+ from {
+ opacity: 0;
+ transform: translateY(-10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+/* Additional polish */
+input[type="date"]::before {
+ content: attr(placeholder);
+ width: 100%;
+ color: var(--muted-foreground);
+}
+
+input[type="date"]:focus::before,
+input[type="date"]:valid::before {
+ display: none;
+}
diff --git a/frontend/components/analysis/AnalysisForm.tsx b/frontend/components/analysis/AnalysisForm.tsx
index 95493e3f..c4dda477 100644
--- a/frontend/components/analysis/AnalysisForm.tsx
+++ b/frontend/components/analysis/AnalysisForm.tsx
@@ -58,14 +58,14 @@ const formSchema = z.object({
.url("請輸入有效的 URL")
.optional()
.or(z.literal("")),
- quick_think_api_key: z.string().optional().or(z.literal("")),
- deep_think_api_key: z.string().optional().or(z.literal("")),
+ quick_think_api_key: z.string().min(1, "請輸入快速思維模型 API Key"),
+ deep_think_api_key: z.string().min(1, "請輸入深層思維模型 API Key"),
embedding_base_url: z
.string()
.url("請輸入有效的 URL")
.optional()
.or(z.literal("")),
- embedding_api_key: z.string().optional().or(z.literal("")),
+ embedding_api_key: z.string().min(1, "請輸入嵌入模型 API Key"),
alpha_vantage_api_key: z.string().min(1, "請輸入 Alpha Vantage API Key"),
});
@@ -586,12 +586,12 @@ export function AnalysisForm({ onSubmit, loading = false }: AnalysisFormProps) {
name="quick_think_api_key"
render={({ field }) => (
- 快速思維模型 API Key
+ 快速思維模型 API Key *
- 該模型的專屬 API Key(若留空則使用預設/環境變數)
+ 該模型的專屬 API Key(必填)
@@ -685,12 +685,12 @@ export function AnalysisForm({ onSubmit, loading = false }: AnalysisFormProps) {
name="deep_think_api_key"
render={({ field }) => (
- 深層思維模型 API Key
+ 深層思維模型 API Key *
- 該模型的專屬 API Key(若留空則使用預設/環境變數)
+ 該模型的專屬 API Key(必填)
@@ -756,13 +756,11 @@ export function AnalysisForm({ onSubmit, loading = false }: AnalysisFormProps) {
name="embedding_api_key"
render={({ field }) => (
- 嵌入模型 API Key
+ 嵌入模型 API Key *
-
- 該端點的 API Key(若留空則使用環境變數 OPENAI_API_KEY)
-
+ 該端點的 API Key(必填)
)}