feat(renderer): interactive table with sort, filter & CSV export (M10.9)

- InteractiveTable.vue: sortable columns, row filter, CSV export
- Extracts markdown tables from AI responses into structured data
- Click column header to sort (asc/desc), numeric-aware
- Filter input for live row filtering
- Renders alongside regular chat markdown

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-04 00:00:08 +00:00
co-authored by Claude Opus 4.6
parent 9404085668
commit 04a175171b
3 changed files with 199 additions and 0 deletions
@@ -200,6 +200,15 @@
/>
</div>
<div v-if="inlineTables.length > 0" class="mt-3 space-y-2" @click.stop>
<InteractiveTable
v-for="(table, i) in inlineTables"
:key="`table-${i}`"
:headers="table.headers"
:rows="table.rows"
/>
</div>
<div v-if="inlineNewsLinks.length > 0" class="mt-3 space-y-1" @click.stop>
<NewsCard
v-for="(link, i) in inlineNewsLinks"
@@ -346,6 +355,8 @@ import { extractCashuTokens } from '@/utils/cashu'
import { extractRecipes, extractEvents } from '@/composables/contentExtraction'
import RecipeCard from '@/components/renderers/RecipeCard.vue'
import EventCard from '@/components/renderers/EventCard.vue'
import InteractiveTable from '@/components/renderers/InteractiveTable.vue'
import { extractTables } from '@/composables/useTableExtractor'
const props = withDefaults(
defineProps<{
@@ -443,6 +454,11 @@ const inlineRecipes = computed(() => {
return extractRecipes(props.message.content)
})
const inlineTables = computed(() => {
if (isUser.value) return []
return extractTables(props.message.content)
})
const inlineEvents = computed(() => {
if (isUser.value) return []
return extractEvents(props.message.content)