diff --git a/backend/src/routes/items.ts b/backend/src/routes/items.ts index 518863b..cbdf8c1 100644 --- a/backend/src/routes/items.ts +++ b/backend/src/routes/items.ts @@ -137,6 +137,47 @@ itemsRouter.get('/selected', (req, res) => { * 400: * description: Invalid id */ +/** + * @openapi + * /api/items/add-value: + * post: + * summary: Create a new item with a given value + * tags: [Items] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * required: [value] + * properties: + * value: + * type: string + * responses: + * 200: + * description: Item created + * content: + * application/json: + * schema: + * type: object + * properties: + * id: + * type: integer + * value: + * type: string + * 400: + * description: Invalid value + */ +itemsRouter.post('/add-value', (req, res) => { + const value = req.body?.value + if (typeof value !== 'string' || value.trim() === '') { + res.status(400).json({ error: 'value must be a non-empty string' }) + return + } + const id = store.addItemByValue(value.trim()) + res.json({ id, value: value.trim() }) +}) + itemsRouter.post('/add', (req, res) => { const id = req.body?.id if (id === undefined || id === null || typeof id !== 'number' || !Number.isInteger(id)) { diff --git a/backend/src/services/itemsStore.ts b/backend/src/services/itemsStore.ts index e398ebb..1a5b438 100644 --- a/backend/src/services/itemsStore.ts +++ b/backend/src/services/itemsStore.ts @@ -87,6 +87,15 @@ export function addItem(id: number): boolean { return true } +let nextAutoId = 1_000_001 + +export function addItemByValue(value: string): number { + const id = nextAutoId++ + itemsById.set(id, value) + allItemsOrder.push(id) + return id +} + export function selectItem(id: number): boolean { if (selectedIds.has(id) || !itemsById.has(id)) return false selectedIds.add(id) diff --git a/frontend/app/app.vue b/frontend/app/app.vue index f93fac6..f03f39b 100644 --- a/frontend/app/app.vue +++ b/frontend/app/app.vue @@ -72,6 +72,7 @@ const { deselectItem, reorderItem, addItem, + addItemByValue, } = useItems() onMounted(() => { @@ -94,8 +95,10 @@ async function handleReorder(id: number, afterId: number | null): Promise await reorderItem(id, afterId) } -async function handleAdd(id: number) { - await addItem(id) +async function handleAdd(value: string) { + const item = await addItemByValue(value) + leftSearch.value = item.value + await fetchLeft(true) } diff --git a/frontend/app/components/LeftPanel.vue b/frontend/app/components/LeftPanel.vue index dc05e83..0a3aa2a 100644 --- a/frontend/app/components/LeftPanel.vue +++ b/frontend/app/components/LeftPanel.vue @@ -8,7 +8,7 @@ {{ total }} - @@ -97,7 +102,10 @@ @@ -280,6 +339,12 @@ function submitAdd() { &:active { transform: scale(0.97); } + + &:disabled { + opacity: 0.45; + cursor: not-allowed; + transform: none; + } } .btn-ghost { @@ -520,6 +585,7 @@ function submitAdd() { font-size: 0.875rem; color: var(--text-primary); outline: none; + box-sizing: border-box; transition: border-color 150ms ease, background 150ms ease; @@ -533,11 +599,6 @@ function submitAdd() { border-color: var(--text-primary); background: var(--surface); } - - &::-webkit-inner-spin-button, - &::-webkit-outer-spin-button { - -webkit-appearance: none; - } } .modal-footer { diff --git a/frontend/app/components/RightPanel.vue b/frontend/app/components/RightPanel.vue index ea54f71..e3a16a2 100644 --- a/frontend/app/components/RightPanel.vue +++ b/frontend/app/components/RightPanel.vue @@ -24,9 +24,11 @@ -
+
+