diff --git a/src/css/channel/animations.css b/src/css/channel/animations.css index a0ba1a3..aaedf46 100644 --- a/src/css/channel/animations.css +++ b/src/css/channel/animations.css @@ -36,3 +36,254 @@ align-self: center; flex-shrink: 0; } + +.thread-panel, +.pin-panel { + width: min(380px, 42vw); + min-width: 320px; + height: 100%; + display: flex; + flex-direction: column; + flex-shrink: 0; + background: + linear-gradient(180deg, color-mix(in oklch, var(--surface-elevated) 92%, var(--accent-bg)), var(--surface-ground) 180px), + var(--surface-ground); + border-left: 1px solid var(--border-subtle); + box-shadow: -12px 0 24px oklch(0 0 0 / 6%); +} + +.thread-panel-header, +.pin-panel-header { + min-height: 52px; + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 0 14px 0 16px; + border-bottom: 1px solid var(--border-subtle); + background: color-mix(in oklch, var(--surface-elevated) 88%, transparent); + backdrop-filter: blur(10px); +} + +.thread-panel-title, +.pin-panel-title { + min-width: 0; + display: flex; + align-items: center; + gap: 8px; +} + +.thread-preview-text { + max-width: 180px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.thread-close-btn { + width: 30px; + height: 30px; + display: inline-flex; + align-items: center; + justify-content: center; + border: 1px solid transparent; + border-radius: 8px; + background: transparent; + color: var(--text-muted); + cursor: pointer; + transition: background 120ms ease, border-color 120ms ease, color 120ms ease; +} + +.thread-close-btn:hover { + background: var(--hover-bg); + border-color: var(--border-subtle); + color: var(--text-primary); +} + +.thread-messages, +.pin-list { + flex: 1; + min-height: 0; + overflow-y: auto; + padding: 12px; +} + +.thread-message { + display: flex; + gap: 10px; + padding: 10px; + border: 1px solid transparent; + border-radius: 12px; + transition: background 120ms ease, border-color 120ms ease; +} + +.thread-message:hover { + background: var(--hover-bg); + border-color: var(--border-subtle); +} + +.thread-list-item { + display: flex; + width: 100%; + flex-direction: column; + gap: 5px; + padding: 12px; + border: 1px solid var(--border-subtle); + border-radius: 14px; + background: color-mix(in oklch, var(--surface-elevated) 94%, var(--accent-bg)); + color: var(--text-primary); + text-align: left; + cursor: pointer; + transition: transform 120ms ease, border-color 120ms ease, background 120ms ease; +} + +.thread-list-item:hover:not(:disabled) { + transform: translateY(-1px); + border-color: var(--border-default); + background: var(--surface-elevated); +} + +.thread-list-item:disabled { + cursor: default; + opacity: 0.75; +} + +.thread-message-content { + min-width: 0; + flex: 1; +} + +.thread-message-header { + display: flex; + align-items: baseline; + gap: 8px; + margin-bottom: 2px; +} + +.thread-typing { + padding: 0 14px 8px; +} + +.thread-input-area { + position: relative; + display: flex; + align-items: flex-end; + gap: 8px; + padding: 12px; + border-top: 1px solid var(--border-subtle); + background: color-mix(in oklch, var(--surface-elevated) 86%, transparent); +} + +.thread-input { + min-height: 38px; + max-height: 120px; + flex: 1; + resize: none; + outline: none; + border: 1px solid var(--border-default); + border-radius: 12px; + padding: 9px 11px; + background: var(--input-bg); + color: var(--text-primary); + font-size: 13px; + line-height: 1.45; +} + +.thread-input:focus { + border-color: var(--input-ring); + box-shadow: 0 0 0 3px color-mix(in oklch, var(--input-ring) 18%, transparent); +} + +.thread-reaction-btn, +.thread-send-btn { + width: 38px; + height: 38px; + display: inline-flex; + align-items: center; + justify-content: center; + border: 1px solid var(--border-default); + border-radius: 12px; + background: var(--surface-ground); + color: var(--text-secondary); + cursor: pointer; +} + +.thread-send-btn { + background: var(--accent); + border-color: var(--accent); + color: var(--accent-fg); +} + +.thread-send-btn:disabled { + opacity: 0.45; + cursor: not-allowed; +} + +.thread-emoji-row { + position: absolute; + left: 12px; + bottom: 58px; + display: flex; + gap: 4px; + padding: 6px; + border: 1px solid var(--border-subtle); + border-radius: 12px; + background: var(--surface-overlay); + box-shadow: 0 10px 30px oklch(0 0 0 / 12%); +} + +.emoji-quick-btn { + border: 0; + border-radius: 8px; + padding: 4px 6px; + background: transparent; + cursor: pointer; + font-size: 16px; +} + +.emoji-quick-btn:hover { + background: var(--hover-bg); +} + +.pin-list { + display: flex; + flex-direction: column; + gap: 10px; +} + +.pin-item { + display: flex; + width: 100%; + padding: 12px; + border: 1px solid var(--border-subtle); + border-radius: 14px; + background: color-mix(in oklch, var(--surface-elevated) 94%, var(--accent-bg)); + box-shadow: 0 1px 0 oklch(1 0 0 / 35%) inset; + transition: transform 120ms ease, border-color 120ms ease, background 120ms ease; +} + +.pin-item:hover { + transform: translateY(-1px); + border-color: var(--border-default); + background: var(--surface-elevated); +} + +.pin-empty { + min-height: 160px; + display: flex; + align-items: center; + justify-content: center; + text-align: center; +} + +@media (max-width: 860px) { + .thread-panel, + .pin-panel { + position: absolute; + inset: 0 0 0 auto; + z-index: 30; + width: min(100%, 420px); + min-width: 0; + box-shadow: -18px 0 40px oklch(0 0 0 / 18%); + } +} diff --git a/vite.config.ts b/vite.config.ts index dccd397..2a9d670 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -20,43 +20,6 @@ export default defineConfig({ optimizeDeps: { entries: ["src/**/*.{ts,tsx}"], }, - build: { - rollupOptions: { - output: { - manualChunks(id: string) { - if (id.includes("node_modules")) { - // React + deps that import React — keep together to avoid circular deps - if (id.includes("react-dom") || id.includes("react-router-dom") || id.includes("scheduler") || id.includes("@tanstack/react-query")) { - return "vendor-react"; - } - if (id.includes("react-markdown") || id.includes("remark-gfm") || id.includes("rehype-raw") || id.includes("rehype-sanitize")) { - return "vendor-markdown"; - } - if (id.includes("lucide-react")) { - return "vendor-lucide"; - } - if (id.includes("motion")) { - return "vendor-motion"; - } - if (id.includes("recharts")) { - return "vendor-recharts"; - } - // Streamdown + diagram deps — keep together to avoid circular deps - if (id.includes("streamdown") || id.includes("@streamdown") || id.includes("cytoscape") || id.includes("d3-") || id.includes("dagre")) { - return "vendor-streamdown"; - } - if (id.includes("@tanstack/react-table")) { - return "vendor-table"; - } - if (id.includes("radix-ui")) { - return "vendor-radix"; - } - } - }, - }, - }, - chunkSizeWarningLimit: 400, - }, resolve: { alias: { "@": path.resolve(__dirname, "./src"),