4.2 KiB
4.2 KiB
task, cycles, context, private, started, finished
| task | cycles | context | private | started | finished |
|---|---|---|---|---|---|
| Fix "Similar products already exist" modal layout — match-row cards unreadable on mobile (flex row squishes info text to single characters, Import button overlaps content) | 5 | true | false | 2026-05-28T16:30:42Z | 2026-05-28T16:31:11Z |
files
- resources/js/Pages/CreateProductUltimate.vue [lines 534-560] — fuzzy match modal template:
.match-rowitems with thumb, info, button - resources/js/Pages/CreateProductUltimate.vue [lines 875-914] — scoped CSS:
.match-row,.match-thumb,.match-infoand dark mode overrides
steps
- In
CreateProductUltimate.vuetemplate (lines 534-560), wrap theFileImage+.match-infodiv in a new<div class="match-row-top">inner wrapper, leaving the<button>outside it so the layout becomes: outer.match-row(column) →.match-row-top(thumb + info, row) + button (full-width, below) - Add
w-100class to the Import button so it spans the full card width on mobile - In the scoped CSS, change
.match-rowfromalign-items: centerflex-row to aflex-direction: column; gap: 10pxcolumn layout. Add.match-row-top { display: flex; align-items: center; gap: 12px; }rule. - Remove
align-items: centerfrom.match-row(it now stacks vertically, not horizontally) - Verify
.match-info { flex: 1; min-width: 0; }stays on.match-info(unchanged — still needed inside.match-row-top) - Build:
npm run buildthendocker restart bukidbountyapp
context
Current template structure (lines 534-560):
<div v-for="m in fuzzyMatches" :key="m.hashkey" class="match-row">
<FileImage :src="..." class="match-thumb" fallback="..." />
<div class="match-info">
<div class="fw_6">{{ m.name }}</div>
<div class="text-muted small">
<span v-if="m.category">{{ m.category }}<span v-if="m.subcategory"> · {{ m.subcategory }}</span> · </span>
<span>₱{{ m.price }} / {{ m.unitname }}</span>
</div>
<div v-if="m.already_in_store" class="text-success smallest mt-1">...</div>
</div>
<button class="btn btn-sm btn-primary rounded-pill" :disabled="m.already_in_store || isImporting" @click="importExistingProduct(m)">
<span v-if="isImporting"><LoadingSpinner size="small" /></span>
<span v-else-if="m.already_in_store">In Store</span>
<span v-else>Import to Store</span>
</button>
</div>
Target template structure:
<div v-for="m in fuzzyMatches" :key="m.hashkey" class="match-row">
<div class="match-row-top">
<FileImage :src="..." class="match-thumb" fallback="..." />
<div class="match-info">
<div class="fw_6">{{ m.name }}</div>
<div class="text-muted small">
<span v-if="m.category">{{ m.category }}<span v-if="m.subcategory"> · {{ m.subcategory }}</span> · </span>
<span>₱{{ m.price }} / {{ m.unitname }}</span>
</div>
<div v-if="m.already_in_store" class="text-success smallest mt-1">...</div>
</div>
</div>
<button class="btn btn-sm btn-primary rounded-pill w-100" :disabled="m.already_in_store || isImporting" @click="importExistingProduct(m)">
...
</button>
</div>
Current CSS (lines 875-890):
.match-row {
display: flex;
align-items: center; /* ← causes single-column squish when button competes for width */
gap: 12px;
padding: 12px 0;
border-bottom: 1px solid #f1f5f9;
}
.match-thumb { width: 56px; height: 56px; border-radius: 10px; object-fit: cover; flex-shrink: 0; }
.match-info { flex: 1; min-width: 0; }
Target CSS additions/changes:
.match-row {
display: flex;
flex-direction: column; /* vertical stack: top-row then button */
gap: 10px;
padding: 12px 0;
border-bottom: 1px solid #f1f5f9;
}
.match-row-top {
display: flex;
align-items: center;
gap: 12px;
}
/* .match-thumb and .match-info stay unchanged */
notes
- dictionary: ai-docs/dictionary.md
- linters: none
- constraints:
.bb-modal*styles are scoped toCreateProductUltimate.vue— do NOT touch global CSS. Dark mode override:global(.dark-mode) .match-rowat line 914 only setsborder-bottom-color— no changes needed there. - build:
npm run buildthendocker restart bukidbountyapp(see dictionary Build & Deployment Standards)