diff --git a/.claude/DARK_MODE.md b/.claude/DARK_MODE.md new file mode 100644 index 0000000..d4761c4 --- /dev/null +++ b/.claude/DARK_MODE.md @@ -0,0 +1,188 @@ +# Dark Mode Style Guide + +## The Problem (Pre-January 2025) + +Our dark mode was "very blue" and garish because: + +1. **Slate is blue-tinted** - Tailwind's slate scale has a cool/blue undertone +2. **Cyan accent overload** - used for links, buttons, icons, focus states, everything +3. **Rainbow badge syndrome** - purple, indigo, rose, emerald, amber all fighting +4. **Inconsistent gray scales** - mixing `gray-` and `slate-` classes + +## The Fix: Neutral Grays + Restrained Accent + +Inspired by Discord and Linear's approach: +- True neutral backgrounds (zinc instead of slate) +- Single accent color (cyan) for primary actions only +- High contrast text (AAA compliant, 7.0+ ratio) +- Muted/semantic colors for badges and status +- Visible borders (zinc-600 for definition) + +## Design Principles + +**60-30-10 rule**: 60% background, 30% secondary/text, 10% accent. Don't overuse the accent color. + +**Text contrast for AAA (7.0+)**: +- zinc-100 on zinc-900 = 16.12:1 ✓ +- zinc-300 on zinc-900 = 11.99:1 ✓ (use for secondary text) +- zinc-400 on zinc-900 = 6.91:1 ✗ (below AAA, ok for muted/hints) +- zinc-500 on zinc-900 = 3.67:1 ✗ (placeholder text only) + +**Saturated colors glow on dark**: Use 400-shade colors sparingly. Desaturate or use lighter tones for large areas. + +**Borders matter more in dark mode**: Less visual differentiation between dark grays means borders need to be more visible (zinc-600 instead of zinc-700). + +## Color Palette + +### Backgrounds (zinc scale - true neutral) + +| Use Case | Light | Dark | +|----------|-------|------| +| Page background | `bg-white` | `dark:bg-zinc-900` | +| Elevated surface (cards, panels) | `bg-gray-50` | `dark:bg-zinc-800` | +| Hover/active states | `bg-gray-100` | `dark:bg-zinc-700` | +| Input backgrounds | `bg-white` | `dark:bg-zinc-800` | +| Subtle dividers | `bg-gray-200` | `dark:bg-zinc-700` | + +### Text + +| Use Case | Light | Dark | Dark Contrast | +|----------|-------|------|---------------| +| Primary text | `text-gray-900` | `dark:text-zinc-100` | 16.12:1 ✓ AAA | +| Secondary text | `text-gray-600` | `dark:text-zinc-300` | 11.99:1 ✓ AAA | +| Muted/tertiary | `text-gray-500` | `dark:text-zinc-400` | 6.91:1 ✗ AA only | +| Placeholder | `text-gray-400` | `dark:text-zinc-500` | 3.67:1 ✗ decorative | + +### Borders + +| Use Case | Light | Dark | +|----------|-------|------| +| Default border | `border-gray-200` | `dark:border-zinc-600` | +| Subtle border | `border-gray-100` | `dark:border-zinc-700` | +| Strong border | `border-gray-300` | `dark:border-zinc-500` | +| Focus ring | `ring-cyan-500` | `dark:ring-cyan-400` | + +### Accent Colors (Cyan) + +**Light cyan needs dark text; dark cyan can use white text.** + +Contrast ratios (calculated via WCAG formula): + +| Shade | + White | + Gray-900 | Best Text | +|-------|---------|------------|-----------| +| cyan-400 (#22d3ee) | 1.81:1 ✗ | 9.82:1 ✓ AAA | dark | +| cyan-500 (#06b6d4) | 2.43:1 ✗ | 7.31:1 ✓ AAA | dark | +| cyan-600 (#0891b2) | 3.68:1 ✗ | 4.82:1 ✓ AA | dark | +| cyan-700 (#0e7490) | 5.36:1 ✓ AA | 3.31:1 ✗ | white | +| cyan-800 (#155e75) | 7.27:1 ✓ AAA | 2.44:1 ✗ | white | + +| Use Case | Classes | Notes | +|----------|---------|-------| +| Primary button | `bg-cyan-400 hover:bg-cyan-300 text-gray-900` | Bright, AAA | +| Selected/active state | `bg-cyan-400 text-gray-900` | Bright, AAA | +| Inline card/mention ref | `bg-cyan-700 text-white` | Darker, AA | +| Link text | `text-cyan-600 dark:text-cyan-400` | Text only | +| Focus ring | `ring-cyan-500 dark:ring-cyan-400` | Decorative | +| Toggle switch (on) | `bg-cyan-600` | No text label | + +### Status/Semantic Colors + +Keep these muted in dark mode: + +| Status | Light | Dark | +|--------|-------|------| +| Success | `text-green-600` / `bg-green-100` | `dark:text-green-400` / `dark:bg-green-900/30` | +| Warning | `text-amber-600` / `bg-amber-100` | `dark:text-amber-400` / `dark:bg-amber-900/30` | +| Error | `text-red-600` / `bg-red-100` | `dark:text-red-400` / `dark:bg-red-900/30` | +| Info | `text-blue-600` / `bg-blue-100` | `dark:text-blue-400` / `dark:bg-blue-900/30` | + +### MTG-Specific + +Rarity colors stay as-is (established MTG conventions): + +```css +--color-rarity-common: #1a1718; +--color-rarity-uncommon: #707883; +--color-rarity-rare: #a58e4a; +--color-rarity-mythic: #bf4427; +--color-rarity-timeshifted: #652978; +``` + +For generic badges (set codes, format tags), prefer neutral styling: +- `bg-zinc-100 dark:bg-zinc-800` +- `border-zinc-200 dark:border-zinc-700` +- `text-zinc-600 dark:text-zinc-400` + +## Component Patterns + +### Cards/Panels + +```tsx +
+

Title

+

Description

