@ -5,17 +5,21 @@
< / div >
< / div >
< VAlert v -else -if = " error & & ! list " type = "error" :message ="error" class = "mb-4" >
< VAlert v -else -if = " error & & ! list " type = "error" :message ="error" class = "mb-4" >
< template # actions > < VButton @click ="fetchListDetails" > Retry < / VButton > < / template >
< template # actions >
< VButton @click ="fetchListDetails" > Retry < / VButton >
< / template >
< / VAlert >
< / VAlert >
< template v -else -if = " list " >
< template v -else -if = " list " >
<!-- Header -- >
<!-- Header -- >
< div class = "neo-list-header" >
< div class = "neo-list-header" >
< VHeading level = "1" :text ="list.name" class = "mb-3 neo-title" / > { /* Kept neo-title for existing style */ }
< VHeading :level = "1" :text ="list.name" class = "mb-3 neo-title" / >
< div class = "neo-header-actions" >
< div class = "neo-header-actions" >
< VButton @ click = "showCostSummaryDialog = true" :disabled ="!isOnline" icon -left = " clipboard " > Cost Summary < / VButton >
< VButton @ click = "showCostSummaryDialog = true" :disabled ="!isOnline" icon -left = " clipboard " > Cost Summary
< / VButton >
< VButton @click ="openOcrDialog" :disabled ="!isOnline" icon -left = " plus " > Add via OCR < / VButton >
< VButton @click ="openOcrDialog" :disabled ="!isOnline" icon -left = " plus " > Add via OCR < / VButton >
< VBadge : text = "list.group_id ? 'Group List' : 'Personal List'" : variant = "list.group_id ? 'info' : 'success'" class = "neo-status" / > { /* Kept neo-status for existing style */ }
< VBadge : text = "list.group_id ? 'Group List' : 'Personal List'" : variant = "list.group_id ? 'accent' : 'settled'"
class = "neo-status" / >
< / div >
< / div >
< / div >
< / div >
< p v-if ="list.description" class="neo-description" > {{ list.description }} < / p >
< p v-if ="list.description" class="neo-description" > {{ list.description }} < / p >
@ -24,41 +28,34 @@
< VCard v-if ="itemsAreLoading" class="py-10 text-center mt-4" >
< VCard v-if ="itemsAreLoading" class="py-10 text-center mt-4" >
< VSpinner label = "Loading items..." size = "lg" / >
< VSpinner label = "Loading items..." size = "lg" / >
< / VCard >
< / VCard >
< VCard v -else -if = " ! itemsAreLoading & & list.items.length = = = 0 " variant = "empty-state" empty -icon = " clipboard " empty -title = " No Items Yet ! " empty -message = " Add some items using the form below. " class = "mt-4" / >
< VCard v -else -if = " ! itemsAreLoading & & list.items.length = = = 0 " variant = "empty-state" empty -icon = " clipboard "
empty - title = "No Items Yet!" empty - message = "Add some items using the form below." class = "mt-4" / >
< VCard v -else class = "mt-4" >
< VCard v -else class = "mt-4" >
< VList class = "item-list-tight" > { /* Assuming item-list-tight might be needed or VList default is fine */ }
< VList class = "item-list-tight" >
< VListItem v-for ="item in list.items" :key="item.id" class="item-with-actions" :class="{ 'bg-gray-100 opacity-70': item.is_complete }" >
< VListItem v -for = " item in list.items " :key ="item.id" class = "item-with-actions"
: class = "{ 'bg-gray-100 opacity-70': item.is_complete }" >
< template # default >
< template # default >
< div class = "flex items-center flex-grow gap-2" >
< div class = "flex items-center flex-grow gap-2" >
< VCheckbox
< VCheckbox :model-value ="item.is_complete" @ update : modelValue = "confirmUpdateItem(item, $event)"
: model - value = "item.is_complete"
: disabled = "item.updating" : aria - label = "item.name" / >
@ update : modelValue = "confirmUpdateItem(item, $event)"
: disabled = "item.updating"
: aria - label = "item.name"
/ >
< div class = "flex-grow" >
< div class = "flex-grow" >
< span class = "item-name" : class = "{ 'line-through': item.is_complete}"> { { item . name } } < / span >
< span class = "item-name" : class = "{ 'line-through': item.is_complete }" > { { item . name } } < / span >
< span v-if ="item.quantity" class="text-sm text-gray-500 ml-1" > × {{ item.quantity }} < / span >
< span v-if ="item.quantity" class="text-sm text-gray-500 ml-1" > × {{ item.quantity }} < / span >
< div v-if ="item.is_complete" class="mt-1" >
< div v-if ="item.is_complete" class="mt-1" >
< VInput
< VInput type = "number" : model -value = " item.priceInput | | ' ' "
type = "number"
@ update : modelValue = "item.priceInput = $event" placeholder = "Price" size = "sm" class = "w-24"
: model - value = "item.priceInput"
step = "0.01" @ blur = "updateItemPrice(item)"
@ update : modelValue = "item.priceInput = $event"
@ keydown . enter . prevent = "($event.target as HTMLInputElement).blur()" / >
placeholder = "Price"
size = "sm"
class = "w-24"
step = "0.01"
@ blur = "updateItemPrice(item)"
@ keydown . enter . prevent = "($event.target as HTMLInputElement).blur()"
/ >
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >
< div class = "flex items-center gap-1 ml-2" >
< div class = "flex items-center gap-1 ml-2" >
< VButton icon -only = " true " size = "sm" variant = "ghost" @click.stop ="editItem(item)" aria -label = " Edit item " >
< VButton :icon-only ="true" size = "sm" variant = "neutral" @click.stop ="editItem(item)"
aria - label = "Edit item" >
< VIcon name = "edit" / >
< VIcon name = "edit" / >
< / VButton >
< / VButton >
< VButton icon -only = " true " size = "sm" variant = "ghost" color = "danger" @click.stop ="confirmDeleteItem(item)" :disabled ="item.deleting" aria -label = " Delete item " >
< VButton :icon-only ="true" size = "sm" variant = "neutral" color = "danger"
@ click . stop = "confirmDeleteItem(item)" : disabled = "item.deleting" aria - label = "Delete item" >
< VIcon name = "trash" / >
< VIcon name = "trash" / >
< / VButton >
< / VButton >
< / div >
< / div >
@ -69,24 +66,15 @@
<!-- Add New Item Form -- >
<!-- Add New Item Form -- >
< form @submit.prevent ="onAddItem" class = "add-item-form mt-4 p-4 border rounded-lg shadow flex items-center gap-2" >
< form @submit.prevent ="onAddItem" class = "add-item-form mt-4 p-4 border rounded-lg shadow flex items-center gap-2" >
< VIcon name = "plus-circle" class = "text-gray-400 shrink-0" / > { /* Added shrink-0 */ }
< VIcon name = "plus-circle" class = "text-gray-400 shrink-0" / >
< VFormField class = "flex-grow" label = "New item name" :label-sr-only ="true" >
< VFormField class = "flex-grow" label = "New item name" :label-sr-only ="true" >
< VInput
< VInput v -model = " newItem.name " placeholder = "Add a new item" required ref = "itemNameInputRef" / >
v - model = "newItem.name"
placeholder = "Add a new item"
required
ref = "itemNameInputRef"
/ >
< / VFormField >
< / VFormField >
< VFormField label = "Quantity" :label-sr-only ="true" class = "w-24 shrink-0" > { /* Added shrink-0 and changed w-20 to w-24 for better fit */ }
< VFormField label = "Quantity" :label-sr-only ="true" class = "w-24 shrink-0" >
< VInput
< VInput type = "number" : model -value = " newItem.quantity | | ' ' " @ update : modelValue = "newItem.quantity = $event"
type = "number"
placeholder = "Qty" min = "1" / >
v - model = "newItem.quantity"
placeholder = "Qty"
min = "1"
/ >
< / VFormField >
< / VFormField >
< VButton type = "submit" :disabled ="addingItem" class = "shrink-0" > { /* Added shrink-0 */ }
< VButton type = "submit" :disabled ="addingItem" class = "shrink-0" >
< VSpinner v -if = " addingItem " size = "sm" / >
< VSpinner v -if = " addingItem " size = "sm" / >
< span v-else > Add < / span >
< span v-else > Add < / span >
< / VButton >
< / VButton >
@ -167,32 +155,38 @@
<!-- OCR Dialog -- >
<!-- OCR Dialog -- >
< VModal v-model ="showOcrDialogState" title="Add Items via OCR" @update:modelValue="!$event && closeOcrDialog()" >
< VModal v-model ="showOcrDialogState" title="Add Items via OCR" @update:modelValue="!$event && closeOcrDialog()" >
< template # default >
< template # default >
< div v-if ="ocrLoading" class="text-center" > < VSpinner label = "Processing image..." / > < / div >
< div v-if ="ocrLoading" class="text-center" >
< VSpinner label = "Processing image..." / >
< / div >
< VList v -else -if = " ocrItems.length > 0 " >
< VList v -else -if = " ocrItems.length > 0 " >
< VListItem v-for ="(ocrItem, index) in ocrItems" :key ="index" >
< VListItem v-for ="(ocrItem, index) in ocrItems" :key ="index" >
< div class = "flex items-center gap-2" >
< div class = "flex items-center gap-2" >
< VInput type = "text" v -model = " ocrItem.name " class = "flex-grow" required / >
< VInput type = "text" v -model = " ocrItem.name " class = "flex-grow" required / >
< VButton variant = "danger" size = "sm" :icon-only ="true" iconLeft = "trash" @ click = "ocrItems.splice(index, 1)" / >
< VButton variant = "danger" size = "sm" :icon-only ="true" iconLeft = "trash"
@ click = "ocrItems.splice(index, 1)" / >
< / div >
< / div >
< / VListItem >
< / VListItem >
< / VList >
< / VList >
< VFormField v -else label = "Upload Image" :error-message ="ocrError" >
< VFormField v -else label = "Upload Image" : error -message = " ocrError | | undefined " >
< VInput type = "file" id = "ocrFile" accept = "image/*" @change ="handleOcrFileUpload" ref = "ocrFileInputRef" / >
< VInput type = "file" id = "ocrFile" accept = "image/*" @change ="handleOcrFileUpload" ref = "ocrFileInputRef"
: model - value = "''" / >
< / VFormField >
< / VFormField >
< / template >
< / template >
< template # footer >
< template # footer >
< VButton variant = "neutral" @click ="closeOcrDialog" > Cancel < / VButton >
< VButton variant = "neutral" @click ="closeOcrDialog" > Cancel < / VButton >
< VButton v-if ="ocrItems.length > 0" type="button" variant="primary" @click="addOcrItems" :disabled ="addingOcrItems" >
< VButton v -if = " ocrItems.length > 0 " type=" button " variant=" primary " @click=" addOcrItems "
< VSpinner v -if = " addingOcrItems " size = "sm" / > Add Items
: disabled = "addingOcrItems" >
< VSpinner v -if = " addingOcrItems " size = "sm" / > Add Items
< / VButton >
< / VButton >
< / template >
< / template >
< / VModal >
< / VModal >
<!-- Confirmation Dialog -- >
<!-- Confirmation Dialog -- >
< VModal v-model ="showConfirmDialogState" title="Confirmation" @update:modelValue="!$event && cancelConfirmation()" size="sm" >
< VModal v -model = " showConfirmDialogState " title = "Confirmation" @ update : modelValue = "!$event && cancelConfirmation()"
size = "sm" >
< template # default >
< template # default >
< div class = "text-center" >
< div class = "text-center" >
< VIcon name = "alert-triangle" size = "lg" class = "text-yellow-500 mb-2" / > { /* Ensure text-yellow-500 is defined or use VAlert type="warning" */ }
< VIcon name = "alert-triangle" size = "lg" class = "text-yellow-500 mb-2" / >
< p > { { confirmDialogMessage } } < / p >
< p > { { confirmDialogMessage } } < / p >
< / div >
< / div >
< / template >
< / template >
@ -203,9 +197,12 @@
< / VModal >
< / VModal >
<!-- Cost Summary Dialog -- >
<!-- Cost Summary Dialog -- >
< VModal v-model ="showCostSummaryDialog" title="List Cost Summary" @update:modelValue="showCostSummaryDialog = false" size="lg" >
< VModal v -model = " showCostSummaryDialog " title = "List Cost Summary" @ update : modelValue = "showCostSummaryDialog = false"
size = "lg" >
< template # default >
< template # default >
< div v-if ="costSummaryLoading" class="text-center" > < VSpinner label = "Loading summary..." / > < / div >
< div v-if ="costSummaryLoading" class="text-center" >
< VSpinner label = "Loading summary..." / >
< / div >
< VAlert v -else -if = " costSummaryError " type = "error" :message ="costSummaryError" / >
< VAlert v -else -if = " costSummaryError " type = "error" :message ="costSummaryError" / >
< div v -else -if = " listCostSummary " >
< div v -else -if = " listCostSummary " >
< div class = "mb-3 cost-overview" >
< div class = "mb-3 cost-overview" >
@ -230,7 +227,8 @@
< td class = "text-right" > { { formatCurrency ( userShare . items _added _value ) } } < / td >
< td class = "text-right" > { { formatCurrency ( userShare . items _added _value ) } } < / td >
< td class = "text-right" > { { formatCurrency ( userShare . amount _due ) } } < / td >
< td class = "text-right" > { { formatCurrency ( userShare . amount _due ) } } < / td >
< td class = "text-right" >
< td class = "text-right" >
< VBadge :text ="formatCurrency(userShare.balance)" : variant = "parseFloat(String(userShare.balance)) >= 0 ? 'success' : 'pending'" / >
< VBadge :text ="formatCurrency(userShare.balance)"
: variant = "parseFloat(String(userShare.balance)) >= 0 ? 'settled' : 'pending'" / >
< / td >
< / td >
< / tr >
< / tr >
< / tbody >
< / tbody >
@ -245,19 +243,23 @@
< / VModal >
< / VModal >
<!-- Settle Share Modal -- >
<!-- Settle Share Modal -- >
< VModal v-model ="showSettleModal" title="Settle Share" @update:modelValue="!$event && closeSettleShareModal()" size="md" >
< VModal v -model = " showSettleModal " title = "Settle Share" @ update : modelValue = "!$event && closeSettleShareModal()"
size = "md" >
< template # default >
< template # default >
< div v-if ="isSettlementLoading" class="text-center" > < VSpinner label = "Processing settlement..." / > < / div >
< div v-if ="isSettlementLoading" class="text-center" >
< VSpinner label = "Processing settlement..." / >
< / div >
< VAlert v -else -if = " settleAmountError " type = "error" :message ="settleAmountError" / >
< VAlert v -else -if = " settleAmountError " type = "error" :message ="settleAmountError" / >
< div v-else >
< div v-else >
< p > Settle amount for { { selectedSplitForSettlement ? . user ? . name || selectedSplitForSettlement ? . user ? . email || ` User ID: ${ selectedSplitForSettlement ? . user _id } ` } } : < / p >
< p > Settle amount for { { selectedSplitForSettlement ? . user ? . name || selectedSplitForSettlement ? . user ? . email ||
< VFormField label = "Amount" :error-message ="settleAmountError" > { /* Error message was shown above, consider if needed here too */ }
` User ID: ${ selectedSplitForSettlement ? . user _id } ` } } : < / p >
< VFormField label = "Amount" : error -message = " settleAmountError | | undefined " >
< VInput type = "number" v -model = " settleAmount " id = "settleAmount" required / >
< VInput type = "number" v -model = " settleAmount " id = "settleAmount" required / >
< / VFormField >
< / VFormField >
< / div >
< / div >
< / template >
< / template >
< template # footer >
< template # footer >
< VButton variant = "neutral" @click ="closeSettleShareModal" > Cancel < / VButton > { / * Added Cancel for consistency * / }
< VButton variant = "neutral" @click ="closeSettleShareModal" > Cancel < / VButton >
< VButton variant = "primary" @click ="handleConfirmSettle" > Confirm < / VButton >
< VButton variant = "primary" @click ="handleConfirmSettle" > Confirm < / VButton >
< / template >
< / template >
< / VModal >
< / VModal >
@ -265,20 +267,22 @@
<!-- Edit Item Dialog -- >
<!-- Edit Item Dialog -- >
< VModal v-model ="showEditDialog" title="Edit Item" @update:modelValue="!$event && closeEditDialog()" >
< VModal v-model ="showEditDialog" title="Edit Item" @update:modelValue="!$event && closeEditDialog()" >
< template # default >
< template # default >
< VFormField v-if ="editingItem" label="Item Name" class="mb-4" > { / * Added margin * / }
< VFormField v-if ="editingItem" label="Item Name" class="mb-4" >
< VInput type = "text" id = "editItemName" v -model = " editingItem.name " required / >
< VInput type = "text" id = "editItemName" v -model = " editingItem.name " required / >
< / VFormField >
< / VFormField >
< VFormField v-if ="editingItem" label="Quantity" >
< VFormField v-if ="editingItem" label="Quantity" >
< VInput type = "number" id = "editItemQuantity" v -model .number = " editingItem.quantity " min = "1" / >
< VInput type = "number" id = "editItemQuantity" : model -value = " editingItem.quantity | | ' ' "
@ update : modelValue = "editingItem.quantity = $event" min = "1" / >
< / VFormField >
< / VFormField >
< / template >
< / template >
< template # footer >
< template # footer >
< VButton variant = "neutral" @click ="closeEditDialog" > Cancel < / VButton >
< VButton variant = "neutral" @click ="closeEditDialog" > Cancel < / VButton >
< VButton variant = "primary" @click ="handleConfirmEdit" :disabled ="!editingItem?.name.trim()" > Save Changes < / VButton >
< VButton variant = "primary" @click ="handleConfirmEdit" :disabled ="!editingItem?.name.trim()" > Save Changes
< / VButton >
< / template >
< / template >
< / VModal >
< / VModal >
< VAlert v - else type = "info" message = "Group not found or an error occurred." / >
< VAlert v - if= " ! list & & ! pageInitialLoad " type = "info" message = "Group not found or an error occurred." / >
< / main >
< / main >
< / template >
< / template >
@ -533,7 +537,9 @@ const isItemPendingSync = (item: Item) => {
const onAddItem = async ( ) => {
const onAddItem = async ( ) => {
if ( ! list . value || ! newItem . value . name . trim ( ) ) {
if ( ! list . value || ! newItem . value . name . trim ( ) ) {
notificationStore . addNotification ( { message : 'Please enter an item name.' , type : 'warning' } ) ;
notificationStore . addNotification ( { message : 'Please enter an item name.' , type : 'warning' } ) ;
itemNameInputRef . value ? . focus ? . ( ) ; / / U p d a t e d f o c u s c a l l
if ( itemNameInputRef . value ? . $el ) {
( itemNameInputRef . value . $el as HTMLElement ) . focus ( ) ;
}
return ;
return ;
}
}
addingItem . value = true ;
addingItem . value = true ;
@ -569,7 +575,9 @@ const onAddItem = async () => {
} ;
} ;
list . value . items . push ( optimisticItem ) ;
list . value . items . push ( optimisticItem ) ;
newItem . value = { name : '' } ;
newItem . value = { name : '' } ;
itemNameInputRef . value ? . focus ? . ( ) ; / / U p d a t e d f o c u s c a l l
if ( itemNameInputRef . value ? . $el ) {
( itemNameInputRef . value . $el as HTMLElement ) . focus ( ) ;
}
addingItem . value = false ;
addingItem . value = false ;
return ;
return ;
}
}
@ -585,7 +593,9 @@ const onAddItem = async () => {
const addedItem = response . data as Item ;
const addedItem = response . data as Item ;
list . value . items . push ( processListItems ( [ addedItem ] ) [ 0 ] ) ;
list . value . items . push ( processListItems ( [ addedItem ] ) [ 0 ] ) ;
newItem . value = { name : '' } ;
newItem . value = { name : '' } ;
itemNameInputRef . value ? . focus ? . ( ) ; / / U p d a t e d f o c u s c a l l
if ( itemNameInputRef . value ? . $el ) {
( itemNameInputRef . value . $el as HTMLElement ) . focus ( ) ;
}
} catch ( err ) {
} catch ( err ) {
notificationStore . addNotification ( { message : ( err instanceof Error ? err . message : String ( err ) ) || 'Failed to add item.' , type : 'error' } ) ;
notificationStore . addNotification ( { message : ( err instanceof Error ? err . message : String ( err ) ) || 'Failed to add item.' , type : 'error' } ) ;
} finally {
} finally {
@ -729,7 +739,7 @@ const openOcrDialog = () => {
/ / V I n p u t s h o u l d h a n d l e i t s o w n r e s e t i f n e c e s s a r y , o r t h i s r e f m i g h t t a r g e t t h e n a t i v e i n p u t i n s i d e .
/ / V I n p u t s h o u l d h a n d l e i t s o w n r e s e t i f n e c e s s a r y , o r t h i s r e f m i g h t t a r g e t t h e n a t i v e i n p u t i n s i d e .
if ( ocrFileInputRef . value && ocrFileInputRef . value . $el ) { / / A s s u m i n g V I n p u t e x p o s e s $ e l
if ( ocrFileInputRef . value && ocrFileInputRef . value . $el ) { / / A s s u m i n g V I n p u t e x p o s e s $ e l
const inputElement = ocrFileInputRef . value . $el . querySelector ( 'input[type="file"]' ) || ocrFileInputRef . value . $el ;
const inputElement = ocrFileInputRef . value . $el . querySelector ( 'input[type="file"]' ) || ocrFileInputRef . value . $el ;
if ( inputElement ) ( inputElement as HTMLInputElement ) . value = '' ;
if ( inputElement ) ( inputElement as HTMLInputElement ) . value = '' ;
} else if ( ocrFileInputRef . value ) { / / F a l l b a c k i f r e f i s n a t i v e i n p u t
} else if ( ocrFileInputRef . value ) { / / F a l l b a c k i f r e f i s n a t i v e i n p u t
( ocrFileInputRef . value as any ) . value = '' ;
( ocrFileInputRef . value as any ) . value = '' ;
}
}
@ -776,7 +786,7 @@ const handleOcrUpload = async (file: File) => {
ocrLoading . value = false ;
ocrLoading . value = false ;
if ( ocrFileInputRef . value && ocrFileInputRef . value . $el ) {
if ( ocrFileInputRef . value && ocrFileInputRef . value . $el ) {
const inputElement = ocrFileInputRef . value . $el . querySelector ( 'input[type="file"]' ) || ocrFileInputRef . value . $el ;
const inputElement = ocrFileInputRef . value . $el . querySelector ( 'input[type="file"]' ) || ocrFileInputRef . value . $el ;
if ( inputElement ) ( inputElement as HTMLInputElement ) . value = '' ;
if ( inputElement ) ( inputElement as HTMLInputElement ) . value = '' ;
} else if ( ocrFileInputRef . value ) {
} else if ( ocrFileInputRef . value ) {
( ocrFileInputRef . value as any ) . value = '' ;
( ocrFileInputRef . value as any ) . value = '' ;
}
}
@ -872,7 +882,9 @@ useEventListener(window, 'keydown', (event: KeyboardEvent) => {
return ;
return ;
}
}
event . preventDefault ( ) ;
event . preventDefault ( ) ;
itemNameInputRef . value ? . focus ? . ( ) ; / / U p d a t e d f o c u s c a l l
if ( itemNameInputRef . value ? . $el ) {
( itemNameInputRef . value . $el as HTMLElement ) . focus ( ) ;
}
}
}
} ) ;
} ) ;
@ -1340,12 +1352,14 @@ const handleExpenseCreated = (expense: any) => {
flex - direction : column ;
flex - direction : column ;
}
}
. item - name { /* Added for VListItem content */
. item - name {
/* Added for VListItem content */
font - size : 1.1 rem ;
font - size : 1.1 rem ;
font - weight : 700 ;
font - weight : 700 ;
}
}
. neo - item - complete . item - name { /* Adjusted for VListItem */
. neo - item - complete . item - name {
/* Adjusted for VListItem */
text - decoration : line - through ;
text - decoration : line - through ;
/* opacity: 0.6; Combined with bg-gray-100 opacity-70 on VListItem */
/* opacity: 0.6; Combined with bg-gray-100 opacity-70 on VListItem */
}
}
@ -1409,17 +1423,14 @@ const handleExpenseCreated = (expense: any) => {
}
}
. neo - action - button {
. neo - action - button {
background : # fff ;
/* General button, mostly replaced by VButton */
border : 3 px solid # 111 ;
background : # 111 ;
color : white ;
border : none ;
border - radius : 8 px ;
border - radius : 8 px ;
padding : 0.6 rem 1 rem ;
padding : 0.6 rem 1 rem ;
font - weight : 700 ;
font - weight : 700 ;
cursor : pointer ;
cursor : pointer ;
display : flex ;
align - items : center ;
gap : 0.5 rem ;
box - shadow : 3 px 3 px 0 # 111 ;
transition : transform 0.1 s ease - in - out , box - shadow 0.1 s ease - in - out ;
}
}
. neo - action - button : hover {
. neo - action - button : hover {
@ -1437,7 +1448,8 @@ const handleExpenseCreated = (expense: any) => {
cursor : not - allowed ;
cursor : not - allowed ;
}
}
. add - item - form { /* Added for new form styling */
. add - item - form {
/* Added for new form styling */
/* display: flex; (already on class) */
/* display: flex; (already on class) */
/* gap: 0.5rem; (already on class) */
/* gap: 0.5rem; (already on class) */
/* margin-top: 1rem; (original was 2rem, now mt-4) */
/* margin-top: 1rem; (original was 2rem, now mt-4) */
@ -1449,12 +1461,14 @@ const handleExpenseCreated = (expense: any) => {
}
}
. neo - new - item - form { /* Kept for reference, but form tag itself is now styled */
. neo - new - item - form {
/* Kept for reference, but form tag itself is now styled */
width : 100 % ;
width : 100 % ;
gap : 10 px ;
gap : 10 px ;
}
}
. neo - text - input { /* Not directly used by VInput, but kept for reference */
. neo - text - input {
/* Not directly used by VInput, but kept for reference */
flex - grow : 1 ;
flex - grow : 1 ;
border : 2 px solid # 111 ;
border : 2 px solid # 111 ;
border - radius : 8 px ;
border - radius : 8 px ;
@ -1463,7 +1477,8 @@ const handleExpenseCreated = (expense: any) => {
font - weight : 500 ;
font - weight : 500 ;
}
}
. neo - new - item - input { /* Not directly used by VInput, but kept for reference */
. neo - new - item - input {
/* Not directly used by VInput, but kept for reference */
background : transparent ;
background : transparent ;
border : none ;
border : none ;
outline : none ;
outline : none ;
@ -1475,13 +1490,16 @@ const handleExpenseCreated = (expense: any) => {
flex - grow : 1 ;
flex - grow : 1 ;
}
}
. neo - new - item - input : : placeholder { /* VInput handles its own placeholder styling */
. neo - new - item - input : : placeholder {
/* VInput handles its own placeholder styling */
color : # 999 ;
color : # 999 ;
font - weight : 500 ;
font - weight : 500 ;
}
}
. neo - quantity - input { /* Not directly used by VInput, but kept for reference */
. neo - quantity - input {
width : 80 px ; /* This specific width is now on VFormField for quantity */
/* Not directly used by VInput, but kept for reference */
width : 80 px ;
/* This specific width is now on VFormField for quantity */
border : 2 px solid # 111 ;
border : 2 px solid # 111 ;
border - radius : 8 px ;
border - radius : 8 px ;
padding : 0.4 rem ;
padding : 0.4 rem ;
@ -1489,7 +1507,8 @@ const handleExpenseCreated = (expense: any) => {
font - weight : 500 ;
font - weight : 500 ;
}
}
. neo - number - input { /* For price input, now VInput with class="w-24" */
. neo - number - input {
/* For price input, now VInput with class="w-24" */
border : 2 px solid # 111 ;
border : 2 px solid # 111 ;
border - radius : 6 px ;
border - radius : 6 px ;
padding : 0.5 rem ;
padding : 0.5 rem ;
@ -1497,7 +1516,8 @@ const handleExpenseCreated = (expense: any) => {
width : 100 px ;
width : 100 px ;
}
}
. neo - add - button { /* Replaced by VButton */
. neo - add - button {
/* Replaced by VButton */
background : # 111 ;
background : # 111 ;
color : white ;
color : white ;
border : none ;
border : none ;
@ -1509,7 +1529,8 @@ const handleExpenseCreated = (expense: any) => {
height : 2 rem ;
height : 2 rem ;
}
}
. neo - button { /* General button, mostly replaced by VButton */
. neo - button {
/* General button, mostly replaced by VButton */
background : # 111 ;
background : # 111 ;
color : white ;
color : white ;
border : none ;
border : none ;
@ -1520,7 +1541,8 @@ const handleExpenseCreated = (expense: any) => {
cursor : pointer ;
cursor : pointer ;
}
}
. new - item - input { /* Styling for the old li wrapper of add item form, can be removed */
. new - item - input {
/* Styling for the old li wrapper of add item form, can be removed */
margin - top : 0.5 rem ;
margin - top : 0.5 rem ;
padding : 0.5 rem ;
padding : 0.5 rem ;
}
}
@ -1561,7 +1583,8 @@ const handleExpenseCreated = (expense: any) => {
gap : 0.5 rem ;
gap : 0.5 rem ;
}
}
. neo - action - button { /* VButton has its own sizing */
. neo - action - button {
/* VButton has its own sizing */
padding : 0.8 rem ;
padding : 0.8 rem ;
font - size : 0.9 rem ;
font - size : 0.9 rem ;
}
}
@ -1575,7 +1598,8 @@ const handleExpenseCreated = (expense: any) => {
padding : 1 rem ;
padding : 1 rem ;
} * /
} * /
. item - name { /* Adjusted for VListItem */
. item - name {
/* Adjusted for VListItem */
font - size : 1 rem ;
font - size : 1 rem ;
}
}
@ -1588,11 +1612,13 @@ const handleExpenseCreated = (expense: any) => {
height : 1.4 em ;
height : 1.4 em ;
} * /
} * /
. neo - icon - button { /* VButton icon-only replaces this */
. neo - icon - button {
/* VButton icon-only replaces this */
padding : 0.6 rem ;
padding : 0.6 rem ;
}
}
. add - item - form { /* Adjusted form class */
. add - item - form {
/* Adjusted form class */
flex - wrap : wrap ;
flex - wrap : wrap ;
gap : 0.5 rem ;
gap : 0.5 rem ;
}
}
@ -1617,21 +1643,25 @@ const handleExpenseCreated = (expense: any) => {
} * /
} * /
/* Optimize modals for mobile */
/* Optimize modals for mobile */
. modal - container { /* VModal has its own responsive sizing via props/CSS */
. modal - container {
/* VModal has its own responsive sizing via props/CSS */
width : 95 % ;
width : 95 % ;
max - height : 85 vh ;
max - height : 85 vh ;
margin : 1 rem ;
margin : 1 rem ;
}
}
. modal - header { /* VModal slot */
. modal - header {
/* VModal slot */
padding : 1 rem ;
padding : 1 rem ;
}
}
. modal - body { /* VModal slot */
. modal - body {
/* VModal slot */
padding : 1 rem ;
padding : 1 rem ;
}
}
. modal - footer { /* VModal slot */
. modal - footer {
/* VModal slot */
padding : 1 rem ;
padding : 1 rem ;
}
}
@ -1643,17 +1673,20 @@ const handleExpenseCreated = (expense: any) => {
} * /
} * /
/* Optimize loading states for mobile */
/* Optimize loading states for mobile */
. neo - loading - state { /* VSpinner used instead */
. neo - loading - state {
/* VSpinner used instead */
padding : 2 rem 1 rem ;
padding : 2 rem 1 rem ;
}
}
. spinner - dots span { /* VSpinner has its own dot styling */
. spinner - dots span {
/* VSpinner has its own dot styling */
width : 10 px ;
width : 10 px ;
height : 10 px ;
height : 10 px ;
}
}
/* Improve scrolling performance */
/* Improve scrolling performance */
. item - list - tight { /* Assuming VList with this class */
. item - list - tight {
/* Assuming VList with this class */
- webkit - overflow - scrolling : touch ;
- webkit - overflow - scrolling : touch ;
}
}
@ -1689,7 +1722,8 @@ const handleExpenseCreated = (expense: any) => {
} * /
} * /
/* Improve scrolling performance */
/* Improve scrolling performance */
. item - list - tight { /* Assuming VList with this class */
. item - list - tight {
/* Assuming VList with this class */
will - change : transform ;
will - change : transform ;
transform : translateZ ( 0 ) ;
transform : translateZ ( 0 ) ;
}
}
@ -1725,42 +1759,152 @@ const handleExpenseCreated = (expense: any) => {
/* @keyframes dot-pulse { ... } */
/* @keyframes dot-pulse { ... } */
/* Utility classes that might still be used or can be replaced by Tailwind/global equivalents */
/* Utility classes that might still be used or can be replaced by Tailwind/global equivalents */
. flex { display : flex ; }
. flex {
. items - center { align - items : center ; }
display : flex ;
. justify - between { justify - content : space - between ; }
}
. gap - 1 { gap : 0.25 rem ; }
. gap - 2 { gap : 0.5 rem ; }
. items - center {
. ml - 1 { margin - left : 0.25 rem ; }
align - items : center ;
. ml - 2 { margin - left : 0.5 rem ; }
}
. mt - 1 { margin - top : 0.25 rem ; }
. mt - 2 { margin - top : 0.5 rem ; }
. justify - between {
. mt - 4 { margin - top : 1 rem ; }
justify - content : space - between ;
. mb - 2 { margin - bottom : 0.5 rem ; }
}
. mb - 3 { margin - bottom : 1 rem ; } /* Adjusted from 1.5rem to match common spacing */
. mb - 4 { margin - bottom : 1.5 rem ; }
. gap - 1 {
. py - 10 { padding - top : 2.5 rem ; padding - bottom : 2.5 rem ; }
gap : 0.25 rem ;
. py - 4 { padding - top : 1 rem ; padding - bottom : 1 rem ; }
}
. p - 4 { padding : 1 rem ; }
. border { border - width : 1 px ; /* Assuming default border color from global styles or Tailwind */ }
. gap - 2 {
. rounded - lg { border - radius : 0.5 rem ; }
gap : 0.5 rem ;
. shadow { box - shadow : 0 1 px 3 px 0 rgba ( 0 , 0 , 0 , 0.1 ) , 0 1 px 2 px 0 rgba ( 0 , 0 , 0 , 0.06 ) ; /* Example shadow */ }
}
. flex - grow { flex - grow : 1 ; }
. w - 24 { width : 6 rem ; } /* Tailwind w-24 */
. ml - 1 {
. text - sm { font - size : 0.875 rem ; }
margin - left : 0.25 rem ;
. text - gray - 500 { color : # 6 b7280 ; } /* Tailwind gray-500 */
}
. text - gray - 400 { color : # 9 ca3af ; } /* Tailwind gray-400 */
. text - green - 600 { color : # 16 a34a ; } /* Tailwind green-600 */
. ml - 2 {
. text - yellow - 500 { color : # eab308 ; } /* Tailwind yellow-500 */
margin - left : 0.5 rem ;
. line - through { text - decoration : line - through ; }
}
. opacity - 50 { opacity : 0.5 ; }
. opacity - 60 { opacity : 0.6 ; } /* Added for completed item name */
. mt - 1 {
. opacity - 70 { opacity : 0.7 ; } /* Added for completed item background */
margin - top : 0.25 rem ;
. shrink - 0 { flex - shrink : 0 ; }
}
. bg - gray - 100 { background - color : # f3f4f6 ; } /* Tailwind gray-100 */
. mt - 2 {
margin - top : 0.5 rem ;
}
. mt - 4 {
margin - top : 1 rem ;
}
. mb - 2 {
margin - bottom : 0.5 rem ;
}
. mb - 3 {
margin - bottom : 1 rem ;
}
/* Adjusted from 1.5rem to match common spacing */
. mb - 4 {
margin - bottom : 1.5 rem ;
}
. py - 10 {
padding - top : 2.5 rem ;
padding - bottom : 2.5 rem ;
}
. py - 4 {
padding - top : 1 rem ;
padding - bottom : 1 rem ;
}
. p - 4 {
padding : 1 rem ;
}
. border {
border - width : 1 px ;
/* Assuming default border color from global styles or Tailwind */
}
. rounded - lg {
border - radius : 0.5 rem ;
}
. shadow {
box - shadow : 0 1 px 3 px 0 rgba ( 0 , 0 , 0 , 0.1 ) , 0 1 px 2 px 0 rgba ( 0 , 0 , 0 , 0.06 ) ;
/* Example shadow */
}
. flex - grow {
flex - grow : 1 ;
}
. w - 24 {
width : 6 rem ;
}
/* Tailwind w-24 */
. text - sm {
font - size : 0.875 rem ;
}
. text - gray - 500 {
color : # 6 b7280 ;
}
/* Tailwind gray-500 */
. text - gray - 400 {
color : # 9 ca3af ;
}
/* Tailwind gray-400 */
. text - green - 600 {
color : # 16 a34a ;
}
/* Tailwind green-600 */
. text - yellow - 500 {
color : # eab308 ;
}
/* Tailwind yellow-500 */
. line - through {
text - decoration : line - through ;
}
. opacity - 50 {
opacity : 0.5 ;
}
. opacity - 60 {
opacity : 0.6 ;
}
/* Added for completed item name */
. opacity - 70 {
opacity : 0.7 ;
}
/* Added for completed item background */
. shrink - 0 {
flex - shrink : 0 ;
}
. bg - gray - 100 {
background - color : # f3f4f6 ;
}
/* Tailwind gray-100 */
/* Styles for .neo-list-card, .neo-item-list, .neo-item might be replaced by VCard/VList/VListItem defaults or props */
/* Styles for .neo-list-card, .neo-item-list, .neo-item might be replaced by VCard/VList/VListItem defaults or props */
/* Keeping some specific styles for .neo-item-details, .item-name, etc. if they are distinct. */
/* Keeping some specific styles for .neo-item-details, .item-name, etc. if they are distinct. */
. item - with - actions { /* Custom class for VListItem if needed for specific layout */
. item - with - actions {
/* Custom class for VListItem if needed for specific layout */
/* Default VListItem is display:flex, so this might not be needed or just for minor tweaks */
/* Default VListItem is display:flex, so this might not be needed or just for minor tweaks */
}
}
< / style >
< / style >