style(player): tân tân BAMBOORAFT card look — tall cells, condensed black numbers, blue paper

Match the BAMBOORAFT physical sheet:
- Cell aspect changed from square to 3:5 (taller than wide), matching
  the printed paper proportions
- Number cells rendered with .tan-tan-num: condensed system-font stack
  (Arial Narrow / Avenir Next Condensed / Roboto Condensed), font-weight
  900, negative letter-spacing for tight fall-back on platforms without
  a true condensed face. Sized text-2xl / sm:text-3xl to fill the
  taller cells. Black number on white cell.
- Default empty-cell color flipped from Minh Tân brown (#7a4a2b) to
  BAMBOORAFT blue (#1e88e5). Settings store + test updated. Users who
  picked a different color in settings keep their choice.
- Section dividers and labels recolored from orange to matching blue.
- Section labels relabelled to the BAMBOORAFT trio:
  "Tân Tân" / "An khang thịnh vượng" / "Tân Tân tốt nhất"
This commit is contained in:
tiennm99 committed 2026-04-27 00:29:15 +07:00
1 parent 1440c9daf5
commit 7665252607
6 files changed
+48 -30

No files matched your search

+1 -1
View File
@@ -12,7 +12,7 @@
### Shared Components
| File | Purpose |
|------|---------|
| `src/lib/PlayerBoard.svelte` | Reusable player card (9×9 grid rendered as 3 stacked 3×9 mini-cards: Minh Tân / Loại đặc biệt / Tấn tài tấn lộc). Handles crossed state, bingo popup, "Chờ X" toast. Accepts `storagePrefix` prop for multi-card isolation. Empty cells use `--empty-cell-bg` CSS var from settings store. |
| `src/lib/PlayerBoard.svelte` | Reusable player card (9×9 grid rendered as 3 stacked 3×9 mini-cards: Tân Tân / An khang thịnh vượng / Tân Tân tốt nhất). Tall (3:5) cells with condensed bold black numbers (`tan-tan-num` font stack), white number cells, blue empty cells. Handles crossed state, bingo popup, "Chờ X" toast. Accepts `storagePrefix` prop for multi-card isolation. Empty cells use `--empty-cell-bg` CSS var from settings store. |
| `src/lib/SettingsButton.svelte` | Gear icon + modal. Color picker + 8 preset swatches for empty-cell color. Reset-to-default button. Mounted on both `/` and `/master` headers. |
### Game Logic
+4 -2
View File
@@ -16,8 +16,10 @@ That format is intentionally out of scope.
- **Card**: 9 rows × 9 columns. Exactly **5 numbers per row** AND exactly
**5 numbers per column** (45 numbers per card; 36 blanks).
- **Visual layout**: card displayed as 3 stacked 3×9 mini-cards with
traditional separator labels — *Minh Tân*, *Loại đặc biệt*,
*Tấn tài tấn lộc* — matching the physical Minh Tân paper sheet.
traditional separator labels — *Tân Tân*, *An khang thịnh vượng*,
*Tân Tân tốt nhất* — matching the physical Tân Tân BAMBOORAFT paper
sheet (tall non-square cells, condensed bold black numbers on white,
blue empty-cell background by default).
- **Column ranges**: col 0 = 1–9, col 1 = 10–19, …, col 7 = 70–79,
col 8 = 80–90.
- **Within a column**: numbers placed top-to-bottom in **ascending** order.
+29 -13
View File
@@ -3,9 +3,9 @@
:root {
--background: #f8fafc;
--foreground: #1e293b;
/* Default empty-cell color matches a Minh Tân paper card. Overridden
at runtime by the settings store via documentElement.style. */
--empty-cell-bg: #7a4a2b;
/* Default empty-cell color matches a Tân Tân BAMBOORAFT paper card.
Overridden at runtime by the settings store via documentElement.style. */
--empty-cell-bg: #1e88e5;
}
@media (prefers-color-scheme: dark) {
@@ -34,41 +34,57 @@ body {
}
/* Decorative cross-hatch divider between mini-cards on the player sheet,
echoing the ✚✚✚ borders on a physical Minh Tân card. */
echoing the ✚✚✚ blue borders on a Tân Tân BAMBOORAFT card. */
.section-divider {
height: 8px;
background-image: repeating-linear-gradient(
90deg,
transparent 0 6px,
#c2410c 6px 8px,
#1e88e5 6px 8px,
transparent 8px 14px
);
background-color: rgb(255 247 237 / 0.6);
background-color: rgb(227 242 253 / 0.7);
}
@media (prefers-color-scheme: dark) {
.section-divider {
background-color: rgb(67 20 7 / 0.4);
background-color: rgb(13 71 161 / 0.4);
}
}
.section-label {
text-align: center;
font-size: 0.7rem;
font-size: 0.75rem;
letter-spacing: 0.18em;
text-transform: uppercase;
font-weight: 600;
font-weight: 700;
padding: 6px 0;
color: #c2410c;
background-color: rgb(255 247 237 / 0.5);
color: #1565c0;
background-color: rgb(227 242 253 / 0.6);
font-style: italic;
}
@media (prefers-color-scheme: dark) {
.section-label {
color: #fb923c;
background-color: rgb(67 20 7 / 0.4);
color: #64b5f6;
background-color: rgb(13 71 161 / 0.4);
}
}
/* Tân Tân BAMBOORAFT-style number — tall, condensed, heavy black. Stack
prefers a system condensed face; falls back to negative letter-spacing
on platforms without one so the digits still read tall-and-tight. */
.tan-tan-num {
font-family:
"Arial Narrow",
"Avenir Next Condensed",
"Roboto Condensed",
"Liberation Sans Narrow",
system-ui,
sans-serif;
font-weight: 900;
letter-spacing: -0.04em;
line-height: 1;
}
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes pop-in { 0% { opacity: 0; transform: scale(0.5); } 70% { transform: scale(1.05); } 100% { opacity: 1; transform: scale(1); } }
@keyframes bounce-slow { 0%, 100% { transform: translateX(-50%) translateY(0); } 50% { transform: translateX(-50%) translateY(-12px); } }
+10 -10
View File
@@ -140,9 +140,9 @@
// visual segmentation.
const SECTIONS = /** @type {const} */ ([0, 3, 6]);
const SECTION_LABELS = [
"Minh Tân",
"Loại đặc biệt",
"Tấn tài tấn lộc",
"Tân Tân",
"An khang thịnh vượng",
"Tân Tân tốt nhất",
];
</script>
@@ -180,7 +180,7 @@
{#if !hasNumber}
<div
aria-hidden="true"
class="relative flex items-center justify-center aspect-square border-r border-b border-slate-200/80 dark:border-slate-700/60"
class="relative aspect-[3/5] border-r border-b border-slate-300/60 dark:border-slate-700/60"
style:background-color="var(--empty-cell-bg)"
></div>
{:else}
@@ -189,16 +189,16 @@
aria-label="Số {num}{isCrossed ? ', đã đánh dấu' : ''}"
aria-pressed={isCrossed}
onclick={() => handleCellClick(row, col)}
class="relative flex items-center justify-center
aspect-square text-base sm:text-xl font-bold
border-r border-b border-slate-200/80 dark:border-slate-700/60
class="tan-tan-num relative flex items-center justify-center
aspect-[3/5] text-2xl sm:text-3xl
border-r border-b border-slate-300/60 dark:border-slate-700/60
transition-all select-none cursor-pointer
focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-400
{isCrossed
? rowComplete
? 'cell-crossed bg-emerald-100 dark:bg-emerald-900/40 text-emerald-500 dark:text-emerald-400'
: 'cell-crossed bg-red-50 dark:bg-red-950/30 text-red-400 dark:text-red-500'
: 'bg-white dark:bg-slate-800 text-slate-800 dark:text-slate-100 hover:bg-indigo-50 dark:hover:bg-indigo-950/30 hover:text-indigo-600 dark:hover:text-indigo-400'}"
? 'cell-crossed bg-emerald-100 dark:bg-emerald-900/40 text-emerald-600 dark:text-emerald-400'
: 'cell-crossed bg-red-50 dark:bg-red-950/30 text-red-500 dark:text-red-500'
: 'bg-white dark:bg-slate-800 text-black dark:text-slate-100 hover:bg-indigo-50 dark:hover:bg-indigo-950/30 hover:text-indigo-600 dark:hover:text-indigo-400'}"
>
{num}
</button>
+2 -2
View File
@@ -11,8 +11,8 @@ const STORAGE_KEY = "loto_settings";
const HEX6 = /^#[0-9a-fA-F]{6}$/;
export const DEFAULT_SETTINGS = Object.freeze({
/** Brown — matches a Minh Tân paper card. */
emptyCellColor: "#7a4a2b",
/** Blue — matches a Tân Tân BAMBOORAFT paper card. */
emptyCellColor: "#1e88e5",
});
export const settings = $state({ ...DEFAULT_SETTINGS });
+2 -2
View File
@@ -22,8 +22,8 @@ describe("settings-store — defaults", () => {
expect(Object.isFrozen(DEFAULT_SETTINGS)).toBe(true);
});
it("default empty-cell color is brown (#7a4a2b)", () => {
expect(DEFAULT_SETTINGS.emptyCellColor).toBe("#7a4a2b");
it("default empty-cell color is Tân Tân blue (#1e88e5)", () => {
expect(DEFAULT_SETTINGS.emptyCellColor).toBe("#1e88e5");
});
});