+
+``` + +### Buttons + +```tsx +// Primary (cyan bg needs dark text for contrast) + + +// Secondary + + +// Ghost + +``` + +### Links + +```tsx + + Link text + +``` + +### Form Inputs + +```tsx + +``` + +## Checklist for New Components + +- [ ] Uses `zinc-*` for dark backgrounds, not `slate-*` +- [ ] Primary accent is `cyan-*` +- [ ] Cyan backgrounds use dark text (`text-gray-900`), not white +- [ ] Primary text uses `zinc-100`, secondary uses `zinc-300` (AAA compliant) +- [ ] Colored badges only for semantic meaning (rarity, status) +- [ ] Borders use `zinc-600` for visibility +- [ ] Focus states use `cyan-*` ring + +## Alternative Accent Colors Considered + +If cyan doesn't work out, these were researched as alternatives: + +| Color | Hex | Best For | Concerns | +|-------|-----|----------|----------| +| amber-400 | `#fbbf24` | Buttons, gaming/treasure feel | Can read as warning | +| amber-500 | `#f59e0b` | More muted gold | Needs dark text | +| rose-400 | `#fb7185` | Links and buttons both | Could conflict with error red | +| teal-400 | `#2dd4bf` | Warmer cyan alternative | Still cool-toned | + +## References + +- [Discord Color Palette](https://www.color-hex.com/color-palette/114089) +- [Linear UI Redesign](https://linear.app/now/how-we-redesigned-the-linear-ui) +- [Tailwind Zinc Scale](https://tailwindcss.com/docs/customizing-colors) +- [Dark Mode Best Practices](https://appinventiv.com/blog/guide-on-designing-dark-mode-for-mobile-app/) +- [Yellow/Amber Accessibility](https://stephaniewalter.design/blog/yellow-purple-and-the-myth-of-accessibility-limits-color-palettes/) +- [USWDS Color Tokens](https://designsystem.digital.gov/design-tokens/color/theme-tokens/) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index b19e88b..9ab643d 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -65,7 +65,8 @@ "Bash(curl:*)", "Bash(npm run build:lexicons:*)", "Bash(npm run lexicons:lint:*)", - "Bash(npm run lexicons:all:*)" + "Bash(npm run lexicons:all:*)", + "Bash(goat lex:*)" ], "deny": [], "ask": [] diff --git a/CLAUDE.md b/CLAUDE.md index 4da0573..e34629b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -86,15 +86,17 @@ Tailwind CSS v4 is integrated via `@tailwindcss/vite` plugin. Global styles in ` **Dark Mode Support:** - All components and pages must support both light and dark mode -- Use Tailwind's `dark:` variant for dark mode styles (e.g., `bg-white dark:bg-slate-900`) - Theme is managed by `ThemeProvider` in `src/lib/useTheme.tsx` - Dark mode configuration: `@custom-variant dark (&:where(.dark, .dark *))` in `src/styles.css` -- Common patterns: - - Backgrounds: `bg-white dark:bg-slate-900` (page), `bg-gray-100 dark:bg-slate-800` (panels) - - Primary text: `text-gray-900 dark:text-white` - - Secondary text: `text-gray-600 dark:text-gray-400` - - Borders: `border-gray-300 dark:border-slate-700` - - Interactive elements: `hover:bg-gray-100 dark:hover:bg-gray-800` +- **See `.claude/DARK_MODE.md` for the full style guide** +- Key patterns: + - Backgrounds: `bg-white dark:bg-zinc-900` (page), `bg-gray-50 dark:bg-zinc-800` (panels) + - Primary text: `text-gray-900 dark:text-zinc-100` + - Secondary text: `text-gray-600 dark:text-zinc-300` (AAA contrast) + - Borders: `border-gray-200 dark:border-zinc-600` (visible) + - Accent color: `cyan-*` (e.g., `text-cyan-600 dark:text-cyan-400`) + - Focus rings: `focus:ring-cyan-500 dark:focus:ring-cyan-400` +- **DO NOT use**: `slate-*` for dark mode (it's blue-tinted) **Reduced Motion Support:** - Respect `prefers-reduced-motion` for decorative and dramatic animations diff --git a/package.json b/package.json index c50437e..4b85b05 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,8 @@ "lexicons:status": "goat lex status", "lexicons:diff": "goat lex diff", "lexicons:check-dns": "goat lex check-dns --did did:web:deckbelcher.com", - "lexicons:publish": "goat lex publish --username deckbelcher.com", + "lexicons:prepublish": "npm run lexicons:breaking && npm run lexicons:diff && npm run lexicons:status", + "lexicons:publish": "npm run lexicons:prepublish && goat lex publish --username deckbelcher.com", "lexicons:codegen": "lex-cli generate -c ./lex.config.js", "lexicons:scopes": "node --experimental-strip-types scripts/generate-oauth-scopes.ts", "lexicons:all": "npm run lexicons:compile && npm run lexicons:lint && npm run lexicons:breaking && npm run lexicons:codegen && npm run lexicons:scopes", diff --git a/src/components/ActivityFeed.tsx b/src/components/ActivityFeed.tsx index f865d92..ff80161 100644 --- a/src/components/ActivityFeed.tsx +++ b/src/components/ActivityFeed.tsx @@ -25,7 +25,7 @@ export function ActivityFeed({ limit = 6 }: ActivityFeedProps) { if (error || !records) { return ( -
+
Unable to load recent activity
); @@ -33,7 +33,7 @@ export function ActivityFeed({ limit = 6 }: ActivityFeedProps) { if (records.length === 0) { return ( -
+
No recent activity yet
); @@ -78,18 +78,18 @@ function ActivityFeedSkeleton({ count }: { count: number }) {
-
+
{/* Handle */} -
+
{/* Name */} -
+
{/* Format */} -
+
{/* Date */} -
+
))} diff --git a/src/components/CardImage.tsx b/src/components/CardImage.tsx index 7b179fa..6afab2b 100644 --- a/src/components/CardImage.tsx +++ b/src/components/CardImage.tsx @@ -85,7 +85,7 @@ export function CardImage({ {card.name} @@ -108,7 +108,7 @@ export function CardImage({ {card.name} ); @@ -191,7 +191,7 @@ export function CardThumbnail({ card, href, onClick }: CardThumbnailProps) { {card.name}

{card.set_name && ( -

+

{card.set_name}

)} diff --git a/src/components/ClientDate.tsx b/src/components/ClientDate.tsx index 06d4d3b..aecc81b 100644 --- a/src/components/ClientDate.tsx +++ b/src/components/ClientDate.tsx @@ -43,7 +43,7 @@ export function ClientDate({ return ( diff --git a/src/components/DeckPreview.tsx b/src/components/DeckPreview.tsx index 0891e3d..fcc45aa 100644 --- a/src/components/DeckPreview.tsx +++ b/src/components/DeckPreview.tsx @@ -129,34 +129,34 @@ export function DeckPreview({
{showHandle && (handle ? ( -

+

@{handle}

) : ( -
+
))}

{deck.name}

{deck.format && ( -

+

{formatDisplayName(deck.format)}

)} {sectionString && ( -

+

{sectionString}

)} -

+

Updated

diff --git a/src/components/Header.tsx b/src/components/Header.tsx index df1b77e..c325770 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -19,12 +19,12 @@ export default function Header() { return ( <> -
+
Go home diff --git a/src/components/SearchPrimer.tsx b/src/components/SearchPrimer.tsx index 1d46800..fdc7e94 100644 --- a/src/components/SearchPrimer.tsx +++ b/src/components/SearchPrimer.tsx @@ -3,7 +3,7 @@ import { CardSymbol } from "./CardSymbol"; function Code({ children }: { children: React.ReactNode }) { return ( - + {children} ); @@ -14,7 +14,7 @@ function Q({ q }: { q: string }) { {q} @@ -32,7 +32,7 @@ function MainCard({ }) { return (

{title} @@ -53,9 +53,9 @@ function SecondaryCard({ }) { return (
-

+

{title}

{children} @@ -73,7 +73,7 @@ export function SearchPrimer() { return (
{/* Intro blurb */} -
+

Type anything to search by name—we'll find close matches even with typos. @@ -87,7 +87,7 @@ export function SearchPrimer() {

{/* Fields with examples */} -
    +
    • type
    • @@ -120,7 +120,7 @@ export function SearchPrimer() { {/* Operators */} -
        +
        • less than
        • @@ -141,7 +141,7 @@ export function SearchPrimer() { {/* Colors - clearer framing */} -
          +
          {/* Color codes */}
          @@ -166,7 +166,7 @@ export function SearchPrimer() { {/* Card's colors */}
          -

          +

          Card's colors

          @@ -179,7 +179,7 @@ export function SearchPrimer() { {/* Color identity for commander */}

          -

          +

          For commander decks

          @@ -199,7 +199,7 @@ export function SearchPrimer() { {/* Combining */} -

            +
            • both (AND)
            • diff --git a/src/components/SetSymbol.tsx b/src/components/SetSymbol.tsx index 61f7ca7..cf9b2d1 100644 --- a/src/components/SetSymbol.tsx +++ b/src/components/SetSymbol.tsx @@ -20,7 +20,7 @@ const SIZE_CLASSES = { }; const RARITY_CLASSES: Record = { - common: "text-rarity-common dark:text-gray-400", + common: "text-rarity-common dark:text-zinc-300", uncommon: "text-rarity-uncommon", rare: "text-rarity-rare", mythic: "text-rarity-mythic", diff --git a/src/components/UserMenu.tsx b/src/components/UserMenu.tsx index d981de0..13fe177 100644 --- a/src/components/UserMenu.tsx +++ b/src/components/UserMenu.tsx @@ -37,7 +37,7 @@ export default function UserMenu() { {isOpen && ( -
              +
              setIsOpen(false)} - className="w-full flex items-center gap-2 px-4 py-3 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors text-gray-900 dark:text-white text-sm" + className="w-full flex items-center gap-2 px-4 py-3 hover:bg-gray-100 dark:hover:bg-zinc-700 transition-colors text-gray-900 dark:text-white text-sm" > View Profile @@ -70,7 +70,7 @@ export default function UserMenu() { signOut(); setIsOpen(false); }} - className="w-full flex items-center gap-2 px-4 py-3 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors text-gray-900 dark:text-white text-sm" + className="w-full flex items-center gap-2 px-4 py-3 hover:bg-gray-100 dark:hover:bg-zinc-700 transition-colors text-gray-900 dark:text-white text-sm" > Sign Out diff --git a/src/components/comments/CommentForm.tsx b/src/components/comments/CommentForm.tsx index 011b5b0..e1ebdb5 100644 --- a/src/components/comments/CommentForm.tsx +++ b/src/components/comments/CommentForm.tsx @@ -78,12 +78,12 @@ export function CommentForm({ />
              {isPending && ( - + Saving... )} {!isPending && isEditMode && isDirty && ( - + Unsaved changes )} @@ -92,7 +92,7 @@ export function CommentForm({ type="button" onClick={onCancel} disabled={isPending} - className="px-3 py-1.5 text-sm font-medium rounded-md bg-gray-100 dark:bg-slate-800 hover:bg-gray-200 dark:hover:bg-slate-700 text-gray-700 dark:text-gray-300 disabled:opacity-50" + className="px-3 py-1.5 text-sm font-medium rounded-md bg-gray-100 dark:bg-zinc-800 hover:bg-gray-200 dark:hover:bg-zinc-700 text-gray-700 dark:text-zinc-300 disabled:opacity-50" > Cancel @@ -103,7 +103,7 @@ export function CommentForm({ disabled={!hasContent || isPending} className={`px-3 py-1.5 text-sm font-medium rounded-md disabled:opacity-50 disabled:cursor-not-allowed ${ isEditMode - ? "bg-gray-100 dark:bg-slate-800 hover:bg-gray-200 dark:hover:bg-slate-700 text-gray-700 dark:text-gray-300" + ? "bg-gray-100 dark:bg-zinc-800 hover:bg-gray-200 dark:hover:bg-zinc-700 text-gray-700 dark:text-zinc-300" : "bg-blue-600 hover:bg-blue-700 text-white" }`} > diff --git a/src/components/comments/CommentItem.tsx b/src/components/comments/CommentItem.tsx index 10c55cb..c2857f3 100644 --- a/src/components/comments/CommentItem.tsx +++ b/src/components/comments/CommentItem.tsx @@ -123,7 +123,7 @@ export function CommentItem({ if (isError || !record) { return ( -
              +
              [Failed to load {type}]
              ); @@ -137,24 +137,24 @@ export function CommentItem({ @{handle ?? did.slice(0, 16)} - · + · {record.updatedAt && record.updatedAt !== record.createdAt && ( - + (edited) )}
              -
              +
              @@ -163,14 +163,14 @@ export function CommentItem({ ) : ( replyCount > 0 && ( - + {replyCount} @@ -187,7 +187,7 @@ export function CommentItem({ deleteCommentMutation.isPending || deleteReplyMutation.isPending } - className="flex items-center gap-1 text-sm text-gray-500 dark:text-gray-400 hover:text-red-600 dark:hover:text-red-400" + className="flex items-center gap-1 text-sm text-gray-500 dark:text-zinc-300 hover:text-red-600 dark:hover:text-red-400" > @@ -217,12 +217,12 @@ function CommentSkeleton() {
              -
              -
              +
              +
              -
              -
              +
              +
              diff --git a/src/components/comments/CommentThread.tsx b/src/components/comments/CommentThread.tsx index fff22cd..d5faf3e 100644 --- a/src/components/comments/CommentThread.tsx +++ b/src/components/comments/CommentThread.tsx @@ -45,7 +45,7 @@ export function CommentThread({ return (
              0 ? "pl-4 border-l border-gray-200 dark:border-slate-700" : "" + depth > 0 ? "pl-4 border-l border-gray-200 dark:border-zinc-600" : "" } > -
              +
              +
              - -

              + +

              {title}

              {count > 0 && ( - + ({count}) )} @@ -88,7 +88,7 @@ export function CommentsPanel({ @@ -97,19 +97,19 @@ export function CommentsPanel({
              {commentsQuery.isLoading && ( -
              +
              Loading comments...
              )} {!commentsQuery.isLoading && comments.length === 0 && ( -
              +
              No comments yet. Be the first to comment!
              )} {comments.length > 0 && ( -
              +
              {comments.map((comment) => ( {session && ( -
              +
              {showForm ? ( setShowForm(true)} - className="w-full text-left px-3 py-2 text-sm text-gray-500 dark:text-gray-400 bg-gray-50 dark:bg-slate-800 rounded-md hover:bg-gray-100 dark:hover:bg-slate-700" + className="w-full text-left px-3 py-2 text-sm text-gray-500 dark:text-zinc-300 bg-gray-50 dark:bg-zinc-800 rounded-md hover:bg-gray-100 dark:hover:bg-zinc-700" > Write a comment... @@ -160,7 +160,7 @@ export function CommentsPanel({ )} {!session && ( -
              +
              Sign in to comment
              )} diff --git a/src/components/deck/BulkEditPreview.tsx b/src/components/deck/BulkEditPreview.tsx index 4fdd808..e9b0c6f 100644 --- a/src/components/deck/BulkEditPreview.tsx +++ b/src/components/deck/BulkEditPreview.tsx @@ -24,7 +24,7 @@ interface BulkEditPreviewProps { export function BulkEditPreview({ lines }: BulkEditPreviewProps) { return ( -
              +
              {lines.map((line) => ( ))} @@ -43,7 +43,7 @@ function PreviewRow({ line }: { line: PreviewLine }) { case "pending": return (
              - + {line.name}...
              @@ -76,14 +76,14 @@ function ResolvedCardRow({ ? "bg-amber-50 dark:bg-amber-900/40 hover:bg-amber-100 dark:hover:bg-amber-900/50" : line.isNew ? "bg-green-50 dark:bg-green-900/40 hover:bg-green-100 dark:hover:bg-green-900/50" - : "hover:bg-gray-100 dark:hover:bg-slate-800"; + : "hover:bg-gray-100 dark:hover:bg-zinc-800"; return (
              - + {line.quantity} diff --git a/src/components/deck/CardDragOverlay.tsx b/src/components/deck/CardDragOverlay.tsx index 56b6c58..03bc40c 100644 --- a/src/components/deck/CardDragOverlay.tsx +++ b/src/components/deck/CardDragOverlay.tsx @@ -16,7 +16,7 @@ export function CardDragOverlay({ draggedCardId }: CardDragOverlayProps) { return ( {draggedCardId && cardData ? ( -
              +
              {cardData.name} diff --git a/src/components/deck/CardModal.tsx b/src/components/deck/CardModal.tsx index 6d24178..28f7c8a 100644 --- a/src/components/deck/CardModal.tsx +++ b/src/components/deck/CardModal.tsx @@ -117,10 +117,10 @@ export function CardModal({ role="dialog" aria-modal="true" aria-labelledby={titleId} - className="bg-white dark:bg-slate-900 rounded-lg shadow-2xl max-w-md w-full pointer-events-auto border border-gray-300 dark:border-slate-700" + className="bg-white dark:bg-zinc-900 rounded-lg shadow-2xl max-w-md w-full pointer-events-auto border border-gray-300 dark:border-zinc-600" > {/* Header */} -
              +
              {primaryFace ? ( <> @@ -138,7 +138,7 @@ export function CardModal({ )}
              {primaryFace.type_line && ( -
              +
              {primaryFace.type_line}
              )} @@ -156,7 +156,7 @@ export function CardModal({ type="button" onClick={onClose} aria-label="Close" - className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors ml-4" + className="text-gray-400 hover:text-gray-600 dark:hover:text-zinc-300 transition-colors ml-4" > @@ -179,7 +179,7 @@ export function CardModal({ {/* Quantity */}
              -
              +
              Quantity
              @@ -187,9 +187,9 @@ export function CardModal({ type="button" onClick={() => handleQuantityChange(quantity - 1)} disabled={readOnly || quantity <= 1} - className="p-2 rounded-lg bg-gray-100 dark:bg-slate-800 hover:bg-gray-200 dark:hover:bg-slate-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" + className="p-2 rounded-lg bg-gray-100 dark:bg-zinc-800 hover:bg-gray-200 dark:hover:bg-zinc-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" > - +
              {/* Section */}
              -
              +
              Section
              setNewListName(e.target.value)} disabled={createMutation.isPending} placeholder="New list name..." - className="flex-1 px-4 py-2 bg-white dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed" + className="flex-1 px-4 py-2 bg-white dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed" /> @@ -243,7 +243,7 @@ function ListRow({ className={`w-full flex items-center justify-between px-4 py-3 rounded-lg transition-colors ${ isSaved ? "bg-blue-50 dark:bg-blue-900/20 hover:bg-blue-100 dark:hover:bg-blue-900/30" - : "bg-gray-50 dark:bg-slate-800 hover:bg-gray-100 dark:hover:bg-slate-700" + : "bg-gray-50 dark:bg-zinc-800 hover:bg-gray-100 dark:hover:bg-zinc-700" }`} > {toggleMutation.isPending ? ( diff --git a/src/components/profile/ProfileHeader.tsx b/src/components/profile/ProfileHeader.tsx index 6fd6c1e..12cbfc7 100644 --- a/src/components/profile/ProfileHeader.tsx +++ b/src/components/profile/ProfileHeader.tsx @@ -97,7 +97,7 @@ export function ProfileHeader({ href={handleUrl} target="_blank" rel="noopener noreferrer" - className="text-gray-400 hover:text-cyan-500 dark:text-gray-500 dark:hover:text-cyan-400 transition-colors" + className="text-gray-400 hover:text-cyan-500 dark:text-zinc-400 dark:hover:text-cyan-400 transition-colors" title={`Visit ${handleUrl}`} > @@ -109,7 +109,7 @@ export function ProfileHeader({
              @@ -126,13 +126,13 @@ export function ProfileHeader({ }} placeholder="e.g. she/her, they/them" maxLength={64} - className="px-3 py-2 w-full max-w-xs bg-gray-100 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:border-cyan-500" + className="px-3 py-2 w-full max-w-xs bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:border-cyan-500" />
              {/* Bio editor */}
              - + Bio -
              +
              {isSaving && Saving...} {!isSaving && isDirty && Unsaved changes} {!isSaving && !isDirty && hasContent && Saved} @@ -152,7 +152,7 @@ export function ProfileHeader({ @@ -176,7 +176,7 @@ export function ProfileHeader({ href={handleUrl} target="_blank" rel="noopener noreferrer" - className="text-gray-400 hover:text-cyan-500 dark:text-gray-500 dark:hover:text-cyan-400 transition-colors" + className="text-gray-400 hover:text-cyan-500 dark:text-zinc-400 dark:hover:text-cyan-400 transition-colors" title={`Visit ${handleUrl}`} > @@ -185,7 +185,7 @@ export function ProfileHeader({
              {/* Pronouns */} {profile?.pronouns && ( -

              +

              {profile.pronouns}

              )} @@ -194,7 +194,7 @@ export function ProfileHeader({ {hasContent && profile?.bio && ( )} @@ -203,7 +203,7 @@ export function ProfileHeader({ @@ -92,7 +92,7 @@ export function LinkModal({
              @@ -103,7 +103,7 @@ export function LinkModal({ value={url} onChange={(e) => setUrl(e.target.value)} placeholder="example.com" - className="w-full px-3 py-2 border border-gray-300 dark:border-slate-600 rounded-md bg-white dark:bg-slate-700 text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500" + className="w-full px-3 py-2 border border-gray-300 dark:border-zinc-600 rounded-md bg-white dark:bg-zinc-700 text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-zinc-500 focus:outline-none focus:ring-2 focus:ring-blue-500" />
              @@ -111,7 +111,7 @@ export function LinkModal({
              @@ -121,7 +121,7 @@ export function LinkModal({ value={text} onChange={(e) => setText(e.target.value)} placeholder="Display text (optional)" - className="w-full px-3 py-2 border border-gray-300 dark:border-slate-600 rounded-md bg-white dark:bg-slate-700 text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500" + className="w-full px-3 py-2 border border-gray-300 dark:border-zinc-600 rounded-md bg-white dark:bg-zinc-700 text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-zinc-500 focus:outline-none focus:ring-2 focus:ring-blue-500" />
              )} @@ -130,7 +130,7 @@ export function LinkModal({ diff --git a/src/components/richtext/ProseMirrorEditor.tsx b/src/components/richtext/ProseMirrorEditor.tsx index d28d359..0ebf7e3 100644 --- a/src/components/richtext/ProseMirrorEditor.tsx +++ b/src/components/richtext/ProseMirrorEditor.tsx @@ -247,7 +247,7 @@ export function ProseMirrorEditor({ }, attributes: { class: - "focus:outline-none min-h-[8rem] p-3 text-gray-900 dark:text-gray-100", + "focus:outline-none min-h-[8rem] p-3 text-gray-900 dark:text-zinc-100", "data-placeholder": initialPlaceholderRef.current, }, }); @@ -262,7 +262,7 @@ export function ProseMirrorEditor({ return (
              -
              +
              {showToolbar && }
              diff --git a/src/components/richtext/RichtextRenderer.tsx b/src/components/richtext/RichtextRenderer.tsx index 8816d10..f774332 100644 --- a/src/components/richtext/RichtextRenderer.tsx +++ b/src/components/richtext/RichtextRenderer.tsx @@ -81,8 +81,8 @@ const BlockRenderer = memo(function BlockRenderer({ case "com.deckbelcher.richtext#codeBlock": return ( -
              -					
              +				
              +					
               						{block.text}
               					
               				
              @@ -112,7 +112,7 @@ const BlockRenderer = memo(function BlockRenderer({ ); case "com.deckbelcher.richtext#horizontalRuleBlock": - return
              ; + return
              ; default: { const para = block as ParagraphBlock; @@ -257,7 +257,7 @@ function applyFeature( case "com.deckbelcher.richtext.facet#code": return ( - + {content} ); diff --git a/src/components/richtext/RichtextSection.tsx b/src/components/richtext/RichtextSection.tsx index cc814d8..146fe3d 100644 --- a/src/components/richtext/RichtextSection.tsx +++ b/src/components/richtext/RichtextSection.tsx @@ -94,7 +94,7 @@ export function RichtextSection({ availableTags={availableTags} />
              -
              +
              {isSaving && Saving...} {!isSaving && isDirty && Unsaved changes} {!isSaving && !isDirty && hasContent && Saved} @@ -102,7 +102,7 @@ export function RichtextSection({ @@ -120,7 +120,7 @@ export function RichtextSection({ @@ -142,12 +142,12 @@ export function RichtextSection({ >
              {needsTruncation && !isExpanded && ( -
              +
              )}
              @@ -156,7 +156,7 @@ export function RichtextSection({

              -

              +

              {total.toLocaleString()}{" "} {total === 1 ? type === "likes" @@ -168,10 +168,10 @@ export function BacklinkModal({

              @@ -185,7 +185,7 @@ export function BacklinkModal({ ))}
              ) : allRecords.length === 0 ? ( -

              +

              No {type} yet

              ) : ( diff --git a/src/components/social/BacklinkRow.tsx b/src/components/social/BacklinkRow.tsx index 4a40ccb..0f0a40a 100644 --- a/src/components/social/BacklinkRow.tsx +++ b/src/components/social/BacklinkRow.tsx @@ -43,10 +43,10 @@ function LikeRow({ did }: { did: Did }) { {isLoading ? ( - + ) : ( @{handle ?? did.slice(0, 20)} )} @@ -94,9 +94,9 @@ function DeckRow({ did, rkey }: { did: Did; rkey: Rkey }) { export function RowSkeleton() { return ( -
              -
              -
              +
              +
              +
              ); } diff --git a/src/components/social/SocialStats.tsx b/src/components/social/SocialStats.tsx index 7f49595..88b22fb 100644 --- a/src/components/social/SocialStats.tsx +++ b/src/components/social/SocialStats.tsx @@ -77,7 +77,7 @@ export function SocialStats({ const statBase = "flex items-center gap-1 p-2 rounded-lg"; const buttonBase = `${statBase} transition-colors ${ session - ? "hover:bg-gray-100 dark:hover:bg-gray-800 cursor-pointer" + ? "hover:bg-gray-100 dark:hover:bg-zinc-800 cursor-pointer" : "cursor-default opacity-75" }`; @@ -99,7 +99,7 @@ export function SocialStats({ className={`w-5 h-5 ${ isLikedByUser ? "text-rose-400 dark:text-red-400" - : "text-gray-600 dark:text-gray-400" + : "text-gray-600 dark:text-zinc-300" }`} fill={isLikedByUser ? "currentColor" : "none"} /> @@ -112,7 +112,7 @@ export function SocialStats({ className={`text-sm tabular-nums px-1 py-2 rounded ${isLikeLoading ? "opacity-50" : ""} ${ isLikedByUser ? "text-rose-400 dark:text-red-400" - : "text-gray-600 dark:text-gray-400" + : "text-gray-600 dark:text-zinc-300" } ${likeCount > 0 ? "hover:underline cursor-pointer" : "cursor-default"}`} title={likeCount > 0 ? "See who liked this" : undefined} > @@ -141,7 +141,7 @@ export function SocialStats({ className={`w-5 h-5 ${ isSavedByUser ? "text-blue-500 dark:text-blue-400" - : "text-gray-600 dark:text-gray-400" + : "text-gray-600 dark:text-zinc-300" }`} fill={isSavedByUser ? "currentColor" : "none"} /> @@ -154,7 +154,7 @@ export function SocialStats({ className={`text-sm tabular-nums px-1 py-2 rounded ${isSaveLoading ? "opacity-50" : ""} ${ isSavedByUser ? "text-blue-500 dark:text-blue-400" - : "text-gray-600 dark:text-gray-400" + : "text-gray-600 dark:text-zinc-300" } ${saveCount > 0 ? "hover:underline cursor-pointer" : "cursor-default"}`} title={saveCount > 0 ? "See lists with this item" : undefined} > @@ -170,7 +170,7 @@ export function SocialStats({ className={`${statBase} ${ isInUserDeck ? "text-purple-500 dark:text-purple-400" - : "text-gray-600 dark:text-gray-400" + : "text-gray-600 dark:text-zinc-300" }`} title={isInUserDeck ? "In your deck" : "Decks containing this card"} > @@ -186,7 +186,7 @@ export function SocialStats({ className={`text-sm tabular-nums px-1 py-2 rounded ${isDeckCountLoading ? "opacity-50" : ""} ${ isInUserDeck ? "text-purple-500 dark:text-purple-400" - : "text-gray-600 dark:text-gray-400" + : "text-gray-600 dark:text-zinc-300" } ${deckCount > 0 ? "hover:underline cursor-pointer" : "cursor-default"}`} title={deckCount > 0 ? "See decks with this card" : undefined} > @@ -201,7 +201,7 @@ export function SocialStats({ {showCount && !hideCommentCount && ( {commentCount} diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index 00ac325..4d31e78 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -86,12 +86,12 @@ export const Route = createRootRouteWithContext()({ }), notFoundComponent: () => ( -
              +

              404

              -

              Page not found

              +

              Page not found

              ), diff --git a/src/routes/card/$id.tsx b/src/routes/card/$id.tsx index 0353b8a..d2c8929 100644 --- a/src/routes/card/$id.tsx +++ b/src/routes/card/$id.tsx @@ -210,7 +210,7 @@ function CardDetailPage() { if (!isValidId) { return ( -
              +

              Invalid card ID format

              @@ -220,10 +220,10 @@ function CardDetailPage() { if (cardLoading) { return ( -
              +
              -

              +

              Loading card...

              @@ -234,7 +234,7 @@ function CardDetailPage() { if (!card) { return ( -
              +

              Card not found

              ); @@ -252,10 +252,10 @@ function CardDetailPage() { .sort((a, b) => (b.released_at ?? "").localeCompare(a.released_at ?? "")); return ( -
              +
              -
              +
              (
              {idx > 0 && ( -
              +
              )}
              -

              Set

              +

              Set

              ) : ( - — + — )}

              -

              Rarity

              +

              Rarity

              {displayCard.rarity ?? ( - — + — )}

              -

              Artist

              +

              Artist

              {displayCard.artist ?? ( - — + — )}

              -

              +

              Collector Number

              {displayCard.collector_number ?? ( - — + — )}

              @@ -337,13 +337,13 @@ function CardDetailPage() {
              {volatileLoading ? (
              - +   - +   - +  
              @@ -355,7 +355,7 @@ function CardDetailPage() { volatileData.edhrecRank) ? (
              {volatileData.edhrecRank && ( - + #{volatileData.edhrecRank.toLocaleString()} EDHREC )} @@ -401,13 +401,13 @@ function CardDetailPage() {

              Printings

              -
              +
              {Array.from({ length: 8 }).map((_, i) => (
              ))}
              @@ -420,7 +420,7 @@ function CardDetailPage() {

{allPrintings.map((printing) => ( @@ -435,8 +435,8 @@ function CardDetailPage() { onMouseLeave={() => setHoveredPrintingId(null)} className={`px-3 py-1.5 text-sm rounded transition-colors whitespace-nowrap ${ printing.id === id - ? "bg-cyan-500 text-white font-medium" - : "bg-gray-200 dark:bg-slate-700 text-gray-900 dark:text-gray-200 hover:bg-gray-300 dark:hover:bg-slate-600" + ? "bg-cyan-400 text-gray-900 font-medium" + : "bg-gray-200 dark:bg-zinc-700 text-gray-900 dark:text-zinc-200 hover:bg-gray-300 dark:hover:bg-zinc-600" }`} > {printing.set_name} @@ -455,7 +455,7 @@ function CardDetailPage() { {card.legalities && } {card.oracle_id && ( -
+
{face.type_line && (

{face.type_line}

@@ -525,16 +525,16 @@ function FaceInfo({ face, primary = false, cardId, oracleId }: FaceInfoProps) {
{face.oracle_text && ( -
+
)} {hasStats && ( -
+
{face.power && face.toughness && ( - P/T:{" "} + P/T:{" "} {face.power}/{face.toughness} @@ -542,13 +542,13 @@ function FaceInfo({ face, primary = false, cardId, oracleId }: FaceInfoProps) { )} {face.loyalty && ( - Loyalty:{" "} + Loyalty:{" "} {face.loyalty} )} {face.defense && ( - Defense:{" "} + Defense:{" "} {face.defense} )} @@ -571,7 +571,7 @@ function LegalityTable({ legalities }: LegalityTableProps) {
{FORMAT_GROUPS.map((group) => (
-

+

{group.label}

@@ -582,7 +582,7 @@ function LegalityTable({ legalities }: LegalityTableProps) { key={format.value} className="flex items-center justify-between text-sm" > - + {format.label} @@ -605,7 +605,7 @@ function LegalityBadge({ legality }: { legality: string }) { "bg-amber-100 dark:bg-amber-900/40 text-amber-800 dark:text-amber-300", banned: "bg-red-100 dark:bg-red-900/40 text-red-800 dark:text-red-300", not_legal: - "bg-gray-100 dark:bg-slate-700/50 text-gray-500 dark:text-gray-500", + "bg-gray-100 dark:bg-zinc-700/50 text-gray-500 dark:text-zinc-400", }; const labels: Record = { diff --git a/src/routes/cards/index.tsx b/src/routes/cards/index.tsx index 6d0e6e7..caa9251 100644 --- a/src/routes/cards/index.tsx +++ b/src/routes/cards/index.tsx @@ -343,7 +343,7 @@ function CardsPage() { const firstPage = firstPageQuery.data; return ( -
+
@@ -360,7 +360,7 @@ function CardsPage() { replace: true, }) } - className="appearance-none h-9 w-9 sm:w-auto pl-2 sm:pl-3 pr-2 sm:pr-8 py-1.5 bg-gray-100 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-transparent sm:text-gray-900 dark:sm:text-white text-sm focus:outline-none focus:border-cyan-500 transition-colors cursor-pointer" + className="appearance-none h-9 w-9 sm:w-auto pl-2 sm:pl-3 pr-2 sm:pr-8 py-1.5 bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-transparent sm:text-gray-900 dark:sm:text-white text-sm focus:outline-none focus:border-cyan-500 transition-colors cursor-pointer" > {SORT_OPTIONS.map((opt) => ( {SORT_OPTIONS.filter( @@ -427,7 +427,7 @@ function CardsPage() {
{firstPage?.description && (

diff --git a/src/routes/deck/new.tsx b/src/routes/deck/new.tsx index 7ca041e..d4da0ee 100644 --- a/src/routes/deck/new.tsx +++ b/src/routes/deck/new.tsx @@ -53,13 +53,13 @@ function FormatInfoCard({ format }: { format: string }) { // Cube gets special treatment if (info.isCube) { return ( -
+

{displayName}

{info.tagline && ( - + {info.tagline} )} @@ -80,7 +80,7 @@ function FormatInfoCard({ format }: { format: string }) {
-

+

Set your own rules for deck size, card pool, and restrictions.

@@ -88,13 +88,13 @@ function FormatInfoCard({ format }: { format: string }) { } return ( -
+

{displayName}

{info.tagline && ( - + {info.tagline} )} @@ -126,14 +126,14 @@ function FormatInfoCard({ format }: { format: string }) { )} {info.hasSideboard && ( - + 15-card sideboard )}
{info.commanderType && ( -

+

{getCommanderHint(info.commanderType)}

)} @@ -163,13 +163,13 @@ function NewDeckPage() { }; return ( -
+

New Deck

-

+

Choose a format and give your deck a name

@@ -178,7 +178,7 @@ function NewDeckPage() {
@@ -189,14 +189,14 @@ function NewDeckPage() { onChange={(e) => setName(e.target.value)} placeholder="Untitled Deck" autoComplete="off" - className="w-full px-4 py-3 bg-gray-100 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-gray-900 dark:text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-cyan-500 transition-colors" + className="w-full px-4 py-3 bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-cyan-500 transition-colors" />
@@ -204,7 +204,7 @@ function NewDeckPage() { id={formatId} value={format} onChange={(e) => setFormat(e.target.value)} - className="w-full px-4 py-3 bg-gray-100 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-cyan-500 transition-colors" + className="w-full px-4 py-3 bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-cyan-500 transition-colors" > {FORMAT_GROUPS.map((group) => ( @@ -224,14 +224,14 @@ function NewDeckPage() { diff --git a/src/routes/dev/migrate.tsx b/src/routes/dev/migrate.tsx index 2ed8c2d..edb0338 100644 --- a/src/routes/dev/migrate.tsx +++ b/src/routes/dev/migrate.tsx @@ -320,13 +320,13 @@ function MigratePage() { }; return ( -
+

Record Migration

-

+

Migrate old format records (scryfallId) to new format (cardRef with scryfallUri + oracleUri).

@@ -336,7 +336,7 @@ function MigratePage() {
@@ -344,7 +344,7 @@ function MigratePage() { id={inputId} value={input} onChange={(e) => setInput(e.target.value)} - className="w-full h-96 p-3 font-mono text-xs bg-gray-50 dark:bg-slate-800 border border-gray-300 dark:border-slate-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400 focus:border-transparent text-gray-900 dark:text-gray-100" + className="w-full h-96 p-3 font-mono text-xs bg-gray-50 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400 focus:border-transparent text-gray-900 dark:text-zinc-100" placeholder='{"$type": "com.deckbelcher.deck.list", ...}' />
@@ -352,7 +352,7 @@ function MigratePage() {
@@ -360,7 +360,7 @@ function MigratePage() { id={outputId} value={output} readOnly - className="w-full h-96 p-3 font-mono text-xs bg-gray-100 dark:bg-slate-800/50 border border-gray-300 dark:border-slate-600 rounded-lg text-gray-900 dark:text-gray-100" + className="w-full h-96 p-3 font-mono text-xs bg-gray-100 dark:bg-zinc-800/50 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-zinc-100" placeholder="Migrated output will appear here..." />
@@ -397,23 +397,23 @@ function MigratePage() { )}
- + Migration Details -
+

Old format:{" "} - + scryfallId: "uuid"

New format:{" "} - + {`ref: { scryfallUri: "scry:uuid", oracleUri: "oracle:uuid" }`}

-

+

Supports both com.deckbelcher.deck.list and com.deckbelcher.collection.list records.

diff --git a/src/routes/dev/pm-demo.tsx b/src/routes/dev/pm-demo.tsx index 2827625..273bac6 100644 --- a/src/routes/dev/pm-demo.tsx +++ b/src/routes/dev/pm-demo.tsx @@ -88,13 +88,13 @@ function ProseMirrorDemo() { }, [savedDoc]); return ( -
+

ProseMirror Editor Demo

-

+

Testing the new WYSIWYG editor. Use toolbar buttons or markdown shortcuts.

@@ -116,42 +116,42 @@ function ProseMirrorDemo() {

Read-only View

-
+
{lastSaved && ( -

+

Last saved: {lastSaved}

)}
- + Lexicon (storage format) -
+						
 							{JSON.stringify(savedDoc, null, 2)}
 						
- + Tree (ProseMirror) -
+						
 							{JSON.stringify(pmTreeDoc, null, 2)}
 						
- + Roundtrip (lexicon → tree → lexicon) -
+					
 						{JSON.stringify(roundtrippedDoc, null, 2)}
 					
{roundtrippedDoc && savedDoc && ( diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 5b195e2..54aead9 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -9,13 +9,13 @@ function App() { const { session } = useAuth(); return ( -
+

deck belcher dot com

-

+

organize, build, and share decks on the atmosphere

@@ -24,7 +24,7 @@ function App() { {session ? (
@@ -32,14 +32,14 @@ function App() { Create Deck - + Start building ) : (
@@ -47,7 +47,7 @@ function App() { Sign In - + Get started @@ -57,27 +57,27 @@ function App() { -
- +
+
My Decks - + View your collection ) : ( -
-
- +
+
+
- + My Decks - + Sign in to view
@@ -86,15 +86,15 @@ function App() { -
- +
+
Browse Cards - + Search the database @@ -104,7 +104,7 @@ function App() {

Recent Activity

-

+

powered by{" "}

-

+

built on{" "} +

-

+

{error}

@@ -138,7 +138,7 @@ function OAuthCallback() { } return ( -
+

diff --git a/src/routes/profile/$did/deck/$rkey/bulk-edit.tsx b/src/routes/profile/$did/deck/$rkey/bulk-edit.tsx index 5080258..8fa2c49 100644 --- a/src/routes/profile/$did/deck/$rkey/bulk-edit.tsx +++ b/src/routes/profile/$did/deck/$rkey/bulk-edit.tsx @@ -287,7 +287,7 @@ function BulkEditPage() { }, [textLines, resolvedMap, errorMap, parsedByRaw, savedCardIds]); return ( -

+
Bulk Edit: {deck.name} -

+

Edit cards in text format. One card per line.

{/* Section tabs */} -
+
{SECTIONS.map((section) => { const isActive = activeSection === section.value; const isDisabled = isDirty && !isActive; @@ -320,8 +320,8 @@ function BulkEditPage() { isActive ? "text-blue-600 dark:text-blue-400 border-b-2 border-blue-600 dark:border-blue-400" : isDisabled - ? "text-gray-400 dark:text-gray-600 cursor-not-allowed" - : "text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white" + ? "text-gray-400 dark:text-zinc-600 cursor-not-allowed" + : "text-gray-600 dark:text-zinc-300 hover:text-gray-900 dark:hover:text-white" }`} > {section.label} @@ -339,9 +339,9 @@ function BulkEditPage() {
{/* Format hint */} -
+
Format:{" "} - + <quantity> <card name> (SET) <collector#> #tag1 #tag2 @@ -352,7 +352,7 @@ function BulkEditPage() {
{/* Editor container */} -
+