botui/ui/suite/research/research.html

1723 lines
49 KiB
HTML
Raw Normal View History

<link rel="stylesheet" href="research/research.css" />
2025-12-03 18:42:22 -03:00
<!-- Research - AI-Powered Search & Discovery -->
<div class="research-container" id="research-app">
<!-- Sidebar - Sources & Collections -->
<aside class="research-sidebar" id="research-sidebar">
<div class="sidebar-header">
<h2 data-i18n="nav-research">Research</h2>
<button
class="btn-icon"
id="toggle-research-sidebar"
data-i18n-title="action-collapse"
title="Collapse"
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
2025-12-03 18:42:22 -03:00
<polyline points="11 17 6 12 11 7"></polyline>
<polyline points="18 17 13 12 18 7"></polyline>
</svg>
</button>
</div>
<!-- Focus Modes -->
<div class="focus-modes">
<button
class="focus-btn active"
data-focus="all"
data-i18n-title="research-search-all"
title="Search everything"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
2025-12-03 18:42:22 -03:00
<circle cx="12" cy="12" r="10"></circle>
<line x1="2" y1="12" x2="22" y2="12"></line>
<path
d="M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z"
></path>
2025-12-03 18:42:22 -03:00
</svg>
<span data-i18n="label-all">All</span>
2025-12-03 18:42:22 -03:00
</button>
<button
class="focus-btn"
data-focus="academic"
data-i18n-title="research-academic-papers"
title="Academic papers"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
2025-12-03 18:42:22 -03:00
<path d="M2 3h6a4 4 0 014 4v14a3 3 0 00-3-3H2z"></path>
<path d="M22 3h-6a4 4 0 00-4 4v14a3 3 0 013-3h7z"></path>
</svg>
<span data-i18n="research-academic">Academic</span>
2025-12-03 18:42:22 -03:00
</button>
<button
class="focus-btn"
data-focus="code"
data-i18n-title="research-code-docs"
title="Code & documentation"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
2025-12-03 18:42:22 -03:00
<polyline points="16 18 22 12 16 6"></polyline>
<polyline points="8 6 2 12 8 18"></polyline>
</svg>
<span data-i18n="research-code">Code</span>
2025-12-03 18:42:22 -03:00
</button>
<button
class="focus-btn"
data-focus="internal"
data-i18n-title="research-internal-kb"
title="Internal knowledge base"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"
></path>
2025-12-03 18:42:22 -03:00
<polyline points="9 22 9 12 15 12 15 22"></polyline>
</svg>
<span data-i18n="research-internal">Internal</span>
2025-12-03 18:42:22 -03:00
</button>
</div>
<!-- Collections -->
<div class="sidebar-section">
<div class="section-header">
<h3 data-i18n="research-collections">Collections</h3>
<button
class="btn-icon-sm"
data-i18n-title="research-new-collection"
title="New Collection"
hx-post="/api/ui/research/collections/new"
hx-target="#collections-list"
hx-swap="afterbegin"
>
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
2025-12-03 18:42:22 -03:00
<line x1="12" y1="5" x2="12" y2="19"></line>
<line x1="5" y1="12" x2="19" y2="12"></line>
</svg>
</button>
</div>
<div
class="collections-list"
id="collections-list"
hx-get="/api/ui/research/collections"
hx-trigger="load"
hx-swap="innerHTML"
>
2025-12-03 18:42:22 -03:00
<!-- Collections loaded here -->
</div>
</div>
<!-- Recent Searches -->
<div class="sidebar-section">
<h3 data-i18n="research-recent">Recent</h3>
<div
class="recent-list"
id="recent-searches"
hx-get="/api/ui/research/recent"
hx-trigger="load"
hx-swap="innerHTML"
>
2025-12-03 18:42:22 -03:00
<!-- Recent searches loaded here -->
</div>
</div>
<!-- Prompts Library -->
<div class="sidebar-section">
<div class="section-header">
<h3>Prompts</h3>
<button
class="btn-icon-sm"
title="Browse All"
hx-get="/api/ui/research/prompts"
hx-target="#main-results"
>
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
2025-12-03 18:42:22 -03:00
<polyline points="9 18 15 12 9 6"></polyline>
</svg>
</button>
</div>
<div class="prompts-grid">
<button class="prompt-chip" data-prompt="explain">
Explain
</button>
<button class="prompt-chip" data-prompt="compare">
Compare
</button>
<button class="prompt-chip" data-prompt="summarize">
Summarize
</button>
<button class="prompt-chip" data-prompt="analyze">
Analyze
</button>
<button class="prompt-chip" data-prompt="pros-cons">
Pros & Cons
</button>
2025-12-03 18:42:22 -03:00
<button class="prompt-chip" data-prompt="how-to">How to</button>
</div>
</div>
<!-- Sources Categories -->
<div class="sidebar-section">
<h3>Sources</h3>
<div class="sources-categories">
<button class="source-category" data-category="all">
<span class="category-icon">📚</span>
<span class="category-name">All Sources</span>
<span class="category-count" id="count-all">0</span>
</button>
<button class="source-category" data-category="web">
<span class="category-icon">🌐</span>
<span class="category-name">Web</span>
<span class="category-count" id="count-web">0</span>
</button>
<button class="source-category" data-category="docs">
<span class="category-icon">📄</span>
<span class="category-name">Documents</span>
<span class="category-count" id="count-docs">0</span>
</button>
<button class="source-category" data-category="knowledge">
<span class="category-icon">🧠</span>
<span class="category-name">Knowledge Base</span>
<span class="category-count" id="count-kb">0</span>
</button>
</div>
</div>
</aside>
<!-- Main Content -->
<main class="research-main">
<!-- Search Header -->
<div class="search-header">
<form
class="search-form"
id="research-form"
hx-post="/api/ui/research/search"
hx-target="#main-results"
hx-indicator="#search-indicator"
>
2025-12-03 18:42:22 -03:00
<div class="search-input-wrapper">
<svg
class="search-icon"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
2025-12-03 18:42:22 -03:00
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
</svg>
<textarea
name="query"
id="search-input"
placeholder="Ask anything..."
rows="1"
autofocus
></textarea>
<input
type="hidden"
name="focus"
id="focus-mode"
value="all"
/>
<input
type="hidden"
name="pro"
id="pro-mode"
value="false"
/>
2025-12-03 18:42:22 -03:00
</div>
<div class="search-options">
<label class="option-toggle">
<input type="checkbox" id="pro-search-toggle" />
2025-12-03 18:42:22 -03:00
<span class="toggle-label">
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<polygon
points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"
></polygon>
2025-12-03 18:42:22 -03:00
</svg>
Pro Search
</span>
</label>
<label class="option-toggle">
<input type="checkbox" id="include-images-toggle" />
2025-12-03 18:42:22 -03:00
<span class="toggle-label">
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<rect
x="3"
y="3"
width="18"
height="18"
rx="2"
ry="2"
></rect>
2025-12-03 18:42:22 -03:00
<circle cx="8.5" cy="8.5" r="1.5"></circle>
<polyline points="21 15 16 10 5 21"></polyline>
</svg>
Images
</span>
</label>
<button type="submit" class="search-btn">
<span>Search</span>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
2025-12-03 18:42:22 -03:00
<line x1="5" y1="12" x2="19" y2="12"></line>
<polyline points="12 5 19 12 12 19"></polyline>
</svg>
</button>
</div>
</form>
<!-- Search Indicator -->
<div class="search-indicator htmx-indicator" id="search-indicator">
<div class="indicator-dots">
<span></span><span></span><span></span>
</div>
<span class="indicator-text">Searching sources...</span>
</div>
</div>
<!-- Suggestions (shown when no search) -->
<div class="suggestions-panel" id="suggestions-panel">
<h3>Try asking about</h3>
<div class="suggestion-cards">
<button
class="suggestion-card"
data-query="What are the latest developments in AI?"
>
2025-12-03 18:42:22 -03:00
<span class="suggestion-icon">🤖</span>
<span class="suggestion-text">Latest AI developments</span>
</button>
<button
class="suggestion-card"
data-query="Explain quantum computing in simple terms"
>
2025-12-03 18:42:22 -03:00
<span class="suggestion-icon">⚛️</span>
<span class="suggestion-text"
>Quantum computing explained</span
>
2025-12-03 18:42:22 -03:00
</button>
<button
class="suggestion-card"
data-query="Best practices for software architecture"
>
2025-12-03 18:42:22 -03:00
<span class="suggestion-icon">🏗️</span>
<span class="suggestion-text">Software architecture</span>
</button>
<button
class="suggestion-card"
data-query="How to improve productivity with AI tools"
>
2025-12-03 18:42:22 -03:00
<span class="suggestion-icon">📈</span>
<span class="suggestion-text">AI productivity tools</span>
</button>
</div>
<!-- Trending Topics -->
<div class="trending-section">
<h3>Trending</h3>
<div
class="trending-tags"
id="trending-tags"
hx-get="/api/ui/research/trending"
hx-trigger="load"
hx-swap="innerHTML"
>
2025-12-03 18:42:22 -03:00
<!-- Trending tags loaded here -->
</div>
</div>
</div>
<!-- Results Area -->
<div class="results-container" id="main-results">
<!-- Results loaded here via HTMX -->
</div>
</main>
<!-- Sources Panel (Right) -->
<aside class="sources-panel hidden" id="sources-panel">
<div class="sources-header">
<h3>Sources</h3>
<div class="sources-actions">
<button
class="btn-icon-sm"
title="Export Citations"
hx-get="/api/ui/research/export-citations"
hx-swap="none"
>
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"
></path>
2025-12-03 18:42:22 -03:00
<polyline points="7 10 12 15 17 10"></polyline>
<line x1="12" y1="15" x2="12" y2="3"></line>
</svg>
</button>
<button class="btn-icon-sm" id="close-sources">
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
2025-12-03 18:42:22 -03:00
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
</div>
<div class="sources-list" id="sources-list">
<!-- Sources loaded here -->
</div>
</aside>
</div>
<!-- Result Template (for HTMX responses) -->
<template id="result-template">
<div class="result-card">
<div class="result-answer">
<div class="answer-content" id="answer-content">
<!-- AI-generated answer with citations -->
</div>
<div class="answer-actions">
<button class="action-btn" title="Copy">
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<rect
x="9"
y="9"
width="13"
height="13"
rx="2"
ry="2"
></rect>
<path
d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"
></path>
2025-12-03 18:42:22 -03:00
</svg>
</button>
<button class="action-btn" title="Save to Collection">
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M19 21l-7-5-7 5V5a2 2 0 012-2h10a2 2 0 012 2z"
></path>
2025-12-03 18:42:22 -03:00
</svg>
</button>
<button class="action-btn" title="Share">
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
2025-12-03 18:42:22 -03:00
<circle cx="18" cy="5" r="3"></circle>
<circle cx="6" cy="12" r="3"></circle>
<circle cx="18" cy="19" r="3"></circle>
<line x1="8.59" y1="13.51" x2="15.42" y2="17.49"></line>
<line x1="15.41" y1="6.51" x2="8.59" y2="10.49"></line>
</svg>
</button>
<button class="action-btn" title="Export to Paper">
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"
></path>
2025-12-03 18:42:22 -03:00
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
</button>
</div>
</div>
<!-- Related Questions -->
<div class="related-questions">
<h4>Related</h4>
<div class="related-list" id="related-questions">
<!-- Related questions loaded here -->
</div>
</div>
<!-- Sources Preview -->
<div class="sources-preview">
<div class="sources-preview-header">
<h4>Sources</h4>
<button class="btn-text" id="view-all-sources">View all</button>
</div>
<div class="sources-preview-list" id="sources-preview">
<!-- Top sources shown here -->
</div>
</div>
</div>
</template>
<style>
/* Research Container */
.research-container {
display: flex;
height: calc(100vh - 60px);
background: var(--background);
color: var(--foreground);
2025-12-03 18:42:22 -03:00
}
/* Sidebar */
2025-12-03 18:42:22 -03:00
.research-sidebar {
width: 280px;
border-right: 1px solid var(--border);
background: var(--card);
display: flex;
flex-direction: column;
overflow-y: auto;
transition: width 0.2s ease;
2025-12-03 18:42:22 -03:00
}
.research-sidebar.collapsed {
width: 60px;
2025-12-03 18:42:22 -03:00
}
.research-sidebar.collapsed .sidebar-header h2,
.research-sidebar.collapsed .section-header h3,
.research-sidebar.collapsed .sidebar-section h3,
.research-sidebar.collapsed .focus-btn span,
.research-sidebar.collapsed .prompts-grid,
.research-sidebar.collapsed .collections-list,
.research-sidebar.collapsed .recent-list,
.research-sidebar.collapsed .category-name,
.research-sidebar.collapsed .category-count {
display: none;
}
.sidebar-header {
display: flex;
align-items: center;
justify-content: space-between;
2025-12-03 18:42:22 -03:00
padding: 16px;
border-bottom: 1px solid var(--border);
}
.sidebar-header h2 {
font-size: 18px;
font-weight: 600;
margin: 0;
}
/* Focus Modes */
.focus-modes {
display: flex;
flex-wrap: wrap;
gap: 6px;
padding: 12px;
border-bottom: 1px solid var(--border);
}
.focus-btn {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 12px;
border: 1px solid var(--border);
border-radius: 20px;
background: var(--background);
color: var(--foreground);
font-size: 12px;
cursor: pointer;
transition: all 0.15s;
}
.focus-btn:hover {
background: var(--accent);
}
.focus-btn.active {
background: var(--primary);
color: var(--primary-foreground);
border-color: var(--primary);
}
.research-sidebar.collapsed .focus-btn {
padding: 8px;
justify-content: center;
}
/* Sidebar Sections */
.sidebar-section {
padding: 16px;
border-bottom: 1px solid var(--border);
}
.sidebar-section h3 {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
color: var(--muted-foreground);
margin: 0 0 12px 0;
letter-spacing: 0.5px;
}
.section-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.section-header h3 {
margin: 0;
}
.btn-icon-sm {
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
border: none;
border-radius: 4px;
background: transparent;
color: var(--muted-foreground);
cursor: pointer;
}
.btn-icon-sm:hover {
background: var(--accent);
color: var(--foreground);
}
/* Collections */
.collections-list {
display: flex;
flex-direction: column;
gap: 4px;
}
.collection-item {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
border-radius: 6px;
background: transparent;
border: none;
color: var(--foreground);
font-size: 13px;
text-align: left;
cursor: pointer;
transition: background 0.15s;
}
.collection-item:hover {
background: var(--accent);
}
.collection-icon {
font-size: 14px;
}
/* Recent Searches */
.recent-list {
display: flex;
flex-direction: column;
gap: 4px;
}
.recent-item {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 8px;
border-radius: 4px;
background: transparent;
border: none;
color: var(--muted-foreground);
font-size: 12px;
text-align: left;
cursor: pointer;
transition: all 0.15s;
}
.recent-item:hover {
background: var(--accent);
color: var(--foreground);
}
/* Prompts */
.prompts-grid {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.prompt-chip {
padding: 6px 10px;
border: 1px solid var(--border);
border-radius: 14px;
background: var(--background);
color: var(--foreground);
font-size: 11px;
cursor: pointer;
transition: all 0.15s;
}
.prompt-chip:hover {
background: var(--primary);
color: var(--primary-foreground);
border-color: var(--primary);
}
/* Source Categories */
.sources-categories {
display: flex;
flex-direction: column;
gap: 4px;
}
.source-category {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 12px;
border: none;
border-radius: 6px;
background: transparent;
color: var(--foreground);
font-size: 13px;
text-align: left;
cursor: pointer;
transition: background 0.15s;
}
.source-category:hover {
background: var(--accent);
}
.category-icon {
font-size: 16px;
}
.category-name {
flex: 1;
}
.category-count {
font-size: 11px;
padding: 2px 6px;
border-radius: 10px;
background: var(--muted);
color: var(--muted-foreground);
}
/* Main Content */
.research-main {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* Search Header */
.search-header {
padding: 24px 32px;
border-bottom: 1px solid var(--border);
background: var(--card);
}
.search-form {
max-width: 800px;
margin: 0 auto;
2025-12-03 18:42:22 -03:00
}
.search-input-wrapper {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 16px 20px;
border: 2px solid var(--border);
border-radius: 12px;
background: var(--background);
transition: border-color 0.2s;
}
.search-input-wrapper:focus-within {
border-color: var(--primary);
}
.search-icon {
color: var(--muted-foreground);
margin-top: 2px;
flex-shrink: 0;
2025-12-03 18:42:22 -03:00
}
.search-input-wrapper textarea {
flex: 1;
border: none;
background: transparent;
color: var(--foreground);
font-size: 16px;
line-height: 1.5;
resize: none;
outline: none;
min-height: 24px;
max-height: 120px;
}
.search-input-wrapper textarea::placeholder {
color: var(--muted-foreground);
}
.search-options {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 12px;
padding: 0 4px;
}
.option-toggle {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
}
.option-toggle input {
display: none;
}
.toggle-label {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
border-radius: 16px;
background: var(--muted);
color: var(--muted-foreground);
font-size: 12px;
transition: all 0.15s;
}
.option-toggle input:checked + .toggle-label {
background: var(--primary);
color: var(--primary-foreground);
}
.search-btn {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 20px;
border: none;
border-radius: 8px;
background: var(--primary);
color: var(--primary-foreground);
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
}
.search-btn:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
/* Search Indicator */
.search-indicator {
display: none;
align-items: center;
justify-content: center;
gap: 12px;
padding: 16px;
margin-top: 16px;
}
.search-indicator.htmx-request {
display: flex;
}
.indicator-dots {
display: flex;
gap: 4px;
}
.indicator-dots span {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--primary);
animation: bounce 1.4s infinite ease-in-out both;
}
.indicator-dots span:nth-child(1) {
animation-delay: -0.32s;
}
.indicator-dots span:nth-child(2) {
animation-delay: -0.16s;
}
@keyframes bounce {
0%,
80%,
100% {
transform: scale(0);
}
40% {
transform: scale(1);
}
}
.indicator-text {
color: var(--muted-foreground);
font-size: 14px;
}
/* Suggestions Panel */
2025-12-03 18:42:22 -03:00
.suggestions-panel {
flex: 1;
padding: 40px 32px;
overflow-y: auto;
max-width: 900px;
margin: 0 auto;
width: 100%;
}
.suggestions-panel.hidden {
display: none;
}
.suggestions-panel h3 {
font-size: 14px;
font-weight: 600;
color: var(--muted-foreground);
margin: 0 0 16px 0;
2025-12-03 18:42:22 -03:00
}
.suggestion-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 12px;
margin-bottom: 32px;
}
.suggestion-card {
display: flex;
align-items: center;
gap: 12px;
padding: 16px;
border: 1px solid var(--border);
border-radius: 12px;
background: var(--card);
color: var(--foreground);
text-align: left;
cursor: pointer;
transition: all 0.2s;
}
.suggestion-card:hover {
border-color: var(--primary);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.suggestion-icon {
font-size: 24px;
}
.suggestion-text {
font-size: 14px;
font-weight: 500;
}
/* Trending */
.trending-section {
margin-top: 24px;
}
.trending-tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.trending-tag {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 14px;
border: 1px solid var(--border);
border-radius: 20px;
background: var(--background);
color: var(--foreground);
font-size: 13px;
cursor: pointer;
transition: all 0.15s;
}
.trending-tag:hover {
background: var(--accent);
border-color: var(--primary);
}
.trending-tag .trend-icon {
color: var(--chart-1);
}
/* Results Container */
.results-container {
flex: 1;
overflow-y: auto;
padding: 24px 32px;
}
.results-container:empty + .suggestions-panel {
display: block;
}
.results-container:not(:empty) + .suggestions-panel {
display: none;
}
/* Result Card */
.result-card {
max-width: 900px;
margin: 0 auto;
}
.result-answer {
background: var(--card);
border: 1px solid var(--border);
border-radius: 12px;
padding: 24px;
margin-bottom: 24px;
}
.answer-content {
font-size: 15px;
line-height: 1.8;
}
.answer-content h1,
.answer-content h2,
.answer-content h3 {
margin-top: 24px;
margin-bottom: 12px;
}
.answer-content p {
margin: 12px 0;
}
.answer-content ul,
.answer-content ol {
padding-left: 24px;
margin: 12px 0;
}
.answer-content code {
background: var(--muted);
padding: 2px 6px;
border-radius: 4px;
font-family: monospace;
font-size: 13px;
}
.answer-content pre {
background: var(--muted);
padding: 16px;
border-radius: 8px;
overflow-x: auto;
margin: 16px 0;
}
/* Citations */
.citation {
display: inline-flex;
align-items: center;
justify-content: center;
width: 18px;
height: 18px;
margin: 0 2px;
border-radius: 4px;
background: var(--primary);
color: var(--primary-foreground);
font-size: 10px;
font-weight: 600;
cursor: pointer;
vertical-align: super;
transition: transform 0.15s;
}
.citation:hover {
transform: scale(1.1);
}
/* Answer Actions */
.answer-actions {
display: flex;
gap: 8px;
margin-top: 20px;
padding-top: 16px;
border-top: 1px solid var(--border);
}
.action-btn {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--background);
color: var(--muted-foreground);
cursor: pointer;
transition: all 0.15s;
}
.action-btn:hover {
background: var(--accent);
color: var(--foreground);
border-color: var(--primary);
}
/* Related Questions */
.related-questions {
margin-bottom: 24px;
}
.related-questions h4 {
font-size: 14px;
font-weight: 600;
color: var(--muted-foreground);
margin: 0 0 12px 0;
}
.related-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.related-item {
display: flex;
align-items: center;
gap: 10px;
padding: 12px 16px;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--card);
color: var(--foreground);
font-size: 14px;
text-align: left;
cursor: pointer;
transition: all 0.15s;
}
.related-item:hover {
background: var(--accent);
border-color: var(--primary);
}
.related-item svg {
color: var(--primary);
flex-shrink: 0;
}
/* Sources Preview */
.sources-preview {
background: var(--card);
border: 1px solid var(--border);
border-radius: 12px;
padding: 20px;
}
.sources-preview-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
}
.sources-preview-header h4 {
font-size: 14px;
font-weight: 600;
margin: 0;
}
.btn-text {
background: none;
border: none;
color: var(--primary);
font-size: 13px;
cursor: pointer;
}
.btn-text:hover {
text-decoration: underline;
2025-12-03 18:42:22 -03:00
}
.sources-preview-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 12px;
}
.source-card {
display: flex;
gap: 12px;
padding: 12px;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--background);
cursor: pointer;
transition: all 0.15s;
}
.source-card:hover {
border-color: var(--primary);
background: var(--accent);
}
.source-number {
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
border-radius: 4px;
background: var(--muted);
color: var(--foreground);
font-size: 12px;
font-weight: 600;
flex-shrink: 0;
}
.source-info {
flex: 1;
min-width: 0;
}
.source-title {
font-size: 13px;
font-weight: 500;
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.source-domain {
font-size: 11px;
color: var(--muted-foreground);
display: flex;
align-items: center;
gap: 4px;
}
.source-favicon {
width: 12px;
height: 12px;
border-radius: 2px;
2025-12-03 18:42:22 -03:00
}
/* Sources Panel (Right) */
2025-12-03 18:42:22 -03:00
.sources-panel {
width: 360px;
border-left: 1px solid var(--border);
background: var(--card);
display: flex;
flex-direction: column;
transition: transform 0.2s ease;
}
.sources-panel.hidden {
display: none;
}
.sources-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px;
border-bottom: 1px solid var(--border);
}
.sources-header h3 {
font-size: 16px;
font-weight: 600;
margin: 0;
}
.sources-actions {
display: flex;
gap: 4px;
}
.sources-list {
flex: 1;
overflow-y: auto;
padding: 16px;
}
.source-detail-card {
padding: 16px;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--background);
margin-bottom: 12px;
}
.source-detail-header {
display: flex;
align-items: flex-start;
gap: 12px;
margin-bottom: 12px;
}
.source-detail-number {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border-radius: 6px;
background: var(--primary);
color: var(--primary-foreground);
font-size: 13px;
font-weight: 600;
flex-shrink: 0;
}
.source-detail-title {
font-size: 14px;
font-weight: 600;
line-height: 1.4;
margin-bottom: 4px;
}
.source-detail-url {
font-size: 12px;
color: var(--primary);
text-decoration: none;
}
.source-detail-url:hover {
text-decoration: underline;
}
.source-detail-snippet {
font-size: 13px;
color: var(--muted-foreground);
line-height: 1.6;
margin-bottom: 12px;
}
.source-detail-actions {
display: flex;
gap: 8px;
}
.source-action-btn {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 10px;
border: 1px solid var(--border);
border-radius: 4px;
background: var(--background);
color: var(--foreground);
font-size: 11px;
cursor: pointer;
transition: all 0.15s;
}
.source-action-btn:hover {
background: var(--accent);
border-color: var(--primary);
}
/* Responsive */
@media (max-width: 1024px) {
.sources-panel {
position: absolute;
right: 0;
top: 60px;
bottom: 0;
z-index: 50;
}
}
@media (max-width: 768px) {
.research-sidebar {
position: absolute;
left: 0;
top: 0;
bottom: 0;
z-index: 60;
transform: translateX(-100%);
}
.research-sidebar.open {
transform: translateX(0);
}
.search-header {
padding: 16px;
}
.search-input-wrapper {
padding: 12px 16px;
}
.suggestions-panel {
padding: 20px 16px;
}
.suggestion-cards {
grid-template-columns: 1fr;
}
.sources-preview-list {
grid-template-columns: 1fr;
}
.sources-panel {
width: 100%;
}
2025-12-03 18:42:22 -03:00
}
</style>
<script>
(function () {
const searchInput = document.getElementById("search-input");
const suggestionsPanel = document.getElementById("suggestions-panel");
const resultsContainer = document.getElementById("main-results");
const sourcesPanel = document.getElementById("sources-panel");
const sidebar = document.getElementById("research-sidebar");
// Auto-resize textarea
searchInput.addEventListener("input", function () {
this.style.height = "auto";
this.style.height = Math.min(this.scrollHeight, 120) + "px";
2025-12-03 18:42:22 -03:00
});
// Handle Enter to submit (Shift+Enter for new line)
searchInput.addEventListener("keydown", function (e) {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
document.getElementById("research-form").requestSubmit();
}
2025-12-03 18:42:22 -03:00
});
// Focus modes
document.querySelectorAll(".focus-btn").forEach((btn) => {
btn.addEventListener("click", function () {
document
.querySelectorAll(".focus-btn")
.forEach((b) => b.classList.remove("active"));
this.classList.add("active");
document.getElementById("focus-mode").value =
this.dataset.focus;
});
2025-12-03 18:42:22 -03:00
});
// Pro search toggle
document
.getElementById("pro-search-toggle")
.addEventListener("change", function () {
document.getElementById("pro-mode").value = this.checked;
});
2025-12-03 18:42:22 -03:00
// Suggestion cards
document.querySelectorAll(".suggestion-card").forEach((card) => {
card.addEventListener("click", function () {
searchInput.value = this.dataset.query;
searchInput.style.height = "auto";
searchInput.style.height = searchInput.scrollHeight + "px";
document.getElementById("research-form").requestSubmit();
});
});
// Prompt chips
document.querySelectorAll(".prompt-chip").forEach((chip) => {
chip.addEventListener("click", function () {
const prompt = this.dataset.prompt;
const currentValue = searchInput.value.trim();
const prefixes = {
explain: "Explain ",
compare: "Compare ",
summarize: "Summarize ",
analyze: "Analyze ",
"pros-cons": "What are the pros and cons of ",
"how-to": "How to ",
};
searchInput.value = prefixes[prompt] + currentValue;
searchInput.focus();
});
});
// Toggle sidebar
document
.getElementById("toggle-research-sidebar")
.addEventListener("click", function () {
sidebar.classList.toggle("collapsed");
});
// View all sources
document.addEventListener("click", function (e) {
if (
e.target.id === "view-all-sources" ||
e.target.closest("#view-all-sources")
) {
sourcesPanel.classList.remove("hidden");
2025-12-03 18:42:22 -03:00
}
});
// Close sources panel
document
.getElementById("close-sources")
.addEventListener("click", function () {
sourcesPanel.classList.add("hidden");
});
// Citation click handler
document.addEventListener("click", function (e) {
if (e.target.classList.contains("citation")) {
const sourceNum = e.target.textContent;
sourcesPanel.classList.remove("hidden");
// Scroll to source in panel
const sourceCard = sourcesPanel.querySelector(
`[data-source="${sourceNum}"]`,
);
if (sourceCard) {
sourceCard.scrollIntoView({
behavior: "smooth",
block: "center",
});
sourceCard.classList.add("highlight");
setTimeout(
() => sourceCard.classList.remove("highlight"),
2000,
);
}
2025-12-03 18:42:22 -03:00
}
});
// Related question click
document.addEventListener("click", function (e) {
const relatedItem = e.target.closest(".related-item");
if (relatedItem) {
searchInput.value = relatedItem.textContent.trim();
document.getElementById("research-form").requestSubmit();
window.scrollTo({ top: 0, behavior: "smooth" });
2025-12-03 18:42:22 -03:00
}
});
// Trending tag click
document.addEventListener("click", function (e) {
const trendingTag = e.target.closest(".trending-tag");
if (trendingTag) {
searchInput.value =
trendingTag.dataset.query || trendingTag.textContent.trim();
document.getElementById("research-form").requestSubmit();
}
});
// Copy answer
document.addEventListener("click", function (e) {
const copyBtn = e.target.closest('.action-btn[title="Copy"]');
if (copyBtn) {
const content = document.getElementById("answer-content");
if (content) {
navigator.clipboard.writeText(content.innerText);
// Show feedback
const originalTitle = copyBtn.title;
copyBtn.title = "Copied!";
setTimeout(() => (copyBtn.title = originalTitle), 2000);
}
}
});
// Export to Paper
document.addEventListener("click", function (e) {
const exportBtn = e.target.closest(
'.action-btn[title="Export to Paper"]',
);
if (exportBtn) {
const content = document.getElementById("answer-content");
if (content) {
// Send to Paper via HTMX
htmx.ajax("POST", "/api/ui/paper/import", {
values: {
content: content.innerHTML,
title: searchInput.value,
},
}).then(() => {
// Navigate to Paper
window.location.hash = "#paper";
});
}
}
});
// Source category click
document.querySelectorAll(".source-category").forEach((cat) => {
cat.addEventListener("click", function () {
const category = this.dataset.category;
htmx.ajax("GET", `/api/research/sources?category=${category}`, {
target: "#sources-list",
});
sourcesPanel.classList.remove("hidden");
2025-12-03 18:42:22 -03:00
});
});
// Handle search results display
htmx.on("#main-results", "htmx:afterSwap", function () {
// Hide suggestions when results are shown
suggestionsPanel.classList.add("hidden");
// Update source counts
updateSourceCounts();
2025-12-03 18:42:22 -03:00
});
function updateSourceCounts() {
// This would typically come from the API response
// For now, we'll use placeholder logic
htmx.ajax("GET", "/api/ui/research/source-counts", {
swap: "none",
}).then((response) => {
// Update counts in sidebar
2025-12-03 18:42:22 -03:00
});
}
// Collection item click
document.addEventListener("click", function (e) {
const collectionItem = e.target.closest(".collection-item");
if (collectionItem) {
const collectionId = collectionItem.dataset.id;
htmx.ajax("GET", `/api/research/collections/${collectionId}`, {
target: "#main-results",
});
}
});
// Recent item click
document.addEventListener("click", function (e) {
const recentItem = e.target.closest(".recent-item");
if (recentItem) {
searchInput.value = recentItem.dataset.query;
document.getElementById("research-form").requestSubmit();
}
});
// Mobile sidebar toggle
window.toggleResearchSidebar = function () {
sidebar.classList.toggle("open");
};
})();
2025-12-03 18:42:22 -03:00
</script>