Better Cards
This commit is contained in:
@@ -119,6 +119,10 @@
|
|||||||
transition: transform 170ms ease;
|
transition: transform 170ms ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.preview-card .card-center-icon {
|
||||||
|
font-size: 1.18rem;
|
||||||
|
}
|
||||||
|
|
||||||
.preview-card.dragging {
|
.preview-card.dragging {
|
||||||
opacity: 0.65;
|
opacity: 0.65;
|
||||||
}
|
}
|
||||||
@@ -286,10 +290,18 @@
|
|||||||
width: 4.3rem;
|
width: 4.3rem;
|
||||||
height: 6rem;
|
height: 6rem;
|
||||||
border-radius: 0.4rem;
|
border-radius: 0.4rem;
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: transform 120ms ease;
|
transition: transform 120ms ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vote-card .card-center-icon {
|
||||||
|
font-size: 1.65rem;
|
||||||
|
}
|
||||||
|
|
||||||
.vote-card:hover {
|
.vote-card:hover {
|
||||||
transform: translateY(-0.2rem);
|
transform: translateY(-0.2rem);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,6 +165,34 @@ input[type="number"]::-webkit-inner-spin-button {
|
|||||||
color: var(--card-text);
|
color: var(--card-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-corner {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
line-height: 1;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-corner.top-left {
|
||||||
|
top: 0.34rem;
|
||||||
|
left: 0.34rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-corner.bottom-right {
|
||||||
|
right: 0.34rem;
|
||||||
|
bottom: 0.34rem;
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-center-icon {
|
||||||
|
z-index: 1;
|
||||||
|
line-height: 1;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
.vote-card.is-selected {
|
.vote-card.is-selected {
|
||||||
outline: var(--selected-outline);
|
outline: var(--selected-outline);
|
||||||
outline-offset: -0.35rem;
|
outline-offset: -0.35rem;
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ const SPECIAL_CARD_ORDER = {
|
|||||||
'☕': 3,
|
'☕': 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const CARD_ICONS = ['★', '◆', '✦', '☀', '☘', '⚙', '♣', '♠', '♥', '♦', '✚', '⚡', '☾', '✿'];
|
||||||
|
|
||||||
const roomConfigForm = document.getElementById('room-config-form');
|
const roomConfigForm = document.getElementById('room-config-form');
|
||||||
const statusLine = document.getElementById('config-status');
|
const statusLine = document.getElementById('config-status');
|
||||||
const scaleSelect = document.getElementById('estimation-scale');
|
const scaleSelect = document.getElementById('estimation-scale');
|
||||||
@@ -82,6 +84,36 @@ function createCard(value) {
|
|||||||
return { id: String(nextCardID++), value: value.toString() };
|
return { id: String(nextCardID++), value: value.toString() };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function iconForCard(value) {
|
||||||
|
if (value === '?') return '❓';
|
||||||
|
if (value === '☕') return '☕';
|
||||||
|
if (value === '∞') return '∞';
|
||||||
|
|
||||||
|
let hash = 0;
|
||||||
|
for (let i = 0; i < value.length; i += 1) {
|
||||||
|
hash = (hash * 31 + value.charCodeAt(i)) >>> 0;
|
||||||
|
}
|
||||||
|
return CARD_ICONS[hash % CARD_ICONS.length];
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendCardFace(el, value) {
|
||||||
|
const topLeft = document.createElement('span');
|
||||||
|
topLeft.className = 'card-corner top-left';
|
||||||
|
topLeft.textContent = value;
|
||||||
|
|
||||||
|
const center = document.createElement('span');
|
||||||
|
center.className = 'card-center-icon';
|
||||||
|
center.textContent = iconForCard(value);
|
||||||
|
|
||||||
|
const bottomRight = document.createElement('span');
|
||||||
|
bottomRight.className = 'card-corner bottom-right';
|
||||||
|
bottomRight.textContent = value;
|
||||||
|
|
||||||
|
el.appendChild(topLeft);
|
||||||
|
el.appendChild(center);
|
||||||
|
el.appendChild(bottomRight);
|
||||||
|
}
|
||||||
|
|
||||||
function getCardsForScale(scale) {
|
function getCardsForScale(scale) {
|
||||||
return (SCALE_PRESETS[scale] || SCALE_PRESETS.fibonacci).map(createCard);
|
return (SCALE_PRESETS[scale] || SCALE_PRESETS.fibonacci).map(createCard);
|
||||||
}
|
}
|
||||||
@@ -157,8 +189,8 @@ function buildCardElement(card) {
|
|||||||
const cardEl = document.createElement('div');
|
const cardEl = document.createElement('div');
|
||||||
cardEl.className = 'preview-card';
|
cardEl.className = 'preview-card';
|
||||||
cardEl.dataset.cardId = card.id;
|
cardEl.dataset.cardId = card.id;
|
||||||
cardEl.textContent = card.value;
|
|
||||||
cardEl.draggable = true;
|
cardEl.draggable = true;
|
||||||
|
appendCardFace(cardEl, card.value);
|
||||||
|
|
||||||
const removeBtn = document.createElement('button');
|
const removeBtn = document.createElement('button');
|
||||||
removeBtn.type = 'button';
|
removeBtn.type = 'button';
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const USERNAME_KEY = 'scrumPoker.username';
|
const USERNAME_KEY = 'scrumPoker.username';
|
||||||
|
const CARD_ICONS = ['★', '◆', '✦', '☀', '☘', '⚙', '♣', '♠', '♥', '♦', '✚', '⚡', '☾', '✿'];
|
||||||
|
|
||||||
const roomID = document.body.dataset.roomId;
|
const roomID = document.body.dataset.roomId;
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
@@ -137,6 +138,36 @@ function parseNumericVote(value) {
|
|||||||
return Number(value);
|
return Number(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function iconForCard(value) {
|
||||||
|
if (value === '?') return '❓';
|
||||||
|
if (value === '☕') return '☕';
|
||||||
|
if (value === '∞') return '∞';
|
||||||
|
|
||||||
|
let hash = 0;
|
||||||
|
for (let i = 0; i < value.length; i += 1) {
|
||||||
|
hash = (hash * 31 + value.charCodeAt(i)) >>> 0;
|
||||||
|
}
|
||||||
|
return CARD_ICONS[hash % CARD_ICONS.length];
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendCardFace(el, value) {
|
||||||
|
const topLeft = document.createElement('span');
|
||||||
|
topLeft.className = 'card-corner top-left';
|
||||||
|
topLeft.textContent = value;
|
||||||
|
|
||||||
|
const center = document.createElement('span');
|
||||||
|
center.className = 'card-center-icon';
|
||||||
|
center.textContent = iconForCard(value);
|
||||||
|
|
||||||
|
const bottomRight = document.createElement('span');
|
||||||
|
bottomRight.className = 'card-corner bottom-right';
|
||||||
|
bottomRight.textContent = value;
|
||||||
|
|
||||||
|
el.appendChild(topLeft);
|
||||||
|
el.appendChild(center);
|
||||||
|
el.appendChild(bottomRight);
|
||||||
|
}
|
||||||
|
|
||||||
function calculateSummary(state) {
|
function calculateSummary(state) {
|
||||||
const rows = new Map();
|
const rows = new Map();
|
||||||
const numericVotes = [];
|
const numericVotes = [];
|
||||||
@@ -221,7 +252,8 @@ function renderCards(cards, participants, isRevealed) {
|
|||||||
const card = document.createElement('button');
|
const card = document.createElement('button');
|
||||||
card.type = 'button';
|
card.type = 'button';
|
||||||
card.className = 'vote-card';
|
card.className = 'vote-card';
|
||||||
card.textContent = value;
|
card.setAttribute('aria-label', `Vote ${value}`);
|
||||||
|
appendCardFace(card, value);
|
||||||
|
|
||||||
if (selfVote === value && !isRevealed) {
|
if (selfVote === value && !isRevealed) {
|
||||||
card.classList.add('is-selected');
|
card.classList.add('is-selected');
|
||||||
|
|||||||
Reference in New Issue
Block a user