This commit is contained in:
Oscar
2026-06-04 13:42:20 +03:00
parent dd86c564c4
commit 40a281b87e
4 changed files with 46 additions and 13 deletions

View File

@@ -10,12 +10,14 @@
</svg>
<span class="brand-tag">TMC</span>
<span class="brand-sep" aria-hidden="true" />
<h1 class="brand-title">Items <em>Manager</em></h1>
<h1 class="brand-title">
Items <em>Manager</em>
</h1>
</div>
<div class="header-right">
<span class="header-meta-label">Item collection</span>
<span class="header-vsep" aria-hidden="true" />
<time class="header-date">{{ formattedDate }}</time>
<!-- <span class="header-vsep" aria-hidden="true" /> -->
<!-- <time class="header-date">{{ formattedDate }}</time> -->
</div>
</div>
</header>
@@ -24,6 +26,7 @@
:items="leftItems"
:loading="leftLoading"
:has-more="leftHasMore"
:total="leftItemsTotal"
:search="leftSearch"
@update:search="leftSearch = $event"
@load-more="fetchLeft()"
@@ -34,6 +37,7 @@
:items="rightItems"
:loading="rightLoading"
:has-more="rightHasMore"
:total="rightItemsTotal"
:search="rightSearch"
@update:search="rightSearch = $event"
@load-more="fetchRight()"
@@ -53,7 +57,9 @@ const formattedDate = computed(() =>
const {
leftItems,
leftItemsTotal,
rightItems,
rightItemsTotal,
leftSearch,
rightSearch,
leftLoading,
@@ -128,7 +134,7 @@ async function handleAdd(id: number) {
.header-brand {
display: flex;
align-items: center;
gap: 11px;
gap: 12px;
}
.brand-icon {
@@ -156,7 +162,7 @@ async function handleAdd(id: number) {
.brand-title {
margin: 0;
font-family: var(--font-serif);
font-size: 1.08rem;
font-size: 1rem;
font-weight: 400;
color: var(--text-primary);
letter-spacing: -0.025em;

View File

@@ -2,9 +2,12 @@
<div class="panel">
<div class="panel-header">
<div class="panel-title-row">
<h2 class="panel-title">
All items
</h2>
<div class="panel-title-row">
<h2 class="panel-title">
All items
</h2>
<span v-if="total" class="item-count">{{ total }}</span>
</div>
<button class="btn-primary" @click="showAddModal = true">
<svg width="11" height="11" viewBox="0 0 11 11" fill="none" aria-hidden="true">
<path d="M5.5 1V10M1 5.5H10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
@@ -97,6 +100,7 @@ import { onUnmounted, ref, watch } from 'vue'
const props = defineProps<{
items: Item[]
total: number | string
loading: boolean
hasMore: boolean
search: string
@@ -176,6 +180,22 @@ function submitAdd() {
flex-shrink: 0;
}
.item-count {
display: inline-flex;
align-items: center;
justify-content: center;
margin-left: 8px;
min-width: 18px;
height: 18px;
padding: 0 5px;
background: var(--surface-subtle);
border: 1px solid var(--border);
border-radius: 9999px;
font-family: var(--font-mono);
font-size: 0.65rem;
color: var(--text-secondary);
}
.panel-title-row {
display: flex;
align-items: center;

View File

@@ -5,7 +5,7 @@
<h2 class="panel-title">
Selected items
</h2>
<span v-if="items.length" class="item-count">{{ items.length }}</span>
<span v-if="total" class="item-count">{{ total }}</span>
</div>
<div class="search-wrap">
<span class="search-icon" aria-hidden="true">
@@ -48,7 +48,7 @@
<circle cx="6" cy="10" r="1.2" />
</svg>
</span>
<span class="item-order">{{ index + 1 }}</span>
<!-- <span class="item-order">{{ index + 1 }}</span> -->
<span class="item-id">{{ item.id }}</span>
<button class="action-btn" title="Remove from selected" @click="emit('deselect', item.id!)">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
@@ -78,6 +78,7 @@ import { VueDraggableNext } from 'vue-draggable-next'
const props = defineProps<{
items: Item[]
total: number | string
loading: boolean
hasMore: boolean
search: string

View File

@@ -1,4 +1,4 @@
import type { Item, PaginatedItems } from '~/services/api'
import type { Item } from '~/services/api'
import { ref } from 'vue'
import { Api } from '~/services/api'
@@ -8,6 +8,8 @@ export function useItems() {
const leftItems = ref<Item[]>([])
const rightItems = ref<Item[]>([])
const rightItemsTotal = ref(0)
const leftItemsTotal = ref(0)
const leftSearch = ref('')
const rightSearch = ref('')
const leftLoading = ref(false)
@@ -27,13 +29,14 @@ export function useItems() {
return
leftLoading.value = true
try {
const data: PaginatedItems = await client.api.itemsList({
const data = await client.api.itemsList({
page: leftPage.value,
limit: 20,
...(leftSearch.value ? { search: leftSearch.value } : {}),
})
leftItems.value.push(...(data.data ?? []))
leftHasMore.value = data.hasMore ?? false
leftItemsTotal.value = data.total || 0
leftPage.value++
}
finally {
@@ -51,13 +54,14 @@ export function useItems() {
return
rightLoading.value = true
try {
const data: PaginatedItems = await client.api.itemsSelectedList({
const data = await client.api.itemsSelectedList({
page: rightPage.value,
limit: 20,
...(rightSearch.value ? { search: rightSearch.value } : {}),
})
rightItems.value.push(...(data.data ?? []))
rightHasMore.value = data.hasMore ?? false
rightItemsTotal.value = data.total || 0
rightPage.value++
}
finally {
@@ -86,7 +90,9 @@ export function useItems() {
return {
leftItems,
leftItemsTotal,
rightItems,
rightItemsTotal,
leftSearch,
rightSearch,
leftLoading,