diff --git a/.github/example.png b/.github/example.png deleted file mode 100644 index d90795b..0000000 Binary files a/.github/example.png and /dev/null differ diff --git a/ChatGPT_UI_Ideas/c1.webp b/ChatGPT_UI_Ideas/c1.webp deleted file mode 100644 index f680976..0000000 Binary files a/ChatGPT_UI_Ideas/c1.webp and /dev/null differ diff --git a/ChatGPT_UI_Ideas/c2.webp b/ChatGPT_UI_Ideas/c2.webp deleted file mode 100644 index f325bee..0000000 Binary files a/ChatGPT_UI_Ideas/c2.webp and /dev/null differ diff --git a/ChatGPT_UI_Ideas/c3.webp b/ChatGPT_UI_Ideas/c3.webp deleted file mode 100644 index a6fc545..0000000 Binary files a/ChatGPT_UI_Ideas/c3.webp and /dev/null differ diff --git a/client/index.css b/client/index.css index 2075cdb..db3cdea 100644 --- a/client/index.css +++ b/client/index.css @@ -1,183 +1,612 @@ -@import "tailwindcss"; +@import 'tailwindcss'; + +/* ============================================================================ + EchoAI · "Midnight Indigo" — premium SaaS workspace + Slate/graphite surfaces · one electric-indigo accent · crisp 14px geometry + Dark-first, with a premium light variant (.theme-light) + ========================================================================== */ + +:root { + /* Dark (default) */ + --bg: #0b0d12; + --bg-2: #090a0e; + --panel: #14171f; + --surface: #14171f; + --surface-2: #1a1e28; + --surface-3: #232834; + --border: rgba(255, 255, 255, 0.07); + --border-strong: rgba(255, 255, 255, 0.13); + + --text: #e6e9ef; + --text-dim: #99a0b2; + --text-faint: rgba(230, 233, 239, 0.42); + + --accent: #6366f1; + --accent-2: #818cf8; + --accent-ink: #aab2fc; + --accent-soft: rgba(99, 102, 241, 0.16); + --accent-ring: rgba(99, 102, 241, 0.5); + --on-accent: #ffffff; + + /* orb pastels — indigo marble */ + --p1: #818cf8; + --p2: #a5b4fc; + --p3: #38bdf8; + --p4: #c4b5fd; + + --danger: #f0708a; + --danger-soft: rgba(240, 112, 138, 0.16); + + --r-xl: 18px; + --r-lg: 16px; + --r-md: 14px; + --r-sm: 10px; + + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4); + --shadow-md: 0 10px 34px -14px rgba(0, 0, 0, 0.66); + --shadow-lg: 0 30px 70px -30px rgba(0, 0, 0, 0.85); + + --font-display: 'Fraunces', Georgia, 'Times New Roman', serif; + --font-body: 'Plus Jakarta Sans', ui-sans-serif, system-ui, sans-serif; + + color-scheme: dark; +} + +/* Premium light variant */ +.theme-light { + --bg: #ffffff; + --bg-2: #f7f8fa; + --panel: #f7f8fa; + --surface: #ffffff; + --surface-2: #f4f5f8; + --surface-3: #eceef3; + --border: rgba(11, 13, 18, 0.08); + --border-strong: rgba(11, 13, 18, 0.14); + + --text: #0b0d12; + --text-dim: #5b6170; + --text-faint: rgba(11, 13, 18, 0.4); + + --accent: #6366f1; + --accent-2: #4f46e5; + --accent-ink: #4f46e5; + --accent-soft: rgba(99, 102, 241, 0.1); + --accent-ring: rgba(99, 102, 241, 0.32); + --on-accent: #ffffff; + + --danger: #dc5670; + --danger-soft: rgba(220, 86, 112, 0.1); + + --shadow-sm: 0 1px 2px rgba(11, 13, 18, 0.05), 0 2px 8px rgba(11, 13, 18, 0.04); + --shadow-md: 0 10px 32px -14px rgba(11, 13, 18, 0.18); + --shadow-lg: 0 30px 64px -30px rgba(11, 13, 18, 0.24); + + color-scheme: light; +} * { box-sizing: border-box; - scroll-behavior: smooth; } -html, body { +html, +body { height: 100%; margin: 0; padding: 0; overflow-x: hidden; } +html { + scroll-behavior: smooth; +} + +body { + background: var(--bg); + color: var(--text); + font-family: var(--font-body); + font-size: 15px; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; +} + #root { height: 100%; min-height: 100vh; } -/* Custom scrollbar */ -::-webkit-scrollbar { - width: 6px; +::selection { + background: var(--accent-soft); + color: var(--text); } -::-webkit-scrollbar-track { - background: transparent; +.font-display { + font-family: var(--font-display); + font-optical-sizing: auto; + letter-spacing: -0.01em; } -::-webkit-scrollbar-thumb { - background: rgba(255, 255, 255, 0.2); - border-radius: 3px; +/* ---------------------------------------------------------------------------- + Ambient background — a single soft indigo glow + -------------------------------------------------------------------------- */ +.aura { + position: fixed; + inset: 0; + z-index: 0; + background: + radial-gradient(50% 34% at 62% 4%, var(--accent-soft), transparent 62%), + radial-gradient(70% 50% at 85% -12%, var(--accent-soft), transparent 70%), + var(--bg); } -::-webkit-scrollbar-thumb:hover { - background: rgba(255, 255, 255, 0.3); +/* ---------------------------------------------------------------------------- + THE ORB — soft indigo glass marble + -------------------------------------------------------------------------- */ +.orb { + position: relative; + width: var(--orb-size, 116px); + height: var(--orb-size, 116px); + flex: 0 0 auto; } - -/* Light mode scrollbar */ -.light-mode ::-webkit-scrollbar-thumb { - background: rgba(0, 0, 0, 0.2); +.orb__halo { + position: absolute; + inset: -26%; + border-radius: 50%; + background: conic-gradient(from 200deg, var(--p1), var(--p2), var(--p3), var(--p4), var(--p1)); + filter: blur(30px); + opacity: 0.5; + animation: halo 16s ease-in-out infinite; } - -.light-mode ::-webkit-scrollbar-thumb:hover { - background: rgba(0, 0, 0, 0.3); +.orb__ball { + position: absolute; + inset: 0; + border-radius: 50%; + background: + radial-gradient(circle at 34% 28%, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0) 42%), + linear-gradient(145deg, var(--p1) 0%, var(--p2) 40%, var(--p3) 74%, var(--p4) 100%); + box-shadow: + inset 0 -8px 22px rgba(56, 50, 120, 0.4), + inset 0 8px 16px rgba(255, 255, 255, 0.4), + var(--shadow-md); } - -/* Smooth animations */ -@keyframes fadeInUp { - from { - opacity: 0; - transform: translateY(20px); - } - to { - opacity: 1; - transform: translateY(0); - } +.orb__sheen { + position: absolute; + top: 13%; + left: 19%; + width: 32%; + height: 21%; + border-radius: 50%; + background: radial-gradient(circle, rgba(255, 255, 255, 0.92), transparent 70%); + filter: blur(2px); } +.orb--breathe { animation: breathe 7s ease-in-out infinite; } +.orb--thinking .orb__halo { opacity: 0.8; animation-duration: 6s; } +.orb--thinking { animation: breathe 2.8s ease-in-out infinite; } +.orb--sm { --orb-size: 28px; } +.orb--sm .orb__halo { filter: blur(8px); inset: -18%; } -@keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } +@keyframes halo { + 0%, 100% { transform: rotate(0deg) scale(1); } + 50% { transform: rotate(40deg) scale(1.08); } } - -@keyframes pulse { - 0%, 100% { - opacity: 1; - } - 50% { - opacity: 0.5; - } +@keyframes breathe { + 0%, 100% { transform: scale(1); } + 50% { transform: scale(1.035); } } -@keyframes bounce { - 0%, 20%, 53%, 80%, 100% { - transform: translate3d(0, 0, 0); - } - 40%, 43% { - transform: translate3d(0, -8px, 0); - } - 70% { - transform: translate3d(0, -4px, 0); - } - 90% { - transform: translate3d(0, -2px, 0); - } +/* ---------------------------------------------------------------------------- + Workspace shell — sidebar + -------------------------------------------------------------------------- */ +.sidebar { + display: flex; + flex-direction: column; + width: 274px; + flex: 0 0 274px; + height: 100%; + background: var(--panel); + border-right: 1px solid var(--border); } -.animate-fadeInUp { - animation: fadeInUp 0.6s ease-out; +.scrim { + position: fixed; + inset: 0; + z-index: 30; + background: rgba(4, 5, 8, 0.55); + backdrop-filter: blur(2px); } -.animate-fadeIn { - animation: fadeIn 0.4s ease-out; +.nav-item { + position: relative; + display: flex; + align-items: center; + gap: 10px; + width: 100%; + padding: 9px 11px; + border-radius: var(--r-sm); + color: var(--text-dim); + cursor: pointer; + border: 1px solid transparent; + transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease; +} +.nav-item:hover { + background: var(--surface-2); + color: var(--text); +} +.nav-item--active { + background: var(--accent-soft); + color: var(--text); + border-color: var(--accent-ring); +} +.nav-item__title { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 13.5px; + font-weight: 500; +} +.nav-actions { + display: flex; + align-items: center; + gap: 2px; + opacity: 0; + transition: opacity 0.2s ease; } +.nav-item:hover .nav-actions, +.nav-item--active .nav-actions { opacity: 1; } +.nav-action { + display: grid; + place-items: center; + width: 26px; + height: 26px; + border-radius: 8px; + color: var(--text-faint); + transition: background 0.18s ease, color 0.18s ease; +} +.nav-action:hover { background: var(--surface-3); color: var(--text); } +.nav-action--danger:hover { color: var(--danger); } -.animate-pulse-slow { - animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; +.nav-edit { + flex: 1; + min-width: 0; + background: var(--bg); + border: 1px solid var(--accent-ring); + border-radius: 8px; + padding: 4px 8px; + color: var(--text); + font-family: var(--font-body); + font-size: 13.5px; + outline: none; } -.animate-bounce-slow { - animation: bounce 2s infinite; +.profile-row { + display: flex; + align-items: center; + gap: 10px; + padding: 9px; + border-radius: var(--r-md); + background: var(--surface); + border: 1px solid var(--border); +} +.avatar { + display: grid; + place-items: center; + width: 34px; + height: 34px; + flex: 0 0 auto; + border-radius: 50%; + color: var(--on-accent); + font-size: 13px; + font-weight: 700; + background: linear-gradient(140deg, var(--accent), var(--accent-2)); } -/* Glass morphism effect */ -.glass { - background: rgba(255, 255, 255, 0.1); - backdrop-filter: blur(10px); - border: 1px solid rgba(255, 255, 255, 0.2); +/* ---------------------------------------------------------------------------- + Buttons & chips + -------------------------------------------------------------------------- */ +.icon-btn { + display: inline-grid; + place-items: center; + width: 38px; + height: 38px; + border-radius: 10px; + color: var(--text-dim); + background: var(--surface); + border: 1px solid var(--border); + transition: all 0.22s ease; + cursor: pointer; } +.icon-btn:hover { + color: var(--text); + border-color: var(--border-strong); + background: var(--surface-2); +} +.icon-btn:active { transform: scale(0.95); } -.glass-dark { - background: rgba(0, 0, 0, 0.1); - backdrop-filter: blur(10px); - border: 1px solid rgba(255, 255, 255, 0.1); +.chip { + display: inline-flex; + align-items: center; + gap: 7px; + padding: 6px 12px; + border-radius: 999px; + font-size: 12px; + font-weight: 500; + color: var(--accent-ink); + background: var(--accent-soft); + border: 1px solid var(--accent-ring); +} +.chip__dot { + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--accent-2); + animation: live 2.6s ease-in-out infinite; +} +@keyframes live { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.4; } } -/* Gradient text */ -.gradient-text { - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; +.btn-accent { + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: var(--r-md); + color: var(--on-accent); + background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%); + border: none; + font-family: var(--font-body); + font-weight: 600; + font-size: 14px; + cursor: pointer; + box-shadow: 0 10px 26px -12px var(--accent-ring); + transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease; +} +.btn-accent:hover:not(:disabled) { + filter: brightness(1.08) saturate(1.04); + transform: translateY(-1px); + box-shadow: 0 16px 32px -12px var(--accent-ring); } +.btn-accent:active:not(:disabled) { transform: scale(0.97); } +.btn-accent:disabled { + cursor: not-allowed; + color: var(--text-faint); + background: var(--surface-3); + box-shadow: none; +} +.btn-round { border-radius: 999px; } -/* Custom focus styles */ -.focus-ring:focus { - outline: none; - box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.3); +.btn-soft { + border-radius: var(--r-md); + padding: 12px 18px; + font-weight: 600; + font-size: 14px; + color: var(--text); + background: var(--surface-2); + border: 1px solid var(--border); + transition: all 0.22s ease; + cursor: pointer; } +.btn-soft:hover:not(:disabled) { + border-color: var(--border-strong); + background: var(--surface-3); +} +.btn-soft:disabled { opacity: 0.5; cursor: not-allowed; } -/* Smooth transitions */ -.transition-all { - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +/* ---------------------------------------------------------------------------- + Suggestion cards + -------------------------------------------------------------------------- */ +.suggest-card { + position: relative; + overflow: hidden; + text-align: left; + padding: 18px; + border-radius: var(--r-lg); + background: var(--surface); + border: 1px solid var(--border); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04), var(--shadow-sm); + cursor: pointer; + transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.28s ease, + border-color 0.28s ease; +} +.suggest-card::after { + content: ''; + position: absolute; + inset: 0; + border-radius: inherit; + background: radial-gradient(130% 80% at 50% -10%, var(--accent-soft), transparent 60%); + opacity: 0; + transition: opacity 0.3s ease; + pointer-events: none; + z-index: 0; +} +.suggest-card > * { + position: relative; + z-index: 1; +} +.suggest-card:hover { + transform: translateY(-3px); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06), var(--shadow-md); + border-color: var(--accent-ring); +} +.suggest-card:hover::after { opacity: 1; } +.suggest-card:hover .suggest-card__arrow { transform: translate(3px, -3px); color: var(--accent); } +.suggest-card:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--accent-ring); } +.suggest-card__icon { + display: grid; + place-items: center; + width: 42px; + height: 42px; + border-radius: 12px; + color: var(--accent-ink); + background: linear-gradient(140deg, var(--accent-soft), transparent); + border: 1px solid var(--border); +} +.suggest-card__arrow { + color: var(--text-faint); + transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1), color 0.28s ease; } -/* Hover effects */ -.hover-lift:hover { - transform: translateY(-2px); - box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15); +/* ---------------------------------------------------------------------------- + Chat bubbles + -------------------------------------------------------------------------- */ +.bubble { + max-width: 100%; + padding: 12px 16px; + border-radius: var(--r-lg); + font-size: 15px; + line-height: 1.65; + white-space: pre-wrap; + word-break: break-word; +} +.bubble-user { + color: var(--on-accent); + background: var(--accent); + border-bottom-right-radius: 6px; + box-shadow: 0 10px 24px -16px var(--accent-ring); +} +.bubble-ai { + color: var(--text); + background: var(--surface); + border: 1px solid var(--border); + border-bottom-left-radius: 6px; + box-shadow: var(--shadow-sm); +} +.bubble-error { + color: var(--text); + background: var(--danger-soft); + border: 1px solid var(--danger); + border-bottom-left-radius: 6px; } -/* Typing indicator */ -.typing-indicator { - display: inline-block; +/* ---------------------------------------------------------------------------- + Composer + -------------------------------------------------------------------------- */ +.composer { position: relative; - width: 40px; - height: 20px; + border-radius: var(--r-lg); + background: var(--surface); + border: 1px solid var(--border); + box-shadow: var(--shadow-md); + transition: border-color 0.25s ease, box-shadow 0.25s ease; +} +.composer:focus-within { + border-color: var(--accent-ring); + box-shadow: 0 0 0 3px var(--accent-soft), var(--shadow-md); +} +.composer textarea { + width: 100%; + resize: none; + border: 0; + background: transparent; + outline: none; + color: var(--text); + font-family: var(--font-body); + font-size: 15px; + line-height: 1.6; } +.composer textarea::placeholder { color: var(--text-faint); } -.typing-indicator::before, -.typing-indicator::after { - content: ''; - position: absolute; - top: 0; - left: 0; +/* ---------------------------------------------------------------------------- + Typing indicator + -------------------------------------------------------------------------- */ +.shimmer { + background: linear-gradient(90deg, var(--text-faint) 0%, var(--text) 35%, var(--text-faint) 65%); + background-size: 200% 100%; + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + animation: shimmer 2.6s linear infinite; +} +@keyframes shimmer { + to { background-position: -200% 0; } +} +.dot-3 span { + display: inline-block; width: 6px; height: 6px; + margin: 0 2px; border-radius: 50%; - background: currentColor; - animation: typing 1.4s infinite ease-in-out; + background: var(--accent-2); + animation: dotty 1.4s ease-in-out infinite; +} +.dot-3 span:nth-child(2) { animation-delay: 0.18s; } +.dot-3 span:nth-child(3) { animation-delay: 0.36s; } +@keyframes dotty { + 0%, 70%, 100% { transform: translateY(0); opacity: 0.4; } + 35% { transform: translateY(-6px); opacity: 1; } } -.typing-indicator::after { - left: 8px; - animation-delay: 0.2s; +/* ---------------------------------------------------------------------------- + Modal + form + -------------------------------------------------------------------------- */ +.modal-card { + position: relative; + border-radius: var(--r-xl); + background: var(--surface); + border: 1px solid var(--border); + box-shadow: var(--shadow-lg); +} +.field { + width: 100%; + padding: 12px 44px 12px 14px; + border-radius: var(--r-md); + background: var(--surface-2); + border: 1px solid var(--border); + color: var(--text); + font-family: var(--font-body); + font-size: 14px; + transition: border-color 0.22s ease, box-shadow 0.22s ease; +} +.field::placeholder { color: var(--text-faint); } +.field:focus { + outline: none; + border-color: var(--accent-ring); + box-shadow: 0 0 0 3px var(--accent-soft); +} +.info-panel { + border-radius: var(--r-md); + background: var(--surface-2); + border: 1px solid var(--border); } -.typing-indicator::before { - animation-delay: 0.4s; +/* ---------------------------------------------------------------------------- + Motion + -------------------------------------------------------------------------- */ +@keyframes rise { + from { opacity: 0; transform: translateY(12px); } + to { opacity: 1; transform: translateY(0); } +} +@keyframes fade { + from { opacity: 0; } + to { opacity: 1; } } +.rise { animation: rise 0.6s cubic-bezier(0.22, 1, 0.36, 1) both; } +.fade { animation: fade 0.5s ease both; } +.msg-in { animation: rise 0.45s cubic-bezier(0.22, 1, 0.36, 1) both; } -@keyframes typing { - 0%, 60%, 100% { - transform: translateY(0); - } - 30% { - transform: translateY(-10px); +/* ---------------------------------------------------------------------------- + Scrollbar + -------------------------------------------------------------------------- */ +::-webkit-scrollbar { width: 8px; height: 8px; } +::-webkit-scrollbar-track { background: transparent; } +::-webkit-scrollbar-thumb { + background: var(--border-strong); + border-radius: 999px; + border: 2px solid transparent; + background-clip: padding-box; +} +::-webkit-scrollbar-thumb:hover { background: var(--text-faint); background-clip: padding-box; } + +/* ---------------------------------------------------------------------------- + Reduced motion + -------------------------------------------------------------------------- */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.001ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.001ms !important; } } diff --git a/client/index.html b/client/index.html index 0b03d94..04b361a 100644 --- a/client/index.html +++ b/client/index.html @@ -3,7 +3,18 @@
- + + + + + + + + +