Current section

Files

Jump to
arcana lib arcana_web assets.ex
Raw

lib/arcana_web/assets.ex

defmodule ArcanaWeb.Assets do
@moduledoc false
@behaviour Plug
# Bundle Phoenix LiveView JavaScript at compile time
@external_resource phoenix_js = Application.app_dir(:phoenix, "priv/static/phoenix.min.js")
@external_resource phoenix_html_js =
Application.app_dir(:phoenix_html, "priv/static/phoenix_html.js")
@external_resource live_view_js =
Application.app_dir(
:phoenix_live_view,
"priv/static/phoenix_live_view.min.js"
)
@phoenix_js File.read!(phoenix_js)
@phoenix_html_js File.read!(phoenix_html_js)
@live_view_js File.read!(live_view_js)
@app_js """
let liveSocket = new window.LiveView.LiveSocket("/live", window.Phoenix.Socket)
liveSocket.connect()
window.liveSocket = liveSocket
"""
@js [@phoenix_js, @phoenix_html_js, @live_view_js, @app_js] |> Enum.join("\n")
@js_hash :crypto.hash(:md5, @js) |> Base.encode16(case: :lower) |> binary_part(0, 8)
@css """
.arcana-dashboard {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 1.5rem;
color: #1f2937;
}
.arcana-tabs {
display: flex;
gap: 0.5rem;
border-bottom: 2px solid #e5e7eb;
margin-bottom: 1.5rem;
}
.arcana-tab {
padding: 0.75rem 1.5rem;
border: none;
background: transparent;
font-size: 1rem;
font-weight: 500;
color: #6b7280;
cursor: pointer;
border-bottom: 2px solid transparent;
margin-bottom: -2px;
transition: all 0.15s ease;
text-decoration: none;
}
.arcana-tab:hover {
color: #7c3aed;
}
.arcana-tab.active {
color: #7c3aed;
border-bottom-color: #7c3aed;
}
.arcana-dashboard h2 {
font-size: 1.5rem;
font-weight: 600;
color: #111827;
margin: 0 0 1rem 0;
}
.arcana-ingest-form,
.arcana-search-form {
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
padding: 1rem;
margin-bottom: 1.5rem;
}
.arcana-ingest-form textarea,
.arcana-search-form input[type="text"] {
width: 100%;
padding: 0.75rem;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
font-size: 0.875rem;
margin-bottom: 0.75rem;
box-sizing: border-box;
}
.arcana-ingest-form textarea:focus,
.arcana-search-form input:focus,
.arcana-search-form select:focus {
outline: none;
border-color: #7c3aed;
box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);
}
.arcana-search-options {
display: flex;
gap: 1rem;
flex-wrap: wrap;
margin-bottom: 0.75rem;
}
.arcana-search-options label {
display: flex;
flex-direction: column;
gap: 0.25rem;
font-size: 0.75rem;
font-weight: 500;
color: #6b7280;
}
.arcana-search-options select,
.arcana-search-options input[type="number"] {
padding: 0.5rem;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
font-size: 0.875rem;
min-width: 100px;
}
.arcana-ingest-form button,
.arcana-search-form button {
background: #7c3aed;
color: white;
padding: 0.625rem 1.25rem;
border: none;
border-radius: 0.375rem;
font-size: 0.875rem;
font-weight: 500;
cursor: pointer;
transition: background-color 0.15s ease;
}
.arcana-ingest-form button:hover,
.arcana-search-form button:hover {
background: #6d28d9;
}
.arcana-ingest-options {
display: flex;
gap: 1rem;
margin-bottom: 0.75rem;
}
.arcana-ingest-options label {
display: flex;
flex-direction: column;
gap: 0.25rem;
font-size: 0.75rem;
font-weight: 500;
color: #6b7280;
}
.arcana-ingest-options select {
padding: 0.5rem;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
font-size: 0.875rem;
min-width: 120px;
}
.arcana-ingest-options select:focus {
outline: none;
border-color: #7c3aed;
box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);
}
.arcana-empty {
color: #6b7280;
font-style: italic;
padding: 2rem;
text-align: center;
background: #f9fafb;
border-radius: 0.5rem;
}
.arcana-documents-table,
.arcana-results-table,
.arcana-table {
width: 100%;
border-collapse: collapse;
font-size: 0.875rem;
}
.arcana-documents-table th,
.arcana-results-table th,
.arcana-table th {
text-align: left;
padding: 0.75rem;
background: #f3f4f6;
border-bottom: 2px solid #e5e7eb;
font-weight: 600;
color: #374151;
}
.arcana-documents-table td,
.arcana-results-table td,
.arcana-table td {
padding: 0.75rem;
border-bottom: 1px solid #e5e7eb;
vertical-align: middle;
}
.arcana-documents-table td:nth-child(1) {
max-width: 120px;
word-break: break-all;
}
.arcana-documents-table td:nth-child(2) {
max-width: 300px;
}
.arcana-documents-table td:nth-child(5),
.arcana-documents-table td:nth-child(6),
.arcana-documents-table td:nth-child(7) {
white-space: nowrap;
}
.arcana-documents-table tr:hover,
.arcana-results-table tr:hover,
.arcana-table tr:hover {
background: #f9fafb;
}
.arcana-documents-table code,
.arcana-results-table code,
.arcana-table code {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
font-size: 0.75rem;
background: #ede9fe;
color: #6d28d9;
padding: 0.125rem 0.375rem;
border-radius: 0.25rem;
}
.arcana-metadata {
font-size: 0.75rem;
color: #6b7280;
max-width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.arcana-stats {
display: flex;
gap: 1.5rem;
margin-bottom: 1.5rem;
padding: 1rem;
background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%);
border-radius: 0.5rem;
color: white;
align-items: center;
}
.arcana-brand {
font-size: 1.5rem;
font-weight: 700;
letter-spacing: -0.025em;
padding-right: 1.5rem;
border-right: 1px solid rgba(255, 255, 255, 0.3);
margin-right: 0.5rem;
display: flex;
align-items: center;
align-self: center;
}
.arcana-stat {
text-align: center;
}
.arcana-stat-value {
font-size: 1.5rem;
font-weight: 700;
}
.arcana-stat-label {
font-size: 0.75rem;
opacity: 0.9;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.arcana-stat-divider {
width: 1px;
height: 2rem;
background: rgba(255, 255, 255, 0.3);
margin: 0 0.5rem;
}
.arcana-pagination {
display: flex;
gap: 0.5rem;
justify-content: center;
margin-top: 1rem;
padding-top: 1rem;
border-top: 1px solid #e5e7eb;
}
.arcana-page-btn {
padding: 0.5rem 0.75rem;
border: 1px solid #d1d5db;
background: white;
border-radius: 0.375rem;
font-size: 0.875rem;
cursor: pointer;
transition: all 0.15s ease;
}
.arcana-page-btn:hover {
border-color: #7c3aed;
color: #7c3aed;
}
.arcana-page-btn.active {
background: #7c3aed;
border-color: #7c3aed;
color: white;
}
.arcana-view-btn {
background: transparent;
color: #7c3aed;
border: 1px solid #7c3aed;
}
.arcana-view-btn:hover {
background: #7c3aed;
color: white;
}
.arcana-filter-bar {
display: flex;
align-items: center;
gap: 0.5rem;
flex-wrap: wrap;
padding: 0.75rem 1rem;
background: #f3f4f6;
border-radius: 0.5rem;
margin-bottom: 1rem;
}
.arcana-filter-label {
font-size: 0.875rem;
font-weight: 500;
color: #6b7280;
margin-right: 0.5rem;
}
.arcana-filter-btn {
padding: 0.375rem 0.75rem;
font-size: 0.875rem;
border: 1px solid #d1d5db;
border-radius: 9999px;
background: white;
color: #374151;
cursor: pointer;
transition: all 0.15s ease;
}
.arcana-filter-btn:hover {
border-color: #7c3aed;
color: #7c3aed;
}
.arcana-filter-btn.active {
background: #7c3aed;
border-color: #7c3aed;
color: white;
}
.arcana-filter-clear {
background: #fef2f2;
border-color: #fecaca;
color: #dc2626;
}
.arcana-filter-clear:hover {
background: #fee2e2;
border-color: #dc2626;
}
.arcana-doc-detail {
/* No background - inherits from page */
}
.arcana-doc-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
}
.arcana-doc-header h2 {
margin: 0;
}
.arcana-close-btn {
background: transparent;
color: #6b7280;
border: 1px solid #d1d5db;
padding: 0.5rem 1rem;
border-radius: 0.375rem;
font-size: 0.875rem;
cursor: pointer;
transition: all 0.15s ease;
text-decoration: none;
}
.arcana-close-btn:hover {
border-color: #7c3aed;
color: #7c3aed;
}
.arcana-doc-info {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
background: #f9fafb;
border: 1px solid #e5e7eb;
padding: 1rem;
border-radius: 0.5rem;
margin-bottom: 1.5rem;
}
.arcana-doc-field label {
display: block;
font-size: 0.75rem;
font-weight: 500;
color: #6b7280;
margin-bottom: 0.25rem;
}
.arcana-doc-section {
margin-bottom: 1.5rem;
}
.arcana-doc-section h3 {
font-size: 1rem;
font-weight: 600;
color: #374151;
margin: 0 0 0.75rem 0;
}
.arcana-doc-content {
background: #f9fafb;
border: 1px solid #e5e7eb;
padding: 1rem;
border-radius: 0.5rem;
font-size: 0.875rem;
white-space: pre-wrap;
word-wrap: break-word;
margin: 0;
max-height: 300px;
overflow-y: auto;
}
/* Info page grid layout */
.arcana-info-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1.5rem;
margin-bottom: 1.5rem;
}
.arcana-info-section {
background: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
padding: 1rem;
}
.arcana-info-section h3 {
font-size: 0.875rem;
font-weight: 600;
color: #7c3aed;
margin: 0 0 0.75rem 0;
padding-bottom: 0.5rem;
border-bottom: 1px solid #f3e8ff;
}
.arcana-info-section .arcana-doc-info {
margin-bottom: 0;
background: transparent;
border: none;
padding: 0;
}
.arcana-info-full {
grid-column: 1 / -1;
}
.arcana-not-configured {
color: #9ca3af;
}
.arcana-status-badge {
display: inline-block;
padding: 0.125rem 0.5rem;
border-radius: 9999px;
font-size: 0.75rem;
font-weight: 500;
}
.arcana-status-badge.enabled {
background: #d1fae5;
color: #065f46;
}
.arcana-status-badge.disabled {
background: #f3f4f6;
color: #6b7280;
}
/* Maintenance page styles */
.arcana-maintenance-section {
background: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
padding: 1.25rem;
margin-bottom: 2rem;
}
.arcana-maintenance-section h3 {
font-size: 0.875rem;
font-weight: 600;
color: #7c3aed;
margin: 0 0 0.75rem 0;
padding-bottom: 0.5rem;
border-bottom: 1px solid #f3e8ff;
}
.arcana-maintenance-section .arcana-doc-info {
margin-bottom: 0;
background: transparent;
border: none;
padding: 0;
}
.arcana-orphan-section {
background: #fef3c7;
border-color: #f59e0b;
}
.arcana-orphan-section h3 {
color: #b45309;
border-bottom-color: #fcd34d;
}
.arcana-orphan-count {
font-weight: 600;
color: #b45309;
}
.arcana-chunks-list {
display: flex;
flex-direction: column;
gap: 1rem;
}
.arcana-chunk {
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
overflow: hidden;
}
.arcana-chunk-header {
display: flex;
justify-content: space-between;
padding: 0.5rem 1rem;
background: #f3f4f6;
font-size: 0.75rem;
font-weight: 500;
}
.arcana-chunk-index {
color: #7c3aed;
}
.arcana-chunk-tokens {
color: #6b7280;
}
.arcana-chunk-text {
padding: 1rem;
margin: 0;
font-size: 0.875rem;
white-space: pre-wrap;
word-wrap: break-word;
background: #f9fafb;
}
.arcana-btn {
background: transparent;
color: #374151;
border: 1px solid #d1d5db;
padding: 0.375rem 0.75rem;
border-radius: 0.25rem;
font-size: 0.75rem;
cursor: pointer;
transition: all 0.15s ease;
}
.arcana-btn:hover {
border-color: #7c3aed;
color: #7c3aed;
}
.arcana-btn-primary {
background: #7c3aed;
color: white;
border-color: #7c3aed;
}
.arcana-btn-primary:hover {
background: #6d28d9;
border-color: #6d28d9;
color: white;
}
.arcana-btn-danger {
background: transparent;
color: #dc2626;
border-color: #dc2626;
}
.arcana-btn-danger:hover {
background: #dc2626;
color: white;
}
.arcana-form-row {
display: flex;
gap: 0.5rem;
align-items: center;
}
.arcana-input {
padding: 0.5rem;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
font-size: 0.875rem;
}
.arcana-input:focus {
outline: none;
border-color: #7c3aed;
box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);
}
.arcana-confirm-delete {
display: flex;
gap: 0.5rem;
align-items: center;
}
.arcana-confirm-delete span {
font-size: 0.75rem;
color: #dc2626;
font-weight: 500;
}
/* Evaluation styles */
.arcana-eval-nav {
display: flex;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.arcana-eval-nav-btn {
padding: 0.5rem 1rem;
border: 1px solid #d1d5db;
background: white;
border-radius: 0.375rem;
font-size: 0.875rem;
cursor: pointer;
transition: all 0.15s ease;
}
.arcana-eval-nav-btn:hover {
border-color: #7c3aed;
color: #7c3aed;
}
.arcana-eval-nav-btn.active {
background: #7c3aed;
border-color: #7c3aed;
color: white;
}
.arcana-eval-message {
padding: 0.75rem 1rem;
border-radius: 0.375rem;
margin-bottom: 1rem;
font-size: 0.875rem;
}
.arcana-eval-message.success {
background: #d1fae5;
color: #065f46;
border: 1px solid #a7f3d0;
}
.arcana-eval-message.error {
background: #fee2e2;
color: #991b1b;
border: 1px solid #fecaca;
}
.arcana-run-form {
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
padding: 1rem;
margin-bottom: 1.5rem;
display: flex;
gap: 1rem;
align-items: flex-end;
}
.arcana-run-form label {
display: flex;
flex-direction: column;
gap: 0.25rem;
font-size: 0.75rem;
font-weight: 500;
color: #6b7280;
}
.arcana-run-form select {
padding: 0.5rem;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
font-size: 0.875rem;
min-width: 120px;
}
.arcana-run-form button {
background: #7c3aed;
color: white;
padding: 0.625rem 1.25rem;
border: none;
border-radius: 0.375rem;
font-size: 0.875rem;
font-weight: 500;
cursor: pointer;
transition: background-color 0.15s ease;
}
.arcana-run-form button:hover {
background: #6d28d9;
}
.arcana-run-form button:disabled {
background: #9ca3af;
cursor: not-allowed;
}
.arcana-metrics-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
margin-bottom: 1.5rem;
}
.arcana-metric-card {
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
padding: 1rem;
text-align: center;
}
.arcana-metric-value {
font-size: 1.5rem;
font-weight: 700;
color: #7c3aed;
}
.arcana-metric-label {
font-size: 0.75rem;
color: #6b7280;
margin-top: 0.25rem;
}
.arcana-test-case {
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
padding: 1rem;
margin-bottom: 0.75rem;
}
.arcana-test-case-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 0.5rem;
}
.arcana-test-case-question {
font-weight: 500;
color: #111827;
}
.arcana-test-case-meta {
display: flex;
gap: 1rem;
font-size: 0.75rem;
color: #6b7280;
}
.arcana-test-case-badge {
display: inline-block;
padding: 0.125rem 0.5rem;
border-radius: 9999px;
font-size: 0.625rem;
font-weight: 500;
text-transform: uppercase;
}
.arcana-test-case-badge.synthetic {
background: #ddd6fe;
color: #5b21b6;
}
.arcana-test-case-badge.manual {
background: #bfdbfe;
color: #1e40af;
}
.arcana-actions-cell {
text-align: center;
white-space: nowrap;
}
.arcana-icon-btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.375rem;
background: transparent;
color: #9ca3af;
border: none;
border-radius: 0.25rem;
cursor: pointer;
}
.arcana-icon-btn:hover {
color: #7c3aed;
background: #f3f4f6;
}
.arcana-delete-btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.375rem;
background: transparent;
color: #9ca3af;
border: none;
border-radius: 0.25rem;
cursor: pointer;
}
.arcana-delete-btn:hover {
color: #dc2626;
background: #fef2f2;
}
.arcana-run-card {
background: white;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
margin-bottom: 1rem;
overflow: hidden;
}
.arcana-run-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.75rem 1rem;
background: #f3f4f6;
border-bottom: 1px solid #e5e7eb;
}
.arcana-run-header-left {
display: flex;
align-items: center;
gap: 0.75rem;
}
.arcana-run-status {
padding: 0.25rem 0.75rem;
border-radius: 9999px;
font-size: 0.75rem;
font-weight: 500;
}
.arcana-run-status.completed {
background: #d1fae5;
color: #065f46;
}
.arcana-run-status.running {
background: #fef3c7;
color: #92400e;
}
.arcana-run-status.failed {
background: #fee2e2;
color: #991b1b;
}
.arcana-run-body {
padding: 1rem;
}
.arcana-run-config {
font-size: 0.75rem;
color: #6b7280;
margin-bottom: 0.75rem;
}
/* Upload styles */
.arcana-dropzone {
position: relative;
border: 2px dashed #d1d5db;
border-radius: 0.5rem;
padding: 2rem;
text-align: center;
cursor: pointer;
transition: all 0.15s ease;
margin-bottom: 1rem;
}
.arcana-dropzone:hover {
border-color: #7c3aed;
background: #f5f3ff;
}
.arcana-dropzone p {
margin: 0 0 0.5rem 0;
color: #374151;
}
.arcana-upload-hint {
font-size: 0.75rem;
color: #6b7280;
}
.arcana-file-input {
position: absolute;
inset: 0;
opacity: 0;
cursor: pointer;
}
.arcana-upload-entry {
display: flex;
align-items: center;
gap: 1rem;
padding: 0.5rem;
background: #f9fafb;
border-radius: 0.375rem;
margin-bottom: 0.5rem;
}
.arcana-upload-entry progress {
flex: 1;
height: 0.5rem;
}
.arcana-upload-entry button {
background: transparent;
border: none;
color: #dc2626;
cursor: pointer;
font-size: 1.25rem;
}
.arcana-upload-error {
color: #dc2626;
font-size: 0.75rem;
}
.arcana-upload-btn {
background: #7c3aed;
color: white;
padding: 0.625rem 1.25rem;
border: none;
border-radius: 0.375rem;
font-size: 0.875rem;
font-weight: 500;
cursor: pointer;
}
.arcana-upload-btn:hover {
background: #6d28d9;
}
.arcana-divider {
text-align: center;
color: #6b7280;
font-size: 0.875rem;
margin: 1.5rem 0;
position: relative;
}
.arcana-divider::before,
.arcana-divider::after {
content: "";
position: absolute;
top: 50%;
width: 40%;
height: 1px;
background: #e5e7eb;
}
.arcana-divider::before {
left: 0;
}
.arcana-divider::after {
right: 0;
}
/* Search Results Styles */
.arcana-search-results {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.arcana-search-result {
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
overflow: hidden;
background: white;
}
.arcana-result-header {
display: flex;
align-items: center;
gap: 1rem;
padding: 0.75rem 1rem;
background: #f9fafb;
border-bottom: 1px solid #e5e7eb;
}
.arcana-result-score {
min-width: 60px;
}
.arcana-result-score .score-value {
font-weight: 600;
color: #7c3aed;
font-size: 0.875rem;
}
.arcana-result-meta {
display: flex;
align-items: center;
gap: 0.5rem;
flex: 1;
}
.arcana-result-meta code {
font-size: 0.7rem;
}
.arcana-chunk-badge {
background: #ede9fe;
color: #6d28d9;
padding: 0.125rem 0.5rem;
border-radius: 9999px;
font-size: 0.75rem;
font-weight: 500;
}
.arcana-result-actions {
display: flex;
gap: 0.5rem;
}
.arcana-result-btn {
padding: 0.375rem 0.75rem;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
background: white;
font-size: 0.75rem;
cursor: pointer;
transition: all 0.15s ease;
}
.arcana-result-btn:hover {
border-color: #7c3aed;
color: #7c3aed;
}
.arcana-result-btn-primary {
background: #7c3aed;
border-color: #7c3aed;
color: white;
}
.arcana-result-btn-primary:hover {
background: #6d28d9;
border-color: #6d28d9;
color: white;
}
.arcana-result-text {
padding: 1rem;
font-size: 0.875rem;
white-space: pre-wrap;
word-wrap: break-word;
color: #374151;
max-height: 100px;
overflow: hidden;
position: relative;
}
.arcana-result-text.expanded {
max-height: none;
overflow: visible;
}
/* Collection checkboxes - shared between Search and Ask tabs */
.arcana-ask-collections {
margin: 1rem 0;
}
.arcana-ask-collections > label {
display: block;
font-size: 0.875rem;
font-weight: 500;
color: #374151;
margin-bottom: 0.5rem;
}
.arcana-llm-select-toggle {
margin-bottom: 0.75rem;
padding: 0.75rem;
background: #f5f3ff;
border: 1px solid #ddd6fe;
border-radius: 0.5rem;
}
.arcana-llm-select-toggle .arcana-checkbox-label {
margin: 0;
}
.arcana-collection-checkboxes {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.arcana-collection-check {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.375rem 0.75rem;
background: white;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
font-size: 0.8125rem;
cursor: pointer;
transition: all 0.15s ease;
}
.arcana-collection-check:hover {
border-color: #7c3aed;
background: #faf5ff;
}
.arcana-collection-check:has(input:checked) {
border-color: #7c3aed;
background: #ede9fe;
color: #5b21b6;
}
.arcana-collection-check input {
accent-color: #7c3aed;
}
.arcana-collection-hint {
display: block;
margin-top: 0.375rem;
font-size: 0.75rem;
color: #6b7280;
}
/* Tab description */
.arcana-tab-description {
color: #6b7280;
margin-bottom: 1rem;
font-size: 0.875rem;
}
/* Ask tab styles */
.arcana-ask-mode-nav {
display: inline-flex;
background: #f3f4f6;
border-radius: 0.5rem;
padding: 0.25rem;
margin-bottom: 0.75rem;
}
.arcana-mode-btn {
padding: 0.5rem 1rem;
border: none;
background: transparent;
color: #6b7280;
font-size: 0.875rem;
font-weight: 500;
border-radius: 0.375rem;
cursor: pointer;
transition: all 0.15s ease;
}
.arcana-mode-btn:hover {
color: #374151;
}
.arcana-mode-btn.active {
background: white;
color: #7c3aed;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.arcana-mode-description {
color: #9ca3af;
font-size: 0.8125rem;
margin-bottom: 1rem;
font-style: italic;
}
.arcana-ask-form {
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
padding: 1rem;
margin-bottom: 1.5rem;
}
.arcana-ask-input textarea {
width: 100%;
padding: 0.75rem;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
font-size: 0.875rem;
resize: vertical;
box-sizing: border-box;
}
.arcana-ask-input textarea:focus {
outline: none;
border-color: #7c3aed;
box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);
}
.arcana-ask-options {
margin-top: 1rem;
padding-top: 1rem;
border-top: 1px solid #e5e7eb;
}
.arcana-ask-options h4 {
font-size: 0.875rem;
font-weight: 600;
color: #374151;
margin: 0 0 0.75rem 0;
}
.arcana-pipeline {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
align-items: center;
}
.arcana-pipeline > li {
display: flex;
flex-direction: column;
align-items: center;
}
.arcana-pipeline > li:not(:last-child)::after {
content: '';
display: block;
width: 2px;
height: 1.25rem;
background: #c4b5fd;
}
.arcana-pipeline > li:has(> .arcana-pipeline-step:not(:has(input:checked)):not(.fixed)):not(:last-child)::after {
background: none;
border-left: 2px dashed #d1d5db;
}
.arcana-pipeline-step {
display: flex;
flex-direction: column;
align-items: center;
width: 240px;
padding: 0.625rem 1rem;
background: #fafafa;
border: 2px dashed #d1d5db;
border-radius: 0.5rem;
cursor: pointer;
transition: all 0.15s ease;
text-align: center;
}
.arcana-pipeline-step:has(input:checked) {
background: #ede9fe;
border: 2px solid #7c3aed;
}
.arcana-pipeline-step:has(input:checked) .arcana-step-label {
color: #6d28d9;
}
.arcana-pipeline-step:not(.fixed):hover {
border-color: #a78bfa;
}
.arcana-pipeline-step.fixed {
background: #f0fdf4;
border: 2px solid #86efac;
cursor: default;
}
.arcana-pipeline-step.fixed .arcana-step-label {
color: #15803d;
}
.arcana-pipeline-step input[type="checkbox"],
.arcana-pipeline-step input[type="radio"] {
position: absolute;
opacity: 0;
width: 0;
height: 0;
}
.arcana-step-label {
font-size: 0.875rem;
font-weight: 600;
color: #374151;
}
.arcana-pipeline-step small {
font-size: 0.75rem;
color: #6b7280;
margin-top: 0.125rem;
}
.arcana-pipeline-fork {
display: flex;
align-items: center;
gap: 0.75rem;
}
.arcana-pipeline-fork .arcana-pipeline-step {
width: 160px;
}
.arcana-fork-or {
font-size: 0.75rem;
font-weight: 500;
color: #9ca3af;
text-transform: uppercase;
}
.arcana-pipeline-step:has(input:disabled) {
opacity: 0.5;
cursor: not-allowed;
}
.arcana-checkbox-label {
display: flex;
flex-direction: column;
padding: 0.75rem;
background: white;
border: 1px solid #e5e7eb;
border-radius: 0.375rem;
cursor: pointer;
transition: all 0.15s ease;
}
.arcana-checkbox-label:hover {
border-color: #7c3aed;
}
.arcana-checkbox-label input[type="checkbox"] {
position: absolute;
opacity: 0;
width: 0;
height: 0;
}
.arcana-checkbox-label span {
font-size: 0.875rem;
font-weight: 500;
color: #374151;
}
.arcana-checkbox-label small {
font-size: 0.75rem;
color: #6b7280;
margin-top: 0.25rem;
}
.arcana-checkbox-label:has(input:checked) {
background: #ede9fe;
border-color: #7c3aed;
}
.arcana-checkbox-label:has(input:checked) span {
color: #6d28d9;
}
.arcana-checkbox-label:has(input:disabled) {
opacity: 0.5;
cursor: not-allowed;
}
.arcana-ask-actions {
display: flex;
gap: 0.5rem;
margin-top: 1rem;
}
.arcana-ask-actions button {
background: #7c3aed;
color: white;
padding: 0.625rem 1.25rem;
border: none;
border-radius: 0.375rem;
font-size: 0.875rem;
font-weight: 500;
cursor: pointer;
transition: background-color 0.15s ease;
}
.arcana-ask-actions button:hover {
background: #6d28d9;
}
.arcana-ask-actions button:disabled {
background: #9ca3af;
cursor: not-allowed;
}
.arcana-ask-actions button[type="button"] {
background: transparent;
color: #6b7280;
border: 1px solid #d1d5db;
}
.arcana-ask-actions button[type="button"]:hover {
border-color: #7c3aed;
color: #7c3aed;
background: transparent;
}
.arcana-ask-loading {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 1.5rem;
background: #f9fafb;
border-radius: 0.5rem;
color: #6b7280;
}
.arcana-spinner {
width: 1.25rem;
height: 1.25rem;
border: 2px solid #e5e7eb;
border-top-color: #7c3aed;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.arcana-ask-results {
margin-top: 1.5rem;
}
.arcana-ask-answer {
background: white;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
overflow: hidden;
margin-bottom: 1rem;
}
.arcana-ask-answer h3 {
margin: 0;
padding: 0.75rem 1rem;
background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%);
color: white;
font-size: 0.875rem;
font-weight: 600;
}
.arcana-answer-content {
padding: 1rem;
font-size: 0.875rem;
line-height: 1.6;
white-space: pre-wrap;
}
.arcana-ask-section {
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
padding: 1rem;
margin-bottom: 1rem;
}
.arcana-ask-section h4 {
margin: 0 0 0.75rem 0;
font-size: 0.875rem;
font-weight: 600;
color: #374151;
}
.arcana-query-list {
margin: 0;
padding-left: 1.5rem;
font-size: 0.875rem;
color: #374151;
}
.arcana-query-list li {
margin-bottom: 0.25rem;
}
.arcana-collection-badges {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.arcana-collection-badge {
background: #ede9fe;
color: #6d28d9;
padding: 0.25rem 0.75rem;
border-radius: 9999px;
font-size: 0.75rem;
font-weight: 500;
}
/* Grounding Styles */
.arcana-grounding-score {
font-weight: 500;
font-size: 0.75rem;
padding: 0.125rem 0.5rem;
border-radius: 9999px;
margin-left: 0.5rem;
}
.arcana-grounding-score.good { background: #d1fae5; color: #065f46; }
.arcana-grounding-score.warn { background: #fef3c7; color: #92400e; }
.arcana-grounding-score.bad { background: #fee2e2; color: #991b1b; }
.arcana-grounding-spans h5 {
font-size: 0.8rem;
font-weight: 600;
color: #6b7280;
margin: 0.75rem 0 0.5rem 0;
}
.arcana-span {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.5rem;
padding: 0.375rem 0.5rem;
border-radius: 0.375rem;
margin-bottom: 0.25rem;
font-size: 0.8rem;
}
.arcana-span.hallucinated {
background: #fef2f2;
border-left: 3px solid #ef4444;
}
.arcana-span.faithful {
background: #f0fdf4;
border-left: 3px solid #22c55e;
}
.arcana-span-text {
font-family: ui-monospace, monospace;
font-size: 0.8rem;
}
.arcana-span-score {
font-size: 0.7rem;
color: #9ca3af;
}
.arcana-span-sources {
display: flex;
gap: 0.25rem;
flex-wrap: wrap;
width: 100%;
}
.arcana-source-badge {
font-size: 0.65rem;
background: #f3f4f6;
color: #6b7280;
padding: 0.125rem 0.375rem;
border-radius: 0.25rem;
}
.arcana-source-badge.clickable {
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 0.25rem;
list-style: none;
}
.arcana-source-badge.clickable:hover {
background: #e5e7eb;
}
.arcana-source-badge.clickable::-webkit-details-marker {
display: none;
}
.arcana-source-label {
font-weight: 600;
color: #4b5563;
}
.arcana-source-overlap {
color: #9ca3af;
}
.arcana-source-detail {
display: inline;
}
.arcana-source-preview {
font-size: 0.7rem;
color: #4b5563;
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 0.25rem;
padding: 0.5rem;
margin-top: 0.375rem;
margin-bottom: 0.25rem;
line-height: 1.5;
width: 100%;
}
/* Answer highlighting */
.arcana-hl-hallucinated {
background: #fecaca;
border-bottom: 2px solid #ef4444;
border-radius: 2px;
padding: 0 1px;
}
.arcana-hl-faithful {
background: #bbf7d0;
border-bottom: 2px solid #22c55e;
border-radius: 2px;
padding: 0 1px;
}
/* Graph Tab Styles */
.arcana-graph-subtabs {
display: flex;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.arcana-subtab-btn {
padding: 0.5rem 1rem;
border: 1px solid #d1d5db;
background: white;
border-radius: 0.375rem;
font-size: 0.875rem;
cursor: pointer;
transition: all 0.15s ease;
}
.arcana-subtab-btn:hover {
border-color: #7c3aed;
color: #7c3aed;
}
.arcana-subtab-btn.active {
background: #7c3aed;
border-color: #7c3aed;
color: white;
}
.arcana-graph-table {
margin-top: 1rem;
}
/* Entity type badges */
.arcana-entity-type-badge {
display: inline-block;
padding: 0.125rem 0.5rem;
border-radius: 9999px;
font-size: 0.75rem;
font-weight: 500;
text-transform: lowercase;
}
.arcana-entity-type-badge.person {
background: #dbeafe;
color: #1e40af;
}
.arcana-entity-type-badge.organization {
background: #dcfce7;
color: #166534;
}
.arcana-entity-type-badge.technology {
background: #fce7f3;
color: #9d174d;
}
.arcana-entity-type-badge.concept {
background: #fef3c7;
color: #92400e;
}
.arcana-entity-type-badge.location {
background: #e0e7ff;
color: #3730a3;
}
.arcana-entity-type-badge.event {
background: #f3e8ff;
color: #6b21a8;
}
/* Relationship strength meter */
.arcana-strength-meter {
display: inline-flex;
gap: 2px;
align-items: center;
}
.arcana-strength-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: #e5e7eb;
}
.arcana-strength-dot.filled {
background: #7c3aed;
}
/* Community status indicators */
.arcana-status-ready {
color: #16a34a;
}
.arcana-status-pending {
color: #d97706;
}
.arcana-status-empty {
color: #9ca3af;
}
.arcana-no-summary {
color: #9ca3af;
font-style: italic;
}
/* Graph empty state */
.arcana-empty-state {
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
padding: 2rem;
text-align: center;
}
.arcana-empty-state h3 {
margin: 0 0 1rem 0;
color: #374151;
}
.arcana-empty-state p {
color: #6b7280;
margin: 0.5rem 0;
}
.arcana-empty-state pre {
background: #1f2937;
color: #e5e7eb;
padding: 0.75rem 1rem;
border-radius: 0.375rem;
display: inline-block;
margin: 1rem 0;
font-size: 0.875rem;
}
.arcana-empty-state code {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
}
/* Entity detail panel */
.arcana-entity-row {
cursor: pointer;
transition: background-color 0.15s;
}
.arcana-entity-row.selected {
background: #ede9fe;
}
.arcana-entity-detail {
margin-top: 1.5rem;
padding: 1.5rem;
background: #faf5ff;
border: 1px solid #e9d5ff;
border-radius: 0.5rem;
}
.arcana-entity-detail-header {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1rem;
}
.arcana-entity-detail-header h3 {
margin: 0;
font-size: 1.125rem;
color: #1f2937;
}
.arcana-entity-detail-close {
margin-left: auto;
background: transparent;
border: none;
font-size: 1.5rem;
color: #6b7280;
cursor: pointer;
padding: 0;
line-height: 1;
}
.arcana-entity-detail-close:hover {
color: #374151;
}
.arcana-entity-description {
color: #4b5563;
margin: 0 0 1rem 0;
}
.arcana-entity-relationships h4,
.arcana-entity-mentions h4 {
margin: 0 0 0.5rem 0;
font-size: 0.875rem;
color: #6b7280;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.arcana-rel-cards {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.arcana-rel-card {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 0.75rem;
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 0.375rem;
font-size: 0.875rem;
}
.arcana-rel-type {
font-family: monospace;
background: #ede9fe;
color: #5b21b6;
padding: 0.125rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
}
.arcana-rel-arrow {
color: #9ca3af;
font-weight: bold;
}
.arcana-rel-target,
.arcana-rel-source {
font-weight: 500;
color: #1f2937;
}
.arcana-rel-self {
color: #6b7280;
font-style: italic;
font-size: 0.75rem;
}
.arcana-mention-preview {
background: white;
border: 1px solid #e5e7eb;
border-radius: 0.375rem;
padding: 0.75rem;
margin-bottom: 0.5rem;
}
.arcana-mention-preview p {
margin: 0 0 0.5rem 0;
font-size: 0.875rem;
color: #374151;
}
.arcana-view-in-docs {
font-size: 0.75rem;
color: #7c3aed;
text-decoration: none;
}
.arcana-view-in-docs:hover {
text-decoration: underline;
}
/* Relationship detail panel */
.arcana-relationship-row {
cursor: pointer;
transition: background-color 0.15s;
}
.arcana-relationship-row.selected {
background: #ede9fe;
}
.arcana-relationship-detail {
margin-top: 1.5rem;
padding: 1.5rem;
background: #faf5ff;
border: 1px solid #e9d5ff;
border-radius: 0.5rem;
}
.arcana-relationship-detail-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 1rem;
}
.arcana-relationship-visual {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 1rem;
}
.arcana-relationship-source,
.arcana-relationship-target {
font-weight: 600;
color: #1f2937;
}
.arcana-relationship-arrow {
color: #9ca3af;
}
.arcana-relationship-type {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
font-size: 0.875rem;
background: #ede9fe;
color: #6d28d9;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
}
.arcana-relationship-detail-close {
background: transparent;
border: none;
font-size: 1.5rem;
color: #6b7280;
cursor: pointer;
padding: 0;
line-height: 1;
}
.arcana-relationship-detail-close:hover {
color: #374151;
}
.arcana-relationship-strength {
margin-bottom: 0.75rem;
color: #4b5563;
}
.arcana-relationship-description {
color: #4b5563;
margin: 0;
}
.arcana-empty-hint {
font-size: 0.8125rem;
}
/* Community detail panel */
.arcana-community-row {
cursor: pointer;
transition: background-color 0.15s;
}
.arcana-community-row.selected {
background: #ede9fe;
}
.arcana-community-detail {
margin-top: 1.5rem;
padding: 1.5rem;
background: #faf5ff;
border: 1px solid #e9d5ff;
border-radius: 0.5rem;
}
.arcana-community-detail-header {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1rem;
}
.arcana-community-detail-header h3 {
margin: 0;
font-size: 1.125rem;
color: #1f2937;
}
.arcana-community-level-badge {
display: inline-block;
padding: 0.125rem 0.5rem;
border-radius: 9999px;
font-size: 0.75rem;
font-weight: 500;
background: #ddd6fe;
color: #5b21b6;
}
.arcana-community-detail-close {
margin-left: auto;
background: transparent;
border: none;
font-size: 1.5rem;
color: #6b7280;
cursor: pointer;
padding: 0;
line-height: 1;
}
.arcana-community-detail-close:hover {
color: #374151;
}
.arcana-community-summary,
.arcana-community-entities,
.arcana-community-relationships {
margin-bottom: 1rem;
}
.arcana-community-summary h4,
.arcana-community-entities h4,
.arcana-community-relationships h4 {
margin: 0 0 0.5rem 0;
font-size: 0.875rem;
color: #6b7280;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.arcana-community-summary p {
margin: 0;
color: #374151;
line-height: 1.5;
}
.arcana-community-entities ul,
.arcana-community-relationships ul {
list-style: none;
padding: 0;
margin: 0;
}
.arcana-community-entities li,
.arcana-community-relationships li {
padding: 0.5rem 0;
border-bottom: 1px solid #e5e7eb;
display: flex;
align-items: center;
gap: 0.5rem;
}
.arcana-community-entities li:last-child,
.arcana-community-relationships li:last-child {
border-bottom: none;
}
.arcana-community-no-summary {
color: #9ca3af;
font-style: italic;
}
/* Collection selector */
.arcana-collection-selector {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1rem;
}
.arcana-collection-selector label {
font-size: 0.875rem;
font-weight: 500;
color: #374151;
}
.arcana-collection-selector select {
padding: 0.5rem;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
font-size: 0.875rem;
min-width: 200px;
}
.arcana-collection-selector select:focus {
outline: none;
border-color: #7c3aed;
box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);
}
/* Entity/Relationship/Community views */
.arcana-entities-view,
.arcana-relationships-view,
.arcana-communities-view {
margin-top: 1rem;
}
/* Deep Search toggle (simple mode, below textarea) */
.arcana-deep-search-toggle {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 0.75rem;
margin-top: 0.5rem;
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 0.375rem;
cursor: pointer;
font-size: 0.8125rem;
}
.arcana-deep-search-toggle:hover {
background: #f3f4f6;
}
.arcana-deep-search-toggle input[type="checkbox"] {
accent-color: #7c3aed;
}
.arcana-deep-search-toggle span {
font-weight: 500;
color: #374151;
}
.arcana-deep-search-toggle small {
color: #6b7280;
font-size: 0.75rem;
}
/* Graph Context section */
.arcana-graph-context {
margin: 1.5rem 0;
padding: 1rem;
background: linear-gradient(to right, #faf5ff, #f3e8ff);
border: 1px solid #e9d5ff;
border-radius: 0.5rem;
}
.arcana-graph-context-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
}
.arcana-graph-context-header h4 {
margin: 0;
color: #7c3aed;
font-size: 1rem;
}
.arcana-toggle-btn {
background: transparent;
border: 1px solid #d8b4fe;
border-radius: 0.25rem;
padding: 0.25rem 0.5rem;
cursor: pointer;
color: #7c3aed;
font-size: 0.75rem;
}
.arcana-toggle-btn:hover {
background: #f3e8ff;
}
.arcana-no-matches {
color: #9ca3af;
font-style: italic;
margin: 0.5rem 0;
}
.arcana-matched-entities,
.arcana-matched-relationships {
margin-top: 0.75rem;
}
.arcana-matched-entities h5,
.arcana-matched-relationships h5 {
margin: 0 0 0.5rem 0;
font-size: 0.875rem;
color: #6b21a8;
}
.arcana-matched-entities ul,
.arcana-matched-relationships ul {
list-style: none;
padding: 0;
margin: 0;
}
.arcana-matched-entities li,
.arcana-matched-relationships li {
padding: 0.375rem 0;
display: flex;
align-items: center;
gap: 0.5rem;
border-bottom: 1px solid #f3e8ff;
}
.arcana-matched-entities li:last-child,
.arcana-matched-relationships li:last-child {
border-bottom: none;
}
.arcana-entity-name {
font-weight: 500;
color: #1f2937;
}
.arcana-entity-type {
font-size: 0.75rem;
padding: 0.125rem 0.5rem;
background: #e9d5ff;
color: #7c3aed;
border-radius: 9999px;
}
.arcana-view-in-graph {
margin-left: auto;
font-size: 0.75rem;
color: #7c3aed;
text-decoration: none;
}
.arcana-view-in-graph:hover {
text-decoration: underline;
}
.arcana-rel-source,
.arcana-rel-target {
color: #1f2937;
}
.arcana-rel-type {
font-size: 0.75rem;
color: #7c3aed;
font-family: monospace;
}
/* Graph attribution in chunks */
.arcana-graph-attribution {
display: block;
font-size: 0.75rem;
color: #7c3aed;
margin-top: 0.25rem;
font-style: italic;
}
"""
@css_hash :crypto.hash(:md5, @css) |> Base.encode16(case: :lower) |> binary_part(0, 8)
@doc """
Returns the current hash for the given asset type.
"""
def current_hash(:js), do: @js_hash
def current_hash(:css), do: @css_hash
@impl Plug
def init(asset), do: asset
@impl Plug
def call(conn, asset) do
{content, content_type} =
case asset do
:js -> {@js, "text/javascript"}
:css -> {@css, "text/css"}
end
conn
|> Plug.Conn.put_resp_header("content-type", content_type)
|> Plug.Conn.put_resp_header("cache-control", "public, max-age=31536000, immutable")
|> Plug.Conn.delete_resp_header("x-frame-options")
|> Plug.Conn.put_private(:plug_skip_csrf_protection, true)
|> Plug.Conn.send_resp(200, content)
end
end