@mideind/netskrafl-react 1.4.0 → 1.5.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.
@@ -929,14 +929,11 @@ div.netskrafl-container * {
929
929
  }
930
930
 
931
931
  .netskrafl-container div.board table.board {
932
- transform: scale(1);
933
- transform-origin: 0 0;
932
+ transform: translate(0px, 0px) scale(1);
933
+ transition: none;
934
+ transform-origin: top left;
934
935
  transform-box: view-box;
935
936
  touch-action: pan-x pan-y;
936
- /*
937
- !!! Scrolling into view doesn't seem to work with this transition enabled
938
- transition: transform .2s ease-in-out;
939
- */
940
937
  }
941
938
 
942
939
  .netskrafl-container table.board tr {
@@ -6281,7 +6278,7 @@ div.netskrafl-container input[type="checkbox"] {
6281
6278
  .netskrafl-container div.info {
6282
6279
  display: block;
6283
6280
  position: absolute;
6284
- bottom: 148px;
6281
+ bottom: 152px;
6285
6282
  top: auto;
6286
6283
  left: 28px;
6287
6284
  width: 50px;
@@ -6363,6 +6360,7 @@ div.netskrafl-container input[type="checkbox"] {
6363
6360
  width: auto;
6364
6361
  height: auto;
6365
6362
  margin: 0;
6363
+ overflow: visible; /* No scrollbars in fullscreen mode */
6366
6364
  }
6367
6365
  .netskrafl-container .board td {
6368
6366
  min-height: 30px;
@@ -7585,7 +7583,7 @@ div.netskrafl-container input[type="checkbox"] {
7585
7583
  .netskrafl-container .modal-dialog.gatadagsins-help {
7586
7584
  visibility: visible;
7587
7585
  position: fixed;
7588
- top: 50%;
7586
+ top: 52%;
7589
7587
  left: 50%;
7590
7588
  transform: translate(-50%, -50%);
7591
7589
  z-index: 10000;
@@ -7608,7 +7606,7 @@ div.netskrafl-container input[type="checkbox"] {
7608
7606
  padding: 15px;
7609
7607
  border-bottom: 1px solid #e0e0e0;
7610
7608
  display: flex;
7611
- justify-content: space-between;
7609
+ justify-content: flex-start;
7612
7610
  align-items: center;
7613
7611
  }
7614
7612
 
@@ -7618,22 +7616,37 @@ div.netskrafl-container input[type="checkbox"] {
7618
7616
  color: #333;
7619
7617
  }
7620
7618
 
7621
- .netskrafl-container .modal-dialog.gatadagsins-help .modal-header .close {
7622
- background: none;
7619
+ .netskrafl-container .modal-dialog.gatadagsins-help .modal-content {
7620
+ position: relative;
7621
+ }
7622
+
7623
+ .netskrafl-container .modal-dialog.gatadagsins-help .close {
7624
+ position: absolute;
7625
+ top: 10px;
7626
+ right: 10px;
7627
+ background-color: var(--malfridur-accent);
7623
7628
  border: none;
7624
- font-size: 28px;
7629
+ border-radius: 6px;
7625
7630
  cursor: pointer;
7626
7631
  padding: 0;
7627
- width: 30px;
7628
- height: 30px;
7632
+ width: 36px;
7633
+ height: 36px;
7629
7634
  display: flex;
7630
7635
  align-items: center;
7631
7636
  justify-content: center;
7632
- color: #999;
7637
+ color: white;
7638
+ z-index: 10;
7639
+ transition: all 0.2s ease;
7633
7640
  }
7634
7641
 
7635
- .netskrafl-container .modal-dialog.gatadagsins-help .modal-header .close:hover {
7636
- color: #333;
7642
+ .netskrafl-container .modal-dialog.gatadagsins-help .close .glyphicon {
7643
+ font-size: 18px;
7644
+ top: 0;
7645
+ }
7646
+
7647
+ .netskrafl-container .modal-dialog.gatadagsins-help .close:hover {
7648
+ background-color: var(--logo-accent);
7649
+ transform: scale(1.05);
7637
7650
  }
7638
7651
 
7639
7652
  .netskrafl-container .modal-dialog.gatadagsins-help .modal-body {
@@ -7718,9 +7731,9 @@ div.netskrafl-container input[type="checkbox"] {
7718
7731
  width: 100%;
7719
7732
  height: 100%;
7720
7733
  background-color: rgba(0, 0, 0, 0.5);
7721
- z-index: 9999;
7734
+ /* z-index: 9999; */
7722
7735
  overflow: hidden;
7723
- touch-action: none;
7736
+ /* touch-action: none; */
7724
7737
  }
7725
7738
 
7726
7739
  /* Larger screen adjustments */
@@ -7734,6 +7747,7 @@ div.netskrafl-container input[type="checkbox"] {
7734
7747
 
7735
7748
  .netskrafl-container .modal-dialog.gatadagsins-help .modal-header {
7736
7749
  padding: 20px;
7750
+ padding-right: 20px;
7737
7751
  }
7738
7752
 
7739
7753
  .netskrafl-container .modal-dialog.gatadagsins-help .modal-header h2 {
@@ -7834,6 +7848,7 @@ div.gatadagsins-board-area.celebrate div.netskrafl-tile.netskrafl-racktile{
7834
7848
  flex-direction: row;
7835
7849
  justify-content: space-evenly;
7836
7850
  align-items: center;
7851
+ margin-bottom: 20px;
7837
7852
  }
7838
7853
 
7839
7854
  /* Override rack positioning for Gáta Dagsins */
@@ -8697,7 +8712,11 @@ div.gatadagsins-board-area.celebrate div.netskrafl-tile.netskrafl-racktile{
8697
8712
  /* ================= LEADERBOARD VIEW STYLES =============== */
8698
8713
 
8699
8714
  .netskrafl-container .leaderboard-view {
8715
+ display: flex;
8716
+ flex-direction: column;
8700
8717
  padding: 0px 10px;
8718
+ height: 100%;
8719
+ overflow: hidden;
8701
8720
  }
8702
8721
 
8703
8722
  .netskrafl-container .leaderboard-view.loading,
@@ -8716,6 +8735,7 @@ div.gatadagsins-board-area.celebrate div.netskrafl-tile.netskrafl-racktile{
8716
8735
  display: flex;
8717
8736
  flex-direction: column;
8718
8737
  align-items: center;
8738
+ flex-shrink: 0;
8719
8739
  }
8720
8740
 
8721
8741
  .netskrafl-container .leaderboard-title {
@@ -8736,13 +8756,16 @@ div.gatadagsins-board-area.celebrate div.netskrafl-tile.netskrafl-racktile{
8736
8756
  display: flex;
8737
8757
  flex-direction: column;
8738
8758
  gap: 8px;
8759
+ overflow-y: auto;
8760
+ height: 360px;
8761
+ overscroll-behavior-y: contain;
8739
8762
  }
8740
8763
 
8741
8764
  .netskrafl-container .leaderboard-entry {
8742
8765
  display: flex;
8743
8766
  align-items: center;
8744
- gap: 12px;
8745
- padding: 10px;
8767
+ gap: 8px;
8768
+ padding: 8px;
8746
8769
  background-color: #f8f8f8;
8747
8770
  border-radius: 6px;
8748
8771
  transition: all 0.3s ease;
@@ -8788,6 +8811,45 @@ div.gatadagsins-board-area.celebrate div.netskrafl-tile.netskrafl-racktile{
8788
8811
  color: var(--malfridur-green);
8789
8812
  }
8790
8813
 
8814
+ .netskrafl-container .entry-star {
8815
+ display: inline-block;
8816
+ margin-right: 8px;
8817
+ color: var(--malfridur-secondary);
8818
+ line-height: 1;
8819
+ }
8820
+
8821
+ .netskrafl-container .entry-star .glyphicon {
8822
+ font-size: 13px;
8823
+ }
8824
+
8825
+ /* ================= HELP DIALOG BONUS SQUARES =============== */
8826
+
8827
+ .netskrafl-container .help-bonus-square {
8828
+ display: inline-block;
8829
+ width: 12px;
8830
+ height: 12px;
8831
+ border-radius: 2px;
8832
+ margin-left: 4px;
8833
+ margin-right: 4px;
8834
+ vertical-align: middle;
8835
+ }
8836
+
8837
+ .netskrafl-container .help-bonus-square.double-letter {
8838
+ background-color: var(--double-letter-color);
8839
+ }
8840
+
8841
+ .netskrafl-container .help-bonus-square.triple-letter {
8842
+ background-color: var(--triple-letter-color);
8843
+ }
8844
+
8845
+ .netskrafl-container .help-bonus-square.double-word {
8846
+ background-color: var(--double-word-color);
8847
+ }
8848
+
8849
+ .netskrafl-container .help-bonus-square.triple-word {
8850
+ background-color: var(--triple-word-color);
8851
+ }
8852
+
8791
8853
  /* ================= MOBILE STATS BUTTON =============== */
8792
8854
 
8793
8855
  .netskrafl-container .mobile-stats-button {
@@ -8825,7 +8887,7 @@ div.gatadagsins-board-area.celebrate div.netskrafl-tile.netskrafl-racktile{
8825
8887
  .netskrafl-container .modal-dialog.stats-modal {
8826
8888
  visibility: visible;
8827
8889
  position: fixed;
8828
- top: 50%;
8890
+ top: 52%;
8829
8891
  left: 50%;
8830
8892
  transform: translate(-50%, -50%);
8831
8893
  z-index: 10000;
@@ -8884,7 +8946,7 @@ div.gatadagsins-board-area.celebrate div.netskrafl-tile.netskrafl-racktile{
8884
8946
  .netskrafl-container .modal-dialog.stats-modal .modal-body {
8885
8947
  padding-top: 15px;
8886
8948
  padding-bottom: 15px;
8887
- overflow-y: auto;
8949
+ overflow-y: hidden;
8888
8950
  flex: 1;
8889
8951
  overscroll-behavior-y: contain;
8890
8952
  }
@@ -8892,6 +8954,11 @@ div.gatadagsins-board-area.celebrate div.netskrafl-tile.netskrafl-racktile{
8892
8954
  /* Desktop styles for Gáta Dagsins */
8893
8955
 
8894
8956
  @media all and (min-width: 1024px) {
8957
+
8958
+ .modal-backdrop-netskrafl {
8959
+ z-index: 9999;
8960
+ }
8961
+
8895
8962
  /* Show all thermometer moves on desktop */
8896
8963
  .netskrafl-container .thermometer-move-overlay:nth-child(n+2) {
8897
8964
  display: flex;
@@ -9018,6 +9085,11 @@ div.gatadagsins-board-area.celebrate div.netskrafl-tile.netskrafl-racktile{
9018
9085
  width: 100%;
9019
9086
  }
9020
9087
 
9088
+ .netskrafl-container .leaderboard-list {
9089
+ height: 514px; /* Space for 10 entries */
9090
+ overscroll-behavior-y: contain;
9091
+ }
9092
+
9021
9093
  /* Show thermometer on desktop */
9022
9094
  .netskrafl-container div.gatadagsins-thermometer-column {
9023
9095
  display: flex;
@@ -9034,7 +9106,7 @@ div.gatadagsins-board-area.celebrate div.netskrafl-tile.netskrafl-racktile{
9034
9106
  margin-top: 0;
9035
9107
  padding-top: 8px;
9036
9108
  padding-bottom: 24px;
9037
- overflow-x: hidden;
9109
+ overflow: hidden;
9038
9110
  }
9039
9111
 
9040
9112
  .netskrafl-container div.gatadagsins-rack-area {
@@ -9042,6 +9114,7 @@ div.gatadagsins-board-area.celebrate div.netskrafl-tile.netskrafl-racktile{
9042
9114
  /* Push left to compensate for row ids
9043
9115
  on the left side of the board */
9044
9116
  padding-left: 36px;
9117
+ margin-bottom: 0;
9045
9118
  }
9046
9119
 
9047
9120
  /* Show desktop score on desktop */
@@ -9086,4 +9159,8 @@ div.gatadagsins-board-area.celebrate div.netskrafl-tile.netskrafl-racktile{
9086
9159
  margin-right: 5px;
9087
9160
  }
9088
9161
 
9162
+ .netskrafl-container div.gatadagsins-container div.info {
9163
+ bottom: 42px;
9164
+ }
9165
+
9089
9166
  }
package/dist/cjs/index.js CHANGED
@@ -31452,7 +31452,6 @@ const Movelist = (initialVnode) => {
31452
31452
  view,
31453
31453
  move,
31454
31454
  info: {
31455
- key: i.toString(),
31456
31455
  leftTotal: leftTotal, rightTotal: rightTotal,
31457
31456
  player: player, co: co, tiles: tiles, score: score
31458
31457
  }
@@ -31761,79 +31760,6 @@ const GameView = {
31761
31760
  For further information, see https://github.com/mideind/Netskrafl
31762
31761
 
31763
31762
  */
31764
- const vwReview = (view) => {
31765
- // A review of a finished game
31766
- var _a;
31767
- const model = view.model;
31768
- if (!model.game)
31769
- return undefined;
31770
- const game = model.game;
31771
- let moveIndex = (_a = model.reviewMove) !== null && _a !== void 0 ? _a : 0;
31772
- let bestMoves = model.bestMoves || [];
31773
- function vwRightColumn() {
31774
- // A container for the right-side header and area components
31775
- function vwRightHeading() {
31776
- // The right-side heading on the game screen
31777
- const fairplay = game.fairplay;
31778
- const player = game.player;
31779
- let sc0 = "";
31780
- let sc1 = "";
31781
- if (moveIndex) {
31782
- let s0 = 0;
31783
- let s1 = 0;
31784
- for (let i = 0; i < moveIndex; i++) {
31785
- // Add up the scores until and including this move
31786
- let m = game.moves[i];
31787
- if (i % 2 === 0)
31788
- s0 += m[1][2];
31789
- else
31790
- s1 += m[1][2];
31791
- }
31792
- sc0 = s0.toString();
31793
- sc1 = s1.toString();
31794
- }
31795
- return m(".heading", [
31796
- m(".logowrapper", m(".header-logo", m(m.route.Link, {
31797
- href: "/page",
31798
- class: "backlink"
31799
- }, m(NetskraflLogoOnly)))),
31800
- m(".playerwrapper", [
31801
- m(".leftplayer" + (player === 1 ? ".autoplayercolor" : ".humancolor"), [
31802
- m(".player", m(PlayerName, { view, side: "left" })),
31803
- m(".scorewrapper", m(".scoreleft", sc0)),
31804
- ]),
31805
- m(".rightplayer" + (player === 1 ? ".humancolor" : ".autoplayercolor"), [
31806
- m(".player", m(PlayerName, { view, side: "right" })),
31807
- m(".scorewrapper", m(".scoreright", sc1)),
31808
- ]),
31809
- m(".fairplay", { style: { visibility: fairplay ? "visible" : "hidden" } }, m("span.fairplay-btn.large", { title: ts("Skraflað án hjálpartækja") }))
31810
- ])
31811
- ]);
31812
- }
31813
- function vwRightArea() {
31814
- // A container for the list of best possible moves
31815
- return m(".right-area", vwBestMoves(view, moveIndex, bestMoves));
31816
- }
31817
- return m(".rightcol", [vwRightHeading(), vwRightArea()]);
31818
- }
31819
- let r = [];
31820
- if (game) {
31821
- // Create a list of major elements that we're showing
31822
- r.push(vwRightColumn());
31823
- r.push(m(BoardReview, { view, moveIndex }));
31824
- if (model.reviewMove !== null && moveIndex === 0) {
31825
- // Only show the stats overlay if moveIndex is 0
31826
- const n = vwStatsReview(view);
31827
- n && r.push(n);
31828
- }
31829
- }
31830
- return m("div", // Removing this div messes up Mithril
31831
- [
31832
- m(".game-container", r),
31833
- m(LeftLogo), // Button to go back to main screen
31834
- m(Info) // Help button
31835
- ]);
31836
- };
31837
31763
  const vwBestMoves = (view, moveIndex, bestMoves) => {
31838
31764
  // List of best moves, in a game review
31839
31765
  const model = view.model;
@@ -31888,7 +31814,7 @@ const vwBestMoves = (view, moveIndex, bestMoves) => {
31888
31814
  // and thus cannot be confused with the above abbreviations)
31889
31815
  wrdclass = "othermove";
31890
31816
  if (tiles == "--")
31891
- dispText = ts("Stafaleif: (engin)");
31817
+ dispText = ts("Stafaleif: engin");
31892
31818
  else
31893
31819
  dispText = [ts("Stafaleif: "), m("i.upper", tiles)];
31894
31820
  }
@@ -31905,8 +31831,8 @@ const vwBestMoves = (view, moveIndex, bestMoves) => {
31905
31831
  if (!game || !moveIndex || moveIndex > game.moves.length)
31906
31832
  return r;
31907
31833
  // Prepend a header that describes the move being reviewed
31908
- const m = game.moves[moveIndex - 1];
31909
- const [co, tiles, score] = m[1];
31834
+ const move = game.moves[moveIndex - 1];
31835
+ const [co, tiles, score] = move[1];
31910
31836
  r.push(bestHeader(co, tiles, score));
31911
31837
  const mlist = bestMoves;
31912
31838
  for (let i = 0; i < mlist.length; i++) {
@@ -31918,7 +31844,7 @@ const vwBestMoves = (view, moveIndex, bestMoves) => {
31918
31844
  }
31919
31845
  return r;
31920
31846
  }
31921
- return m(".movelist-container", [m(".movelist.bestmoves", bestMoveList())]);
31847
+ return m(".movelist-container", m(".movelist.bestmoves", bestMoveList()));
31922
31848
  };
31923
31849
  const vwBestMove = (view, moveIndex, bestMoveIndex, move, info) => {
31924
31850
  // Displays a move in a list of best available moves
@@ -32217,6 +32143,81 @@ const vwButtonsReview = (view, moveIndex) => {
32217
32143
  r.push(n);
32218
32144
  return r;
32219
32145
  };
32146
+ const Review = (initialVnode) => {
32147
+ // A review of a finished game
32148
+ const { view } = initialVnode.attrs;
32149
+ function vwRightColumn(game, moveIndex, bestMoves) {
32150
+ // A container for the right-side header and area components
32151
+ function vwRightHeading() {
32152
+ // The right-side heading on the game screen
32153
+ const fairplay = game.fairplay;
32154
+ const player = game.player;
32155
+ let sc0 = "";
32156
+ let sc1 = "";
32157
+ if (moveIndex) {
32158
+ let s0 = 0;
32159
+ let s1 = 0;
32160
+ for (let i = 0; i < moveIndex; i++) {
32161
+ // Add up the scores until and including this move
32162
+ let m = game.moves[i];
32163
+ if (i % 2 === 0)
32164
+ s0 += m[1][2];
32165
+ else
32166
+ s1 += m[1][2];
32167
+ }
32168
+ sc0 = s0.toString();
32169
+ sc1 = s1.toString();
32170
+ }
32171
+ return m(".heading", [
32172
+ m(".logowrapper", m(".header-logo", m(m.route.Link, {
32173
+ href: "/page",
32174
+ class: "backlink"
32175
+ }, m(NetskraflLogoOnly)))),
32176
+ m(".playerwrapper", [
32177
+ m(".leftplayer" + (player === 1 ? ".autoplayercolor" : ".humancolor"), [
32178
+ m(".player", m(PlayerName, { view, side: "left" })),
32179
+ m(".scorewrapper", m(".scoreleft", sc0)),
32180
+ ]),
32181
+ m(".rightplayer" + (player === 1 ? ".humancolor" : ".autoplayercolor"), [
32182
+ m(".player", m(PlayerName, { view, side: "right" })),
32183
+ m(".scorewrapper", m(".scoreright", sc1)),
32184
+ ]),
32185
+ m(".fairplay", { style: { visibility: fairplay ? "visible" : "hidden" } }, m("span.fairplay-btn.large", { title: ts("Skraflað án hjálpartækja") }))
32186
+ ])
32187
+ ]);
32188
+ }
32189
+ function vwRightArea() {
32190
+ // A container for the list of best possible moves
32191
+ return m(".right-area", vwBestMoves(view, moveIndex, bestMoves));
32192
+ }
32193
+ return m(".rightcol", [vwRightHeading(), vwRightArea()]);
32194
+ }
32195
+ return {
32196
+ view: () => {
32197
+ var _a;
32198
+ let r = [];
32199
+ const { model } = view;
32200
+ const { game } = model;
32201
+ if (game) {
32202
+ // Create a list of major elements that we're showing
32203
+ const moveIndex = (_a = model.reviewMove) !== null && _a !== void 0 ? _a : 0;
32204
+ const bestMoves = model.bestMoves || [];
32205
+ r.push(vwRightColumn(game, moveIndex, bestMoves));
32206
+ r.push(m(BoardReview, { view, moveIndex }));
32207
+ if (model.reviewMove !== null && moveIndex === 0) {
32208
+ // Only show the stats overlay if moveIndex is 0
32209
+ const n = vwStatsReview(view);
32210
+ n && r.push(n);
32211
+ }
32212
+ }
32213
+ return m("div", [
32214
+ m(".game-container", r),
32215
+ m(LeftLogo), // Button to go back to main screen
32216
+ m(Info) // Help button
32217
+ ]);
32218
+ }
32219
+ };
32220
+ };
32220
32221
  const BoardReview = {
32221
32222
  // The board area within a game review screen
32222
32223
  view: (vnode) => {
@@ -32296,8 +32297,7 @@ class View {
32296
32297
  views.push(m(GameView, { key: "game", view: this }));
32297
32298
  break;
32298
32299
  case "review":
32299
- const n = vwReview(this);
32300
- n && views.push(n);
32300
+ views.push(m(Review, { key: "review", view: this }));
32301
32301
  break;
32302
32302
  case "thanks":
32303
32303
  // Display a thank-you dialog on top of the normal main screen
@@ -35875,6 +35875,8 @@ class Actions {
35875
35875
  if (state && !state.uiFullscreen) {
35876
35876
  state.uiFullscreen = true;
35877
35877
  if (view) {
35878
+ // Reset zoom when switching to fullscreen (desktop always uses scale 1)
35879
+ view.resetScale();
35878
35880
  view.notifyMediaChange();
35879
35881
  }
35880
35882
  m.redraw();
@@ -36215,6 +36217,8 @@ class Actions {
36215
36217
  // Listen to user stats (if user is logged in)
36216
36218
  if (state === null || state === void 0 ? void 0 : state.userId) {
36217
36219
  attachFirebaseListener(`gatadagsins/users/${locale}/${state.userId}/stats`, (json, firstAttach) => this.onUserStatsUpdate(json, firstAttach));
36220
+ // Listen to personal best move (entire achievement object)
36221
+ attachFirebaseListener(basePath + `achievements/${state.userId}`, (json, firstAttach) => this.onPersonalBestScoreUpdate(json, firstAttach));
36218
36222
  }
36219
36223
  }
36220
36224
  detachListenerFromRiddle(date, locale) {
@@ -36227,6 +36231,7 @@ class Actions {
36227
36231
  detachFirebaseListener(basePath + "leaders");
36228
36232
  if (state === null || state === void 0 ? void 0 : state.userId) {
36229
36233
  detachFirebaseListener(`gatadagsins/users/${locale}/${state.userId}/stats`);
36234
+ detachFirebaseListener(basePath + `achievements/${state.userId}`);
36230
36235
  }
36231
36236
  }
36232
36237
  onRiddleGlobalScoreUpdate(json, firstAttach) {
@@ -36277,6 +36282,35 @@ class Actions {
36277
36282
  }
36278
36283
  m.redraw();
36279
36284
  }
36285
+ onPersonalBestScoreUpdate(json, firstAttach) {
36286
+ const { riddle } = this.model;
36287
+ if (!riddle || !json)
36288
+ return;
36289
+ // Extract the full move from Firebase
36290
+ const score = json.score || 0;
36291
+ const word = json.word || "";
36292
+ const coord = json.coord || "";
36293
+ const timestamp = json.timestamp || new Date().toISOString();
36294
+ // Only proceed if we didn't already have this score or better
36295
+ if (score <= riddle.personalBestScore || !word || !coord)
36296
+ return;
36297
+ riddle.personalBestScore = score;
36298
+ // Check if this move is already in playerMoves
36299
+ // (this is a safety precaution; normally the
36300
+ // move should not be there already)
36301
+ const moveExists = riddle.playerMoves.some(m => m.word === word && m.coord === coord && m.score === score);
36302
+ // If not already present, add it to playerMoves
36303
+ // This enables clicking on it to see it on the board
36304
+ if (!moveExists) {
36305
+ riddle.playerMoves.push({
36306
+ word,
36307
+ score,
36308
+ coord,
36309
+ timestamp
36310
+ });
36311
+ }
36312
+ m.redraw();
36313
+ }
36280
36314
  async fetchRiddle(date, locale) {
36281
36315
  // Create the game via model
36282
36316
  if (!this.model)
@@ -36634,7 +36668,6 @@ const MobileStatus = () => {
36634
36668
  return null;
36635
36669
  const { bestPossibleScore, globalBestScore, personalBestScore } = riddle;
36636
36670
  // Determine if player achieved best possible score
36637
- const achieved = bestMove !== undefined;
36638
36671
  const celebrate = bestMove && bestMove.word !== "";
36639
36672
  // Determine current leader score (may be this player or another)
36640
36673
  let leaderScore = 0;
@@ -36671,8 +36704,7 @@ const MobileStatus = () => {
36671
36704
  ]),
36672
36705
  // Best possible score
36673
36706
  m(".mobile-status-item.right.best-possible"
36674
- + (celebrate ? ".celebrate" : "")
36675
- + (achieved ? ".achieved" : ""), {
36707
+ + (celebrate ? ".celebrate" : ""), {
36676
36708
  onclick: () => celebrate && onMoveClick(bestMove.word, bestMove.coord)
36677
36709
  }, [
36678
36710
  // Wrapper for score and corona to position them together
@@ -36793,25 +36825,17 @@ const BestPossibleScore = () => {
36793
36825
  const { score, bestMove, onMoveClick } = vnode.attrs;
36794
36826
  // Determine the label based on achievement status
36795
36827
  let topLabel;
36796
- if (bestMove !== undefined) {
36797
- if (bestMove.word) {
36798
- // Current player achieved it - show their word
36799
- topLabel = removeBlankMarkers(bestMove.word);
36800
- }
36801
- else {
36802
- // Someone else achieved it - indicate this
36803
- topLabel = ts("Besta mögulega lögn\n(er þegar fundin)");
36804
- }
36828
+ if (bestMove !== undefined && bestMove.word) {
36829
+ // Current player achieved it - show their word
36830
+ topLabel = removeBlankMarkers(bestMove.word);
36805
36831
  }
36806
36832
  else {
36807
36833
  // Not achieved yet - show default label
36808
36834
  topLabel = ts("Besta mögulega lögn");
36809
36835
  }
36810
- const achieved = bestMove !== undefined;
36811
36836
  const celebrate = bestMove && bestMove.word !== "";
36812
36837
  return m(".thermometer-best-score"
36813
- + (celebrate ? ".celebrate" : "")
36814
- + (achieved ? ".achieved" : ""), m(".thermometer-best-score-container", {
36838
+ + (celebrate ? ".celebrate" : ""), m(".thermometer-best-score-container", {
36815
36839
  onclick: () => celebrate && onMoveClick(bestMove.word, bestMove.coord)
36816
36840
  }, [
36817
36841
  // Sun corona behind the circle when celebrating
@@ -37047,7 +37071,10 @@ const LeaderboardView = {
37047
37071
  m(".leaderboard-header", [
37048
37072
  m(".leaderboard-title", formatDate(date)),
37049
37073
  ]),
37050
- m(".leaderboard-list", leaderboard.map((entry, index) => {
37074
+ m(".leaderboard-list", {
37075
+ // Allow touch scrolling but prevent events from bubbling to backdrop
37076
+ ontouchmove: (e) => { e.stopPropagation(); }
37077
+ }, leaderboard.map((entry, index) => {
37051
37078
  const rank = index + 1;
37052
37079
  const isCurrentUser = entry.userId === currentUserId;
37053
37080
  const medal = getMedalIcon(rank);
@@ -37055,7 +37082,9 @@ const LeaderboardView = {
37055
37082
  m(".entry-rank", [
37056
37083
  medal ? m("span.medal", medal) : m("span.rank-number", rank.toString())
37057
37084
  ]),
37058
- m(".entry-name", isCurrentUser ? ts("Þú") : entry.displayName),
37085
+ m(".entry-name", isCurrentUser
37086
+ ? [m("span.entry-star", glyph("star")), ts("Þú")]
37087
+ : entry.displayName),
37059
37088
  m(".entry-score", entry.score.toString())
37060
37089
  ]);
37061
37090
  }))
@@ -37156,7 +37185,7 @@ const GataDagsinsRightSide = {
37156
37185
  view: (vnode) => {
37157
37186
  const { view, selectedMoves, bestMove, onStatsClick } = vnode.attrs;
37158
37187
  const { riddle } = view.model;
37159
- const handleMoveClick = (word, coord) => {
37188
+ const onMoveClick = (word, coord) => {
37160
37189
  if (riddle && word && coord) {
37161
37190
  // Recreate the word on the board
37162
37191
  riddle.recreateWordOnBoard(word, coord);
@@ -37168,15 +37197,15 @@ const GataDagsinsRightSide = {
37168
37197
  view,
37169
37198
  selectedMoves,
37170
37199
  bestMove,
37171
- onMoveClick: handleMoveClick,
37172
- onStatsClick
37200
+ onMoveClick,
37201
+ onStatsClick,
37173
37202
  })),
37174
37203
  // Desktop-only tabbed view (hidden on mobile, visible on desktop)
37175
37204
  m(".gatadagsins-thermometer-column", m(RightSideTabs, {
37176
37205
  view,
37177
37206
  selectedMoves,
37178
37207
  bestMove,
37179
- onMoveClick: handleMoveClick
37208
+ onMoveClick,
37180
37209
  })),
37181
37210
  ] : null);
37182
37211
  }
@@ -37207,14 +37236,13 @@ const GataDagsinsHelp = {
37207
37236
  ontouchmove: (e) => { e.preventDefault(); e.stopPropagation(); }
37208
37237
  }),
37209
37238
  m(".modal-dialog.gatadagsins-help", m(".modal-content", [
37210
- // Header with close button
37211
- m(".modal-header", [
37212
- m("h2", "Um Gátu dagsins"),
37213
- m("button.close", {
37214
- onclick: closeHelp,
37215
- "aria-label": "Loka"
37216
- }, m("span", { "aria-hidden": "true" }, "×"))
37217
- ]),
37239
+ // Close button (positioned absolutely in top-right corner)
37240
+ m("button.close", {
37241
+ onclick: closeHelp,
37242
+ "aria-label": "Loka"
37243
+ }, glyph("remove")),
37244
+ // Header
37245
+ m(".modal-header", m("h2", "Um Gátu dagsins")),
37218
37246
  // Body with help content
37219
37247
  m(".modal-body", [
37220
37248
  m("p", "Gáta dagsins er dagleg krossgátuþraut, svipuð skrafli, þar sem þú reynir að finna " +
@@ -37233,8 +37261,20 @@ const GataDagsinsHelp = {
37233
37261
  m("ul", [
37234
37262
  m("li", "Hver stafur gefur 1-10 stig eftir gildi hans"),
37235
37263
  m("li", "Orð sem nota allar 7 stafaflísarnar gefa 50 stiga bónus"),
37236
- m("li", "Sumir reitir á borðinu tvöfalda eða þrefalda stafagildið"),
37237
- m("li", "Sumir reitir tvöfalda eða þrefalda heildarorðagildið"),
37264
+ m("li", [
37265
+ "Sumir reitir á borðinu ",
37266
+ m("span.help-bonus-square.double-letter"),
37267
+ "tvöfalda eða ",
37268
+ m("span.help-bonus-square.triple-letter"),
37269
+ "þrefalda stafagildið"
37270
+ ]),
37271
+ m("li", [
37272
+ "Sumir reitir ",
37273
+ m("span.help-bonus-square.double-word"),
37274
+ "tvöfalda eða ",
37275
+ m("span.help-bonus-square.triple-word"),
37276
+ "þrefalda heildarorðagildið"
37277
+ ]),
37238
37278
  ]),
37239
37279
  m("h3", "Hitamælir"),
37240
37280
  m("p", "Hitamælirinn hægra megin (eða efst á farsímum) sýnir:"),