Skip to content

Commit 3cdd923

Browse files
committed
feat: expose more features to shared deck view
1 parent 7c64ceb commit 3cdd923

5 files changed

Lines changed: 425 additions & 45 deletions

File tree

‎assets/css/app.css‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,12 @@
143143
}
144144

145145
.app-shell-main--full {
146+
box-sizing: border-box;
146147
height: 100dvh;
147-
padding-top: calc(0.5rem + env(safe-area-inset-top, 0px));
148-
padding-bottom: calc(0.75rem + env(safe-area-inset-bottom, 0px));
148+
padding-top: env(safe-area-inset-top, 0px);
149+
padding-right: env(safe-area-inset-right, 0px);
150+
padding-bottom: env(safe-area-inset-bottom, 0px);
151+
padding-left: env(safe-area-inset-left, 0px);
149152
}
150153

151154
.control-toolbar {

‎assets/react/src/components/deck-playtester.tsx‎

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import { Badge } from "./ui/badge"
4040
import { Button } from "./ui/button"
4141

4242
type DeckPlaytesterProps = {
43+
closeSlot?: ReactNode
4344
deckId: string
4445
deckName: string
4546
initialState: PlaytestState
@@ -405,7 +406,7 @@ function cardZone(state: PlaytestState, cardId: string): PlaytestZone | null {
405406
return zones.find((zone) => state[zone].some((card) => card.id === cardId)) || null
406407
}
407408

408-
export function DeckPlaytester({ deckId, deckName, initialState }: DeckPlaytesterProps) {
409+
export function DeckPlaytester({ closeSlot, deckId, deckName, initialState }: DeckPlaytesterProps) {
409410
const [snapshot, setSnapshot] = useState(() => initialSnapshot(initialState))
410411
const [history, setHistory] = useState<PlaytestSnapshot[]>([])
411412
const [selectedCardId, setSelectedCardId] = useState<string | null>(null)
@@ -1026,9 +1027,9 @@ export function DeckPlaytester({ deckId, deckName, initialState }: DeckPlayteste
10261027
}, [activeKeyboardCard, changeLife, draw, keepHand, moveActiveKeyboardCard, mulligan, nextTurn, openingHand, shuffle, toggleTapped, undo, untapAll])
10271028

10281029
return (
1029-
<div className="h-[100dvh] overflow-hidden border-0 bg-[#0d0e0c] text-base-content shadow-2xl sm:h-[calc(100dvh-1.25rem)] sm:rounded-box sm:border sm:border-base-300 lg:min-h-[42rem]">
1030+
<div className="h-full min-h-0 overflow-hidden border-0 bg-[#0d0e0c] text-base-content shadow-2xl sm:rounded-box sm:border sm:border-base-300">
10301031
<div className="grid h-full grid-rows-[2.75rem_minmax(0,1fr)_auto_12rem] lg:grid-cols-[minmax(0,1fr)_14rem] lg:grid-rows-[2.75rem_minmax(0,1fr)_10.5rem]">
1031-
<PlaytestTopBar deckId={deckId} deckName={deckName} turn={turn} />
1032+
<PlaytestTopBar closeSlot={closeSlot} deckId={deckId} deckName={deckName} turn={turn} />
10321033

10331034
<main className="relative row-start-2 min-h-0 overflow-hidden border-y border-base-300/70 bg-[radial-gradient(circle_at_center,color-mix(in_oklch,var(--color-primary),transparent_88%),transparent_34rem)] lg:col-start-1">
10341035
<div className="absolute left-3 top-3 z-10 flex items-center gap-2 text-[0.65rem] font-black uppercase tracking-[0.22em] text-base-content/35">
@@ -1227,10 +1228,12 @@ export function DeckPlaytester({ deckId, deckName, initialState }: DeckPlayteste
12271228
}
12281229

12291230
function PlaytestTopBar({
1231+
closeSlot,
12301232
deckId,
12311233
deckName,
12321234
turn,
12331235
}: {
1236+
closeSlot?: ReactNode
12341237
deckId: string
12351238
deckName: string
12361239
turn: number
@@ -1243,14 +1246,16 @@ function PlaytestTopBar({
12431246
<div className="hidden rounded border border-base-300 bg-base-200 px-3 py-1 text-xs font-bold text-base-content/70 sm:block">
12441247
Turn {turn}
12451248
</div>
1246-
<Link
1247-
to="/decks/$id"
1248-
params={{ id: deckId }}
1249-
className="btn btn-ghost btn-xs gap-1 text-base-content/60"
1250-
>
1251-
<X className="h-3.5 w-3.5" />
1252-
Close
1253-
</Link>
1249+
{closeSlot || (
1250+
<Link
1251+
to="/decks/$id"
1252+
params={{ id: deckId }}
1253+
className="btn btn-ghost btn-xs gap-1 text-base-content/60"
1254+
>
1255+
<X className="h-3.5 w-3.5" />
1256+
Close
1257+
</Link>
1258+
)}
12541259
</header>
12551260
)
12561261
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
export type ExportableDeckCard = {
2+
card?: { name?: string | null } | null
3+
finish?: string | null
4+
preferredPrinting?: {
5+
collectorNumber?: string | null
6+
setCode?: string | null
7+
} | null
8+
quantity?: number | null
9+
zone?: string | null
10+
}
11+
12+
const EXPORT_ZONES = ["mainboard", "sideboard", "commander", "maybeboard"] as const
13+
14+
export function exportDecklistText(deckCards: ExportableDeckCard[]) {
15+
return EXPORT_ZONES.map((zone) => exportZone(deckCards, zone))
16+
.filter((section): section is string => Boolean(section))
17+
.join("\n\n")
18+
}
19+
20+
function exportZone(deckCards: ExportableDeckCard[], zone: string) {
21+
const lines = deckCards
22+
.filter((deckCard) => deckCard.zone === zone)
23+
.sort((left, right) =>
24+
(left.card?.name?.trim() || "").localeCompare(right.card?.name?.trim() || ""),
25+
)
26+
.map(exportLine)
27+
.filter(Boolean)
28+
29+
if (!lines.length) return null
30+
31+
const label =
32+
zone === "mainboard"
33+
? "Mainboard"
34+
: zone === "sideboard"
35+
? "Sideboard"
36+
: zone === "commander"
37+
? "Commander"
38+
: zone === "maybeboard"
39+
? "Maybeboard"
40+
: zone.charAt(0).toUpperCase() + zone.slice(1)
41+
42+
return `${label}\n${lines.join("\n")}`
43+
}
44+
45+
function exportLine(deckCard: ExportableDeckCard) {
46+
const name = deckCard.card?.name?.trim() || ""
47+
if (!name) return null
48+
49+
return [
50+
`${Math.max(deckCard.quantity || 0, 0)}x`,
51+
name,
52+
exportPrinting(deckCard.preferredPrinting),
53+
exportFinish(deckCard.finish),
54+
]
55+
.filter((part): part is string => Boolean(part))
56+
.join(" ")
57+
}
58+
59+
function exportPrinting(printing: ExportableDeckCard["preferredPrinting"]) {
60+
if (!printing?.setCode && !printing?.collectorNumber) return null
61+
return `(${(printing.setCode || "").toUpperCase()}) ${printing.collectorNumber || ""}`.trim()
62+
}
63+
64+
function exportFinish(finish?: string | null) {
65+
if (finish === "foil") return "*F*"
66+
if (finish === "etched") return "*E*"
67+
return null
68+
}
69+

0 commit comments

Comments
 (0)