@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/esm/index.js CHANGED
@@ -2206,9 +2206,9 @@ const requestMoves = (options) => {
2206
2206
 
2207
2207
  i8n.ts
2208
2208
 
2209
- Single page UI for Explo using the Mithril library
2209
+ Single page UI for Netskrafl/Explo using the Mithril library
2210
2210
 
2211
- Copyright (C) 2023 Miðeind ehf.
2211
+ Copyright (C) 2025 Miðeind ehf.
2212
2212
  Author: Vilhjálmur Þorsteinsson
2213
2213
 
2214
2214
  The Creative Commons Attribution-NonCommercial 4.0
@@ -2374,7 +2374,7 @@ function interpolate_string(message, ips) {
2374
2374
 
2375
2375
  Common type definitions for the Explo/Netskrafl user interface
2376
2376
 
2377
- Copyright (C) 2024 Miðeind ehf.
2377
+ Copyright (C) 2025 Miðeind ehf.
2378
2378
  Author: Vilhjalmur Thorsteinsson
2379
2379
 
2380
2380
  The Creative Commons Attribution-NonCommercial 4.0
@@ -2420,7 +2420,7 @@ const ERROR_MESSAGES = {
2420
2420
 
2421
2421
  Utility functions for the Explo/Netskrafl user interface
2422
2422
 
2423
- Copyright (C) 2024 Miðeind ehf.
2423
+ Copyright (C) 2025 Miðeind ehf.
2424
2424
  Author: Vilhjálmur Þorsteinsson
2425
2425
 
2426
2426
  The Creative Commons Attribution-NonCommercial 4.0
@@ -28124,6 +28124,11 @@ class Game {
28124
28124
  return r;
28125
28125
  }
28126
28126
  ;
28127
+ allowDragDrop() {
28128
+ // Return true if the game allows drag-and-drop of tiles
28129
+ return !this.over && !this.showingDialog && !this.moveInProgress;
28130
+ }
28131
+ ;
28127
28132
  async sendMove(moves) {
28128
28133
  // Send a move to the server
28129
28134
  this.moveInProgress = true;
@@ -28620,9 +28625,9 @@ class Game {
28620
28625
 
28621
28626
  Model.ts
28622
28627
 
28623
- Single page UI for Explo/Netskrafl using the Mithril library
28628
+ Single page UI for Netskrafl/Explo using the Mithril library
28624
28629
 
28625
- Copyright (C) 2024 Miðeind ehf.
28630
+ Copyright (C) 2025 Miðeind ehf.
28626
28631
  Author: Vilhjálmur Þorsteinsson
28627
28632
 
28628
28633
  The Creative Commons Attribution-NonCommercial 4.0
@@ -29420,9 +29425,9 @@ class Model {
29420
29425
 
29421
29426
  Actions.ts
29422
29427
 
29423
- Single page UI for Explo using the Mithril library
29428
+ Single page UI for Netskrafl/Explo using the Mithril library
29424
29429
 
29425
- Copyright (C) 2024 Miðeind ehf.
29430
+ Copyright (C) 2025 Miðeind ehf.
29426
29431
  Author: Vilhjálmur Þorsteinsson
29427
29432
 
29428
29433
  The Creative Commons Attribution-NonCommercial 4.0
@@ -29694,7 +29699,7 @@ function createRouteResolver(actions) {
29694
29699
 
29695
29700
  Logo.ts
29696
29701
 
29697
- Animated Explo / Netskrafl logo & legend component
29702
+ Animated Netskrafl logo & legend component
29698
29703
 
29699
29704
  Copyright (C) 2025 Miðeind ehf.
29700
29705
  Original author: Vilhjálmur Þorsteinsson
@@ -29704,42 +29709,9 @@ function createRouteResolver(actions) {
29704
29709
  For further information, see https://github.com/mideind/Netskrafl
29705
29710
 
29706
29711
  */
29707
- // SVG code for Explo logo
29708
- const headerLogo = `<svg width="134" height="134" viewBox="-32 -8 134 134" fill="none" xmlns="http://www.w3.org/2000/svg">`;
29709
- const circle = `<circle class="shadow" cx="35" cy="59" r="63" fill="#ffffff"/>`;
29710
- const pieces = [
29711
- // Orange box on top
29712
- [
29713
- `<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"/>`,
29714
- `<path d="M43.5323 25.1457V37.6877L21.7354 25.1457V12.5416L43.5323 25.1457Z" fill="#E69419"/>`,
29715
- `<path d="M65.2661 12.5416V25.1457L43.5312 37.6877V25.1457L65.2661 12.5416Z" fill="#F8DA95"/>`
29716
- ],
29717
- // Red box
29718
- [
29719
- `<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"/>`,
29720
- `<path d="M21.7349 50.23V62.7719L0 50.23V37.688L21.7349 50.23Z" fill="#721D19"/>`
29721
- ],
29722
- // Green box
29723
- [
29724
- `<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"/>`,
29725
- `<path d="M43.5323 62.7716V75.3756L21.7354 62.7716V50.2296L43.5323 62.7716Z" fill="#496A38"/>`,
29726
- `<path d="M65.2661 50.2296V62.7716L43.5312 75.3756V62.7716L65.2661 50.2296Z" fill="#B7C7AD"/>`
29727
- ],
29728
- // Light blue box
29729
- [
29730
- `<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"/>`,
29731
- `<path d="M21.7349 87.918V100.46L0 87.918V75.376L21.7349 87.918Z" fill="#5699A5"/>`
29732
- ],
29733
- // Pink box at the bottom
29734
- [
29735
- `<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"/>`,
29736
- `<path d="M43.5323 100.46V113.002L21.7354 100.46V87.9177L43.5323 100.46Z" fill="#B6676D"/>`,
29737
- `<path d="M65.2661 87.9177V100.46L43.5312 113.002V100.46L65.2661 87.9177Z" fill="#EACFD1"/>`
29738
- ]
29739
- ];
29740
29712
  // SVG code for the letters 'netskrafl'
29741
- const headerLetters = `<svg viewBox="0 0 992.73 323.47" fill="none" xmlns="http://www.w3.org/2000/svg">`;
29742
- const letters = [
29713
+ const HEADER_LETTERS = `<svg viewBox="0 0 992.73 323.47" fill="none" xmlns="http://www.w3.org/2000/svg">`;
29714
+ const LETTERS = [
29743
29715
  [`<path fill="#514c4c"`,
29744
29716
  ` 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"`,
29745
29717
  ` transform="translate(-1401.69 -918.27)"/>`],
@@ -29765,76 +29737,53 @@ const letters = [
29765
29737
  ` 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"`,
29766
29738
  ` transform="translate(-1401.69 -918.27)"/>`]
29767
29739
  ];
29768
- const footer = `</svg>`;
29769
- const WIDTH = 134;
29770
- const NUM_STEPS = pieces.length;
29771
- const AnimatedExploLogo = (initialVnode) => {
29772
- // Animation step time in milliseconds
29773
- const msStepTime = initialVnode.attrs.msStepTime || 0;
29774
- const width = initialVnode.attrs.width;
29775
- const scale = width / WIDTH;
29776
- const withCircle = initialVnode.attrs.withCircle || false;
29777
- const once = initialVnode.attrs.once ? true : false;
29778
- const className = initialVnode.attrs.className;
29779
- let delta = 1;
29780
- let step = msStepTime ? 0 : NUM_STEPS;
29781
- let ival = 0;
29782
- function doStep() {
29783
- // Check whether we're still in the delay period
29784
- // Check if we need to reverse direction
29785
- if (delta < 0 && step == 0) {
29786
- delta = 1;
29787
- }
29788
- else if (delta > 0 && step == NUM_STEPS) {
29789
- // All steps completed; should we reverse direction
29790
- // or stop the animation (if once == true)?
29791
- if (once) {
29792
- // We're done
29793
- delta = 0;
29794
- clearInterval(ival);
29795
- ival = 0;
29796
- }
29797
- else
29798
- // Reverse direction
29799
- delta = -1;
29800
- }
29801
- step += delta;
29802
- m.redraw();
29803
- }
29804
- return {
29805
- oninit: () => {
29806
- if (msStepTime)
29807
- ival = setInterval(doStep, msStepTime);
29808
- },
29809
- onremove: () => {
29810
- if (ival != 0) {
29811
- clearInterval(ival);
29812
- ival = 0;
29813
- }
29814
- },
29815
- view: () => {
29816
- let r = [headerLogo];
29817
- if (withCircle)
29818
- // Include white background circle, with drop shadow
29819
- r.push(circle);
29820
- for (let i = 0; i < step; i++)
29821
- for (let piece of pieces[i])
29822
- r.push(piece);
29823
- r.push(footer);
29824
- let attribs = {
29825
- style: {
29826
- "transform": `scale(${scale})`,
29827
- "transform-origin": "left top"
29828
- }
29829
- };
29830
- if (className !== undefined && className !== null)
29831
- attribs.class = className;
29832
- return m("div", attribs, m.trust(r.join("\n")));
29833
- }
29834
- };
29835
- };
29740
+ const FOOTER = `</svg>`;
29741
+ // Netskrafl logo SVG components
29742
+ const LOGO_WIDTH = 182;
29743
+ const LOGO_HEIGHT = 210;
29744
+ const NETSKRAFL_LOGO_ARRAY = [
29745
+ `<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"/>`,
29746
+ `<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"/>`,
29747
+ `<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"/>`,
29748
+ `<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"/>`,
29749
+ `<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"/>`,
29750
+ `<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"/>`,
29751
+ `<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"/>`,
29752
+ `<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"/>`,
29753
+ `<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"/>`,
29754
+ `<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"/>`,
29755
+ `<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"/>`,
29756
+ `<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"/>`,
29757
+ `<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"/>`,
29758
+ `<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"/>`,
29759
+ `<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"/>`,
29760
+ `<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"/>`,
29761
+ `<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"/>`,
29762
+ `<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"/>`,
29763
+ `<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"/>`,
29764
+ ];
29765
+ const NETSKRAFL_LOGO = `
29766
+ <svg preserveAspectRatio="xMidYMid meet" width="100%" height="100%" viewBox="0 0 ${LOGO_WIDTH} ${LOGO_HEIGHT}" fill="none" xmlns="http://www.w3.org/2000/svg">
29767
+ ${NETSKRAFL_LOGO_ARRAY.join("\n")}
29768
+ </svg>`;
29769
+ const NETSKRAFL_LOGO_HTML = m.trust(NETSKRAFL_LOGO);
29770
+ // Calculate dimensions for the background circle
29771
+ const PADDING = 20; // 10px margin on each side
29772
+ const SQUARE_SIZE = Math.max(LOGO_WIDTH, LOGO_HEIGHT) + (PADDING * 2);
29773
+ const CIRCLE_RADIUS = SQUARE_SIZE / 2 - 5; // Slightly smaller than container
29774
+ // Updated circle with proper size and positioning
29775
+ const CIRCLE = `<circle cx="${SQUARE_SIZE / 2}" cy="${SQUARE_SIZE / 2}" r="${CIRCLE_RADIUS}" fill="#ffffff"/>`;
29776
+ // Create container SVG with the logo properly centered
29777
+ const NETSKRAFL_LOGO_WITH_CIRCLE = `
29778
+ <svg preserveAspectRatio="xMidYMid meet" width="100%" height="100%" viewBox="0 0 ${SQUARE_SIZE} ${SQUARE_SIZE}" fill="none" xmlns="http://www.w3.org/2000/svg">
29779
+ ${CIRCLE}
29780
+ <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}">
29781
+ ${NETSKRAFL_LOGO_ARRAY.join("\n")}
29782
+ </svg>
29783
+ </svg>`;
29784
+ const NETSKRAFL_LOGO_WITH_CIRCLE_HTML = m.trust(NETSKRAFL_LOGO_WITH_CIRCLE);
29836
29785
  const LETTER_WIDTH = 992.73;
29837
- const NUM_LETTER_STEPS = letters.length;
29786
+ const NUM_LETTER_STEPS = LETTERS.length;
29838
29787
  const NetskraflLegend = (initialVnode) => {
29839
29788
  // Animation step time in milliseconds
29840
29789
  const msStepTime = initialVnode.attrs.msStepTime || 0;
@@ -29847,30 +29796,31 @@ const NetskraflLegend = (initialVnode) => {
29847
29796
  function doStep() {
29848
29797
  // Check whether we're still in the delay period
29849
29798
  // Check if we need to reverse direction
29850
- if (delta < 0 && step == 0)
29799
+ if (delta < 0 && step === 0)
29851
29800
  delta = 1;
29852
- else if (delta > 0 && step == NUM_LETTER_STEPS)
29801
+ else if (delta > 0 && step === NUM_LETTER_STEPS)
29853
29802
  delta = -1;
29854
29803
  step += delta;
29855
29804
  m.redraw();
29856
29805
  }
29857
29806
  return {
29858
- oninit: () => {
29859
- if (msStepTime)
29807
+ oncreate: () => {
29808
+ if (msStepTime && ival === 0) {
29860
29809
  ival = setInterval(doStep, msStepTime);
29810
+ }
29861
29811
  },
29862
29812
  onremove: () => {
29863
- if (ival != 0) {
29813
+ if (ival !== 0) {
29864
29814
  clearInterval(ival);
29865
29815
  ival = 0;
29866
29816
  }
29867
29817
  },
29868
29818
  view: () => {
29869
- let r = [headerLetters];
29819
+ let r = [HEADER_LETTERS];
29870
29820
  for (let i = 0; i < step; i++)
29871
- for (let letter of letters[i])
29821
+ for (let letter of LETTERS[i])
29872
29822
  r.push(letter);
29873
- r.push(footer);
29823
+ r.push(FOOTER);
29874
29824
  const attribs = {
29875
29825
  style: {
29876
29826
  "transform": `scale(${scale})`,
@@ -29883,52 +29833,28 @@ const NetskraflLegend = (initialVnode) => {
29883
29833
  }
29884
29834
  };
29885
29835
  };
29886
- const NETSKRAFL_LOGO = `
29887
- <svg width="182" height="210" viewBox="0 0 182 210" fill="none" xmlns="http://www.w3.org/2000/svg">
29888
- <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"/>
29889
- <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"/>
29890
- <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"/>
29891
- <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"/>
29892
- <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"/>
29893
- <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"/>
29894
- <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"/>
29895
- <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"/>
29896
- <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"/>
29897
- <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"/>
29898
- <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"/>
29899
- <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"/>
29900
- <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"/>
29901
- <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"/>
29902
- <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"/>
29903
- <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"/>
29904
- <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"/>
29905
- <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"/>
29906
- <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"/>
29907
- <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"/>
29908
- <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"/>
29909
- <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"/>
29910
- <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"/>
29911
- <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"/>
29912
- <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"/>
29913
- <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"/>
29914
- <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"/>
29915
- <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"/>
29916
- <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"/>
29917
- <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"/>
29918
- <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"/>
29919
- <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"/>
29920
- </svg>
29921
- `;
29922
29836
  const NetskraflLogoOnly = () => {
29923
29837
  // The Netskrafl logo
29924
29838
  return {
29925
29839
  view: (vnode) => {
29926
- const { width, height } = vnode.attrs;
29840
+ const { width, height, className } = vnode.attrs;
29927
29841
  const style = [
29928
29842
  width ? `width: ${width}px;` : '',
29929
29843
  height ? `height: ${height}px;` : ''
29930
29844
  ].filter(Boolean).join(' ');
29931
- return m(".netskrafl-logo", { style }, m.trust(NETSKRAFL_LOGO));
29845
+ return m(`.${className || "netskrafl-logo"}`, { style }, NETSKRAFL_LOGO_HTML);
29846
+ }
29847
+ };
29848
+ };
29849
+ const AnimatedNetskraflLogo = (initialVnode) => {
29850
+ const { attrs } = initialVnode;
29851
+ const { width, withCircle } = attrs;
29852
+ return {
29853
+ view: () => {
29854
+ const divStyle = {};
29855
+ if (width !== undefined)
29856
+ divStyle.width = `${width}px`;
29857
+ return m(".animated-netskrafl-logo", { style: divStyle }, withCircle ? NETSKRAFL_LOGO_WITH_CIRCLE_HTML : NETSKRAFL_LOGO_HTML);
29932
29858
  }
29933
29859
  };
29934
29860
  };
@@ -29936,7 +29862,7 @@ const NetskraflLogoOnly = () => {
29936
29862
  const SPINNER_INITIAL_DELAY = 800; // milliseconds
29937
29863
  const Spinner = {
29938
29864
  // Show a spinner wait box, after an initial delay
29939
- oninit: (vnode) => {
29865
+ oncreate: (vnode) => {
29940
29866
  vnode.state.show = false;
29941
29867
  vnode.state.ival = setTimeout(() => {
29942
29868
  vnode.state.show = true;
@@ -29952,7 +29878,7 @@ const Spinner = {
29952
29878
  view: (vnode) => {
29953
29879
  if (!vnode.state.show)
29954
29880
  return undefined;
29955
- return m(".modal-dialog", { id: 'spinner-dialog', style: { visibility: 'visible' } }, m("div.animated-spinner", m(AnimatedExploLogo, { msStepTime: 200, width: 120, withCircle: true })));
29881
+ return m(".modal-dialog", { id: 'spinner-dialog', style: { visibility: 'visible' } }, m(".animated-spinner", m(AnimatedNetskraflLogo, { withCircle: true })));
29956
29882
  }
29957
29883
  };
29958
29884
  const TextInput = () => {
@@ -30049,18 +29975,21 @@ const OnlinePresence = (initialVnode) => {
30049
29975
  const askServer = attrs.online === undefined;
30050
29976
  const id = attrs.id;
30051
29977
  const userId = attrs.userId;
29978
+ let loading = false;
30052
29979
  async function _update() {
30053
- if (askServer) {
29980
+ if (askServer && !loading) {
29981
+ loading = true;
30054
29982
  const json = await request({
30055
29983
  method: "POST",
30056
29984
  url: "/onlinecheck",
30057
29985
  body: { user: userId }
30058
29986
  });
30059
29987
  online = json && json.online;
29988
+ loading = false;
30060
29989
  }
30061
29990
  }
30062
29991
  return {
30063
- oninit: _update,
29992
+ oncreate: _update,
30064
29993
  view: (vnode) => {
30065
29994
  var _a, _b;
30066
29995
  if (!askServer)
@@ -30337,6 +30266,7 @@ const WaitDialog = (initialVnode) => {
30337
30266
  const path = 'user/' + userId + "/wait/" + oppId;
30338
30267
  // Flag set when the new game has been initiated
30339
30268
  let pointOfNoReturn = false;
30269
+ let initialized = false;
30340
30270
  async function updateOnline() {
30341
30271
  // Initiate an online check on the opponent
30342
30272
  try {
@@ -30372,24 +30302,26 @@ const WaitDialog = (initialVnode) => {
30372
30302
  catch (e) {
30373
30303
  }
30374
30304
  }
30305
+ const oncreate = async () => {
30306
+ if (!userId || !oppId || initialized)
30307
+ return; // Should not happen
30308
+ initialized = true;
30309
+ updateOnline();
30310
+ // Attach a Firebase listener to the wait path
30311
+ attachFirebaseListener(path, (json) => {
30312
+ if (json !== true && json.game) {
30313
+ // A new game has been created and initiated by the server
30314
+ pointOfNoReturn = true;
30315
+ detachFirebaseListener(path);
30316
+ // We don't need to pop the dialog; that is done automatically
30317
+ // by the route resolver upon m.route.set()
30318
+ // Navigate to the newly initiated game
30319
+ m.route.set("/game/" + json.game);
30320
+ }
30321
+ });
30322
+ };
30375
30323
  return {
30376
- oninit: () => {
30377
- if (!userId || !oppId)
30378
- return; // Should not happen
30379
- updateOnline();
30380
- // Attach a Firebase listener to the wait path
30381
- attachFirebaseListener(path, (json) => {
30382
- if (json !== true && json.game) {
30383
- // A new game has been created and initiated by the server
30384
- pointOfNoReturn = true;
30385
- detachFirebaseListener(path);
30386
- // We don't need to pop the dialog; that is done automatically
30387
- // by the route resolver upon m.route.set()
30388
- // Navigate to the newly initiated game
30389
- m.route.set("/game/" + json.game);
30390
- }
30391
- });
30392
- },
30324
+ oncreate,
30393
30325
  view: () => {
30394
30326
  return m(".modal-dialog", { id: "wait-dialog", style: { visibility: "visible" } }, m(".ui-widget.ui-widget-content.ui-corner-all", { "id": "wait-form" }, [
30395
30327
  m(".chall-hdr", m("table", m("tbody", m("tr", [
@@ -30443,8 +30375,12 @@ const AcceptDialog = (initialVnode) => {
30443
30375
  const key = attrs.challengeKey;
30444
30376
  let oppNick = attrs.oppNick;
30445
30377
  let oppReady = true;
30378
+ let loading = false;
30446
30379
  async function waitCheck() {
30447
30380
  // Initiate a wait status check on the opponent
30381
+ if (loading)
30382
+ return; // Already checking
30383
+ loading = true;
30448
30384
  try {
30449
30385
  const json = await request({
30450
30386
  method: "POST",
@@ -30464,9 +30400,12 @@ const AcceptDialog = (initialVnode) => {
30464
30400
  }
30465
30401
  catch (e) {
30466
30402
  }
30403
+ finally {
30404
+ loading = false;
30405
+ }
30467
30406
  }
30468
30407
  return {
30469
- oninit: () => waitCheck(),
30408
+ oncreate: waitCheck,
30470
30409
  view: () => {
30471
30410
  return m(".modal-dialog", { id: "accept-dialog", style: { visibility: "visible" } }, m(".ui-widget.ui-widget-content.ui-corner-all", { id: "accept-form" }, [
30472
30411
  m(".chall-hdr", m("table", m("tbody", m("tr", [
@@ -30655,7 +30594,7 @@ const FriendCancelConfirmDialog = (initialVnode) => {
30655
30594
 
30656
30595
  Login.ts
30657
30596
 
30658
- Login UI for Explo using the Mithril library
30597
+ Login UI for Metskrafl using the Mithril library
30659
30598
 
30660
30599
  Copyright (C) 2025 Miðeind ehf.
30661
30600
  Author: Vilhjálmur Þorsteinsson
@@ -30698,12 +30637,9 @@ const LoginForm = (initialVnode) => {
30698
30637
  return m.fragment({}, [
30699
30638
  // This is visible on large screens
30700
30639
  m("div.loginform-large", [
30701
- m(AnimatedExploLogo, {
30640
+ m(NetskraflLogoOnly, {
30702
30641
  className: "login-logo",
30703
30642
  width: 200,
30704
- withCircle: false,
30705
- msStepTime: 150,
30706
- once: true
30707
30643
  }),
30708
30644
  m(NetskraflLegend, {
30709
30645
  className: "login-legend",
@@ -30719,12 +30655,9 @@ const LoginForm = (initialVnode) => {
30719
30655
  ]),
30720
30656
  // This is visible on small screens
30721
30657
  m("div.loginform-small", [
30722
- m(AnimatedExploLogo, {
30658
+ m(NetskraflLogoOnly, {
30723
30659
  className: "login-logo",
30724
30660
  width: 160,
30725
- withCircle: false,
30726
- msStepTime: 150,
30727
- once: true
30728
30661
  }),
30729
30662
  m(NetskraflLegend, {
30730
30663
  className: "login-legend",
@@ -31701,7 +31634,7 @@ const Main = () => {
31701
31634
  glyph("thumbs-down", { title: ts("Hafna") })
31702
31635
  :
31703
31636
  glyph("hand-right", { title: ts("Afturkalla") })),
31704
- m(clickable ? "a" : "span", clickable ? {
31637
+ m(clickable ? "a.flex" : "span.flex", clickable ? {
31705
31638
  href: "#",
31706
31639
  onclick: clickChallenge,
31707
31640
  class: oppReady ? "opp-ready" : ""
@@ -32051,9 +31984,13 @@ const PromoDialog = (initialVnode) => {
32051
31984
  const view = initialVnode.attrs.view;
32052
31985
  const model = view.model;
32053
31986
  let html = "";
31987
+ let loading = false;
32054
31988
  function _fetchContent(vnode) {
32055
31989
  // Fetch the content
32056
- model.loadPromoContent(vnode.attrs.kind, (contentHtml) => { html = contentHtml; });
31990
+ if (html !== "" || loading)
31991
+ return; // Already fetching or fetched
31992
+ loading = true;
31993
+ model.loadPromoContent(vnode.attrs.kind, (contentHtml) => { html = contentHtml; loading = false; });
32057
31994
  }
32058
31995
  function _onUpdate(vnode, initFunc) {
32059
31996
  var noButtons = vnode.dom.getElementsByClassName("btn-promo-no");
@@ -32074,7 +32011,7 @@ const PromoDialog = (initialVnode) => {
32074
32011
  initFunc();
32075
32012
  }
32076
32013
  return {
32077
- oninit: _fetchContent,
32014
+ oncreate: _fetchContent,
32078
32015
  view: (vnode) => {
32079
32016
  let initFunc = vnode.attrs.initFunc;
32080
32017
  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", {
@@ -32107,33 +32044,46 @@ const UserInfoDialog = (initialVnode) => {
32107
32044
  let stats = {};
32108
32045
  let recentList = [];
32109
32046
  let versusAll = true; // Show games against all opponents or just the current user?
32047
+ let loadingStats = false;
32048
+ let loadingRecentList = false;
32110
32049
  function _updateStats(vnode) {
32111
32050
  // Fetch the statistics of the given user
32051
+ if (loadingStats)
32052
+ return;
32053
+ loadingStats = true;
32112
32054
  model.loadUserStats(vnode.attrs.userid, (json) => {
32113
32055
  if (json && json.result === 0)
32114
32056
  stats = json;
32115
32057
  else
32116
32058
  stats = {};
32059
+ loadingStats = false;
32060
+ m.redraw();
32117
32061
  });
32118
32062
  }
32119
32063
  function _updateRecentList(vnode) {
32120
32064
  var _a, _b;
32121
32065
  // Fetch the recent game list of the given user
32066
+ if (loadingRecentList)
32067
+ return;
32068
+ loadingRecentList = true;
32122
32069
  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) => {
32123
32070
  if (json && json.result === 0)
32124
32071
  recentList = json.recentlist;
32125
32072
  else
32126
32073
  recentList = [];
32074
+ loadingRecentList = false;
32075
+ m.redraw();
32127
32076
  });
32128
32077
  }
32129
32078
  function _setVersus(vnode, vsState) {
32130
32079
  if (versusAll != vsState) {
32131
32080
  versusAll = vsState;
32081
+ loadingRecentList = false;
32132
32082
  _updateRecentList(vnode);
32133
32083
  }
32134
32084
  }
32135
32085
  return {
32136
- oninit: (vnode) => {
32086
+ oncreate: (vnode) => {
32137
32087
  _updateRecentList(vnode);
32138
32088
  _updateStats(vnode);
32139
32089
  },
@@ -32406,8 +32356,8 @@ const Buttons = (initialVnode) => {
32406
32356
  const model = view.model;
32407
32357
  return {
32408
32358
  view: () => {
32409
- // The set of buttons below the game board, alongside the rack (fullscreen view)
32410
- // or below the rack (mobile view)
32359
+ // The set of buttons below the game board, alongside the rack
32360
+ // (fullscreen view) or below the rack (mobile view)
32411
32361
  const game = model.game;
32412
32362
  let r = [];
32413
32363
  if (!game)
@@ -32434,7 +32384,8 @@ const Buttons = (initialVnode) => {
32434
32384
  if (s.showMove) {
32435
32385
  // "Plain" move button for fullscreen
32436
32386
  const submit_move = ts("submit_move"); // 'Move' or 'Leika'
32437
- r.push(makeButton("submitmove", !s.tilesPlaced || s.showingDialog, () => { game.submitMove(); view.updateScale(); }, submit_move, [submit_move, glyph("play")]));
32387
+ const disabled = !s.tilesPlaced || s.showingDialog;
32388
+ r.push(makeButton("submitmove", disabled, () => { game.submitMove(); view.updateScale(); }, submit_move, [submit_move, glyph("play")]));
32438
32389
  }
32439
32390
  if (s.showMoveMobile) {
32440
32391
  // Submit-Move button on mobile, which also shows the score
@@ -32489,12 +32440,14 @@ const Buttons = (initialVnode) => {
32489
32440
  // Pass move: shown if no tiles have been placed
32490
32441
  // and we're not showing a dialog, or if this is
32491
32442
  // the last move by the opponent in a manual game
32492
- r.push(makeButton("submitpass", (s.tilesPlaced || s.showingDialog) && !s.lastChallenge, () => game.submitPass(), // Note: plain game.submitPass doesn't work here
32443
+ const disabled = (s.tilesPlaced || s.showingDialog) && !s.lastChallenge;
32444
+ r.push(makeButton("submitpass", disabled, () => game.submitPass(), // Note: plain game.submitPass doesn't work here
32493
32445
  ts("Pass"), glyph("forward")));
32494
32446
  }
32495
32447
  if (s.showExchange) {
32496
32448
  // Exchange tiles from the rack
32497
- r.push(makeButton("submitexchange", s.tilesPlaced || s.showingDialog || !s.exchangeAllowed, () => game.submitExchange(), // Note: plain game.submitExchange doesn't work here
32449
+ const disabled = (s.tilesPlaced || s.showingDialog) && !s.exchangeAllowed;
32450
+ r.push(makeButton("submitexchange", disabled, () => game.submitExchange(), // Note: plain game.submitExchange doesn't work here
32498
32451
  ts("Skipta stöfum"), glyph("refresh")));
32499
32452
  }
32500
32453
  if (s.showResign) {
@@ -32532,7 +32485,9 @@ const Buttons = (initialVnode) => {
32532
32485
  }
32533
32486
  // Is the server processing a move?
32534
32487
  if (game === null || game === void 0 ? void 0 : game.moveInProgress) {
32535
- r.push(m(".waitmove", m(".animated-waitmove", m(AnimatedExploLogo, { msStepTime: 100, width: 38, withCircle: false }))));
32488
+ r.push(m(".waitmove", m(".animated-waitmove", m(AnimatedNetskraflLogo, {
32489
+ withCircle: false,
32490
+ }))));
32536
32491
  }
32537
32492
  return m(".buttons", r);
32538
32493
  }
@@ -32543,7 +32498,7 @@ const Buttons = (initialVnode) => {
32543
32498
 
32544
32499
  Dragdrop.ts
32545
32500
 
32546
- Single page UI for Explo using the Mithril library
32501
+ Single page UI for Netskrafl/Explo using the Mithril library
32547
32502
 
32548
32503
  Copyright (C) 2025 Miðeind ehf.
32549
32504
  Author: Vilhjálmur Þorsteinsson
@@ -32843,23 +32798,21 @@ const Tile = (initialVnode) => {
32843
32798
  classes.push("dim");
32844
32799
  */
32845
32800
  }
32846
- if (game.showingDialog === null && !game.over) {
32847
- if (t.draggable) {
32848
- attrs.onmousedown = dragHandler;
32849
- attrs.ontouchstart = dragHandler;
32850
- /*
32851
- attrs.onclick = (ev: MouseEvent) => {
32852
- // When clicking a tile, make it selected (blinking)
32853
- if (coord === game.selectedSq)
32854
- // Clicking again: deselect
32855
- game.selectedSq = null;
32856
- else
32857
- game.selectedSq = coord;
32858
- ev.stopPropagation();
32859
- return false;
32860
- };
32861
- */
32862
- }
32801
+ if (t.draggable && game.allowDragDrop()) {
32802
+ attrs.onmousedown = dragHandler;
32803
+ attrs.ontouchstart = dragHandler;
32804
+ /*
32805
+ attrs.onclick = (ev: MouseEvent) => {
32806
+ // When clicking a tile, make it selected (blinking)
32807
+ if (coord === game.selectedSq)
32808
+ // Clicking again: deselect
32809
+ game.selectedSq = null;
32810
+ else
32811
+ game.selectedSq = coord;
32812
+ ev.stopPropagation();
32813
+ return false;
32814
+ };
32815
+ */
32863
32816
  }
32864
32817
  return m(classes.join("."), attrs, [t.letter === " " ? nbsp() : t.letter, m(".letterscore", t.score)]);
32865
32818
  }
@@ -33985,7 +33938,7 @@ const GameView = () => {
33985
33938
 
33986
33939
  Review.ts
33987
33940
 
33988
- Single page UI for Explo using the Mithril library
33941
+ Single page UI for Netskrafl/Explo using the Mithril library
33989
33942
 
33990
33943
  Copyright (C) 2025 Miðeind ehf.
33991
33944
  Author: Vilhjálmur Þorsteinsson
@@ -34478,9 +34431,9 @@ const BoardReview = (initialVnode) => {
34478
34431
 
34479
34432
  Page.ts
34480
34433
 
34481
- Single page UI for Explo using the Mithril library
34434
+ Single page UI for Netskrafl/Explo using the Mithril library
34482
34435
 
34483
- Copyright (C) 2024 Miðeind ehf.
34436
+ Copyright (C) 2025 Miðeind ehf.
34484
34437
  Author: Vilhjálmur Þorsteinsson
34485
34438
 
34486
34439
  The Creative Commons Attribution-NonCommercial 4.0
@@ -34494,51 +34447,6 @@ const BoardReview = (initialVnode) => {
34494
34447
  cf. https://github.com/pakx/the-mithril-diaries/wiki/Basic-App-Structure
34495
34448
 
34496
34449
  */
34497
- /*
34498
- // EXPERIMENTAL
34499
- function insertStyleSheet(url: string) {
34500
- // Insert a link rel="stylesheet" element into the document head,
34501
- // if it isn't there already
34502
- const head = document.head;
34503
- if (!head) return;
34504
- const links = head.getElementsByTagName("link");
34505
- for (const link of links) {
34506
- if (link.href === url) return;
34507
- }
34508
- const link = document.createElement("link");
34509
- link.rel = "stylesheet";
34510
- link.href = url;
34511
- head.appendChild(link);
34512
- }
34513
- */
34514
- function updateFontFaceUrls(serverUrl) {
34515
- // Get all stylesheets in the document
34516
- try {
34517
- const styleSheets = document.styleSheets;
34518
- // Iterate through each stylesheet
34519
- for (const styleSheet of styleSheets) {
34520
- // Iterate through each CSS rule in the stylesheet
34521
- for (const rule of styleSheet.cssRules) {
34522
- // Check if the rule is a @font-face rule
34523
- if (rule instanceof CSSFontFaceRule) {
34524
- // Update the src property with new URLs
34525
- const src = rule.style.getPropertyValue("src");
34526
- if (src.includes("glyphicons-")) {
34527
- rule.style.setProperty("src", `
34528
- url('${serverUrl}/static/glyphicons-regular.eot') format('embedded-opentype'),
34529
- url('${serverUrl}/static/glyphicons-regular.woff') format('woff'),
34530
- url('${serverUrl}/static/glyphicons-regular.ttf') format('truetype')
34531
- `);
34532
- }
34533
- }
34534
- }
34535
- }
34536
- }
34537
- catch (e) {
34538
- // Handle any errors that occur while accessing stylesheets
34539
- console.error("Error when updating font face URLs: ", e);
34540
- }
34541
- }
34542
34450
  async function main(state, container) {
34543
34451
  // The main UI entry point, called from page.html
34544
34452
  if (!container) {
@@ -34547,10 +34455,6 @@ async function main(state, container) {
34547
34455
  }
34548
34456
  // Set up Netskrafl backend server URLs
34549
34457
  setServerUrl(state.serverUrl, state.movesUrl, state.movesAccessKey);
34550
- // Insert the Explo CSS stylesheet
34551
- // insertStyleSheet("./index.css");
34552
- // Update font URLs to point to the backend server
34553
- updateFontFaceUrls(state.serverUrl);
34554
34458
  try {
34555
34459
  const loginData = await loginUserByEmail(state.userEmail, state.userNick, state.userFullname, state.token);
34556
34460
  if (loginData.status === "expired") {
@@ -34560,6 +34464,8 @@ async function main(state, container) {
34560
34464
  }
34561
34465
  if (loginData.status === "success") {
34562
34466
  state.userId = loginData.user_id;
34467
+ // Use the nickname from the server, if available
34468
+ state.userNick = loginData.nickname || state.userNick;
34563
34469
  // Log in to Firebase with the token passed from the server
34564
34470
  await loginFirebase(state, loginData.firebase_token);
34565
34471
  // Everything looks OK:
@@ -34823,8 +34729,8 @@ class View {
34823
34729
  if (!html)
34824
34730
  return "";
34825
34731
  return m("div.help-tabs", {
34732
+ oncreate: (vnode) => { makeTabs(this, id, createFunc, true, vnode); },
34826
34733
  oninit: (vnode) => { vnode.state.selected = tabNumber || 1; },
34827
- oncreate: (vnode) => { makeTabs(this, id, createFunc, true, vnode); }
34828
34734
  /* onupdate: updateSelection */
34829
34735
  }, m.trust(html));
34830
34736
  }
@@ -35037,13 +34943,14 @@ class View {
35037
34943
  // they can be invoked while the last_chall dialog is being
35038
34944
  // displayed. We therefore allow them to cover the last_chall
35039
34945
  // dialog. On mobile, both dialogs are displayed simultaneously.
35040
- if (game.last_chall)
34946
+ if (game.last_chall) {
35041
34947
  r.push(m(".chall-info", { style: { visibility: "visible" } }, [
35042
34948
  glyph("info-sign"), nbsp(),
35043
34949
  // "Your opponent emptied the rack - you can challenge or pass"
35044
34950
  mt("span.pass-explain", "opponent_emptied_rack")
35045
34951
  ]));
35046
- if (game.showingDialog == "resign")
34952
+ }
34953
+ if (game.showingDialog == "resign") {
35047
34954
  r.push(m(".resign", { style: { visibility: "visible" } }, [
35048
34955
  glyph("exclamation-sign"), nbsp(), ts("Viltu gefa leikinn?"), nbsp(),
35049
34956
  m("span.mobile-break", m("br")),
@@ -35051,8 +34958,9 @@ class View {
35051
34958
  m("span.mobile-space"),
35052
34959
  m("span.yesnobutton", { onclick: () => game.confirmResign(false) }, [glyph("remove"), ts(" Nei")])
35053
34960
  ]));
34961
+ }
35054
34962
  if (game.showingDialog == "pass") {
35055
- if (game.last_chall)
34963
+ if (game.last_chall) {
35056
34964
  r.push(m(".pass-last", { style: { visibility: "visible" } }, [
35057
34965
  glyph("forward"), nbsp(), ts("Segja pass?"),
35058
34966
  mt("span.pass-explain", "Viðureign lýkur þar með"),
@@ -35062,7 +34970,8 @@ class View {
35062
34970
  m("span.mobile-space"),
35063
34971
  m("span.yesnobutton", { onclick: () => game.confirmPass(false) }, [glyph("remove"), ts(" Nei")])
35064
34972
  ]));
35065
- else
34973
+ }
34974
+ else {
35066
34975
  r.push(m(".pass", { style: { visibility: "visible" } }, [
35067
34976
  glyph("forward"), nbsp(), ts("Segja pass?"),
35068
34977
  mt("span.pass-explain", "2x3 pöss í röð ljúka viðureign"),
@@ -35071,8 +34980,9 @@ class View {
35071
34980
  m("span.mobile-space"),
35072
34981
  m("span.yesnobutton", { onclick: () => game.confirmPass(false) }, [glyph("remove"), ts(" Nei")])
35073
34982
  ]));
34983
+ }
35074
34984
  }
35075
- if (game.showingDialog == "exchange")
34985
+ if (game.showingDialog == "exchange") {
35076
34986
  r.push(m(".exchange", { style: { visibility: "visible" } }, [
35077
34987
  glyph("refresh"), nbsp(),
35078
34988
  ts("Smelltu á flísarnar sem þú vilt skipta"), nbsp(),
@@ -35081,7 +34991,8 @@ class View {
35081
34991
  m("span.mobile-space"),
35082
34992
  m("span.yesnobutton", { title: ts('Hætta við'), onclick: () => game.confirmExchange(false) }, glyph("remove"))
35083
34993
  ]));
35084
- if (game.showingDialog == "chall")
34994
+ }
34995
+ if (game.showingDialog == "chall") {
35085
34996
  r.push(m(".chall", { style: { visibility: "visible" } }, [
35086
34997
  glyph("ban-circle"), nbsp(), ts("Véfengja lögn?"),
35087
34998
  mt("span.pass-explain", "Röng véfenging kostar 10 stig"), nbsp(),
@@ -35090,6 +35001,7 @@ class View {
35090
35001
  m("span.mobile-space"),
35091
35002
  m("span.yesnobutton", { onclick: () => game.confirmChallenge(false) }, [glyph("remove"), ts(" Nei")])
35092
35003
  ]));
35004
+ }
35093
35005
  return r;
35094
35006
  }
35095
35007
  } // class View
@@ -35107,7 +35019,7 @@ View.dialogViews = {
35107
35019
  accept: (view, args) => view.vwAccept(args)
35108
35020
  };
35109
35021
 
35110
- const CSS_LINK_ID = "netskrafl-styles";
35022
+ // const CSS_LINK_ID = "netskrafl-styles";
35111
35023
  const DEFAULT_STATE = {
35112
35024
  projectId: "netskrafl",
35113
35025
  firebaseAPIKey: "",
@@ -35179,28 +35091,24 @@ const NetskraflImpl = ({ state, tokenExpired }) => {
35179
35091
  const ref = React.createRef();
35180
35092
  const completeState = { ...DEFAULT_STATE, ...state };
35181
35093
  const { userEmail } = completeState;
35094
+ /*
35182
35095
  useEffect(() => {
35183
- // Check if the stylesheet is already added by another instance
35184
- if (document.getElementById(CSS_LINK_ID)) {
35185
- // Optionally, you might want to increment a usage counter
35186
- // and only remove the link when the counter is zero.
35187
- // For simplicity, we'll assume one global link is fine.
35188
- return;
35189
- }
35190
- const link = document.createElement("link");
35191
- const styleUrl = `${window.location.origin}/static/css/netskrafl.css`;
35192
- link.id = CSS_LINK_ID;
35193
- link.rel = "stylesheet";
35194
- link.type = "text/css";
35195
- link.href = styleUrl;
35196
- // Optional: for CORS, though if it's the same base domain, it might not be needed
35197
- // link.crossOrigin = "anonymous";
35198
- document.head.appendChild(link);
35096
+ // Check whether the stylesheet is already present
35097
+ if (document.getElementById(CSS_LINK_ID)) return;
35098
+ // Load and link the stylesheet into the document head
35099
+ const link = document.createElement("link");
35100
+ const styleUrl = `${window.location.origin}/static/css/netskrafl.css`;
35101
+ link.id = CSS_LINK_ID;
35102
+ link.rel = "stylesheet";
35103
+ link.type = "text/css";
35104
+ link.href = styleUrl;
35105
+ document.head.appendChild(link);
35106
+ // We don't bother to remove the stylesheet when the component is unmounted
35199
35107
  }, []);
35108
+ */
35200
35109
  useEffect(() => {
35201
35110
  var _a;
35202
35111
  // Load the Netskrafl (Mithril) UI for a new user
35203
- // console.log("Mounting Netskrafl UI for user", userEmail);
35204
35112
  if (!userEmail)
35205
35113
  return;
35206
35114
  const container = ref.current;
@@ -35210,8 +35118,7 @@ const NetskraflImpl = ({ state, tokenExpired }) => {
35210
35118
  }
35211
35119
  const elemId = `netskrafl-user-${userEmail}`;
35212
35120
  if (((_a = container.firstElementChild) === null || _a === void 0 ? void 0 : _a.id) === elemId) {
35213
- // Already exists and correctly mounted
35214
- // console.log("Netskrafl UI already mounted with elemId", elemId);
35121
+ // The Netskrafl UI is already correctly mounted
35215
35122
  return;
35216
35123
  }
35217
35124
  try {
@@ -35232,9 +35139,9 @@ const NetskraflImpl = ({ state, tokenExpired }) => {
35232
35139
  container.innerHTML = "";
35233
35140
  }
35234
35141
  return () => {
35235
- // console.log("Dismounting Netskrafl UI for user", userEmail);
35236
35142
  // Move the Netskrafl UI to a hidden div under the body element
35237
35143
  // when the component is unmounted
35144
+ // console.log("Dismounting Netskrafl UI for user", userEmail);
35238
35145
  const container = document.getElementById("netskrafl-container");
35239
35146
  const div = container === null || container === void 0 ? void 0 : container.firstElementChild;
35240
35147
  if ((div === null || div === void 0 ? void 0 : div.id) === elemId) {