feat(phase-4-09): create new components — FolderRow, FolderBreadcrumb, FolderDeleteModal, ShareModal, DocumentPreviewModal, SearchBar, SortControls, AuditLogTab

- FolderRow: inline rename, three-dot menu, delete/rename callbacks, outside-click close
- FolderBreadcrumb: truncation at depth > 4, nav aria-label, ol structure
- FolderDeleteModal: role=dialog, warning icon, doc count in body, Keep/Delete buttons
- ShareModal: handle input, recipients list with revoke, 404/409 error handling
- DocumentPreviewModal: iframe with proxy URL only (never presigned), Escape/overlay close
- SearchBar: role=search, aria-label, Escape clears
- SortControls: aria-pressed, direction indicator, toggle vs switch logic
- AuditLogTab: filters, paginated table, CSV export via window.location.href
- api/client.js: add adminListAuditLog function
This commit is contained in:
curo1305
2026-05-25 22:10:23 +02:00
parent 437c9d134b
commit 36721575a5
9 changed files with 845 additions and 0 deletions
@@ -0,0 +1,49 @@
<template>
<div class="flex items-center gap-1">
<span class="sr-only">Sort by:</span>
<button
v-for="option in sortOptions"
:key="option.value"
@click="handleClick(option.value)"
:aria-pressed="sort === option.value"
:aria-label="sort === option.value ? `Sort by ${option.label}, ${order === 'asc' ? 'ascending' : 'descending'}` : `Sort by ${option.label}`"
class="text-xs font-medium px-2 py-1 rounded transition-colors"
:class="sort === option.value
? 'text-indigo-600 font-semibold bg-indigo-50'
: 'text-gray-500 hover:text-gray-900'"
>
{{ option.label }}{{ sort === option.value ? (order === 'asc' ? ' ↑' : ' ↓') : '' }}
</button>
</div>
</template>
<script setup>
const props = defineProps({
sort: {
type: String,
default: 'date',
},
order: {
type: String,
default: 'desc',
},
})
const emit = defineEmits(['change'])
const sortOptions = [
{ value: 'name', label: 'Name' },
{ value: 'date', label: 'Date' },
{ value: 'size', label: 'Size' },
]
function handleClick(value) {
if (props.sort === value) {
// Toggle order
emit('change', { sort: value, order: props.order === 'asc' ? 'desc' : 'asc' })
} else {
// Switch to new sort, default desc
emit('change', { sort: value, order: 'desc' })
}
}
</script>