@mideind/netskrafl-react 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/css/netskrafl.css +1498 -1417
- package/dist/cjs/index.js +190 -165
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/css/netskrafl.css +1498 -1417
- package/dist/esm/index.js +190 -165
- package/dist/esm/index.js.map +1 -1
- package/package.json +2 -1
package/dist/esm/index.js
CHANGED
|
@@ -29204,7 +29204,7 @@ const BestDisplay = () => {
|
|
|
29204
29204
|
// Make sure blank tiles get a different color
|
|
29205
29205
|
for (let i = 0; i < bw.length; i++)
|
|
29206
29206
|
if (bw[i] == '?') {
|
|
29207
|
-
s.push(m("span.blanktile", bw[i + 1]));
|
|
29207
|
+
s.push(m("span.netskrafl-blanktile", bw[i + 1]));
|
|
29208
29208
|
i += 1;
|
|
29209
29209
|
}
|
|
29210
29210
|
else
|
|
@@ -30000,7 +30000,7 @@ const BlankDialog = () => {
|
|
|
30000
30000
|
onclick: (ev) => { game.placeBlank(letter); ev.preventDefault(); },
|
|
30001
30001
|
onmouseover: buttonOver,
|
|
30002
30002
|
onmouseout: buttonOut
|
|
30003
|
-
}, m(".blank-choice.tile.racktile", letter)));
|
|
30003
|
+
}, m(".blank-choice.netskrafl-tile.netskrafl-racktile", letter)));
|
|
30004
30004
|
len--;
|
|
30005
30005
|
}
|
|
30006
30006
|
r.push(m("tr", c));
|
|
@@ -30095,25 +30095,26 @@ const Bag = () => {
|
|
|
30095
30095
|
For further information, see https://github.com/mideind/Netskrafl
|
|
30096
30096
|
|
|
30097
30097
|
*/
|
|
30098
|
-
function makeButton(cls, disabled, onclick, title, children, id) {
|
|
30098
|
+
function makeButton(cls, disabled, onclick, title, children, visible, id) {
|
|
30099
30099
|
// Create a button element, wrapping the disabling logic
|
|
30100
30100
|
// and other boilerplate
|
|
30101
|
-
const
|
|
30101
|
+
const attrs = {
|
|
30102
30102
|
onmouseout: buttonOut,
|
|
30103
30103
|
onmouseover: buttonOver,
|
|
30104
|
+
style: { visibility: visible === false ? "hidden" : "visible" },
|
|
30104
30105
|
};
|
|
30105
30106
|
if (title)
|
|
30106
|
-
|
|
30107
|
+
attrs.title = title;
|
|
30107
30108
|
if (id)
|
|
30108
|
-
|
|
30109
|
+
attrs.id = id;
|
|
30109
30110
|
if (disabled)
|
|
30110
|
-
|
|
30111
|
+
attrs.onclick = (ev) => ev.preventDefault();
|
|
30111
30112
|
else
|
|
30112
|
-
|
|
30113
|
+
attrs.onclick = (ev) => {
|
|
30113
30114
|
onclick && onclick();
|
|
30114
30115
|
ev.preventDefault();
|
|
30115
30116
|
};
|
|
30116
|
-
return m("." + cls + (disabled ? ".disabled" : ""),
|
|
30117
|
+
return m("." + cls + (disabled ? ".disabled" : ""), attrs, children // children may be omitted
|
|
30117
30118
|
);
|
|
30118
30119
|
}
|
|
30119
30120
|
const Score = {
|
|
@@ -30135,20 +30136,20 @@ const Score = {
|
|
|
30135
30136
|
const RecallButton = {
|
|
30136
30137
|
view: (vnode) => {
|
|
30137
30138
|
// Create a tile recall button
|
|
30138
|
-
const { view, game, disabled } = vnode.attrs;
|
|
30139
|
+
const { view, game, disabled, visible = true } = vnode.attrs;
|
|
30139
30140
|
if (!game)
|
|
30140
30141
|
return undefined;
|
|
30141
|
-
return makeButton("recallbtn", !!disabled, () => { game.resetRack(); view.updateScale(); }, ts("Færa stafi aftur í rekka"), glyph("down-arrow"));
|
|
30142
|
+
return makeButton("recallbtn", !!disabled, () => { game.resetRack(); view.updateScale(); }, ts("Færa stafi aftur í rekka"), glyph("down-arrow"), visible);
|
|
30142
30143
|
}
|
|
30143
30144
|
};
|
|
30144
30145
|
const ScrambleButton = {
|
|
30145
30146
|
view: (vnode) => {
|
|
30146
30147
|
// Create a tile scramble button
|
|
30147
|
-
const { game, disabled } = vnode.attrs;
|
|
30148
|
+
const { game, disabled, visible = true } = vnode.attrs;
|
|
30148
30149
|
if (!game)
|
|
30149
30150
|
return undefined;
|
|
30150
30151
|
return makeButton("scramblebtn", !!disabled, () => game.rescrambleRack(), // Note: plain game.rescrambleRack doesn't work here
|
|
30151
|
-
ts("Stokka upp rekka"), glyph("random"));
|
|
30152
|
+
ts("Stokka upp rekka"), glyph("random"), visible);
|
|
30152
30153
|
}
|
|
30153
30154
|
};
|
|
30154
30155
|
const ButtonsRecallScramble = {
|
|
@@ -30164,9 +30165,9 @@ const ButtonsRecallScramble = {
|
|
|
30164
30165
|
if (s.showRecall && !s.showingDialog)
|
|
30165
30166
|
// Show a 'Recall tiles' button
|
|
30166
30167
|
return m(RecallButton, { view, game });
|
|
30167
|
-
|
|
30168
|
-
|
|
30169
|
-
return
|
|
30168
|
+
const visible = s.showScramble && !s.tilesPlaced;
|
|
30169
|
+
const disabled = s.showingDialog;
|
|
30170
|
+
return m(ScrambleButton, { view, game, visible, disabled });
|
|
30170
30171
|
}
|
|
30171
30172
|
};
|
|
30172
30173
|
const Buttons = {
|
|
@@ -30243,7 +30244,7 @@ const Buttons = {
|
|
|
30243
30244
|
}
|
|
30244
30245
|
};
|
|
30245
30246
|
}
|
|
30246
|
-
r.push(makeButton(classes.join("."), s.showingDialog, action, text, legend, "move-mobile"));
|
|
30247
|
+
r.push(makeButton(classes.join("."), s.showingDialog, action, text, legend, true, "move-mobile"));
|
|
30247
30248
|
}
|
|
30248
30249
|
if (s.showForceResignMobile) {
|
|
30249
30250
|
// Force resignation button (only shown on mobile,
|
|
@@ -30262,7 +30263,7 @@ const Buttons = {
|
|
|
30262
30263
|
}
|
|
30263
30264
|
if (s.showExchange) {
|
|
30264
30265
|
// Exchange tiles from the rack
|
|
30265
|
-
const disabled =
|
|
30266
|
+
const disabled = !s.exchangeAllowed || s.tilesPlaced || s.showingDialog;
|
|
30266
30267
|
r.push(makeButton("submitexchange", disabled, () => game.submitExchange(), // Note: plain game.submitExchange doesn't work here
|
|
30267
30268
|
ts("Skipta stöfum"), glyph("refresh")));
|
|
30268
30269
|
}
|
|
@@ -30559,24 +30560,24 @@ const Tile = (initialVnode) => {
|
|
|
30559
30560
|
const isRackTile = coord[0] === 'R';
|
|
30560
30561
|
// A single tile, on the board or in the rack
|
|
30561
30562
|
const t = game.tiles[coord];
|
|
30562
|
-
let classes = [".tile"];
|
|
30563
|
+
let classes = [".netskrafl-tile"];
|
|
30563
30564
|
let attrs = {};
|
|
30564
30565
|
if (t.tile === '?')
|
|
30565
|
-
classes.push("blanktile");
|
|
30566
|
+
classes.push("netskrafl-blanktile");
|
|
30566
30567
|
if (EXTRA_WIDE_LETTERS.includes(t.letter))
|
|
30567
30568
|
// Extra wide letter: handle specially
|
|
30568
|
-
classes.push("extra-wide");
|
|
30569
|
+
classes.push("netskrafl-extra-wide");
|
|
30569
30570
|
else if (WIDE_LETTERS.includes(t.letter))
|
|
30570
30571
|
// Wide letter: handle specially
|
|
30571
|
-
classes.push("wide");
|
|
30572
|
+
classes.push("netskrafl-wide");
|
|
30572
30573
|
if (isRackTile || t.draggable) {
|
|
30573
30574
|
// Rack tile, or at least a draggable one
|
|
30574
|
-
classes.push(opponent ? "freshtile" : "racktile");
|
|
30575
|
+
classes.push(opponent ? "netskrafl-freshtile" : "netskrafl-racktile");
|
|
30575
30576
|
if (isRackTile && game.showingDialog === "exchange") {
|
|
30576
30577
|
// Rack tile, and we're showing the exchange dialog
|
|
30577
30578
|
if (t.xchg)
|
|
30578
30579
|
// Chosen as an exchange tile
|
|
30579
|
-
classes.push("xchgsel");
|
|
30580
|
+
classes.push("netskrafl-xchgsel");
|
|
30580
30581
|
// Exchange dialog is live: add a click handler for the
|
|
30581
30582
|
// exchange state
|
|
30582
30583
|
attrs.onclick = (ev) => {
|
|
@@ -30589,7 +30590,7 @@ const Tile = (initialVnode) => {
|
|
|
30589
30590
|
else if (t.freshtile) {
|
|
30590
30591
|
// A fresh tile on the board that has
|
|
30591
30592
|
// just been played by the opponent
|
|
30592
|
-
classes.push("freshtile");
|
|
30593
|
+
classes.push("netskrafl-freshtile");
|
|
30593
30594
|
}
|
|
30594
30595
|
if (t.index) {
|
|
30595
30596
|
// Make fresh or highlighted tiles appear sequentally by animation
|
|
@@ -32195,11 +32196,11 @@ const vwButtonsReview = (view, moveIndex) => {
|
|
|
32195
32196
|
() => {
|
|
32196
32197
|
// Navigate to previous moveIndex
|
|
32197
32198
|
model.loadBestMoves(moveIndex ? moveIndex - 1 : 0);
|
|
32198
|
-
}, "Sjá fyrri leik", m("span", { id: "nav-prev-visible" }, [glyph("chevron-left"), " Fyrri"]), "navprev"));
|
|
32199
|
+
}, "Sjá fyrri leik", m("span", { id: "nav-prev-visible" }, [glyph("chevron-left"), " Fyrri"]), true, "navprev"));
|
|
32199
32200
|
r.push(makeButton("navbtn", (!moveIndex) || (moveIndex >= numMoves), () => {
|
|
32200
32201
|
// Navigate to next moveIndex
|
|
32201
32202
|
model.loadBestMoves(moveIndex + 1);
|
|
32202
|
-
}, "Sjá næsta leik", m("span", { id: "nav-next-visible" }, ["Næsti ", glyph("chevron-right")]), "navnext"));
|
|
32203
|
+
}, "Sjá næsta leik", m("span", { id: "nav-next-visible" }, ["Næsti ", glyph("chevron-right")]), true, "navnext"));
|
|
32203
32204
|
// Show the score difference between an actual moveIndex and
|
|
32204
32205
|
// a particular moveIndex on the best moveIndex list
|
|
32205
32206
|
if (model.highlightedMove !== null) {
|
|
@@ -32409,39 +32410,68 @@ class View {
|
|
|
32409
32410
|
this.boardScale = 1.0;
|
|
32410
32411
|
const boardParent = document.getElementById("board-parent");
|
|
32411
32412
|
const board = boardParent === null || boardParent === void 0 ? void 0 : boardParent.children[0];
|
|
32412
|
-
if (board)
|
|
32413
|
-
board.
|
|
32413
|
+
if (board) {
|
|
32414
|
+
board.style.transition = 'none';
|
|
32415
|
+
board.style.transformOrigin = 'top left';
|
|
32416
|
+
board.style.transform = `translate(0, 0) scale(1.0)`;
|
|
32417
|
+
}
|
|
32414
32418
|
if (boardParent)
|
|
32415
32419
|
boardParent.scrollTo(0, 0);
|
|
32416
32420
|
}
|
|
32417
32421
|
updateScale() {
|
|
32418
32422
|
var _a;
|
|
32419
32423
|
const model = this.model;
|
|
32420
|
-
|
|
32424
|
+
// Use either the regular game or the riddle (Gáta Dagsins)
|
|
32425
|
+
const game = model.game || model.riddle;
|
|
32421
32426
|
// Update the board scale (zoom)
|
|
32422
32427
|
function scrollIntoView(sq) {
|
|
32423
|
-
// Scroll a square above and to the left of the placed tile into view
|
|
32428
|
+
// Scroll a square above and to the left of the placed tile into view,
|
|
32429
|
+
// with a smooth concurrent zoom and pan animation,
|
|
32430
|
+
// taking clamping into account to ensure that the board always fills
|
|
32431
|
+
// the viewport.
|
|
32432
|
+
const boardParent = document.getElementById("board-parent");
|
|
32433
|
+
const board = boardParent === null || boardParent === void 0 ? void 0 : boardParent.children[0];
|
|
32434
|
+
if (!board || !boardParent)
|
|
32435
|
+
return;
|
|
32424
32436
|
const offset = 3;
|
|
32425
32437
|
const vec = toVector(sq);
|
|
32426
32438
|
const row = Math.max(0, vec.row - offset);
|
|
32427
32439
|
const col = Math.max(0, vec.col - offset);
|
|
32428
32440
|
const c = coord(row, col);
|
|
32429
|
-
|
|
32430
|
-
|
|
32431
|
-
|
|
32432
|
-
// the transform and hence the size of the board has been
|
|
32433
|
-
// updated in the browser, before calculating the client rects
|
|
32434
|
-
if (board)
|
|
32435
|
-
board.setAttribute("style", `transform: scale(${ZOOM_FACTOR})`);
|
|
32441
|
+
// Temporarily set scale to calculate target scroll position
|
|
32442
|
+
board.style.transformOrigin = 'top left';
|
|
32443
|
+
board.style.transform = `translate(0, 0) scale(1.0)`;
|
|
32436
32444
|
const el = document.getElementById("sq_" + c);
|
|
32437
32445
|
const elRect = el === null || el === void 0 ? void 0 : el.getBoundingClientRect();
|
|
32438
|
-
const boardRect = boardParent
|
|
32439
|
-
if (
|
|
32440
|
-
|
|
32441
|
-
|
|
32442
|
-
|
|
32443
|
-
|
|
32444
|
-
|
|
32446
|
+
const boardRect = boardParent.getBoundingClientRect();
|
|
32447
|
+
if (elRect && boardRect) {
|
|
32448
|
+
// Get the dimensions of the scrollable area
|
|
32449
|
+
const viewportWidth = boardParent.clientWidth;
|
|
32450
|
+
const viewportHeight = boardParent.clientHeight;
|
|
32451
|
+
// The offsetWidth/Height include borders, so we use those
|
|
32452
|
+
const scaledBoardWidth = board.offsetWidth * ZOOM_FACTOR;
|
|
32453
|
+
const scaledBoardHeight = board.offsetHeight * ZOOM_FACTOR;
|
|
32454
|
+
// Calculate maximum scroll positions (board edges)
|
|
32455
|
+
const maxScrollLeft = scaledBoardWidth - viewportWidth;
|
|
32456
|
+
const maxScrollTop = scaledBoardHeight - viewportHeight;
|
|
32457
|
+
// Calculate desired scroll position to put the target into
|
|
32458
|
+
// the top left corner of the viewport, or as close as possible
|
|
32459
|
+
let targetScrollLeft = Math.min(elRect.left - boardRect.left, maxScrollLeft);
|
|
32460
|
+
let targetScrollTop = Math.min(elRect.top - boardRect.top, maxScrollTop);
|
|
32461
|
+
// Now animate both translate (for pan) and scale (for zoom) concurrently
|
|
32462
|
+
board.style.transition = 'transform 0.3s ease-in-out';
|
|
32463
|
+
// Note: transforms are applied right to left
|
|
32464
|
+
board.style.transform =
|
|
32465
|
+
`translate(${-targetScrollLeft}px, ${-targetScrollTop}px) scale(${ZOOM_FACTOR})`;
|
|
32466
|
+
// When animation completes, commit to actual scroll position and reset translate
|
|
32467
|
+
board.addEventListener('transitionend', function handler() {
|
|
32468
|
+
// First reset the transform (remove translate, keep scale)
|
|
32469
|
+
board.style.transition = 'none';
|
|
32470
|
+
board.style.transform = `translate(0, 0) scale(${ZOOM_FACTOR})`;
|
|
32471
|
+
// Now set the actual scroll position (already clamped)
|
|
32472
|
+
boardParent.scrollTo(targetScrollLeft, targetScrollTop);
|
|
32473
|
+
board.removeEventListener('transitionend', handler);
|
|
32474
|
+
}, { once: true });
|
|
32445
32475
|
}
|
|
32446
32476
|
}
|
|
32447
32477
|
if (!game || ((_a = model.state) === null || _a === void 0 ? void 0 : _a.uiFullscreen) || game.moveInProgress) {
|
|
@@ -32728,14 +32758,14 @@ class View {
|
|
|
32728
32758
|
// displayed. We therefore allow them to cover the last_chall
|
|
32729
32759
|
// dialog. On mobile, both dialogs are displayed simultaneously.
|
|
32730
32760
|
if (game.last_chall) {
|
|
32731
|
-
r.push(m(".chall-info",
|
|
32761
|
+
r.push(m(".chall-info", [
|
|
32732
32762
|
glyph("info-sign"), nbsp(),
|
|
32733
32763
|
// "Your opponent emptied the rack - you can challenge or pass"
|
|
32734
32764
|
mt("span.pass-explain", "opponent_emptied_rack")
|
|
32735
32765
|
]));
|
|
32736
32766
|
}
|
|
32737
32767
|
if (game.showingDialog == "resign") {
|
|
32738
|
-
r.push(m(".resign",
|
|
32768
|
+
r.push(m(".resign", [
|
|
32739
32769
|
glyph("exclamation-sign"), nbsp(), ts("Viltu gefa leikinn?"), nbsp(),
|
|
32740
32770
|
m("span.mobile-break", m("br")),
|
|
32741
32771
|
m("span.yesnobutton", { onclick: () => game.confirmResign(true) }, [glyph("ok"), ts(" Já")]),
|
|
@@ -32745,7 +32775,7 @@ class View {
|
|
|
32745
32775
|
}
|
|
32746
32776
|
if (game.showingDialog == "pass") {
|
|
32747
32777
|
if (game.last_chall) {
|
|
32748
|
-
r.push(m(".pass-last",
|
|
32778
|
+
r.push(m(".pass-last", [
|
|
32749
32779
|
glyph("forward"), nbsp(), ts("Segja pass?"),
|
|
32750
32780
|
mt("span.pass-explain", "Viðureign lýkur þar með"),
|
|
32751
32781
|
nbsp(),
|
|
@@ -32756,7 +32786,7 @@ class View {
|
|
|
32756
32786
|
]));
|
|
32757
32787
|
}
|
|
32758
32788
|
else {
|
|
32759
|
-
r.push(m(".pass",
|
|
32789
|
+
r.push(m(".pass", [
|
|
32760
32790
|
glyph("forward"), nbsp(), ts("Segja pass?"),
|
|
32761
32791
|
mt("span.pass-explain", "2x3 pöss í röð ljúka viðureign"),
|
|
32762
32792
|
nbsp(), m("span.mobile-break", m("br")),
|
|
@@ -32767,7 +32797,7 @@ class View {
|
|
|
32767
32797
|
}
|
|
32768
32798
|
}
|
|
32769
32799
|
if (game.showingDialog == "exchange") {
|
|
32770
|
-
r.push(m(".exchange",
|
|
32800
|
+
r.push(m(".exchange", [
|
|
32771
32801
|
glyph("refresh"), nbsp(),
|
|
32772
32802
|
ts("Smelltu á flísarnar sem þú vilt skipta"), nbsp(),
|
|
32773
32803
|
m("span.mobile-break", m("br")),
|
|
@@ -32777,7 +32807,7 @@ class View {
|
|
|
32777
32807
|
]));
|
|
32778
32808
|
}
|
|
32779
32809
|
if (game.showingDialog == "chall") {
|
|
32780
|
-
r.push(m(".chall",
|
|
32810
|
+
r.push(m(".chall", [
|
|
32781
32811
|
glyph("ban-circle"), nbsp(), ts("Véfengja lögn?"),
|
|
32782
32812
|
mt("span.pass-explain", "Röng véfenging kostar 10 stig"), nbsp(),
|
|
32783
32813
|
m("span.mobile-break", m("br")),
|
|
@@ -33116,6 +33146,7 @@ class BaseGame {
|
|
|
33116
33146
|
this.currentError = null;
|
|
33117
33147
|
this.currentMessage = null;
|
|
33118
33148
|
this.localturn = true;
|
|
33149
|
+
this.moveInProgress = false;
|
|
33119
33150
|
// UI state
|
|
33120
33151
|
this.showingDialog = null;
|
|
33121
33152
|
this.selectedSq = null;
|
|
@@ -36208,12 +36239,12 @@ class Actions {
|
|
|
36208
36239
|
score: json[userId].score || 0,
|
|
36209
36240
|
timestamp: json[userId].timestamp || ''
|
|
36210
36241
|
}));
|
|
36211
|
-
// Sort by score descending, then by timestamp
|
|
36242
|
+
// Sort by score descending, then by timestamp ascending (earlier first)
|
|
36212
36243
|
entries.sort((a, b) => {
|
|
36213
36244
|
if (b.score !== a.score) {
|
|
36214
36245
|
return b.score - a.score;
|
|
36215
36246
|
}
|
|
36216
|
-
return
|
|
36247
|
+
return a.timestamp.localeCompare(b.timestamp);
|
|
36217
36248
|
});
|
|
36218
36249
|
this.model.leaderboard = entries;
|
|
36219
36250
|
}
|
|
@@ -36579,13 +36610,16 @@ const SunCorona = {
|
|
|
36579
36610
|
const MobileStatus = () => {
|
|
36580
36611
|
return {
|
|
36581
36612
|
view: (vnode) => {
|
|
36582
|
-
const { riddle, selectedMoves, bestMove, onMoveClick } = vnode.attrs;
|
|
36613
|
+
const { riddle, selectedMoves, bestMove, onMoveClick, onStatsClick } = vnode.attrs;
|
|
36583
36614
|
const { bestPossibleScore, globalBestScore } = riddle;
|
|
36584
36615
|
// Determine if player achieved best possible score
|
|
36585
36616
|
const achieved = bestMove !== undefined;
|
|
36586
36617
|
const celebrate = bestMove && bestMove.word !== "";
|
|
36587
36618
|
// Get player's current best score
|
|
36588
|
-
|
|
36619
|
+
// If the player achieved the best possible score, it's in bestMove (not selectedMoves)
|
|
36620
|
+
const playerBestScore = (bestMove && bestMove.word !== "")
|
|
36621
|
+
? bestMove.score
|
|
36622
|
+
: (selectedMoves.length > 0 ? selectedMoves[0].score : 0);
|
|
36589
36623
|
// Determine current leader score (may be this player or another)
|
|
36590
36624
|
let leaderScore = 0;
|
|
36591
36625
|
let isPlayerLeading = false;
|
|
@@ -36600,19 +36634,27 @@ const MobileStatus = () => {
|
|
|
36600
36634
|
}
|
|
36601
36635
|
return m(".mobile-status-container", [
|
|
36602
36636
|
// Current word score (leftmost) - uses RiddleScore component in mobile mode
|
|
36603
|
-
m(".mobile-status-item", m(RiddleScore, { riddle, mode: "mobile" })),
|
|
36604
|
-
//
|
|
36605
|
-
m(".mobile-status-
|
|
36606
|
-
|
|
36607
|
-
|
|
36608
|
-
|
|
36609
|
-
|
|
36610
|
-
|
|
36611
|
-
|
|
36612
|
-
|
|
36637
|
+
m(".mobile-status-item.left", m(RiddleScore, { riddle, mode: "mobile" })),
|
|
36638
|
+
// Interactive card containing player best and leader scores
|
|
36639
|
+
m(".mobile-status-card", {
|
|
36640
|
+
onclick: onStatsClick,
|
|
36641
|
+
title: ts("Tölfræði og stigatafla")
|
|
36642
|
+
}, [
|
|
36643
|
+
// Player's best score
|
|
36644
|
+
m(".mobile-status-card-item.player-best", [
|
|
36645
|
+
m(".mobile-status-label", ts("Þín besta:")),
|
|
36646
|
+
m(".mobile-status-score", playerBestScore.toString())
|
|
36647
|
+
]),
|
|
36648
|
+
// Current leader score
|
|
36649
|
+
m(".mobile-status-card-item.leader" + (isPlayerLeading ? ".is-player" : ""), [
|
|
36650
|
+
m(".mobile-status-label", isPlayerLeading ? ts("Þú leiðir!") : ts("Leiðandi:")),
|
|
36651
|
+
m(".mobile-status-score", leaderScore.toString())
|
|
36652
|
+
]),
|
|
36653
|
+
// Chevron indicator (overlaid at bottom center)
|
|
36654
|
+
m(".mobile-status-card-icon", glyph("chevron-down"))
|
|
36613
36655
|
]),
|
|
36614
36656
|
// Best possible score
|
|
36615
|
-
m(".mobile-status-item.best-possible"
|
|
36657
|
+
m(".mobile-status-item.right.best-possible"
|
|
36616
36658
|
+ (celebrate ? ".celebrate" : "")
|
|
36617
36659
|
+ (achieved ? ".achieved" : ""), {
|
|
36618
36660
|
onclick: () => celebrate && onMoveClick(bestMove.word, bestMove.coord)
|
|
@@ -37085,7 +37127,7 @@ const RightSideTabs = () => {
|
|
|
37085
37127
|
const GataDagsinsRightSide = {
|
|
37086
37128
|
// Component containing both mobile status bar and desktop tabbed view
|
|
37087
37129
|
view: (vnode) => {
|
|
37088
|
-
const { view, selectedMoves, bestMove } = vnode.attrs;
|
|
37130
|
+
const { view, selectedMoves, bestMove, onStatsClick } = vnode.attrs;
|
|
37089
37131
|
const { riddle } = view.model;
|
|
37090
37132
|
const handleMoveClick = (word, coord) => {
|
|
37091
37133
|
if (riddle && word && coord) {
|
|
@@ -37099,7 +37141,8 @@ const GataDagsinsRightSide = {
|
|
|
37099
37141
|
riddle,
|
|
37100
37142
|
selectedMoves,
|
|
37101
37143
|
bestMove,
|
|
37102
|
-
onMoveClick: handleMoveClick
|
|
37144
|
+
onMoveClick: handleMoveClick,
|
|
37145
|
+
onStatsClick
|
|
37103
37146
|
})),
|
|
37104
37147
|
// Desktop-only tabbed view (hidden on mobile, visible on desktop)
|
|
37105
37148
|
m(".gatadagsins-thermometer-column", m(RightSideTabs, {
|
|
@@ -37129,64 +37172,72 @@ const GataDagsinsRightSide = {
|
|
|
37129
37172
|
const GataDagsinsHelp = {
|
|
37130
37173
|
view: (vnode) => {
|
|
37131
37174
|
const closeHelp = vnode.attrs.onClose;
|
|
37132
|
-
return
|
|
37133
|
-
//
|
|
37134
|
-
m(".modal-
|
|
37135
|
-
|
|
37136
|
-
|
|
37137
|
-
|
|
37138
|
-
|
|
37139
|
-
|
|
37140
|
-
|
|
37141
|
-
|
|
37142
|
-
|
|
37143
|
-
|
|
37144
|
-
|
|
37145
|
-
|
|
37146
|
-
|
|
37147
|
-
m("li", "Þú færð borð með allmörgum stöfum sem þegar hafa verið lagðir."),
|
|
37148
|
-
m("li", "Neðst á skjánum eru stafaflísar sem þú getur notað til að mynda orð."),
|
|
37149
|
-
m("li", "Dragðu flísar á borðið til að mynda orð, annaðhvort lárétt eða lóðrétt."),
|
|
37150
|
-
m("li", "Orðin verða að tengjast við stafi sem fyrir eru á borðinu."),
|
|
37151
|
-
m("li", "Þú sérð jafnóðum hvort lögnin á borðinu er gild og hversu mörg stig hún gefur."),
|
|
37152
|
-
m("li", "Þú getur prófað eins mörg orð og þú vilt - besta skorið þitt er vistað."),
|
|
37153
|
-
]),
|
|
37154
|
-
m("h3", "Stigagjöf"),
|
|
37155
|
-
m("p", "Þú færð stig fyrir hvern staf í orðinu, auk bónusstiga fyrir lengri orð:"),
|
|
37156
|
-
m("ul", [
|
|
37157
|
-
m("li", "Hver stafur gefur 1-10 stig eftir gildi hans"),
|
|
37158
|
-
m("li", "Orð sem nota allar 7 stafaflísarnar gefa 50 stiga bónus"),
|
|
37159
|
-
m("li", "Sumir reitir á borðinu tvöfalda eða þrefalda stafagildið"),
|
|
37160
|
-
m("li", "Sumir reitir tvöfalda eða þrefalda heildarorðagildið"),
|
|
37161
|
-
]),
|
|
37162
|
-
m("h3", "Hitamælir"),
|
|
37163
|
-
m("p", "Hitamælirinn hægra megin (eða efst á farsímum) sýnir:"),
|
|
37164
|
-
m("ul", [
|
|
37165
|
-
m("li", m("strong", "Besta mögulega skor:"), " Hæstu stig sem hægt er að ná á þessu borði."),
|
|
37166
|
-
m("li", m("strong", "Besta skor dagsins:"), " Hæstu stig sem einhver leikmaður hefur náð í dag."),
|
|
37167
|
-
m("li", m("strong", "Þín bestu orð:"), " Orðin sem þú hefur lagt og stigin fyrir þau."),
|
|
37168
|
-
m("li", "Þú getur smellt á orð á hitamælinum til að fá þá lögn aftur á borðið."),
|
|
37175
|
+
return [
|
|
37176
|
+
// Backdrop
|
|
37177
|
+
m(".modal-backdrop-netskrafl", {
|
|
37178
|
+
onclick: (e) => { e.preventDefault(); },
|
|
37179
|
+
onwheel: (e) => { e.preventDefault(); e.stopPropagation(); },
|
|
37180
|
+
ontouchmove: (e) => { e.preventDefault(); e.stopPropagation(); }
|
|
37181
|
+
}),
|
|
37182
|
+
m(".modal-dialog.gatadagsins-help", m(".modal-content", [
|
|
37183
|
+
// Header with close button
|
|
37184
|
+
m(".modal-header", [
|
|
37185
|
+
m("h2", "Um Gátu dagsins"),
|
|
37186
|
+
m("button.close", {
|
|
37187
|
+
onclick: closeHelp,
|
|
37188
|
+
"aria-label": "Loka"
|
|
37189
|
+
}, m("span", { "aria-hidden": "true" }, "×"))
|
|
37169
37190
|
]),
|
|
37170
|
-
|
|
37171
|
-
m("
|
|
37172
|
-
m("
|
|
37173
|
-
|
|
37174
|
-
m("
|
|
37175
|
-
m("
|
|
37176
|
-
|
|
37177
|
-
|
|
37178
|
-
|
|
37179
|
-
|
|
37180
|
-
|
|
37181
|
-
|
|
37182
|
-
|
|
37191
|
+
// Body with help content
|
|
37192
|
+
m(".modal-body", [
|
|
37193
|
+
m("p", "Gáta dagsins er dagleg krossgátuþraut, svipuð skrafli, þar sem þú reynir að finna " +
|
|
37194
|
+
"stigahæsta orðið sem hægt er að mynda með gefnum stöfum."),
|
|
37195
|
+
m("h3", "Hvernig á að spila"),
|
|
37196
|
+
m("ul", [
|
|
37197
|
+
m("li", "Þú færð borð með allmörgum stöfum sem þegar hafa verið lagðir."),
|
|
37198
|
+
m("li", "Neðst á skjánum eru stafaflísar sem þú getur notað til að mynda orð."),
|
|
37199
|
+
m("li", "Dragðu flísar á borðið til að mynda orð, annaðhvort lárétt eða lóðrétt."),
|
|
37200
|
+
m("li", "Orðin verða að tengjast við stafi sem fyrir eru á borðinu."),
|
|
37201
|
+
m("li", "Þú sérð jafnóðum hvort lögnin á borðinu er gild og hversu mörg stig hún gefur."),
|
|
37202
|
+
m("li", "Þú getur prófað eins mörg orð og þú vilt - besta skorið þitt er vistað."),
|
|
37203
|
+
]),
|
|
37204
|
+
m("h3", "Stigagjöf"),
|
|
37205
|
+
m("p", "Þú færð stig fyrir hvern staf í orðinu, auk bónusstiga fyrir lengri orð:"),
|
|
37206
|
+
m("ul", [
|
|
37207
|
+
m("li", "Hver stafur gefur 1-10 stig eftir gildi hans"),
|
|
37208
|
+
m("li", "Orð sem nota allar 7 stafaflísarnar gefa 50 stiga bónus"),
|
|
37209
|
+
m("li", "Sumir reitir á borðinu tvöfalda eða þrefalda stafagildið"),
|
|
37210
|
+
m("li", "Sumir reitir tvöfalda eða þrefalda heildarorðagildið"),
|
|
37211
|
+
]),
|
|
37212
|
+
m("h3", "Hitamælir"),
|
|
37213
|
+
m("p", "Hitamælirinn hægra megin (eða efst á farsímum) sýnir:"),
|
|
37214
|
+
m("ul", [
|
|
37215
|
+
m("li", m("strong", "Besta mögulega skor:"), " Hæstu stig sem hægt er að ná á þessu borði."),
|
|
37216
|
+
m("li", m("strong", "Besta skor dagsins:"), " Hæstu stig sem einhver leikmaður hefur náð í dag."),
|
|
37217
|
+
m("li", m("strong", "Þín bestu orð:"), " Orðin sem þú hefur lagt og stigin fyrir þau."),
|
|
37218
|
+
m("li", "Þú getur smellt á orð á hitamælinum til að fá þá lögn aftur á borðið."),
|
|
37219
|
+
]),
|
|
37220
|
+
m("h3", "Ábendingar"),
|
|
37221
|
+
m("ul", [
|
|
37222
|
+
m("li", "Reyndu að nota dýra stafi (eins og X, Ý, Þ) á tvöföldunar- eða þreföldunarreitum."),
|
|
37223
|
+
m("li", "Lengri orð gefa mun fleiri stig vegna bónussins."),
|
|
37224
|
+
m("li", "Þú getur dregið allar flísar til baka með bláa endurkalls-hnappnum."),
|
|
37225
|
+
m("li", "Ný gáta birtist á hverjum nýjum degi - klukkan 00:00!"),
|
|
37226
|
+
]),
|
|
37227
|
+
m("h3", "Um leikinn"),
|
|
37228
|
+
m("p", [
|
|
37229
|
+
"Gáta dagsins er systkini ",
|
|
37230
|
+
m("a", { href: "https://netskrafl.is", target: "_blank" }, "Netskrafls"),
|
|
37231
|
+
", hins sívinsæla íslenska krossgátuleiks á netinu. ",
|
|
37232
|
+
"Leikurinn er þróaður af Miðeind ehf."
|
|
37233
|
+
]),
|
|
37183
37234
|
]),
|
|
37184
|
-
|
|
37185
|
-
|
|
37186
|
-
|
|
37187
|
-
|
|
37188
|
-
|
|
37189
|
-
]
|
|
37235
|
+
// Footer with close button
|
|
37236
|
+
m(".modal-footer", m("button.btn.btn-primary", {
|
|
37237
|
+
onclick: closeHelp
|
|
37238
|
+
}, "Loka"))
|
|
37239
|
+
])),
|
|
37240
|
+
];
|
|
37190
37241
|
}
|
|
37191
37242
|
};
|
|
37192
37243
|
|
|
@@ -37223,19 +37274,22 @@ const StatsModal = () => {
|
|
|
37223
37274
|
};
|
|
37224
37275
|
return [
|
|
37225
37276
|
// Backdrop
|
|
37226
|
-
m(".modal-backdrop", {
|
|
37227
|
-
onclick:
|
|
37277
|
+
m(".modal-backdrop-netskrafl", {
|
|
37278
|
+
onclick: (e) => { e.preventDefault(); },
|
|
37279
|
+
onwheel: (e) => { e.preventDefault(); e.stopPropagation(); },
|
|
37280
|
+
ontouchmove: (e) => { e.preventDefault(); e.stopPropagation(); }
|
|
37228
37281
|
}),
|
|
37229
37282
|
// Modal dialog
|
|
37230
|
-
m(".modal-dialog.stats-modal",
|
|
37283
|
+
m(".modal-dialog.stats-modal", {
|
|
37284
|
+
onwheel: (e) => { e.stopPropagation(); },
|
|
37285
|
+
ontouchmove: (e) => { e.stopPropagation(); }
|
|
37286
|
+
}, [
|
|
37231
37287
|
m(".modal-content", [
|
|
37232
|
-
//
|
|
37233
|
-
m(".
|
|
37234
|
-
|
|
37235
|
-
|
|
37236
|
-
|
|
37237
|
-
}, "×")
|
|
37238
|
-
]),
|
|
37288
|
+
// Close button in top right
|
|
37289
|
+
m("button.close", {
|
|
37290
|
+
onclick: onClose,
|
|
37291
|
+
"aria-label": "Loka"
|
|
37292
|
+
}, glyph("remove")),
|
|
37239
37293
|
// Tab navigation
|
|
37240
37294
|
m(TabBar, {
|
|
37241
37295
|
tabs,
|
|
@@ -37262,30 +37316,6 @@ const StatsModal = () => {
|
|
|
37262
37316
|
};
|
|
37263
37317
|
};
|
|
37264
37318
|
|
|
37265
|
-
/*
|
|
37266
|
-
|
|
37267
|
-
MobileStatsButton.ts
|
|
37268
|
-
|
|
37269
|
-
Button to open stats modal on mobile
|
|
37270
|
-
|
|
37271
|
-
Copyright (C) 2025 Miðeind ehf.
|
|
37272
|
-
Author: Vilhjálmur Þorsteinsson
|
|
37273
|
-
|
|
37274
|
-
The Creative Commons Attribution-NonCommercial 4.0
|
|
37275
|
-
International Public License (CC-BY-NC 4.0) applies to this software.
|
|
37276
|
-
For further information, see https://github.com/mideind/Netskrafl
|
|
37277
|
-
|
|
37278
|
-
*/
|
|
37279
|
-
const MobileStatsButton = {
|
|
37280
|
-
view: (vnode) => {
|
|
37281
|
-
const { onClick } = vnode.attrs;
|
|
37282
|
-
return m(".mobile-stats-button", {
|
|
37283
|
-
onclick: onClick,
|
|
37284
|
-
title: "Tölfræði og stigatafla"
|
|
37285
|
-
}, m(".stats-icon", glyph("stats")));
|
|
37286
|
-
}
|
|
37287
|
-
};
|
|
37288
|
-
|
|
37289
37319
|
/*
|
|
37290
37320
|
|
|
37291
37321
|
GataDagsins.ts
|
|
@@ -37391,7 +37421,7 @@ const GataDagsins$1 = () => {
|
|
|
37391
37421
|
// Board and rack component (left side)
|
|
37392
37422
|
m(GataDagsinsBoardAndRack, { view }),
|
|
37393
37423
|
// Right-side component with scores and comparisons
|
|
37394
|
-
m(GataDagsinsRightSide, { view, selectedMoves, bestMove }),
|
|
37424
|
+
m(GataDagsinsRightSide, { view, selectedMoves, bestMove, onStatsClick: toggleStatsModal }),
|
|
37395
37425
|
// Blank dialog
|
|
37396
37426
|
riddle.askingForBlank
|
|
37397
37427
|
? m(BlankDialog, { game: riddle })
|
|
@@ -37405,13 +37435,8 @@ const GataDagsins$1 = () => {
|
|
|
37405
37435
|
((_a = model.state) === null || _a === void 0 ? void 0 : _a.beginner) ? m(Beginner, { view }) : "",
|
|
37406
37436
|
// Custom Info button for GataDagsins that shows help dialog
|
|
37407
37437
|
m(".info", { title: ts("Upplýsingar og hjálp") }, m("a.iconlink", { href: "#", onclick: (e) => { e.preventDefault(); toggleHelp(); } }, glyph("info-sign"))),
|
|
37408
|
-
// Mobile stats button (hidden on desktop)
|
|
37409
|
-
m(MobileStatsButton, { onClick: toggleStatsModal }),
|
|
37410
37438
|
// Help dialog and backdrop
|
|
37411
|
-
showHelp ?
|
|
37412
|
-
m(".modal-backdrop", { onclick: (e) => { e.preventDefault(); } }),
|
|
37413
|
-
m(GataDagsinsHelp, { onClose: toggleHelp })
|
|
37414
|
-
] : "",
|
|
37439
|
+
showHelp ? m(GataDagsinsHelp, { onClose: toggleHelp }) : "",
|
|
37415
37440
|
// Stats modal and backdrop (mobile only)
|
|
37416
37441
|
showStatsModal ? m(StatsModal, { view, onClose: toggleStatsModal }) : "",
|
|
37417
37442
|
]);
|