@mideind/netskrafl-react 1.0.0-beta.6 → 1.0.0-beta.7

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.
Files changed (67) hide show
  1. package/dist/cjs/css/netskrafl.css +859 -177
  2. package/dist/cjs/index.js +206 -299
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/esm/css/netskrafl.css +859 -177
  5. package/dist/esm/index.js +205 -298
  6. package/dist/esm/index.js.map +1 -1
  7. package/package.json +13 -2
  8. package/.eslintignore +0 -8
  9. package/.eslintrc.json +0 -13
  10. package/rollup.config.js +0 -67
  11. package/src/components/index.ts +0 -2
  12. package/src/components/netskrafl/Netskrafl.stories.tsx +0 -66
  13. package/src/components/netskrafl/Netskrafl.tsx +0 -155
  14. package/src/components/netskrafl/Netskrafl.types.ts +0 -7
  15. package/src/components/netskrafl/index.ts +0 -2
  16. package/src/css/fonts.css +0 -4
  17. package/src/css/glyphs.css +0 -223
  18. package/src/css/main.css +0 -4
  19. package/src/css/skrafl-explo.css +0 -6636
  20. package/src/fonts/glyphicons-regular.eot +0 -0
  21. package/src/fonts/glyphicons-regular.ttf +0 -0
  22. package/src/fonts/glyphicons-regular.woff +0 -0
  23. package/src/index.ts +0 -4
  24. package/src/messages/messages.json +0 -1576
  25. package/src/mithril/actions.ts +0 -319
  26. package/src/mithril/bag.ts +0 -65
  27. package/src/mithril/bestdisplay.ts +0 -74
  28. package/src/mithril/blankdialog.ts +0 -94
  29. package/src/mithril/board.ts +0 -339
  30. package/src/mithril/buttons.ts +0 -303
  31. package/src/mithril/challengedialog.ts +0 -186
  32. package/src/mithril/channel.ts +0 -162
  33. package/src/mithril/chat.ts +0 -228
  34. package/src/mithril/components.ts +0 -496
  35. package/src/mithril/dragdrop.ts +0 -219
  36. package/src/mithril/elopage.ts +0 -202
  37. package/src/mithril/friend.ts +0 -227
  38. package/src/mithril/game.ts +0 -1378
  39. package/src/mithril/gameview.ts +0 -111
  40. package/src/mithril/globalstate.ts +0 -33
  41. package/src/mithril/i18n.ts +0 -187
  42. package/src/mithril/localstorage.ts +0 -133
  43. package/src/mithril/login.ts +0 -122
  44. package/src/mithril/logo.ts +0 -323
  45. package/src/mithril/main.ts +0 -755
  46. package/src/mithril/mithril.ts +0 -29
  47. package/src/mithril/model.ts +0 -855
  48. package/src/mithril/movelistitem.ts +0 -226
  49. package/src/mithril/page.ts +0 -856
  50. package/src/mithril/playername.ts +0 -91
  51. package/src/mithril/promodialog.ts +0 -82
  52. package/src/mithril/recentlist.ts +0 -148
  53. package/src/mithril/request.ts +0 -52
  54. package/src/mithril/review.ts +0 -634
  55. package/src/mithril/rightcolumn.ts +0 -398
  56. package/src/mithril/searchbutton.ts +0 -118
  57. package/src/mithril/statsdisplay.ts +0 -109
  58. package/src/mithril/tabs.ts +0 -169
  59. package/src/mithril/tile.ts +0 -145
  60. package/src/mithril/twoletter.ts +0 -76
  61. package/src/mithril/types.ts +0 -384
  62. package/src/mithril/userinfodialog.ts +0 -171
  63. package/src/mithril/util.ts +0 -304
  64. package/src/mithril/wait.ts +0 -246
  65. package/src/mithril/wordcheck.ts +0 -102
  66. package/tsconfig.json +0 -28
  67. package/vite.config.ts +0 -12
