This commit is contained in:
Pavel Flegr 2026-05-07 19:35:59 +02:00
commit d61129dfe5

View file

@ -355,10 +355,8 @@
border-radius: 8px; border-radius: 8px;
border: 1px solid rgba(0,0,0,.15); border: 1px solid rgba(0,0,0,.15);
box-shadow: 0 6px 18px rgba(0,0,0,.5); box-shadow: 0 6px 18px rgba(0,0,0,.5);
display: flex; display: block;
flex-direction: column; overflow: hidden;
justify-content: space-between;
padding: 5px 6px;
cursor: default; cursor: default;
position: relative; position: relative;
user-select: none; user-select: none;
@ -388,7 +386,21 @@
.card.red { color: var(--red); } .card.red { color: var(--red); }
.card.black { color: #1a1a2e; } .card.black { color: #1a1a2e; }
.card-img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
background: #fff;
}
.card-fallback {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 5px 6px;
}
.card-corner { font-size: .7rem; font-weight: 800; line-height: 1; } .card-corner { font-size: .7rem; font-weight: 800; line-height: 1; }
.card-corner-bot { transform: rotate(180deg); } .card-corner-bot { transform: rotate(180deg); }
.card-center { font-size: 2rem; text-align: center; } .card-center { font-size: 2rem; text-align: center; }
@ -1209,6 +1221,54 @@ const SUIT_ICONS = { hearts:'♥', diamonds:'🍃', spades:'🔔', clubs:'🌰'
const SUIT_NAMES = { hearts:'Červený', diamonds:'Zelený', spades:'Kule', clubs:'Žaludy' }; const SUIT_NAMES = { hearts:'Červený', diamonds:'Zelený', spades:'Kule', clubs:'Žaludy' };
const SUIT_COLOR = { hearts:'red', diamonds:'black', spades:'black', clubs:'black' }; const SUIT_COLOR = { hearts:'red', diamonds:'black', spades:'black', clubs:'black' };
const VALUE_LABEL = { '7':'VII','8':'VIII','9':'IX','10':'X', under:'Sp', upper:'Sv', king:'Kr', ace:'Eso' }; const VALUE_LABEL = { '7':'VII','8':'VIII','9':'IX','10':'X', under:'Sp', upper:'Sv', king:'Kr', ace:'Eso' };
const GERMAN_CARD_FILES = {
hearts: {
'7': 'Playing card-german-hart-07.svg',
'8': 'Playing card-german-hart-08.svg',
'9': 'Playing card-german-hart-09.svg',
'10': 'Playing card-german-hart-10.svg',
under: 'Playing card-german-hart-11 unter.svg',
upper: 'Playing card-german-hart-12 ober.svg',
king: 'Playing card-german-hart-13 konig.svg',
ace: 'Playing card-german-hart-01 daus.svg'
},
diamonds: {
'7': 'Playing card-german-blatt-07.svg',
'8': 'Playing card-german-blatt-08.svg',
'9': 'Playing card-german-blatt-09.svg',
'10': 'Playing card-german-blatt-10.svg',
under: 'Playing card-german-blatt-11 jack.svg',
upper: 'Playing card-german-blatt-12 queen.svg',
king: 'Playing card-german-blatt-13 king.svg',
ace: 'Playing card-german-blatt-01 daus.svg'
},
spades: {
'7': 'Playing card-german-schellen-07.svg',
'8': 'Playing card-german-schellen-08.svg',
'9': 'Playing card-german-schellen-09.svg',
'10': 'Playing card-german-schellen-10.svg',
under: 'Playing card-german-schellen-11 jack.svg',
upper: 'Playing card-german-schellen-12 queen.svg',
king: 'Playing card-german-schellen-13 king.svg',
ace: 'Playing card-german-schellen-01.svg'
},
clubs: {
'7': 'Playing card-german-eichel-07.svg',
'8': 'Playing card-german-eichel-08.svg',
'9': 'Playing card-german-eichel-09.svg',
'10': 'Playing card-german-eichel-10.svg',
under: 'Playing card-german-eichel-11 unter.svg',
upper: 'Playing card-german-eichel-12 ober.svg',
king: 'Playing card-german-eichel-13 konig.svg',
ace: 'Playing card-german-eichel-01 daus.svg'
}
};
function cardAssetUrl(card) {
const file = GERMAN_CARD_FILES[card.suit] && GERMAN_CARD_FILES[card.suit][card.value];
if (!file) return null;
return `https://commons.wikimedia.org/wiki/Special:FilePath/${encodeURIComponent(file)}`;
}
// ── WebSocket ────────────────────────────────────────────────────────── // ── WebSocket ──────────────────────────────────────────────────────────
function connect() { function connect() {
@ -1821,10 +1881,17 @@ function buildCardHTML(card, playable, selected = false) {
const val = VALUE_LABEL[card.value] || card.value; const val = VALUE_LABEL[card.value] || card.value;
const icon = SUIT_ICONS[card.suit]; const icon = SUIT_ICONS[card.suit];
const cls = ['card', colorClass, playable ? 'playable' : '', selected ? 'selected' : ''].filter(Boolean).join(' '); const cls = ['card', colorClass, playable ? 'playable' : '', selected ? 'selected' : ''].filter(Boolean).join(' ');
const assetUrl = cardAssetUrl(card);
const img = assetUrl
? `<img class="card-img" src="${assetUrl}" alt="${escHtml(val + ' ' + (SUIT_NAMES[card.suit] || card.suit))}" loading="lazy" referrerpolicy="no-referrer" onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">`
: '';
return `<div class="${cls}"> return `<div class="${cls}">
<div class="card-corner">${val}<br>${icon}</div> ${img}
<div class="card-center">${icon}</div> <div class="card-fallback" style="${assetUrl ? 'display:none;' : 'display:flex;'}">
<div class="card-corner card-corner-bot">${val}<br>${icon}</div> <div class="card-corner">${val}<br>${icon}</div>
<div class="card-center">${icon}</div>
<div class="card-corner card-corner-bot">${val}<br>${icon}</div>
</div>
</div>`; </div>`;
} }