diff --git a/backend/src/controllers/flashcardController.js b/backend/src/controllers/flashcardController.js index 50f50a2..4a43a44 100644 --- a/backend/src/controllers/flashcardController.js +++ b/backend/src/controllers/flashcardController.js @@ -125,12 +125,16 @@ function addCardsBulk(req, res) { if (!Array.isArray(cards) || !cards.length) return res.status(400).json({ error: 'cards[] required' }); const maxIdx = db.prepare(`SELECT MAX(order_idx) AS m FROM flashcard_cards WHERE deck_id = ?`) .get(deck.id)?.m ?? -1; - const stmt = db.prepare(`INSERT INTO flashcard_cards (deck_id, front, back, order_idx) VALUES (?,?,?,?)`); + const stmt = db.prepare(`INSERT INTO flashcard_cards (deck_id, front, back, front_image, back_image, order_idx) VALUES (?,?,?,?,?,?)`); const inserted = []; const ins = db.transaction(() => { cards.forEach((c, i) => { - const r = stmt.run(deck.id, c.front || '', c.back || '', maxIdx + 1 + i); - inserted.push({ id: r.lastInsertRowid, front: c.front, back: c.back }); + const front = stripTags((c.front || '').slice(0, 5000)); + const back = stripTags((c.back || '').slice(0, 5000)); + const fImg = safeImg(c.front_image); + const bImg = safeImg(c.back_image); + const r = stmt.run(deck.id, front, back, fImg, bImg, maxIdx + 1 + i); + inserted.push({ id: r.lastInsertRowid, front, back, front_image: fImg, back_image: bImg }); }); }); ins(); diff --git a/frontend/flashcards.html b/frontend/flashcards.html index 9078d8c..1f00004 100644 --- a/frontend/flashcards.html +++ b/frontend/flashcards.html @@ -164,6 +164,19 @@ #new-card-imgs { display: none; gap: 14px; align-items: center; margin-bottom: 14px; flex-wrap: wrap; } .new-img-lbl { font-size: .7rem; font-weight: 700; color: var(--text-3); margin-right: 4px; } + /* bulk import preview */ + .bulk-preview-list { max-height: 56vh; overflow-y: auto; display: flex; flex-direction: column; + gap: 8px; margin-bottom: 6px; padding-right: 4px; } + .bulk-row { display: grid; grid-template-columns: 24px 1fr 1fr; gap: 8px; align-items: start; + background: var(--surface-2); border: 1px solid var(--border); border-radius: 10px; padding: 8px 10px; } + .bulk-row-n { font-size: .7rem; font-weight: 800; color: var(--text-3); padding-top: 3px; } + .bulk-row-side { display: flex; flex-direction: column; gap: 6px; min-width: 0; } + .bulk-row-txt { font-size: .8rem; color: var(--text); white-space: pre-wrap; word-break: break-word; line-height: 1.35; } + .bulk-row-empty { color: var(--text-3); font-style: italic; } + .bulk-img-wrap { position: relative; display: inline-block; } + .bulk-img-thumb { max-width: 110px; max-height: 64px; border-radius: 6px; display: block; + border: 1px solid var(--border); object-fit: cover; } + .card-add-bar { display: flex; gap: 10px; align-items: center; } .card-add-input { flex: 1; padding: 10px 14px; border: 1.5px solid var(--border); border-radius: 10px; font-family: 'Manrope', sans-serif; font-size: .88rem; background: #fff; @@ -463,16 +476,30 @@