package/dist/cjs/index.js CHANGED
@@ -2208,9 +2208,9 @@ const requestMoves = (options) => {
2208
2208
 
2209
2209
  i8n.ts
2210
2210
 
2211
- Single page UI for Explo using the Mithril library
2211
+ Single page UI for Netskrafl/Explo using the Mithril library
2212
2212
 
2213
- Copyright (C) 2023 Miðeind ehf.
2213
+ Copyright (C) 2025 Miðeind ehf.
2214
2214
  Author: Vilhjálmur Þorsteinsson
2215
2215
 
2216
2216
  The Creative Commons Attribution-NonCommercial 4.0
@@ -2376,7 +2376,7 @@ function interpolate_string(message, ips) {
2376
2376
 
2377
2377
  Common type definitions for the Explo/Netskrafl user interface
2378
2378
 
2379
- Copyright (C) 2024 Miðeind ehf.
2379
+ Copyright (C) 2025 Miðeind ehf.
2380
2380
  Author: Vilhjalmur Thorsteinsson
2381
2381
 
2382
2382
  The Creative Commons Attribution-NonCommercial 4.0
@@ -2422,7 +2422,7 @@ const ERROR_MESSAGES = {
2422
2422
 
2423
2423
  Utility functions for the Explo/Netskrafl user interface
2424
2424
 
2425
- Copyright (C) 2024 Miðeind ehf.
2425
+ Copyright (C) 2025 Miðeind ehf.
2426
2426
  Author: Vilhjálmur Þorsteinsson
2427
2427
 
2428
2428
  The Creative Commons Attribution-NonCommercial 4.0
@@ -28126,6 +28126,11 @@ class Game {
28126
28126
  return r;
28127
28127
  }
28128
28128
  ;
28129
+ allowDragDrop() {
28130
+ // Return true if the game allows drag-and-drop of tiles
28131
+ return !this.over && !this.showingDialog && !this.moveInProgress;
28132
+ }
28133
+ ;
28129
28134
  async sendMove(moves) {
28130
28135
  // Send a move to the server
28131
28136
  this.moveInProgress = true;
@@ -28622,9 +28627,9 @@ class Game {
28622
28627
 
28623
28628
  Model.ts
28624
28629
 
28625
- Single page UI for Explo/Netskrafl using the Mithril library
28630
+ Single page UI for Netskrafl/Explo using the Mithril library
28626
28631
 
28627
- Copyright (C) 2024 Miðeind ehf.
28632
+ Copyright (C) 2025 Miðeind ehf.
28628
28633
  Author: Vilhjálmur Þorsteinsson
28629
28634
 
28630
28635
  The Creative Commons Attribution-NonCommercial 4.0
@@ -29422,9 +29427,9 @@ class Model {
29422
29427
 
29423
29428
  Actions.ts
29424
29429
 
29425
- Single page UI for Explo using the Mithril library
29430
+ Single page UI for Netskrafl/Explo using the Mithril library
29426
29431
 
29427
- Copyright (C) 2024 Miðeind ehf.
29432
+ Copyright (C) 2025 Miðeind ehf.
29428
29433
  Author: Vilhjálmur Þorsteinsson
29429
29434
 
29430
29435
  The Creative Commons Attribution-NonCommercial 4.0
@@ -29696,7 +29701,7 @@ function createRouteResolver(actions) {
29696
29701
 
29697
29702
  Logo.ts
29698
29703
 
29699
- Animated Explo / Netskrafl logo & legend component
29704
+ Animated Netskrafl logo & legend component
29700
29705
 
29701
29706
  Copyright (C) 2025 Miðeind ehf.
29702
29707
  Original author: Vilhjálmur Þorsteinsson
@@ -29706,42 +29711,9 @@ function createRouteResolver(actions) {
29706
29711
  For further information, see https://github.com/mideind/Netskrafl
29707
29712
 
29708
29713
  */
29709
- // SVG code for Explo logo
29710
- const headerLogo = `<svg width="134" height="134" viewBox="-32 -8 134 134" fill="none" xmlns="http://www.w3.org/2000/svg">`;
29711
- const circle = `<circle class="shadow" cx="35" cy="59" r="63" fill="#ffffff"/>`;
29712
- const pieces = [
29713
- // Orange box on top
29714
- [
29715
- `<path d="M65.2672 12.542L54.3998 18.813L43.5323 25.146L32.6649 18.813L21.7354 12.542L43.5323 0L65.2672 12.542Z" fill="#FDC12C"/>`,
29716
- `<path d="M43.5323 25.1457V37.6877L21.7354 25.1457V12.5416L43.5323 25.1457Z" fill="#E69419"/>`,
29717
- `<path d="M65.2661 12.5416V25.1457L43.5312 37.6877V25.1457L65.2661 12.5416Z" fill="#F8DA95"/>`
29718
- ],
29719
- // Red box
29720
- [
29721
- `<path d="M43.5318 37.6847L32.6644 43.9557L21.7349 50.2267L10.8674 43.9557L0 37.6847L21.7349 25.1427L43.5318 37.6847Z" fill="#AA3731"/>`,
29722
- `<path d="M21.7349 50.23V62.7719L0 50.23V37.688L21.7349 50.23Z" fill="#721D19"/>`
29723
- ],
29724
- // Green box
29725
- [
29726
- `<path d="M65.2672 50.23L54.3998 56.501L43.5323 62.7719L32.6028 56.501L21.7354 50.23L43.5323 37.688L65.2672 50.23Z" fill="#669256"/>`,
29727
- `<path d="M43.5323 62.7716V75.3756L21.7354 62.7716V50.2296L43.5323 62.7716Z" fill="#496A38"/>`,
29728
- `<path d="M65.2661 50.2296V62.7716L43.5312 75.3756V62.7716L65.2661 50.2296Z" fill="#B7C7AD"/>`
29729
- ],
29730
- // Light blue box
29731
- [
29732
- `<path d="M43.5318 75.3754L32.6644 81.6464L21.7349 87.9174L10.8674 81.6464L0 75.3754L21.7349 62.7714L43.5318 75.3754Z" fill="#83C8CE"/>`,
29733
- `<path d="M21.7349 87.918V100.46L0 87.918V75.376L21.7349 87.918Z" fill="#5699A5"/>`
29734
- ],
29735
- // Pink box at the bottom
29736
- [
29737
- `<path d="M65.2672 87.918L54.3998 94.1889L43.5323 100.46L32.6649 94.1889L21.7354 87.918L43.5323 75.376L65.2672 87.918Z" fill="#E39FA5"/>`,
29738
- `<path d="M43.5323 100.46V113.002L21.7354 100.46V87.9177L43.5323 100.46Z" fill="#B6676D"/>`,
29739
- `<path d="M65.2661 87.9177V100.46L43.5312 113.002V100.46L65.2661 87.9177Z" fill="#EACFD1"/>`
29740
- ]
29741
- ];
29742
29714
  // SVG code for the letters 'netskrafl'
29743
- const headerLetters = `<svg viewBox="0 0 992.73 323.47" fill="none" xmlns="http://www.w3.org/2000/svg">`;
29744
- const letters = [
29715
+ const HEADER_LETTERS = `<svg viewBox="0 0 992.73 323.47" fill="none" xmlns="http://www.w3.org/2000/svg">`;
29716
+ const LETTERS = [
29745
29717
  [`<path fill="#514c4c"`,
29746
29718
  ` d="M1728.66,1133.94a1.85,1.85,0,0,1-2-2v-54.59c0-10.41-4.91-17.28-14.73-17.28-9.43,0-14.93,6.87-14.93,17.28V1132a1.85,1.85,0,0,1-2,2h-23.56a1.86,1.86,0,0,1-2-2v-91.12a1.86,1.86,0,0,1,2-2h23.56a1.85,1.85,0,0,1,2,2v6.68h.2c4.32-5.89,12.37-10.8,24.55-10.8,21,0,32.4,14.53,32.4,35.34V1132a1.86,1.86,0,0,1-2,2Z"`,
29747
29719
  ` transform="translate(-1401.69 -918.27)"/>`],
@@ -29767,76 +29739,53 @@ const letters = [
29767
29739
  ` d="M2291.92,1133.94a1.86,1.86,0,0,1-2-2V1060.3a1,1,0,0,0-1.17-1.18h-5.89a1.86,1.86,0,0,1-2-2v-16.3a1.86,1.86,0,0,1,2-2h5.89a1,1,0,0,0,1.17-1.18v-4.51c0-23.18,10.8-32.8,33.39-32.8h10.8a1.86,1.86,0,0,1,2,2v18.45a1.86,1.86,0,0,1-2,2h-6.09c-8.64,0-10.8,2.16-10.8,10.21v4.71a1,1,0,0,0,1.18,1.18h15.51a1.85,1.85,0,0,1,2,2v16.3a1.85,1.85,0,0,1-2,2h-15.51a1,1,0,0,0-1.18,1.18V1132a1.85,1.85,0,0,1-2,2Zm90.13,1.18c-21,0-29.46-9.23-29.46-30.24v-102.5a1.86,1.86,0,0,1,2-2h23.56a1.86,1.86,0,0,1,2,2v100.34c0,6.48,2.55,9,8.24,9h4.13a1.85,1.85,0,0,1,2,2v19.45a1.85,1.85,0,0,1-2,2Z"`,
29768
29740
  ` transform="translate(-1401.69 -918.27)"/>`]
29769
29741
  ];
29770
- const footer = `</svg>`;
29771
- const WIDTH = 134;
29772
- const NUM_STEPS = pieces.length;
29773
- const AnimatedExploLogo = (initialVnode) => {
29774
- // Animation step time in milliseconds
29775
- const msStepTime = initialVnode.attrs.msStepTime || 0;
29776
- const width = initialVnode.attrs.width;
29777
- const scale = width / WIDTH;
29778
- const withCircle = initialVnode.attrs.withCircle || false;
29779
- const once = initialVnode.attrs.once ? true : false;
29780
- const className = initialVnode.attrs.className;
29781
- let delta = 1;
29782
- let step = msStepTime ? 0 : NUM_STEPS;
29783
- let ival = 0;
29784
- function doStep() {
29785
- // Check whether we're still in the delay period
29786
- // Check if we need to reverse direction
29787
- if (delta < 0 && step == 0) {
29788
- delta = 1;
29789
- }
29790
- else if (delta > 0 && step == NUM_STEPS) {
29791
- // All steps completed; should we reverse direction
29792
- // or stop the animation (if once == true)?
29793
- if (once) {
29794
- // We're done
29795
- delta = 0;
29796
- clearInterval(ival);
29797
- ival = 0;
29798
- }
29799
- else
29800
- // Reverse direction
29801
- delta = -1;
29802
- }
29803
- step += delta;
29804
- m.redraw();
29805
- }
29806
- return {
29807
- oninit: () => {
29808
- if (msStepTime)
29809
- ival = setInterval(doStep, msStepTime);
29810
- },
29811
- onremove: () => {
29812
- if (ival != 0) {
29813
- clearInterval(ival);
29814
- ival = 0;
29815
- }
29816
- },
29817
- view: () => {
29818
- let r = [headerLogo];
29819
- if (withCircle)
29820
- // Include white background circle, with drop shadow
29821
- r.push(circle);
29822
- for (let i = 0; i < step; i++)
29823
- for (let piece of pieces[i])
29824
- r.push(piece);
29825
- r.push(footer);
29826
- let attribs = {
29827
- style: {
29828
- "transform": `scale(${scale})`,
29829
- "transform-origin": "left top"
29830
- }
29831
- };
29832
- if (className !== undefined && className !== null)
29833
- attribs.class = className;
29834
- return m("div", attribs, m.trust(r.join("\n")));
29835
- }
29836
- };
29837
- };
29742
+ const FOOTER = `</svg>`;
29743
+ // Netskrafl logo SVG components
29744
+ const LOGO_WIDTH = 182;
29745
+ const LOGO_HEIGHT = 210;
29746
+ const NETSKRAFL_LOGO_ARRAY = [
29747
+ `<path d="M50.0335 81.1768V58.6393C50.0335 56.9025 48.7821 54.7618 47.2876 53.8732L27.7859 42.6044C26.2932 41.7158 23.7887 41.7158 22.296 42.6044L2.75319 53.8732C1.2587 54.7618 0.00732422 56.9025 0.00732422 58.6393V81.1768C0.00732422 82.9136 1.2587 85.0543 2.75319 85.9428L16.3591 93.7785C18.6617 95.0306 20.2366 97.4944 20.2366 100.322V115.145C20.2366 117.972 18.6617 120.436 16.3591 121.688L7.35643 126.898L2.79251 129.524C1.29981 130.412 0.0484453 132.553 0.0484453 134.29V156.827C0.0484453 158.564 1.29981 160.705 2.79251 161.593L22.296 172.862C23.7887 173.751 26.2932 173.751 27.7859 172.862L47.2876 161.593C48.7821 160.705 50.0335 158.564 50.0335 156.827V134.29C50.0335 132.553 48.7821 130.412 47.2876 129.524L33.6817 121.688C31.3791 120.436 29.806 117.972 29.806 115.145V100.322C29.806 97.4944 31.3791 95.0306 33.6817 93.7785L47.2876 85.9428C48.8232 85.0543 50.0335 82.9136 50.0335 81.1768Z" fill="#F17736"/>`,
29748
+ `<path d="M25.0401 73.1002C25.0401 71.3633 23.7887 69.2227 22.296 68.3341L2.75319 57.0653C1.2587 56.1767 0.00732422 56.9037 0.00732422 58.6404V81.1782C0.00732422 82.9149 1.2587 85.0556 2.75319 85.9441L22.2549 97.2129C23.7494 98.1015 25.0007 97.3745 25.0007 95.6377L25.0401 73.1002Z" fill="#FFAA88"/>`,
29749
+ `<path d="M73.9793 88.4472L68.2856 91.7188C66.9126 92.5267 65.7417 94.3846 65.5397 96.0405V96.0809V96.2021V96.4848V103.028C65.4986 100.524 64.1668 98.0601 61.7838 96.6868L48.9859 89.2954C46.5225 87.8818 43.6157 88.003 41.3543 89.3762L27.7466 97.2118C26.2539 98.0601 25.0007 97.3734 25.0007 95.6367V73.0989C25.0007 71.3622 26.2539 69.2217 27.7466 68.333L47.2483 57.0642C47.6934 56.8219 48.0974 56.7007 48.4603 56.7007C49.3488 56.7007 49.9941 57.4277 49.9941 58.6393V74.351C49.9137 76.9764 51.2866 79.6018 53.7089 81.0155L66.5086 88.4068C68.972 89.7801 71.7572 89.6993 73.9793 88.4472Z" fill="#C94314"/>`,
29750
+ `<path d="M25.0401 148.791C25.0401 147.054 23.7887 144.913 22.296 144.024L2.75319 132.756C1.2587 131.867 0.00732422 132.594 0.00732422 134.331V156.869C0.00732422 158.605 1.2587 160.746 2.75319 161.634L22.2549 172.903C23.7494 173.792 25.0007 173.065 25.0007 171.328L25.0401 148.791Z" fill="#FFAA88"/>`,
29751
+ `<path d="M50.035 156.869C50.035 158.605 48.7837 160.746 47.2892 161.634L27.7875 172.903C26.293 173.792 25.0416 173.065 25.0416 171.328V148.791C25.0416 147.054 26.293 144.913 27.7875 144.024L47.2892 132.756C48.7837 131.867 50.035 132.594 50.035 134.331V156.869Z" fill="#C94314"/>`,
29752
+ `<path d="M115.566 96.4844V119.022C115.566 120.759 114.313 122.899 112.821 123.788L93.3189 135.057C91.9853 135.824 89.9258 135.905 88.392 135.34C88.3116 135.299 88.2311 135.299 88.1507 135.259C88.1096 135.218 88.0685 135.218 87.988 135.178C87.9487 135.138 87.8665 135.138 87.8271 135.097L68.3254 123.828C68.1234 123.707 67.9608 123.586 67.7587 123.424C67.5979 123.263 67.3959 123.101 67.235 122.94C66.266 121.89 65.5385 120.355 65.5385 119.062V103.351C65.5385 103.229 65.5385 103.149 65.5385 103.028V96.4844C65.5385 96.4036 65.5385 96.3228 65.5385 96.2018C65.5385 96.1614 65.5385 96.121 65.5385 96.0806V96.0402C65.7011 94.3843 66.872 92.5261 68.2843 91.7185L73.9781 88.4468L87.786 80.4497C89.3198 79.561 91.7832 79.561 93.2777 80.4497L112.779 91.7185C114.354 92.6069 115.566 94.7477 115.566 96.4844Z" fill="#F17736"/>`,
29753
+ `<path d="M90.573 133.482C90.573 135.097 89.5218 135.824 88.1489 135.259C88.1096 135.219 88.0684 135.219 87.988 135.178C87.9487 135.138 87.8664 135.138 87.8271 135.097L68.3254 123.829C68.1234 123.707 67.9608 123.586 67.7587 123.425C67.5979 123.263 67.3958 123.102 67.235 122.94C66.266 121.89 65.5385 120.355 65.5385 119.063V103.351C65.5385 103.23 65.5385 103.149 65.5385 103.028V96.4847C65.5385 96.4039 65.5385 96.3231 65.5385 96.2019C65.5385 96.1615 65.5385 96.1211 65.5385 96.0807V96.0403C65.7405 94.6268 66.872 94.1016 68.2843 94.9094L76.6828 99.7561L87.8271 106.178C89.3609 107.067 90.573 109.207 90.573 110.944V133.482Z" fill="#FFAA88"/>`,
29754
+ `<path d="M115.566 16.7012V39.2388C115.566 40.9757 114.313 43.1162 112.821 44.0049L93.3189 55.2737C91.9853 56.0411 89.9258 56.1219 88.392 55.5563C88.3116 55.5159 88.2311 55.5159 88.1507 55.4757C88.1096 55.4353 88.0685 55.4353 87.988 55.3949C87.9487 55.3545 87.8665 55.3545 87.8271 55.3141L68.3254 44.0453C68.1234 43.9241 67.9608 43.8029 67.7587 43.6413C67.5979 43.4798 67.3959 43.3182 67.235 43.1566C66.266 42.1066 65.5385 40.5717 65.5385 39.2792V23.5675C65.5385 23.4463 65.5385 23.3657 65.5385 23.2444V16.7012C65.5385 16.6204 65.5385 16.5396 65.5385 16.4186C65.5385 16.3782 65.5385 16.3378 65.5385 16.2974V16.257C65.7011 14.601 66.872 12.7429 68.2843 11.9353L73.9781 8.66365L87.786 0.666489C89.3198 -0.222163 91.7832 -0.222163 93.2777 0.666489L112.779 11.9353C114.354 12.8237 115.566 14.9645 115.566 16.7012Z" fill="#F17736"/>`,
29755
+ `<path d="M89.6624 31.5736C89.6624 29.9159 88.4316 27.8729 86.9616 27.0247L67.7803 16.2696C66.3104 15.4216 65.0796 16.1154 65.0796 17.773V39.2833C65.0796 40.9409 66.3104 42.9841 67.7803 43.832L86.9616 54.5871C88.4316 55.4353 89.6624 54.7414 89.6624 53.0838V31.5736Z" fill="#FFAA88"/>`,
29756
+ `<path d="M115.691 38.9886C115.691 40.7689 114.388 42.9634 112.831 43.8742L92.5219 55.426C90.9673 56.3369 89.6622 55.5916 89.6622 53.8113V30.7077C89.6622 28.9272 90.9673 26.7329 92.5219 25.8219L112.831 14.2702C114.388 13.3593 115.691 14.1045 115.691 15.8848V38.9886Z" fill="#C94314"/>`,
29757
+ `<path d="M115.566 169.984V192.521C115.566 194.258 114.313 196.399 112.821 197.288L93.3189 208.556C91.9853 209.324 89.9258 209.405 88.392 208.839C88.3116 208.799 88.2311 208.799 88.1507 208.758C88.1096 208.718 88.0685 208.718 87.988 208.678C87.9487 208.637 87.8665 208.637 87.8271 208.597L68.3254 197.328C68.1234 197.207 67.9608 197.086 67.7587 196.924C67.5979 196.763 67.3959 196.601 67.235 196.439C66.266 195.389 65.5385 193.854 65.5385 192.562V176.85C65.5385 176.729 65.5385 176.648 65.5385 176.527V169.984C65.5385 169.903 65.5385 169.822 65.5385 169.701C65.5385 169.661 65.5385 169.62 65.5385 169.58V169.54C65.7011 167.884 66.872 166.026 68.2843 165.218L73.9781 161.946L87.786 153.949C89.3198 153.061 91.7832 153.061 93.2777 153.949L112.779 165.218C114.354 166.106 115.566 168.247 115.566 169.984Z" fill="#F17736"/>`,
29758
+ `<path d="M90.573 206.981C90.573 208.596 89.5218 209.323 88.1489 208.758C88.1096 208.718 88.0684 208.718 87.988 208.677C87.9487 208.637 87.8664 208.637 87.8271 208.596L68.3254 197.328C68.1234 197.206 67.9608 197.085 67.7587 196.924C67.5979 196.762 67.3958 196.601 67.235 196.439C66.266 195.389 65.5385 193.854 65.5385 192.562V176.85C65.5385 176.729 65.5385 176.648 65.5385 176.527V169.984C65.5385 169.903 65.5385 169.822 65.5385 169.701C65.5385 169.661 65.5385 169.62 65.5385 169.58V169.539C65.7405 168.126 66.872 167.601 68.2843 168.408L76.6828 173.255L87.8271 179.677C89.3609 180.566 90.573 182.706 90.573 184.443V206.981Z" fill="#FFAA88"/>`,
29759
+ `<path d="M116.102 192.239C116.102 193.975 114.851 196.116 113.356 197.005L93.8544 208.273C92.3617 209.162 91.1085 208.435 91.1085 206.698V184.161C91.1085 182.424 92.3617 180.283 93.8544 179.395L113.356 168.126C114.851 167.237 116.102 167.964 116.102 169.701V192.239Z" fill="#C94314"/>`,
29760
+ `<path d="M139.467 126.291L138.418 126.896L133.855 129.522C132.482 130.33 131.312 132.188 131.11 133.844V134.005V134.248V140.791C131.068 138.286 129.737 135.823 127.354 134.449L114.554 127.058C112.092 125.644 109.184 125.766 106.924 127.139L93.3164 134.974C91.7826 135.823 90.5706 135.136 90.5706 133.359V110.821C90.5706 109.084 91.8219 106.944 93.3164 106.055L112.818 94.7864C114.313 93.898 115.564 94.6248 115.564 96.3617V112.073C115.484 114.699 116.856 117.324 119.279 118.738L132.078 126.129C134.46 127.583 137.247 127.543 139.467 126.291Z" fill="#C94314"/>`,
29761
+ `<path d="M160.869 100.362V115.145C160.869 117.972 162.444 120.436 164.745 121.688L178.353 129.524C179.845 130.412 181.099 132.553 181.099 134.29V156.827C181.099 158.564 179.845 160.705 178.353 161.593L158.851 172.862C157.478 173.629 155.338 173.71 153.844 173.104C153.763 173.064 153.722 173.064 153.642 173.024C153.561 172.983 153.44 172.943 153.359 172.862L133.858 161.593C133.493 161.391 133.13 161.068 132.808 160.745C131.837 159.695 131.112 158.16 131.112 156.827V141.156C131.112 141.035 131.112 140.954 131.112 140.833V134.29C131.112 134.209 131.112 134.128 131.112 134.047C131.112 134.007 131.112 133.926 131.112 133.886C131.273 132.23 132.444 130.331 133.858 129.564L138.42 126.939L139.469 126.333L140.803 125.565L147.424 121.728C147.585 121.647 147.707 121.567 147.868 121.486C149.927 120.153 151.3 117.851 151.3 115.185V100.402C151.3 97.5752 149.725 95.1114 147.424 93.8593L133.858 86.0236C132.363 85.135 131.112 82.9944 131.112 81.2577V58.6393C131.112 56.9025 132.363 54.7618 133.858 53.8732L153.359 42.6044C154.893 41.7158 157.356 41.7158 158.851 42.6044L178.353 53.8732C179.886 54.7618 181.099 56.9025 181.099 58.6393V81.1769C181.099 82.0653 180.775 83.0348 180.291 83.8829C179.806 84.7311 179.12 85.4986 178.353 85.9428L164.745 93.7785C162.444 95.071 160.869 97.5348 160.869 100.362Z" fill="#F17736"/>`,
29762
+ `<path d="M156.105 73.1002C156.105 71.3633 154.854 69.2227 153.359 68.3341L133.858 57.0653C132.363 56.1767 131.112 56.9037 131.112 58.6404V81.1782C131.112 82.9149 132.363 85.0556 133.858 85.9441L153.359 97.2129C154.854 98.1015 156.105 97.3745 156.105 95.6377V73.1002Z" fill="#FFAA88"/>`,
29763
+ `<path d="M181.096 81.1782C181.096 82.9149 179.845 85.0556 178.35 85.9441L158.849 97.2129C157.356 98.1015 156.103 97.3745 156.103 95.6377V73.1002C156.103 71.3633 157.356 69.2227 158.849 68.3341L178.35 57.0653C179.845 56.1767 181.096 56.9037 181.096 58.6404V81.1782Z" fill="#C94314"/>`,
29764
+ `<path d="M156.105 171.328C156.105 172.903 155.136 173.63 153.844 173.145C153.763 173.105 153.722 173.105 153.642 173.064C153.561 173.024 153.44 172.984 153.359 172.903L133.857 161.634C133.493 161.432 133.13 161.109 132.808 160.786C131.837 159.736 131.112 158.201 131.112 156.868V141.197C131.112 141.076 131.112 140.995 131.112 140.874V134.331C131.112 134.25 131.112 134.169 131.112 134.088C131.112 134.048 131.112 133.967 131.112 133.927C131.314 132.513 132.443 131.988 133.857 132.796L142.215 137.642L153.359 144.064C154.893 144.953 156.105 147.094 156.105 148.83V171.328Z" fill="#FFAA88"/>`,
29765
+ `<path d="M181.096 156.869C181.096 158.605 179.845 160.746 178.35 161.634L158.849 172.903C157.356 173.792 156.103 173.065 156.103 171.328V148.791C156.103 147.054 157.356 144.913 158.849 144.024L178.35 132.756C179.845 131.867 181.096 132.594 181.096 134.331V156.869Z" fill="#C94314"/>`,
29766
+ ];
29767
+ const NETSKRAFL_LOGO = `
29768
+ <svg preserveAspectRatio="xMidYMid meet" width="100%" height="100%" viewBox="0 0 ${LOGO_WIDTH} ${LOGO_HEIGHT}" fill="none" xmlns="http://www.w3.org/2000/svg">
29769
+ ${NETSKRAFL_LOGO_ARRAY.join("\n")}
29770
+ </svg>`;
29771
+ const NETSKRAFL_LOGO_HTML = m.trust(NETSKRAFL_LOGO);
29772
+ // Calculate dimensions for the background circle
29773
+ const PADDING = 20; // 10px margin on each side
29774
+ const SQUARE_SIZE = Math.max(LOGO_WIDTH, LOGO_HEIGHT) + (PADDING * 2);
29775
+ const CIRCLE_RADIUS = SQUARE_SIZE / 2 - 5; // Slightly smaller than container
29776
+ // Updated circle with proper size and positioning
29777
+ const CIRCLE = `<circle cx="${SQUARE_SIZE / 2}" cy="${SQUARE_SIZE / 2}" r="${CIRCLE_RADIUS}" fill="#ffffff"/>`;
29778
+ // Create container SVG with the logo properly centered
29779
+ const NETSKRAFL_LOGO_WITH_CIRCLE = `
29780
+ <svg preserveAspectRatio="xMidYMid meet" width="100%" height="100%" viewBox="0 0 ${SQUARE_SIZE} ${SQUARE_SIZE}" fill="none" xmlns="http://www.w3.org/2000/svg">
29781
+ ${CIRCLE}
29782
+ <svg x="${(SQUARE_SIZE - LOGO_WIDTH) / 2}" y="${(SQUARE_SIZE - LOGO_HEIGHT) / 2}" width="${LOGO_WIDTH}" height="${LOGO_HEIGHT}" viewBox="0 0 ${LOGO_WIDTH} ${LOGO_HEIGHT}">
29783
+ ${NETSKRAFL_LOGO_ARRAY.join("\n")}
29784
+ </svg>
29785
+ </svg>`;
29786
+ const NETSKRAFL_LOGO_WITH_CIRCLE_HTML = m.trust(NETSKRAFL_LOGO_WITH_CIRCLE);
29838
29787
  const LETTER_WIDTH = 992.73;
29839
- const NUM_LETTER_STEPS = letters.length;
29788
+ const NUM_LETTER_STEPS = LETTERS.length;
29840
29789
  const NetskraflLegend = (initialVnode) => {
29841
29790
  // Animation step time in milliseconds
29842
29791
  const msStepTime = initialVnode.attrs.msStepTime || 0;
@@ -29849,30 +29798,31 @@ const NetskraflLegend = (initialVnode) => {
29849
29798
  function doStep() {
29850
29799
  // Check whether we're still in the delay period
29851
29800
  // Check if we need to reverse direction
29852
- if (delta < 0 && step == 0)
29801
+ if (delta < 0 && step === 0)
29853
29802
  delta = 1;
29854
- else if (delta > 0 && step == NUM_LETTER_STEPS)
29803
+ else if (delta > 0 && step === NUM_LETTER_STEPS)
29855
29804
  delta = -1;
29856
29805
  step += delta;
29857
29806
  m.redraw();
29858
29807
  }
29859
29808
  return {
29860
- oninit: () => {
29861
- if (msStepTime)
29809
+ oncreate: () => {
29810
+ if (msStepTime && ival === 0) {
29862
29811
  ival = setInterval(doStep, msStepTime);
29812
+ }
29863
29813
  },
29864
29814
  onremove: () => {
29865
- if (ival != 0) {
29815
+ if (ival !== 0) {
29866
29816
  clearInterval(ival);
29867
29817
  ival = 0;
29868
29818
  }
29869
29819
  },
29870
29820
  view: () => {
29871
- let r = [headerLetters];
29821
+ let r = [HEADER_LETTERS];
29872
29822
  for (let i = 0; i < step; i++)
29873
- for (let letter of letters[i])
29823
+ for (let letter of LETTERS[i])
29874
29824
  r.push(letter);
29875
- r.push(footer);
29825
+ r.push(FOOTER);
29876
29826
  const attribs = {
29877
29827
  style: {
29878
29828
  "transform": `scale(${scale})`,
@@ -29885,52 +29835,28 @@ const NetskraflLegend = (initialVnode) => {
29885
29835
  }
29886
29836
  };
29887
29837
  };
29888
- const NETSKRAFL_LOGO = `
29889
- <svg width="182" height="210" viewBox="0 0 182 210" fill="none" xmlns="http://www.w3.org/2000/svg">
29890
- <path d="M50.0335 81.1768V58.6393C50.0335 56.9025 48.7821 54.7618 47.2876 53.8732L27.7859 42.6044C26.2932 41.7158 23.7887 41.7158 22.296 42.6044L2.75319 53.8732C1.2587 54.7618 0.00732422 56.9025 0.00732422 58.6393V81.1768C0.00732422 82.9136 1.2587 85.0543 2.75319 85.9428L16.3591 93.7785C18.6617 95.0306 20.2366 97.4944 20.2366 100.322V115.145C20.2366 117.972 18.6617 120.436 16.3591 121.688L7.35643 126.898L2.79251 129.524C1.29981 130.412 0.0484453 132.553 0.0484453 134.29V156.827C0.0484453 158.564 1.29981 160.705 2.79251 161.593L22.296 172.862C23.7887 173.751 26.2932 173.751 27.7859 172.862L47.2876 161.593C48.7821 160.705 50.0335 158.564 50.0335 156.827V134.29C50.0335 132.553 48.7821 130.412 47.2876 129.524L33.6817 121.688C31.3791 120.436 29.806 117.972 29.806 115.145V100.322C29.806 97.4944 31.3791 95.0306 33.6817 93.7785L47.2876 85.9428C48.8232 85.0543 50.0335 82.9136 50.0335 81.1768Z" fill="#F17736"/>
29891
- <path d="M25.0401 73.1002C25.0401 71.3633 23.7887 69.2227 22.296 68.3341L2.75319 57.0653C1.2587 56.1767 0.00732422 56.9037 0.00732422 58.6404V81.1782C0.00732422 82.9149 1.2587 85.0556 2.75319 85.9441L22.2549 97.2129C23.7494 98.1015 25.0007 97.3745 25.0007 95.6377L25.0401 73.1002Z" fill="#FFAA88"/>
29892
- <path d="M73.9793 88.4472L68.2856 91.7188C66.9126 92.5267 65.7417 94.3846 65.5397 96.0405V96.0809V96.2021V96.4848V103.028C65.4986 100.524 64.1668 98.0601 61.7838 96.6868L48.9859 89.2954C46.5225 87.8818 43.6157 88.003 41.3543 89.3762L27.7466 97.2118C26.2539 98.0601 25.0007 97.3734 25.0007 95.6367V73.0989C25.0007 71.3622 26.2539 69.2217 27.7466 68.333L47.2483 57.0642C47.6934 56.8219 48.0974 56.7007 48.4603 56.7007C49.3488 56.7007 49.9941 57.4277 49.9941 58.6393V74.351C49.9137 76.9764 51.2866 79.6018 53.7089 81.0155L66.5086 88.4068C68.972 89.7801 71.7572 89.6993 73.9793 88.4472Z" fill="#C94314"/>
29893
- <path d="M25.0401 148.791C25.0401 147.054 23.7887 144.913 22.296 144.024L2.75319 132.756C1.2587 131.867 0.00732422 132.594 0.00732422 134.331V156.869C0.00732422 158.605 1.2587 160.746 2.75319 161.634L22.2549 172.903C23.7494 173.792 25.0007 173.065 25.0007 171.328L25.0401 148.791Z" fill="#FFAA88"/>
29894
- <path d="M50.035 156.869C50.035 158.605 48.7837 160.746 47.2892 161.634L27.7875 172.903C26.293 173.792 25.0416 173.065 25.0416 171.328V148.791C25.0416 147.054 26.293 144.913 27.7875 144.024L47.2892 132.756C48.7837 131.867 50.035 132.594 50.035 134.331V156.869Z" fill="#C94314"/>
29895
- <path d="M115.566 96.4844V119.022C115.566 120.759 114.313 122.899 112.821 123.788L93.3189 135.057C91.9853 135.824 89.9258 135.905 88.392 135.34C88.3116 135.299 88.2311 135.299 88.1507 135.259C88.1096 135.218 88.0685 135.218 87.988 135.178C87.9487 135.138 87.8665 135.138 87.8271 135.097L68.3254 123.828C68.1234 123.707 67.9608 123.586 67.7587 123.424C67.5979 123.263 67.3959 123.101 67.235 122.94C66.266 121.89 65.5385 120.355 65.5385 119.062V103.351C65.5385 103.229 65.5385 103.149 65.5385 103.028V96.4844C65.5385 96.4036 65.5385 96.3228 65.5385 96.2018C65.5385 96.1614 65.5385 96.121 65.5385 96.0806V96.0402C65.7011 94.3843 66.872 92.5261 68.2843 91.7185L73.9781 88.4468L87.786 80.4497C89.3198 79.561 91.7832 79.561 93.2777 80.4497L112.779 91.7185C114.354 92.6069 115.566 94.7477 115.566 96.4844Z" fill="#F17736"/>
29896
- <path d="M90.573 133.482C90.573 135.097 89.5218 135.824 88.1489 135.259C88.1096 135.219 88.0684 135.219 87.988 135.178C87.9487 135.138 87.8664 135.138 87.8271 135.097L68.3254 123.829C68.1234 123.707 67.9608 123.586 67.7587 123.425C67.5979 123.263 67.3958 123.102 67.235 122.94C66.266 121.89 65.5385 120.355 65.5385 119.063V103.351C65.5385 103.23 65.5385 103.149 65.5385 103.028V96.4847C65.5385 96.4039 65.5385 96.3231 65.5385 96.2019C65.5385 96.1615 65.5385 96.1211 65.5385 96.0807V96.0403C65.7405 94.6268 66.872 94.1016 68.2843 94.9094L76.6828 99.7561L87.8271 106.178C89.3609 107.067 90.573 109.207 90.573 110.944V133.482Z" fill="#FFAA88"/>
29897
- <path d="M139.467 126.291L138.418 126.896L133.855 129.522C132.482 130.33 131.312 132.188 131.11 133.844V134.005V134.248V140.791C131.068 138.286 129.737 135.823 127.354 134.449L114.554 127.058C112.092 125.644 109.184 125.766 106.924 127.139L93.3164 134.974C91.7826 135.823 90.5706 135.136 90.5706 133.359V110.821C90.5706 109.084 91.8219 106.944 93.3164 106.055L112.818 94.7864C114.313 93.898 115.564 94.6248 115.564 96.3617V112.073C115.484 114.699 116.856 117.324 119.279 118.738L132.078 126.129C134.46 127.583 137.247 127.543 139.467 126.291Z" fill="#C94314"/>
29898
- <path d="M160.869 100.362V115.145C160.869 117.972 162.444 120.436 164.745 121.688L178.353 129.524C179.845 130.412 181.099 132.553 181.099 134.29V156.827C181.099 158.564 179.845 160.705 178.353 161.593L158.851 172.862C157.478 173.629 155.338 173.71 153.844 173.104C153.763 173.064 153.722 173.064 153.642 173.024C153.561 172.983 153.44 172.943 153.359 172.862L133.858 161.593C133.493 161.391 133.13 161.068 132.808 160.745C131.837 159.695 131.112 158.16 131.112 156.827V141.156C131.112 141.035 131.112 140.954 131.112 140.833V134.29C131.112 134.209 131.112 134.128 131.112 134.047C131.112 134.007 131.112 133.926 131.112 133.886C131.273 132.23 132.444 130.331 133.858 129.564L138.42 126.939L139.469 126.333L140.803 125.565L147.424 121.728C147.585 121.647 147.707 121.567 147.868 121.486C149.927 120.153 151.3 117.851 151.3 115.185V100.402C151.3 97.5752 149.725 95.1114 147.424 93.8593L133.858 86.0236C132.363 85.135 131.112 82.9944 131.112 81.2577V58.6393C131.112 56.9025 132.363 54.7618 133.858 53.8732L153.359 42.6044C154.893 41.7158 157.356 41.7158 158.851 42.6044L178.353 53.8732C179.886 54.7618 181.099 56.9025 181.099 58.6393V81.1769C181.099 82.0653 180.775 83.0348 180.291 83.8829C179.806 84.7311 179.12 85.4986 178.353 85.9428L164.745 93.7785C162.444 95.071 160.869 97.5348 160.869 100.362Z" fill="#F17736"/>
29899
- <path d="M156.105 73.1002C156.105 71.3633 154.854 69.2227 153.359 68.3341L133.858 57.0653C132.363 56.1767 131.112 56.9037 131.112 58.6404V81.1782C131.112 82.9149 132.363 85.0556 133.858 85.9441L153.359 97.2129C154.854 98.1015 156.105 97.3745 156.105 95.6377V73.1002Z" fill="#FFAA88"/>
29900
- <path d="M181.096 81.1782C181.096 82.9149 179.845 85.0556 178.35 85.9441L158.849 97.2129C157.356 98.1015 156.103 97.3745 156.103 95.6377V73.1002C156.103 71.3633 157.356 69.2227 158.849 68.3341L178.35 57.0653C179.845 56.1767 181.096 56.9037 181.096 58.6404V81.1782Z" fill="#C94314"/>
29901
- <path d="M156.105 171.328C156.105 172.903 155.136 173.63 153.844 173.145C153.763 173.105 153.722 173.105 153.642 173.064C153.561 173.024 153.44 172.984 153.359 172.903L133.857 161.634C133.493 161.432 133.13 161.109 132.808 160.786C131.837 159.736 131.112 158.201 131.112 156.868V141.197C131.112 141.076 131.112 140.995 131.112 140.874V134.331C131.112 134.25 131.112 134.169 131.112 134.088C131.112 134.048 131.112 133.967 131.112 133.927C131.314 132.513 132.443 131.988 133.857 132.796L142.215 137.642L153.359 144.064C154.893 144.953 156.105 147.094 156.105 148.83V171.328Z" fill="#FFAA88"/>
29902
- <path d="M181.096 156.869C181.096 158.605 179.845 160.746 178.35 161.634L158.849 172.903C157.356 173.792 156.103 173.065 156.103 171.328V148.791C156.103 147.054 157.356 144.913 158.849 144.024L178.35 132.756C179.845 131.867 181.096 132.594 181.096 134.331V156.869Z" fill="#C94314"/>
29903
- <path d="M50.0335 81.1768V58.6393C50.0335 56.9025 48.7821 54.7618 47.2876 53.8732L27.7859 42.6044C26.2932 41.7158 23.7887 41.7158 22.296 42.6044L2.75319 53.8732C1.2587 54.7618 0.00732422 56.9025 0.00732422 58.6393V81.1768C0.00732422 82.9136 1.2587 85.0543 2.75319 85.9428L16.3591 93.7785C18.6617 95.0306 20.2366 97.4944 20.2366 100.322V115.145C20.2366 117.972 18.6617 120.436 16.3591 121.688L7.35643 126.898L2.79251 129.524C1.29981 130.412 0.0484453 132.553 0.0484453 134.29V156.827C0.0484453 158.564 1.29981 160.705 2.79251 161.593L22.296 172.862C23.7887 173.751 26.2932 173.751 27.7859 172.862L47.2876 161.593C48.7821 160.705 50.0335 158.564 50.0335 156.827V134.29C50.0335 132.553 48.7821 130.412 47.2876 129.524L33.6817 121.688C31.3791 120.436 29.806 117.972 29.806 115.145V100.322C29.806 97.4944 31.3791 95.0306 33.6817 93.7785L47.2876 85.9428C48.8232 85.0543 50.0335 82.9136 50.0335 81.1768Z" fill="#F17736"/>
29904
- <path d="M25.0401 73.1002C25.0401 71.3633 23.7887 69.2227 22.296 68.3341L2.75319 57.0653C1.2587 56.1767 0.00732422 56.9037 0.00732422 58.6404V81.1782C0.00732422 82.9149 1.2587 85.0556 2.75319 85.9441L22.2549 97.2129C23.7494 98.1015 25.0007 97.3745 25.0007 95.6377L25.0401 73.1002Z" fill="#FFAA88"/>
29905
- <path d="M73.9793 88.4472L68.2856 91.7188C66.9126 92.5267 65.7417 94.3846 65.5397 96.0405V96.0809V96.2021V96.4848V103.028C65.4986 100.524 64.1668 98.0601 61.7838 96.6868L48.9859 89.2954C46.5225 87.8818 43.6157 88.003 41.3543 89.3762L27.7466 97.2118C26.2539 98.0601 25.0007 97.3734 25.0007 95.6367V73.0989C25.0007 71.3622 26.2539 69.2217 27.7466 68.333L47.2483 57.0642C47.6934 56.8219 48.0974 56.7007 48.4603 56.7007C49.3488 56.7007 49.9941 57.4277 49.9941 58.6393V74.351C49.9137 76.9764 51.2866 79.6018 53.7089 81.0155L66.5086 88.4068C68.972 89.7801 71.7572 89.6993 73.9793 88.4472Z" fill="#C94314"/>
29906
- <path d="M25.0401 148.791C25.0401 147.054 23.7887 144.913 22.296 144.024L2.75319 132.756C1.2587 131.867 0.00732422 132.594 0.00732422 134.331V156.869C0.00732422 158.605 1.2587 160.746 2.75319 161.634L22.2549 172.903C23.7494 173.792 25.0007 173.065 25.0007 171.328L25.0401 148.791Z" fill="#FFAA88"/>
29907
- <path d="M50.035 156.869C50.035 158.605 48.7837 160.746 47.2892 161.634L27.7875 172.903C26.293 173.792 25.0416 173.065 25.0416 171.328V148.791C25.0416 147.054 26.293 144.913 27.7875 144.024L47.2892 132.756C48.7837 131.867 50.035 132.594 50.035 134.331V156.869Z" fill="#C94314"/>
29908
- <path d="M115.566 96.4844V119.022C115.566 120.759 114.313 122.899 112.821 123.788L93.3189 135.057C91.9853 135.824 89.9258 135.905 88.392 135.34C88.3116 135.299 88.2311 135.299 88.1507 135.259C88.1096 135.218 88.0685 135.218 87.988 135.178C87.9487 135.138 87.8665 135.138 87.8271 135.097L68.3254 123.828C68.1234 123.707 67.9608 123.586 67.7587 123.424C67.5979 123.263 67.3959 123.101 67.235 122.94C66.266 121.89 65.5385 120.355 65.5385 119.062V103.351C65.5385 103.229 65.5385 103.149 65.5385 103.028V96.4844C65.5385 96.4036 65.5385 96.3228 65.5385 96.2018C65.5385 96.1614 65.5385 96.121 65.5385 96.0806V96.0402C65.7011 94.3843 66.872 92.5261 68.2843 91.7185L73.9781 88.4468L87.786 80.4497C89.3198 79.561 91.7832 79.561 93.2777 80.4497L112.779 91.7185C114.354 92.6069 115.566 94.7477 115.566 96.4844Z" fill="#F17736"/>
29909
- <path d="M90.573 133.482C90.573 135.097 89.5218 135.824 88.1489 135.259C88.1096 135.219 88.0684 135.219 87.988 135.178C87.9487 135.138 87.8664 135.138 87.8271 135.097L68.3254 123.829C68.1234 123.707 67.9608 123.586 67.7587 123.425C67.5979 123.263 67.3958 123.102 67.235 122.94C66.266 121.89 65.5385 120.355 65.5385 119.063V103.351C65.5385 103.23 65.5385 103.149 65.5385 103.028V96.4847C65.5385 96.4039 65.5385 96.3231 65.5385 96.2019C65.5385 96.1615 65.5385 96.1211 65.5385 96.0807V96.0403C65.7405 94.6268 66.872 94.1016 68.2843 94.9094L76.6828 99.7561L87.8271 106.178C89.3609 107.067 90.573 109.207 90.573 110.944V133.482Z" fill="#FFAA88"/>
29910
- <path d="M115.566 16.7012V39.2388C115.566 40.9757 114.313 43.1162 112.821 44.0049L93.3189 55.2737C91.9853 56.0411 89.9258 56.1219 88.392 55.5563C88.3116 55.5159 88.2311 55.5159 88.1507 55.4757C88.1096 55.4353 88.0685 55.4353 87.988 55.3949C87.9487 55.3545 87.8665 55.3545 87.8271 55.3141L68.3254 44.0453C68.1234 43.9241 67.9608 43.8029 67.7587 43.6413C67.5979 43.4798 67.3959 43.3182 67.235 43.1566C66.266 42.1066 65.5385 40.5717 65.5385 39.2792V23.5675C65.5385 23.4463 65.5385 23.3657 65.5385 23.2444V16.7012C65.5385 16.6204 65.5385 16.5396 65.5385 16.4186C65.5385 16.3782 65.5385 16.3378 65.5385 16.2974V16.257C65.7011 14.601 66.872 12.7429 68.2843 11.9353L73.9781 8.66365L87.786 0.666489C89.3198 -0.222163 91.7832 -0.222163 93.2777 0.666489L112.779 11.9353C114.354 12.8237 115.566 14.9645 115.566 16.7012Z" fill="#F17736"/>
29911
- <path d="M89.6624 31.5736C89.6624 29.9159 88.4316 27.8729 86.9616 27.0247L67.7803 16.2696C66.3104 15.4216 65.0796 16.1154 65.0796 17.773V39.2833C65.0796 40.9409 66.3104 42.9841 67.7803 43.832L86.9616 54.5871C88.4316 55.4353 89.6624 54.7414 89.6624 53.0838V31.5736Z" fill="#FFAA88"/>
29912
- <path d="M115.691 38.9886C115.691 40.7689 114.388 42.9634 112.831 43.8742L92.5219 55.426C90.9673 56.3369 89.6622 55.5916 89.6622 53.8113V30.7077C89.6622 28.9272 90.9673 26.7329 92.5219 25.8219L112.831 14.2702C114.388 13.3593 115.691 14.1045 115.691 15.8848V38.9886Z" fill="#C94314"/>
29913
- <path d="M115.566 169.984V192.521C115.566 194.258 114.313 196.399 112.821 197.288L93.3189 208.556C91.9853 209.324 89.9258 209.405 88.392 208.839C88.3116 208.799 88.2311 208.799 88.1507 208.758C88.1096 208.718 88.0685 208.718 87.988 208.678C87.9487 208.637 87.8665 208.637 87.8271 208.597L68.3254 197.328C68.1234 197.207 67.9608 197.086 67.7587 196.924C67.5979 196.763 67.3959 196.601 67.235 196.439C66.266 195.389 65.5385 193.854 65.5385 192.562V176.85C65.5385 176.729 65.5385 176.648 65.5385 176.527V169.984C65.5385 169.903 65.5385 169.822 65.5385 169.701C65.5385 169.661 65.5385 169.62 65.5385 169.58V169.54C65.7011 167.884 66.872 166.026 68.2843 165.218L73.9781 161.946L87.786 153.949C89.3198 153.061 91.7832 153.061 93.2777 153.949L112.779 165.218C114.354 166.106 115.566 168.247 115.566 169.984Z" fill="#F17736"/>
29914
- <path d="M90.573 206.981C90.573 208.596 89.5218 209.323 88.1489 208.758C88.1096 208.718 88.0684 208.718 87.988 208.677C87.9487 208.637 87.8664 208.637 87.8271 208.596L68.3254 197.328C68.1234 197.206 67.9608 197.085 67.7587 196.924C67.5979 196.762 67.3958 196.601 67.235 196.439C66.266 195.389 65.5385 193.854 65.5385 192.562V176.85C65.5385 176.729 65.5385 176.648 65.5385 176.527V169.984C65.5385 169.903 65.5385 169.822 65.5385 169.701C65.5385 169.661 65.5385 169.62 65.5385 169.58V169.539C65.7405 168.126 66.872 167.601 68.2843 168.408L76.6828 173.255L87.8271 179.677C89.3609 180.566 90.573 182.706 90.573 184.443V206.981Z" fill="#FFAA88"/>
29915
- <path d="M116.102 192.239C116.102 193.975 114.851 196.116 113.356 197.005L93.8544 208.273C92.3617 209.162 91.1085 208.435 91.1085 206.698V184.161C91.1085 182.424 92.3617 180.283 93.8544 179.395L113.356 168.126C114.851 167.237 116.102 167.964 116.102 169.701V192.239Z" fill="#C94314"/>
29916
- <path d="M139.467 126.291L138.418 126.896L133.855 129.522C132.482 130.33 131.312 132.188 131.11 133.844V134.005V134.248V140.791C131.068 138.286 129.737 135.823 127.354 134.449L114.554 127.058C112.092 125.644 109.184 125.766 106.924 127.139L93.3164 134.974C91.7826 135.823 90.5706 135.136 90.5706 133.359V110.821C90.5706 109.084 91.8219 106.944 93.3164 106.055L112.818 94.7864C114.313 93.898 115.564 94.6248 115.564 96.3617V112.073C115.484 114.699 116.856 117.324 119.279 118.738L132.078 126.129C134.46 127.583 137.247 127.543 139.467 126.291Z" fill="#C94314"/>
29917
- <path d="M160.869 100.362V115.145C160.869 117.972 162.444 120.436 164.745 121.688L178.353 129.524C179.845 130.412 181.099 132.553 181.099 134.29V156.827C181.099 158.564 179.845 160.705 178.353 161.593L158.851 172.862C157.478 173.629 155.338 173.71 153.844 173.104C153.763 173.064 153.722 173.064 153.642 173.024C153.561 172.983 153.44 172.943 153.359 172.862L133.858 161.593C133.493 161.391 133.13 161.068 132.808 160.745C131.837 159.695 131.112 158.16 131.112 156.827V141.156C131.112 141.035 131.112 140.954 131.112 140.833V134.29C131.112 134.209 131.112 134.128 131.112 134.047C131.112 134.007 131.112 133.926 131.112 133.886C131.273 132.23 132.444 130.331 133.858 129.564L138.42 126.939L139.469 126.333L140.803 125.565L147.424 121.728C147.585 121.647 147.707 121.567 147.868 121.486C149.927 120.153 151.3 117.851 151.3 115.185V100.402C151.3 97.5752 149.725 95.1114 147.424 93.8593L133.858 86.0236C132.363 85.135 131.112 82.9944 131.112 81.2577V58.6393C131.112 56.9025 132.363 54.7618 133.858 53.8732L153.359 42.6044C154.893 41.7158 157.356 41.7158 158.851 42.6044L178.353 53.8732C179.886 54.7618 181.099 56.9025 181.099 58.6393V81.1769C181.099 82.0653 180.775 83.0348 180.291 83.8829C179.806 84.7311 179.12 85.4986 178.353 85.9428L164.745 93.7785C162.444 95.071 160.869 97.5348 160.869 100.362Z" fill="#F17736"/>
29918
- <path d="M156.105 73.1002C156.105 71.3633 154.854 69.2227 153.359 68.3341L133.858 57.0653C132.363 56.1767 131.112 56.9037 131.112 58.6404V81.1782C131.112 82.9149 132.363 85.0556 133.858 85.9441L153.359 97.2129C154.854 98.1015 156.105 97.3745 156.105 95.6377V73.1002Z" fill="#FFAA88"/>
29919
- <path d="M181.096 81.1782C181.096 82.9149 179.845 85.0556 178.35 85.9441L158.849 97.2129C157.356 98.1015 156.103 97.3745 156.103 95.6377V73.1002C156.103 71.3633 157.356 69.2227 158.849 68.3341L178.35 57.0653C179.845 56.1767 181.096 56.9037 181.096 58.6404V81.1782Z" fill="#C94314"/>
29920
- <path d="M156.105 171.328C156.105 172.903 155.136 173.63 153.844 173.145C153.763 173.105 153.722 173.105 153.642 173.064C153.561 173.024 153.44 172.984 153.359 172.903L133.857 161.634C133.493 161.432 133.13 161.109 132.808 160.786C131.837 159.736 131.112 158.201 131.112 156.868V141.197C131.112 141.076 131.112 140.995 131.112 140.874V134.331C131.112 134.25 131.112 134.169 131.112 134.088C131.112 134.048 131.112 133.967 131.112 133.927C131.314 132.513 132.443 131.988 133.857 132.796L142.215 137.642L153.359 144.064C154.893 144.953 156.105 147.094 156.105 148.83V171.328Z" fill="#FFAA88"/>
29921
- <path d="M181.096 156.869C181.096 158.605 179.845 160.746 178.35 161.634L158.849 172.903C157.356 173.792 156.103 173.065 156.103 171.328V148.791C156.103 147.054 157.356 144.913 158.849 144.024L178.35 132.756C179.845 131.867 181.096 132.594 181.096 134.331V156.869Z" fill="#C94314"/>
29922
- </svg>
29923
- `;
29924
29838
  const NetskraflLogoOnly = () => {
29925
29839
  // The Netskrafl logo
29926
29840
  return {
29927
29841
  view: (vnode) => {
29928
- const { width, height } = vnode.attrs;
29842
+ const { width, height, className } = vnode.attrs;
29929
29843
  const style = [
29930
29844
  width ? `width: ${width}px;` : '',
29931
29845
  height ? `height: ${height}px;` : ''
29932
29846
  ].filter(Boolean).join(' ');
29933
- return m(".netskrafl-logo", { style }, m.trust(NETSKRAFL_LOGO));
29847
+ return m(`.${className || "netskrafl-logo"}`, { style }, NETSKRAFL_LOGO_HTML);
29848
+ }
29849
+ };
29850
+ };
29851
+ const AnimatedNetskraflLogo = (initialVnode) => {
29852
+ const { attrs } = initialVnode;
29853
+ const { width, withCircle } = attrs;
29854
+ return {
29855
+ view: () => {
29856
+ const divStyle = {};
29857
+ if (width !== undefined)
29858
+ divStyle.width = `${width}px`;
29859
+ return m(".animated-netskrafl-logo", { style: divStyle }, withCircle ? NETSKRAFL_LOGO_WITH_CIRCLE_HTML : NETSKRAFL_LOGO_HTML);
29934
29860
  }
29935
29861
  };
29936
29862
  };
@@ -29938,7 +29864,7 @@ const NetskraflLogoOnly = () => {
29938
29864
  const SPINNER_INITIAL_DELAY = 800; // milliseconds
29939
29865
  const Spinner = {
29940
29866
  // Show a spinner wait box, after an initial delay
29941
- oninit: (vnode) => {
29867
+ oncreate: (vnode) => {
29942
29868
  vnode.state.show = false;
29943
29869
  vnode.state.ival = setTimeout(() => {
29944
29870
  vnode.state.show = true;
@@ -29954,7 +29880,7 @@ const Spinner = {
29954
29880
  view: (vnode) => {
29955
29881
  if (!vnode.state.show)
29956
29882
  return undefined;
29957
- return m(".modal-dialog", { id: 'spinner-dialog', style: { visibility: 'visible' } }, m("div.animated-spinner", m(AnimatedExploLogo, { msStepTime: 200, width: 120, withCircle: true })));
29883
+ return m(".modal-dialog", { id: 'spinner-dialog', style: { visibility: 'visible' } }, m(".animated-spinner", m(AnimatedNetskraflLogo, { withCircle: true })));
29958
29884
  }
29959
29885
  };
29960
29886
  const TextInput = () => {
@@ -30051,18 +29977,21 @@ const OnlinePresence = (initialVnode) => {
30051
29977
  const askServer = attrs.online === undefined;
30052
29978
  const id = attrs.id;
30053
29979
  const userId = attrs.userId;
29980
+ let loading = false;
30054
29981
  async function _update() {
30055
- if (askServer) {
29982
+ if (askServer && !loading) {
29983
+ loading = true;
30056
29984
  const json = await request({
30057
29985
  method: "POST",
30058
29986
  url: "/onlinecheck",
30059
29987
  body: { user: userId }
30060
29988
  });
30061
29989
  online = json && json.online;
29990
+ loading = false;
30062
29991
  }
30063
29992
  }
30064
29993
  return {
30065
- oninit: _update,
29994
+ oncreate: _update,
30066
29995
  view: (vnode) => {
30067
29996
  var _a, _b;
30068
29997
  if (!askServer)
@@ -30339,6 +30268,7 @@ const WaitDialog = (initialVnode) => {
30339
30268
  const path = 'user/' + userId + "/wait/" + oppId;
30340
30269
  // Flag set when the new game has been initiated
30341
30270
  let pointOfNoReturn = false;
30271
+ let initialized = false;
30342
30272
  async function updateOnline() {
30343
30273
  // Initiate an online check on the opponent
30344
30274
  try {
@@ -30374,24 +30304,26 @@ const WaitDialog = (initialVnode) => {
30374
30304
  catch (e) {
30375
30305
  }
30376
30306
  }
30307
+ const oncreate = async () => {
30308
+ if (!userId || !oppId || initialized)
30309
+ return; // Should not happen
30310
+ initialized = true;
30311
+ updateOnline();
30312
+ // Attach a Firebase listener to the wait path
30313
+ attachFirebaseListener(path, (json) => {
30314
+ if (json !== true && json.game) {
30315
+ // A new game has been created and initiated by the server
30316
+ pointOfNoReturn = true;
30317
+ detachFirebaseListener(path);
30318
+ // We don't need to pop the dialog; that is done automatically
30319
+ // by the route resolver upon m.route.set()
30320
+ // Navigate to the newly initiated game
30321
+ m.route.set("/game/" + json.game);
30322
+ }
30323
+ });
30324
+ };
30377
30325
  return {
30378
- oninit: () => {
30379
- if (!userId || !oppId)
30380
- return; // Should not happen
30381
- updateOnline();
30382
- // Attach a Firebase listener to the wait path
30383
- attachFirebaseListener(path, (json) => {
30384
- if (json !== true && json.game) {
30385
- // A new game has been created and initiated by the server
30386
- pointOfNoReturn = true;
30387
- detachFirebaseListener(path);
30388
- // We don't need to pop the dialog; that is done automatically
30389
- // by the route resolver upon m.route.set()
30390
- // Navigate to the newly initiated game
30391
- m.route.set("/game/" + json.game);
30392
- }
30393
- });
30394
- },
30326
+ oncreate,
30395
30327
  view: () => {
30396
30328
  return m(".modal-dialog", { id: "wait-dialog", style: { visibility: "visible" } }, m(".ui-widget.ui-widget-content.ui-corner-all", { "id": "wait-form" }, [
30397
30329
  m(".chall-hdr", m("table", m("tbody", m("tr", [
@@ -30445,8 +30377,12 @@ const AcceptDialog = (initialVnode) => {
30445
30377
  const key = attrs.challengeKey;
30446
30378
  let oppNick = attrs.oppNick;
30447
30379
  let oppReady = true;
30380
+ let loading = false;
30448
30381
  async function waitCheck() {
30449
30382
  // Initiate a wait status check on the opponent
30383
+ if (loading)
30384
+ return; // Already checking
30385
+ loading = true;
30450
30386
  try {
30451
30387
  const json = await request({
30452
30388
  method: "POST",
@@ -30466,9 +30402,12 @@ const AcceptDialog = (initialVnode) => {
30466
30402
  }
30467
30403
  catch (e) {
30468
30404
  }
30405
+ finally {
30406
+ loading = false;
30407
+ }
30469
30408
  }
30470
30409
  return {
30471
- oninit: () => waitCheck(),
30410
+ oncreate: waitCheck,
30472
30411
  view: () => {
30473
30412
  return m(".modal-dialog", { id: "accept-dialog", style: { visibility: "visible" } }, m(".ui-widget.ui-widget-content.ui-corner-all", { id: "accept-form" }, [
30474
30413
  m(".chall-hdr", m("table", m("tbody", m("tr", [
@@ -30657,7 +30596,7 @@ const FriendCancelConfirmDialog = (initialVnode) => {
30657
30596
 
30658
30597
  Login.ts
30659
30598
 
30660
- Login UI for Explo using the Mithril library
30599
+ Login UI for Metskrafl using the Mithril library
30661
30600
 
30662
30601
  Copyright (C) 2025 Miðeind ehf.
30663
30602
  Author: Vilhjálmur Þorsteinsson
@@ -30700,12 +30639,9 @@ const LoginForm = (initialVnode) => {
30700
30639
  return m.fragment({}, [
30701
30640
  // This is visible on large screens
30702
30641
  m("div.loginform-large", [
30703
- m(AnimatedExploLogo, {
30642
+ m(NetskraflLogoOnly, {
30704
30643
  className: "login-logo",
30705
30644
  width: 200,
30706
- withCircle: false,
30707
- msStepTime: 150,
30708
- once: true
30709
30645
  }),
30710
30646
  m(NetskraflLegend, {
30711
30647
  className: "login-legend",
@@ -30721,12 +30657,9 @@ const LoginForm = (initialVnode) => {
30721
30657
  ]),
30722
30658
  // This is visible on small screens
30723
30659
  m("div.loginform-small", [
30724
- m(AnimatedExploLogo, {
30660
+ m(NetskraflLogoOnly, {
30725
30661
  className: "login-logo",
30726
30662
  width: 160,
30727
- withCircle: false,
30728
- msStepTime: 150,
30729
- once: true
30730
30663
  }),
30731
30664
  m(NetskraflLegend, {
30732
30665
  className: "login-legend",
@@ -31703,7 +31636,7 @@ const Main = () => {
31703
31636
  glyph("thumbs-down", { title: ts("Hafna") })
31704
31637
  :
31705
31638
  glyph("hand-right", { title: ts("Afturkalla") })),
31706
- m(clickable ? "a" : "span", clickable ? {
31639
+ m(clickable ? "a.flex" : "span.flex", clickable ? {
31707
31640
  href: "#",
31708
31641
  onclick: clickChallenge,
31709
31642
  class: oppReady ? "opp-ready" : ""
@@ -32053,9 +31986,13 @@ const PromoDialog = (initialVnode) => {
32053
31986
  const view = initialVnode.attrs.view;
32054
31987
  const model = view.model;
32055
31988
  let html = "";
31989
+ let loading = false;
32056
31990
  function _fetchContent(vnode) {
32057
31991
  // Fetch the content
32058
- model.loadPromoContent(vnode.attrs.kind, (contentHtml) => { html = contentHtml; });
31992
+ if (html !== "" || loading)
31993
+ return; // Already fetching or fetched
31994
+ loading = true;
31995
+ model.loadPromoContent(vnode.attrs.kind, (contentHtml) => { html = contentHtml; loading = false; });
32059
31996
  }
32060
31997
  function _onUpdate(vnode, initFunc) {
32061
31998
  var noButtons = vnode.dom.getElementsByClassName("btn-promo-no");
@@ -32076,7 +32013,7 @@ const PromoDialog = (initialVnode) => {
32076
32013
  initFunc();
32077
32014
  }
32078
32015
  return {
32079
- oninit: _fetchContent,
32016
+ oncreate: _fetchContent,
32080
32017
  view: (vnode) => {
32081
32018
  let initFunc = vnode.attrs.initFunc;
32082
32019
  return m(".modal-dialog", { id: "promo-dialog", style: { visibility: "visible" } }, m(".ui-widget.ui-widget-content.ui-corner-all", { id: "promo-form", className: "promo-" + vnode.attrs.kind }, m("div", {
@@ -32109,33 +32046,46 @@ const UserInfoDialog = (initialVnode) => {
32109
32046
  let stats = {};
32110
32047
  let recentList = [];
32111
32048
  let versusAll = true; // Show games against all opponents or just the current user?
32049
+ let loadingStats = false;
32050
+ let loadingRecentList = false;
32112
32051
  function _updateStats(vnode) {
32113
32052
  // Fetch the statistics of the given user
32053
+ if (loadingStats)
32054
+ return;
32055
+ loadingStats = true;
32114
32056
  model.loadUserStats(vnode.attrs.userid, (json) => {
32115
32057
  if (json && json.result === 0)
32116
32058
  stats = json;
32117
32059
  else
32118
32060
  stats = {};
32061
+ loadingStats = false;
32062
+ m.redraw();
32119
32063
  });
32120
32064
  }
32121
32065
  function _updateRecentList(vnode) {
32122
32066
  var _a, _b;
32123
32067
  // Fetch the recent game list of the given user
32068
+ if (loadingRecentList)
32069
+ return;
32070
+ loadingRecentList = true;
32124
32071
  model.loadUserRecentList(vnode.attrs.userid, versusAll ? null : (_b = (_a = model.state) === null || _a === void 0 ? void 0 : _a.userId) !== null && _b !== void 0 ? _b : "", (json) => {
32125
32072
  if (json && json.result === 0)
32126
32073
  recentList = json.recentlist;
32127
32074
  else
32128
32075
  recentList = [];
32076
+ loadingRecentList = false;
32077
+ m.redraw();
32129
32078
  });
32130
32079
  }
32131
32080
  function _setVersus(vnode, vsState) {
32132
32081
  if (versusAll != vsState) {
32133
32082
  versusAll = vsState;
32083
+ loadingRecentList = false;
32134
32084
  _updateRecentList(vnode);
32135
32085
  }
32136
32086
  }
32137
32087
  return {
32138
- oninit: (vnode) => {
32088
+ oncreate: (vnode) => {
32139
32089
  _updateRecentList(vnode);
32140
32090
  _updateStats(vnode);
32141
32091
  },
@@ -32408,8 +32358,8 @@ const Buttons = (initialVnode) => {
32408
32358
  const model = view.model;
32409
32359
  return {
32410
32360
  view: () => {
32411
- // The set of buttons below the game board, alongside the rack (fullscreen view)
32412
- // or below the rack (mobile view)
32361
+ // The set of buttons below the game board, alongside the rack
32362
+ // (fullscreen view) or below the rack (mobile view)
32413
32363
  const game = model.game;
32414
32364
  let r = [];
32415
32365
  if (!game)
@@ -32436,7 +32386,8 @@ const Buttons = (initialVnode) => {
32436
32386
  if (s.showMove) {
32437
32387
  // "Plain" move button for fullscreen
32438
32388
  const submit_move = ts("submit_move"); // 'Move' or 'Leika'
32439
- r.push(makeButton("submitmove", !s.tilesPlaced || s.showingDialog, () => { game.submitMove(); view.updateScale(); }, submit_move, [submit_move, glyph("play")]));
32389
+ const disabled = !s.tilesPlaced || s.showingDialog;
32390
+ r.push(makeButton("submitmove", disabled, () => { game.submitMove(); view.updateScale(); }, submit_move, [submit_move, glyph("play")]));
32440
32391
  }
32441
32392
  if (s.showMoveMobile) {
32442
32393
  // Submit-Move button on mobile, which also shows the score
@@ -32491,12 +32442,14 @@ const Buttons = (initialVnode) => {
32491
32442
  // Pass move: shown if no tiles have been placed
32492
32443
  // and we're not showing a dialog, or if this is
32493
32444
  // the last move by the opponent in a manual game
32494
- r.push(makeButton("submitpass", (s.tilesPlaced || s.showingDialog) && !s.lastChallenge, () => game.submitPass(), // Note: plain game.submitPass doesn't work here
32445
+ const disabled = (s.tilesPlaced || s.showingDialog) && !s.lastChallenge;
32446
+ r.push(makeButton("submitpass", disabled, () => game.submitPass(), // Note: plain game.submitPass doesn't work here
32495
32447
  ts("Pass"), glyph("forward")));
32496
32448
  }
32497
32449
  if (s.showExchange) {
32498
32450
  // Exchange tiles from the rack
32499
- r.push(makeButton("submitexchange", s.tilesPlaced || s.showingDialog || !s.exchangeAllowed, () => game.submitExchange(), // Note: plain game.submitExchange doesn't work here
32451
+ const disabled = (s.tilesPlaced || s.showingDialog) && !s.exchangeAllowed;
32452
+ r.push(makeButton("submitexchange", disabled, () => game.submitExchange(), // Note: plain game.submitExchange doesn't work here
32500
32453
  ts("Skipta stöfum"), glyph("refresh")));
32501
32454
  }
32502
32455
  if (s.showResign) {
@@ -32534,7 +32487,9 @@ const Buttons = (initialVnode) => {
32534
32487
  }
32535
32488
  // Is the server processing a move?
32536
32489
  if (game === null || game === void 0 ? void 0 : game.moveInProgress) {
32537
- r.push(m(".waitmove", m(".animated-waitmove", m(AnimatedExploLogo, { msStepTime: 100, width: 38, withCircle: false }))));
32490
+ r.push(m(".waitmove", m(".animated-waitmove", m(AnimatedNetskraflLogo, {
32491
+ withCircle: false,
32492
+ }))));
32538
32493
  }
32539
32494
  return m(".buttons", r);
32540
32495
  }
@@ -32545,7 +32500,7 @@ const Buttons = (initialVnode) => {
32545
32500
 
32546
32501
  Dragdrop.ts
32547
32502
 
32548
- Single page UI for Explo using the Mithril library
32503
+ Single page UI for Netskrafl/Explo using the Mithril library
32549
32504
 
32550
32505
  Copyright (C) 2025 Miðeind ehf.
32551
32506
  Author: Vilhjálmur Þorsteinsson
@@ -32845,23 +32800,21 @@ const Tile = (initialVnode) => {
32845
32800
  classes.push("dim");
32846
32801
  */
32847
32802
  }
32848
- if (game.showingDialog === null && !game.over) {
32849
- if (t.draggable) {
32850
- attrs.onmousedown = dragHandler;
32851
- attrs.ontouchstart = dragHandler;
32852
- /*
32853
- attrs.onclick = (ev: MouseEvent) => {
32854
- // When clicking a tile, make it selected (blinking)
32855
- if (coord === game.selectedSq)
32856
- // Clicking again: deselect
32857
- game.selectedSq = null;
32858
- else
32859
- game.selectedSq = coord;
32860
- ev.stopPropagation();
32861
- return false;
32862
- };
32863
- */
32864
- }
32803
+ if (t.draggable && game.allowDragDrop()) {
32804
+ attrs.onmousedown = dragHandler;
32805
+ attrs.ontouchstart = dragHandler;
32806
+ /*
32807
+ attrs.onclick = (ev: MouseEvent) => {
32808
+ // When clicking a tile, make it selected (blinking)
32809
+ if (coord === game.selectedSq)
32810
+ // Clicking again: deselect
32811
+ game.selectedSq = null;
32812
+ else
32813
+ game.selectedSq = coord;
32814
+ ev.stopPropagation();
32815
+ return false;
32816
+ };
32817
+ */
32865
32818
  }
32866
32819
  return m(classes.join("."), attrs, [t.letter === " " ? nbsp() : t.letter, m(".letterscore", t.score)]);
32867
32820
  }
@@ -33987,7 +33940,7 @@ const GameView = () => {
33987
33940
 
33988
33941
  Review.ts
33989
33942
 
33990
- Single page UI for Explo using the Mithril library
33943
+ Single page UI for Netskrafl/Explo using the Mithril library
33991
33944
 
33992
33945
  Copyright (C) 2025 Miðeind ehf.
33993
33946
  Author: Vilhjálmur Þorsteinsson
@@ -34480,9 +34433,9 @@ const BoardReview = (initialVnode) => {
34480
34433
 
34481
34434
  Page.ts
34482
34435
 
34483
- Single page UI for Explo using the Mithril library
34436
+ Single page UI for Netskrafl/Explo using the Mithril library
34484
34437
 
34485
- Copyright (C) 2024 Miðeind ehf.
34438
+ Copyright (C) 2025 Miðeind ehf.
34486
34439
  Author: Vilhjálmur Þorsteinsson
34487
34440
 
34488
34441
  The Creative Commons Attribution-NonCommercial 4.0
@@ -34496,51 +34449,6 @@ const BoardReview = (initialVnode) => {
34496
34449
  cf. https://github.com/pakx/the-mithril-diaries/wiki/Basic-App-Structure
34497
34450
 
34498
34451
  */
34499
- /*
34500
- // EXPERIMENTAL
34501
- function insertStyleSheet(url: string) {
34502
- // Insert a link rel="stylesheet" element into the document head,
34503
- // if it isn't there already
34504
- const head = document.head;
34505
- if (!head) return;
34506
- const links = head.getElementsByTagName("link");
34507
- for (const link of links) {
34508
- if (link.href === url) return;
34509
- }
34510
- const link = document.createElement("link");
34511
- link.rel = "stylesheet";
34512
- link.href = url;
34513
- head.appendChild(link);
34514
- }
34515
- */
34516
- function updateFontFaceUrls(serverUrl) {
34517
- // Get all stylesheets in the document
34518
- try {
34519
- const styleSheets = document.styleSheets;
34520
- // Iterate through each stylesheet
34521
- for (const styleSheet of styleSheets) {
34522
- // Iterate through each CSS rule in the stylesheet
34523
- for (const rule of styleSheet.cssRules) {
34524
- // Check if the rule is a @font-face rule
34525
- if (rule instanceof CSSFontFaceRule) {
34526
- // Update the src property with new URLs
34527
- const src = rule.style.getPropertyValue("src");
34528
- if (src.includes("glyphicons-")) {
34529
- rule.style.setProperty("src", `
34530
- url('${serverUrl}/static/glyphicons-regular.eot') format('embedded-opentype'),
34531
- url('${serverUrl}/static/glyphicons-regular.woff') format('woff'),
34532
- url('${serverUrl}/static/glyphicons-regular.ttf') format('truetype')
34533
- `);
34534
- }
34535
- }
34536
- }
34537
- }
34538
- }
34539
- catch (e) {
34540
- // Handle any errors that occur while accessing stylesheets
34541
- console.error("Error when updating font face URLs: ", e);
34542
- }
34543
- }
34544
34452
  async function main(state, container) {
34545
34453
  // The main UI entry point, called from page.html
34546
34454
  if (!container) {
@@ -34549,10 +34457,6 @@ async function main(state, container) {
34549
34457
  }
34550
34458
  // Set up Netskrafl backend server URLs
34551
34459
  setServerUrl(state.serverUrl, state.movesUrl, state.movesAccessKey);
34552
- // Insert the Explo CSS stylesheet
34553
- // insertStyleSheet("./index.css");
34554
- // Update font URLs to point to the backend server
34555
- updateFontFaceUrls(state.serverUrl);
34556
34460
  try {
34557
34461
  const loginData = await loginUserByEmail(state.userEmail, state.userNick, state.userFullname, state.token);
34558
34462
  if (loginData.status === "expired") {
@@ -34562,6 +34466,8 @@ async function main(state, container) {
34562
34466
  }
34563
34467
  if (loginData.status === "success") {
34564
34468
  state.userId = loginData.user_id;
34469
+ // Use the nickname from the server, if available
34470
+ state.userNick = loginData.nickname || state.userNick;
34565
34471
  // Log in to Firebase with the token passed from the server
34566
34472
  await loginFirebase(state, loginData.firebase_token);
34567
34473
  // Everything looks OK:
@@ -34825,8 +34731,8 @@ class View {
34825
34731
  if (!html)
34826
34732
  return "";
34827
34733
  return m("div.help-tabs", {
34734
+ oncreate: (vnode) => { makeTabs(this, id, createFunc, true, vnode); },
34828
34735
  oninit: (vnode) => { vnode.state.selected = tabNumber || 1; },
34829
- oncreate: (vnode) => { makeTabs(this, id, createFunc, true, vnode); }
34830
34736
  /* onupdate: updateSelection */
34831
34737
  }, m.trust(html));
34832
34738
  }
@@ -35039,13 +34945,14 @@ class View {
35039
34945
  // they can be invoked while the last_chall dialog is being
35040
34946
  // displayed. We therefore allow them to cover the last_chall
35041
34947
  // dialog. On mobile, both dialogs are displayed simultaneously.
35042
- if (game.last_chall)
34948
+ if (game.last_chall) {
35043
34949
  r.push(m(".chall-info", { style: { visibility: "visible" } }, [
35044
34950
  glyph("info-sign"), nbsp(),
35045
34951
  // "Your opponent emptied the rack - you can challenge or pass"
35046
34952
  mt("span.pass-explain", "opponent_emptied_rack")
35047
34953
  ]));
35048
- if (game.showingDialog == "resign")
34954
+ }
34955
+ if (game.showingDialog == "resign") {
35049
34956
  r.push(m(".resign", { style: { visibility: "visible" } }, [
35050
34957
  glyph("exclamation-sign"), nbsp(), ts("Viltu gefa leikinn?"), nbsp(),
35051
34958
  m("span.mobile-break", m("br")),
@@ -35053,8 +34960,9 @@ class View {
35053
34960
  m("span.mobile-space"),
35054
34961
  m("span.yesnobutton", { onclick: () => game.confirmResign(false) }, [glyph("remove"), ts(" Nei")])
35055
34962
  ]));
34963
+ }
35056
34964
  if (game.showingDialog == "pass") {
35057
- if (game.last_chall)
34965
+ if (game.last_chall) {
35058
34966
  r.push(m(".pass-last", { style: { visibility: "visible" } }, [
35059
34967
  glyph("forward"), nbsp(), ts("Segja pass?"),
35060
34968
  mt("span.pass-explain", "Viðureign lýkur þar með"),
@@ -35064,7 +34972,8 @@ class View {
35064
34972
  m("span.mobile-space"),
35065
34973
  m("span.yesnobutton", { onclick: () => game.confirmPass(false) }, [glyph("remove"), ts(" Nei")])
35066
34974
  ]));
35067
- else
34975
+ }
34976
+ else {
35068
34977
  r.push(m(".pass", { style: { visibility: "visible" } }, [
35069
34978
  glyph("forward"), nbsp(), ts("Segja pass?"),
35070
34979
  mt("span.pass-explain", "2x3 pöss í röð ljúka viðureign"),
@@ -35073,8 +34982,9 @@ class View {
35073
34982
  m("span.mobile-space"),
35074
34983
  m("span.yesnobutton", { onclick: () => game.confirmPass(false) }, [glyph("remove"), ts(" Nei")])
35075
34984
  ]));
34985
+ }
35076
34986
  }
35077
- if (game.showingDialog == "exchange")
34987
+ if (game.showingDialog == "exchange") {
35078
34988
  r.push(m(".exchange", { style: { visibility: "visible" } }, [
35079
34989
  glyph("refresh"), nbsp(),
35080
34990
  ts("Smelltu á flísarnar sem þú vilt skipta"), nbsp(),
@@ -35083,7 +34993,8 @@ class View {
35083
34993
  m("span.mobile-space"),
35084
34994
  m("span.yesnobutton", { title: ts('Hætta við'), onclick: () => game.confirmExchange(false) }, glyph("remove"))
35085
34995
  ]));
35086
- if (game.showingDialog == "chall")
34996
+ }
34997
+ if (game.showingDialog == "chall") {
35087
34998
  r.push(m(".chall", { style: { visibility: "visible" } }, [
35088
34999
  glyph("ban-circle"), nbsp(), ts("Véfengja lögn?"),
35089
35000
  mt("span.pass-explain", "Röng véfenging kostar 10 stig"), nbsp(),
@@ -35092,6 +35003,7 @@ class View {
35092
35003
  m("span.mobile-space"),
35093
35004
  m("span.yesnobutton", { onclick: () => game.confirmChallenge(false) }, [glyph("remove"), ts(" Nei")])
35094
35005
  ]));
35006
+ }
35095
35007
  return r;
35096
35008
  }
35097
35009
  } // class View
@@ -35109,7 +35021,7 @@ View.dialogViews = {
35109
35021
  accept: (view, args) => view.vwAccept(args)
35110
35022
  };
35111
35023
 
35112
- const CSS_LINK_ID = "netskrafl-styles";
35024
+ // const CSS_LINK_ID = "netskrafl-styles";
35113
35025
  const DEFAULT_STATE = {
35114
35026
  projectId: "netskrafl",
35115
35027
  firebaseAPIKey: "",
@@ -35181,28 +35093,24 @@ const NetskraflImpl = ({ state, tokenExpired }) => {
35181
35093
  const ref = React.createRef();
35182
35094
  const completeState = { ...DEFAULT_STATE, ...state };
35183
35095
  const { userEmail } = completeState;
35184
- React.useEffect(() => {
35185
- // Check if the stylesheet is already added by another instance
35186
- if (document.getElementById(CSS_LINK_ID)) {
35187
- // Optionally, you might want to increment a usage counter
35188
- // and only remove the link when the counter is zero.
35189
- // For simplicity, we'll assume one global link is fine.
35190
- return;
35191
- }
35192
- const link = document.createElement("link");
35193
- const styleUrl = `${window.location.origin}/static/css/netskrafl.css`;
35194
- link.id = CSS_LINK_ID;
35195
- link.rel = "stylesheet";
35196
- link.type = "text/css";
35197
- link.href = styleUrl;
35198
- // Optional: for CORS, though if it's the same base domain, it might not be needed
35199
- // link.crossOrigin = "anonymous";
35200
- document.head.appendChild(link);
35096
+ /*
35097
+ useEffect(() => {
35098
+ // Check whether the stylesheet is already present
35099
+ if (document.getElementById(CSS_LINK_ID)) return;
35100
+ // Load and link the stylesheet into the document head
35101
+ const link = document.createElement("link");
35102
+ const styleUrl = `${window.location.origin}/static/css/netskrafl.css`;
35103
+ link.id = CSS_LINK_ID;
35104
+ link.rel = "stylesheet";
35105
+ link.type = "text/css";
35106
+ link.href = styleUrl;
35107
+ document.head.appendChild(link);
35108
+ // We don't bother to remove the stylesheet when the component is unmounted
35201
35109
  }, []);
35110
+ */
35202
35111
  React.useEffect(() => {
35203
35112
  var _a;
35204
35113
  // Load the Netskrafl (Mithril) UI for a new user
35205
- // console.log("Mounting Netskrafl UI for user", userEmail);
35206
35114
  if (!userEmail)
35207
35115
  return;
35208
35116
  const container = ref.current;
@@ -35212,8 +35120,7 @@ const NetskraflImpl = ({ state, tokenExpired }) => {
35212
35120
  }
35213
35121
  const elemId = `netskrafl-user-${userEmail}`;
35214
35122
  if (((_a = container.firstElementChild) === null || _a === void 0 ? void 0 : _a.id) === elemId) {
35215
- // Already exists and correctly mounted
35216
- // console.log("Netskrafl UI already mounted with elemId", elemId);
35123
+ // The Netskrafl UI is already correctly mounted
35217
35124
  return;
35218
35125
  }
35219
35126
  try {
@@ -35234,9 +35141,9 @@ const NetskraflImpl = ({ state, tokenExpired }) => {
35234
35141
  container.innerHTML = "";
35235
35142
  }
35236
35143
  return () => {
35237
- // console.log("Dismounting Netskrafl UI for user", userEmail);
35238
35144
  // Move the Netskrafl UI to a hidden div under the body element
35239
35145
  // when the component is unmounted
35146
+ // console.log("Dismounting Netskrafl UI for user", userEmail);
35240
35147
  const container = document.getElementById("netskrafl-container");
35241
35148
  const div = container === null || container === void 0 ? void 0 : container.firstElementChild;
35242
35149
  if ((div === null || div === void 0 ? void 0 : div.id) === elemId) {