Page {{ page.pageNo }}
@@ -258,8 +264,8 @@ export default {
leave-from-class="translate-x-0"
leave-to-class="translate-x-full"
>
-
diff --git a/supernote/server/static/js/components/SummaryPanel.js b/supernote/server/static/js/components/SummaryPanel.js
index 4cfa542..f874f6f 100644
--- a/supernote/server/static/js/components/SummaryPanel.js
+++ b/supernote/server/static/js/components/SummaryPanel.js
@@ -11,7 +11,8 @@ export default {
default: 1
}
},
- setup(props) {
+ emits: ['close', 'has-insights'],
+ setup(props, { emit }) {
const ocrContainerRef = ref(null);
const aiContainerRef = ref(null);
@@ -36,10 +37,10 @@ export default {
try {
const result = await fetchSummaries(props.fileId);
- // Sort by creation time desc
summaries.value = result
.filter(s => (s.dataSource || '').toUpperCase() !== 'OCR')
.sort((a, b) => (b.creationTime || 0) - (a.creationTime || 0));
+ if (summaries.value.length > 0) emit('has-insights');
} catch (e) {
console.error(e);
error.value = "Failed to load summaries.";
@@ -70,8 +71,6 @@ export default {
if (tab === 'ocr') loadOcr();
};
- // Parse segments from a summary item's metadata field.
- // Returns an array of { date_range, summary, page_refs } or null if none.
function parseSegments(item) {
if (!item.metadata) return null;
try {
@@ -82,8 +81,6 @@ export default {
return null;
}
- // For a given summary item, produce the display rows:
- // either the parsed segments or a single fallback row.
const aiRows = computed(() => {
const rows = [];
for (const item of summaries.value) {
@@ -113,10 +110,8 @@ export default {
return rows;
});
- // Find the segment index that best matches activePage.
function segmentIndexForPage(pageNo) {
if (!pageNo || aiRows.value.length === 0) return -1;
- // Walk forward and return the last segment whose pageRefs contains a page <= pageNo
let best = -1;
for (let i = 0; i < aiRows.value.length; i++) {
const refs = aiRows.value[i].pageRefs;
@@ -127,18 +122,26 @@ export default {
return best >= 0 ? best : 0;
}
+ const SCROLL_PADDING = 16; // matches space-y-4 between panel cards
+
function scrollAiToPage(pageNo) {
- if (!aiContainerRef.value) return;
+ const container = aiContainerRef.value;
+ if (!container) return;
const idx = segmentIndexForPage(pageNo);
if (idx < 0) return;
- const el = aiContainerRef.value.querySelector(`[data-ai-segment="${idx}"]`);
- if (el) el.scrollIntoView({ block: 'start', behavior: 'smooth' });
+ const el = container.querySelector(`[data-ai-segment="${idx}"]`);
+ if (!el) return;
+ const top = el.getBoundingClientRect().top - container.getBoundingClientRect().top + container.scrollTop - SCROLL_PADDING;
+ container.scrollTo({ top: Math.max(0, top), behavior: 'smooth' });
}
function scrollOcrToPage(pageNo) {
- if (!ocrContainerRef.value || !pageNo) return;
- const el = ocrContainerRef.value.querySelector(`[data-ocr-page="${pageNo}"]`);
- if (el) el.scrollIntoView({ block: 'start', behavior: 'smooth' });
+ const container = ocrContainerRef.value;
+ if (!container || !pageNo) return;
+ const el = container.querySelector(`[data-ocr-page="${pageNo}"]`);
+ if (!el) return;
+ const top = el.getBoundingClientRect().top - container.getBoundingClientRect().top + container.scrollTop - SCROLL_PADDING;
+ container.scrollTo({ top: Math.max(0, top), behavior: 'smooth' });
}
watch([() => props.activePage, activeTab], ([newPage, tab]) => {
@@ -151,7 +154,6 @@ export default {
onMounted(loadSummaries);
watch(() => props.fileId, () => {
- // Reset all state when the viewed file changes
activeTab.value = 'ai';
ocrPages.value = [];
ocrLoaded.value = false;
@@ -165,7 +167,6 @@ export default {
};
return {
- summaries,
isLoading,
error,
activeTab,
@@ -180,7 +181,7 @@ export default {
};
},
template: `
-
+
@@ -188,7 +189,6 @@ export default {
AI Insights
-