This commit is contained in:
Nikolaj
2026-03-26 13:29:43 +01:00
parent 3a634e84ee
commit 6e23e32bb0
4 changed files with 33 additions and 1 deletions

View File

@@ -243,6 +243,7 @@ WIKIDATA_INSTANCE_TYPE_MAP = {
"Q24034552": CardType.science_thing, # mathematical concept
"Q12089225": CardType.science_thing, # mineral species
"Q55640599": CardType.science_thing, # group of chemical entities
"Q17339814": CardType.science_thing, # group or class of chemical substances
"Q119459661": CardType.science_thing, # scientific activity
"Q113145171": CardType.science_thing, # type of chemical entity

View File

@@ -163,6 +163,14 @@ def get_cards(user: UserModel = Depends(get_current_user), db: Session = Depends
for card in cards
]
@app.get("/cards/in-decks")
def get_cards_in_decks(user: UserModel = Depends(get_current_user), db: Session = Depends(get_db)):
deck_ids = [d.id for d in db.query(DeckModel).filter(DeckModel.user_id == user.id, DeckModel.deleted == False).all()]
if not deck_ids:
return []
card_ids = db.query(DeckCardModel.card_id).filter(DeckCardModel.deck_id.in_(deck_ids)).distinct().all()
return [str(row.card_id) for row in card_ids]
@app.post("/open_pack")
@limiter.limit("10/minute")
async def open_pack(request: Request, user: UserModel = Depends(get_current_user), db: Session = Depends(get_db)):

View File

@@ -8,6 +8,7 @@
let {
allCards = [],
selectedIds = $bindable(new Set()),
inDeckIds = new Set(),
onclose = null,
costLimit = null, // if set, prevents selecting cards that would exceed it
showFooter = true, // set false to hide the Done button (e.g. inline deck builder)
@@ -185,6 +186,9 @@
{#if selectedIds.has(card.id)}
<div class="selected-badge"></div>
{/if}
{#if inDeckIds.has(card.id)}
<div class="in-deck-badge" title="In a deck"></div>
{/if}
</button>
{/each}
</div>
@@ -410,6 +414,21 @@
z-index: 10;
}
.in-deck-badge {
position: absolute;
top: 6px;
right: 6px;
background: rgba(13, 8, 2, 0.75);
color: #7ecfcf;
font-size: 16px;
line-height: 1;
padding: 3px 5px;
border-radius: 6px;
border: 1px solid rgba(126, 207, 207, 0.5);
pointer-events: none;
z-index: 10;
}
.status {
font-family: 'Crimson Text', serif;
font-size: 16px;

View File

@@ -11,20 +11,23 @@
let selectorOpen = $state(false);
let shattering = $state(false);
let result = $state(null); // { gained, shards }
let inDeckIds = $state(new Set());
const selectedCards = $derived(allCards.filter(c => selectedIds.has(c.id)));
const totalYield = $derived(selectedCards.reduce((sum, c) => sum + c.cost, 0));
onMount(async () => {
if (!localStorage.getItem('token')) { goto('/auth'); return; }
const [cardsRes, profileRes] = await Promise.all([
const [cardsRes, profileRes, inDecksRes] = await Promise.all([
apiFetch(`${API_URL}/cards`),
apiFetch(`${API_URL}/profile`),
apiFetch(`${API_URL}/cards/in-decks`),
]);
if (cardsRes.status === 401) { goto('/auth'); return; }
allCards = await cardsRes.json();
const profile = await profileRes.json();
shards = profile.shards;
if (inDecksRes.ok) inDeckIds = new Set(await inDecksRes.json());
});
async function shatter() {
@@ -95,6 +98,7 @@
<CardSelector
allCards={allCards}
bind:selectedIds={selectedIds}
{inDeckIds}
onclose={() => { selectorOpen = false; }}
/>
</div>