@mideind/netskrafl-react 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +8 -0
- package/.eslintrc.json +13 -0
- package/README.md +63 -0
- package/dist/cjs/index.css +6837 -0
- package/dist/cjs/index.js +3046 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/esm/index.css +6837 -0
- package/dist/esm/index.js +3046 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/types.d.ts +41 -0
- package/package.json +63 -0
- package/rollup.config.js +60 -0
- package/src/components/index.ts +2 -0
- package/src/components/netskrafl/Netskrafl.stories.tsx +66 -0
- package/src/components/netskrafl/Netskrafl.tsx +135 -0
- package/src/components/netskrafl/Netskrafl.types.ts +7 -0
- package/src/components/netskrafl/index.ts +2 -0
- package/src/css/fonts.css +4 -0
- package/src/css/glyphs.css +224 -0
- package/src/css/skrafl-explo.css +6616 -0
- package/src/fonts/glyphicons-regular.eot +0 -0
- package/src/fonts/glyphicons-regular.ttf +0 -0
- package/src/fonts/glyphicons-regular.woff +0 -0
- package/src/index.ts +2 -0
- package/src/messages/messages.json +1576 -0
- package/src/mithril/actions.ts +319 -0
- package/src/mithril/bag.ts +65 -0
- package/src/mithril/bestdisplay.ts +74 -0
- package/src/mithril/blankdialog.ts +94 -0
- package/src/mithril/board.ts +336 -0
- package/src/mithril/buttons.ts +303 -0
- package/src/mithril/challengedialog.ts +186 -0
- package/src/mithril/channel.ts +162 -0
- package/src/mithril/chat.ts +228 -0
- package/src/mithril/components.ts +496 -0
- package/src/mithril/dragdrop.ts +219 -0
- package/src/mithril/elopage.ts +180 -0
- package/src/mithril/friend.ts +227 -0
- package/src/mithril/game.ts +1378 -0
- package/src/mithril/gameview.ts +111 -0
- package/src/mithril/globalstate.ts +33 -0
- package/src/mithril/i18n.ts +186 -0
- package/src/mithril/localstorage.ts +133 -0
- package/src/mithril/login.ts +122 -0
- package/src/mithril/logo.ts +270 -0
- package/src/mithril/main.ts +737 -0
- package/src/mithril/mithril.ts +29 -0
- package/src/mithril/model.ts +817 -0
- package/src/mithril/movelistitem.ts +226 -0
- package/src/mithril/page.ts +852 -0
- package/src/mithril/playername.ts +91 -0
- package/src/mithril/promodialog.ts +82 -0
- package/src/mithril/recentlist.ts +148 -0
- package/src/mithril/request.ts +52 -0
- package/src/mithril/review.ts +634 -0
- package/src/mithril/rightcolumn.ts +398 -0
- package/src/mithril/searchbutton.ts +118 -0
- package/src/mithril/statsdisplay.ts +109 -0
- package/src/mithril/tabs.ts +169 -0
- package/src/mithril/tile.ts +145 -0
- package/src/mithril/twoletter.ts +76 -0
- package/src/mithril/types.ts +379 -0
- package/src/mithril/userinfodialog.ts +171 -0
- package/src/mithril/util.ts +304 -0
- package/src/mithril/wait.ts +246 -0
- package/src/mithril/wordcheck.ts +102 -0
- package/tsconfig.json +28 -0
- package/vite.config.ts +12 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/*
|
|
2
|
+
|
|
3
|
+
MovelistItem.ts
|
|
4
|
+
|
|
5
|
+
An item in a move list
|
|
6
|
+
|
|
7
|
+
Copyright (C) 2024 Miðeind ehf.
|
|
8
|
+
Author: Vilhjalmur Thorsteinsson
|
|
9
|
+
|
|
10
|
+
The Creative Commons Attribution-NonCommercial 4.0
|
|
11
|
+
International Public License (CC-BY-NC 4.0) applies to this software.
|
|
12
|
+
For further information, see https://github.com/mideind/Netskrafl
|
|
13
|
+
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { IView, Move, MoveInfo } from "./types";
|
|
17
|
+
import { t, ts } from "./i18n";
|
|
18
|
+
import { nbsp, coord, toVector } from "./util";
|
|
19
|
+
import { VnodeChildren, ComponentFunc, m, VnodeAttrs } from "./mithril";
|
|
20
|
+
import { logEvent } from "./channel";
|
|
21
|
+
|
|
22
|
+
interface IAttributes {
|
|
23
|
+
view: IView;
|
|
24
|
+
move: Move;
|
|
25
|
+
info: MoveInfo;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const MoveListItem: ComponentFunc<IAttributes> = (initialVnode) => {
|
|
29
|
+
// Displays a single move
|
|
30
|
+
|
|
31
|
+
const { view } = initialVnode.attrs;
|
|
32
|
+
const model = view.model;
|
|
33
|
+
const game = model.game!;
|
|
34
|
+
const state = model.state!;
|
|
35
|
+
|
|
36
|
+
function highlightMove(co: string, tiles: string, playerColor: 0 | 1, show: boolean) {
|
|
37
|
+
/* Highlight a move's tiles when hovering over it in the move list */
|
|
38
|
+
const vec = toVector(co);
|
|
39
|
+
let col = vec.col;
|
|
40
|
+
let row = vec.row;
|
|
41
|
+
for (const tile of tiles) {
|
|
42
|
+
if (tile == '?')
|
|
43
|
+
continue;
|
|
44
|
+
const sq = coord(row, col);
|
|
45
|
+
if (sq && game.tiles.hasOwnProperty(sq))
|
|
46
|
+
game.tiles[sq].highlight = show ? playerColor : undefined;
|
|
47
|
+
col += vec.dx;
|
|
48
|
+
row += vec.dy;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function gameOverMove(tiles: string): VnodeChildren {
|
|
53
|
+
// Add a 'game over' div at the bottom of the move list
|
|
54
|
+
// of a completed game. The div includes a button to
|
|
55
|
+
// open a review of the game, if the user is a subscriber.
|
|
56
|
+
return m(".move.gameover",
|
|
57
|
+
[
|
|
58
|
+
m("span.gameovermsg", tiles),
|
|
59
|
+
m("span.statsbutton",
|
|
60
|
+
{
|
|
61
|
+
onclick: (ev: Event) => {
|
|
62
|
+
ev.preventDefault();
|
|
63
|
+
if (state.hasPaid) {
|
|
64
|
+
// Show the game review
|
|
65
|
+
m.route.set("/review/" + game.uuid);
|
|
66
|
+
if (game !== null && game !== undefined) {
|
|
67
|
+
// Log an event for this action
|
|
68
|
+
logEvent("game_review",
|
|
69
|
+
{
|
|
70
|
+
locale: game.locale,
|
|
71
|
+
uuid: game.uuid
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
// Show a friend promotion dialog
|
|
78
|
+
logEvent("click_review",
|
|
79
|
+
{
|
|
80
|
+
userid: state.userId, locale: state.locale
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
view.showFriendPromo();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
t("Skoða yfirlit")
|
|
88
|
+
)
|
|
89
|
+
]
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function createItem(move: Move, info: MoveInfo): VnodeChildren {
|
|
94
|
+
// Add a single move to the move list
|
|
95
|
+
const { leftTotal, rightTotal, player } = info;
|
|
96
|
+
let { co, tiles } = info;
|
|
97
|
+
let score: string | number = info.score;
|
|
98
|
+
let wrdclass = "wordmove";
|
|
99
|
+
let rawCoord = co;
|
|
100
|
+
let tileMoveIncrement = 0; // +1 for tile moves, -1 for successful challenges
|
|
101
|
+
if (co === "") {
|
|
102
|
+
/* Not a regular tile move */
|
|
103
|
+
wrdclass = "othermove";
|
|
104
|
+
if (tiles == "PASS") {
|
|
105
|
+
/* Pass move */
|
|
106
|
+
tiles = " " + ts("Pass") + " ";
|
|
107
|
+
score = "";
|
|
108
|
+
}
|
|
109
|
+
else
|
|
110
|
+
if (tiles.indexOf("EXCH") === 0) {
|
|
111
|
+
/* Exchange move - we don't show the actual tiles exchanged, only their count */
|
|
112
|
+
let numtiles = tiles.slice(5).length;
|
|
113
|
+
const letters = ts(numtiles == 1 ? "letter" : "letters");
|
|
114
|
+
// Exchanged {numtiles} {letters}
|
|
115
|
+
tiles = " " + ts("exchanged", { numtiles: numtiles.toString(), letters: letters }) + " ";
|
|
116
|
+
score = "";
|
|
117
|
+
}
|
|
118
|
+
else
|
|
119
|
+
if (tiles == "RSGN")
|
|
120
|
+
/* Resigned from game */
|
|
121
|
+
tiles = " " + ts("Gaf viðureign") + " ";
|
|
122
|
+
else
|
|
123
|
+
if (tiles == "CHALL") {
|
|
124
|
+
/* Challenge issued */
|
|
125
|
+
tiles = " " + ts("Véfengdi lögn") + " ";
|
|
126
|
+
score = "";
|
|
127
|
+
}
|
|
128
|
+
else
|
|
129
|
+
if (tiles == "RESP") {
|
|
130
|
+
/* Challenge response */
|
|
131
|
+
if (score < 0) {
|
|
132
|
+
// Invalid move
|
|
133
|
+
tiles = " " + ts("Óleyfileg lögn") + " ";
|
|
134
|
+
tileMoveIncrement = -1; // Subtract one from the actual tile moves on the board
|
|
135
|
+
}
|
|
136
|
+
else
|
|
137
|
+
// Unsuccessful challenge
|
|
138
|
+
tiles = " " + ts("Röng véfenging") + " ";
|
|
139
|
+
}
|
|
140
|
+
else
|
|
141
|
+
if (tiles == "TIME") {
|
|
142
|
+
/* Overtime adjustment, 'Extra time' */
|
|
143
|
+
tiles = " " + ts("Umframtími") + " ";
|
|
144
|
+
}
|
|
145
|
+
else
|
|
146
|
+
if (tiles == "OVER") {
|
|
147
|
+
/* Game over */
|
|
148
|
+
tiles = ts("Viðureign lokið");
|
|
149
|
+
wrdclass = "gameover";
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
/* The rack leave at the end of the game (which is always in lowercase
|
|
153
|
+
and thus cannot be confused with the above abbreviations) */
|
|
154
|
+
wrdclass = "wordmove";
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
// Normal tile move
|
|
159
|
+
co = "(" + co + ")";
|
|
160
|
+
// Note: String.replace() will not work here since there may be two question marks in the string
|
|
161
|
+
tiles = tiles.split("?").join(""); /* TBD: Display wildcard characters differently? */
|
|
162
|
+
tileMoveIncrement = 1;
|
|
163
|
+
}
|
|
164
|
+
if (wrdclass == "gameover") {
|
|
165
|
+
// Game over message at bottom of move list
|
|
166
|
+
return gameOverMove(tiles);
|
|
167
|
+
}
|
|
168
|
+
// Normal game move
|
|
169
|
+
let title = (tileMoveIncrement > 0 && !game.manual) ? ts("Smelltu til að fletta upp") : "";
|
|
170
|
+
let playerColor: 0 | 1 = 0;
|
|
171
|
+
let lcp = game.player;
|
|
172
|
+
let cls: string;
|
|
173
|
+
if (player === lcp || (lcp === null && player === 0))
|
|
174
|
+
cls = "humangrad" + (player === 0 ? "_left" : "_right"); /* Local player or player 0 */
|
|
175
|
+
else {
|
|
176
|
+
cls = "autoplayergrad" + (player === 0 ? "_left" : "_right"); /* Remote player or player 1 */
|
|
177
|
+
playerColor = 1;
|
|
178
|
+
}
|
|
179
|
+
const attribs: VnodeAttrs = { };
|
|
180
|
+
if (state.uiFullscreen && tileMoveIncrement > 0) {
|
|
181
|
+
if (!game.manual) {
|
|
182
|
+
if (game.locale == "is_IS") {
|
|
183
|
+
// Tile move and not a manual game: allow word lookup for Icelandic
|
|
184
|
+
attribs.onclick = () => { window.open('https://malid.is/leit/' + tiles, 'malid'); };
|
|
185
|
+
attribs.title = title;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Highlight the move on the board while hovering over it
|
|
189
|
+
attribs.onmouseout = () => {
|
|
190
|
+
move[2] = false; // highlighted
|
|
191
|
+
highlightMove(rawCoord, tiles, playerColor, false);
|
|
192
|
+
};
|
|
193
|
+
attribs.onmouseover = () => {
|
|
194
|
+
move[2] = true; // highlighted
|
|
195
|
+
highlightMove(rawCoord, tiles, playerColor, true);
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (player === 0) {
|
|
199
|
+
// Move by left side player
|
|
200
|
+
return m(".move.leftmove." + cls, attribs,
|
|
201
|
+
[
|
|
202
|
+
m("span.total" + (player == lcp ? ".human" : ".autoplayer"), leftTotal),
|
|
203
|
+
m("span.score" + (move[2] ? ".highlight" : ""), score),
|
|
204
|
+
m("span." + wrdclass, [m("i", tiles), nbsp(), co])
|
|
205
|
+
]
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
// Move by right side player
|
|
210
|
+
return m(".move.rightmove." + cls, attribs,
|
|
211
|
+
[
|
|
212
|
+
m("span." + wrdclass, [co, nbsp(), m("i", tiles)]),
|
|
213
|
+
m("span.score" + (move[2] ? ".highlight" : ""), score),
|
|
214
|
+
m("span.total" + (player == lcp ? ".human" : ".autoplayer"), rightTotal)
|
|
215
|
+
]
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
view: (vnode) => {
|
|
222
|
+
const { move, info } = vnode.attrs;
|
|
223
|
+
return createItem(move, info);
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
};
|