@selimssevgi/cube-design-angular 0.6.2 → 0.7.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.
@@ -9,16 +9,16 @@ function sizeFor(count) {
9
9
  while (s * s * s < count && s < 7) s++;
10
10
  return s;
11
11
  }
12
- const C30 = Math.cos(Math.PI / 6);
12
+ const C30$1 = Math.cos(Math.PI / 6);
13
13
  function poly(pts, k) {
14
14
  const cx = pts.reduce((a, q) => a + q[0], 0) / pts.length;
15
15
  const cy = pts.reduce((a, q) => a + q[1], 0) / pts.length;
16
16
  return pts.map(([x, y]) => `${(cx + (x - cx) * k).toFixed(1)},${(cy + (y - cy) * k).toFixed(1)}`).join(" ");
17
17
  }
18
18
  function squares(n, s, shift) {
19
- const ox = n * s * C30;
19
+ const ox = n * s * C30$1;
20
20
  const oy = n * s;
21
- const p = (x, y, z) => [shift[0] + ox + (x - y) * C30 * s, shift[1] + oy + (x + y) * .5 * s - z * s];
21
+ const p = (x, y, z) => [shift[0] + ox + (x - y) * C30$1 * s, shift[1] + oy + (x + y) * .5 * s - z * s];
22
22
  const out = [];
23
23
  for (let a = 0; a < n; a++) for (let b = n - 1; b >= 0; b--) out.push({
24
24
  face: "left",
@@ -53,9 +53,9 @@ function drawCube(count, colours, width, options = {}) {
53
53
  const n = sizeFor(Math.max(1, count));
54
54
  const hinted = !!options.hint && count < 9;
55
55
  const big = hinted ? n + 1 : n;
56
- const s = width / (2 * big * C30);
56
+ const s = width / (2 * big * C30$1);
57
57
  const hint = hinted ? squares(big, s, [0, 0]).map((q) => poly(q.pts, .86)) : [];
58
- const shift = hinted ? [(big - n) * s * C30, (big - n) * s * 2] : [0, 0];
58
+ const shift = hinted ? [(big - n) * s * C30$1, (big - n) * s * 2] : [0, 0];
59
59
  const k = colours.length ? (options.rot ?? 0) % colours.length : 0;
60
60
  const turned = colours.slice(k).concat(colours.slice(0, k));
61
61
  const stickers = squares(n, s, shift).map((q, i) => ({
@@ -73,6 +73,350 @@ function drawCube(count, colours, width, options = {}) {
73
73
  stickers
74
74
  };
75
75
  }
76
+ const CUBE_ARTS = [
77
+ "stickers",
78
+ "blocks",
79
+ "glass",
80
+ "ribbons",
81
+ "dots"
82
+ ];
83
+ const isArt = (v) => CUBE_ARTS.includes(v);
84
+ const C30 = Math.cos(Math.PI / 6);
85
+ const MOST = 4;
86
+ function edgeFor(count) {
87
+ let n = 1;
88
+ while (n * n * n < count && n < MOST) n++;
89
+ return n;
90
+ }
91
+ function coloursFor(count, colours, options = {}) {
92
+ const n = Math.max(1, count);
93
+ if (options.whole) return Array(n).fill(colours[0] ?? null);
94
+ const k = colours.length ? (options.rot ?? 0) % colours.length : 0;
95
+ const turned = colours.slice(k).concat(colours.slice(0, k));
96
+ return Array.from({ length: n }, (_, i) => turned[i] ?? null);
97
+ }
98
+ function shade(colour, face) {
99
+ if (face === "top") return `color-mix(in srgb, ${colour} 74%, white)`;
100
+ if (face === "right") return `color-mix(in srgb, ${colour} 70%, black)`;
101
+ return colour;
102
+ }
103
+ const fmt = (pts) => pts.map(([x, y]) => `${x.toFixed(1)},${y.toFixed(1)}`).join(" ");
104
+ function projector(n, s, pad = [0, 0]) {
105
+ const ox = pad[0] + n * s * C30;
106
+ const oy = pad[1];
107
+ return (x, y, z) => [ox + (x - y) * C30 * s, oy + n * s + (x + y) * .5 * s - z * s];
108
+ }
109
+ function box(p, a, b) {
110
+ const [x0, y0, z0] = a;
111
+ const [x1, y1, z1] = b;
112
+ return {
113
+ top: [
114
+ p(x0, y0, z1),
115
+ p(x1, y0, z1),
116
+ p(x1, y1, z1),
117
+ p(x0, y1, z1)
118
+ ],
119
+ left: [
120
+ p(x0, y1, z1),
121
+ p(x1, y1, z1),
122
+ p(x1, y1, z0),
123
+ p(x0, y1, z0)
124
+ ],
125
+ right: [
126
+ p(x1, y0, z1),
127
+ p(x1, y1, z1),
128
+ p(x1, y1, z0),
129
+ p(x1, y0, z0)
130
+ ]
131
+ };
132
+ }
133
+ function backOf(p, n) {
134
+ return [
135
+ [
136
+ p(0, 0, 0),
137
+ p(n, 0, 0),
138
+ p(n, n, 0),
139
+ p(0, n, 0)
140
+ ],
141
+ [
142
+ p(0, 0, n),
143
+ p(n, 0, n),
144
+ p(n, 0, 0),
145
+ p(0, 0, 0)
146
+ ],
147
+ [
148
+ p(0, 0, n),
149
+ p(0, n, n),
150
+ p(0, n, 0),
151
+ p(0, 0, 0)
152
+ ]
153
+ ];
154
+ }
155
+ function stackOrder(n) {
156
+ const cells = [];
157
+ for (let z = 0; z < n; z++) for (let d = 0; d <= 2 * (n - 1); d++) for (let x = 0; x < n; x++) {
158
+ const y = d - x;
159
+ if (y >= 0 && y < n) cells.push([
160
+ x,
161
+ y,
162
+ z
163
+ ]);
164
+ }
165
+ return cells;
166
+ }
167
+ const nearLast = (a, b) => a[0] + a[1] + a[2] - (b[0] + b[1] + b[2]);
168
+ function frame(width, n, hint) {
169
+ const big = hint ? n + 1 : n;
170
+ const s = width / (2 * big * C30);
171
+ return {
172
+ s,
173
+ height: 2 * big * s,
174
+ pad: hint ? [(big - n) * s * C30, (big - n) * s * 2] : [0, 0],
175
+ big
176
+ };
177
+ }
178
+ function hintShapes(n, s) {
179
+ const b = box(projector(n + 1, s), [
180
+ 0,
181
+ 0,
182
+ 0
183
+ ], [
184
+ n + 1,
185
+ n + 1,
186
+ n + 1
187
+ ]);
188
+ return [
189
+ "top",
190
+ "left",
191
+ "right"
192
+ ].map((f) => ({
193
+ points: fmt(b[f]),
194
+ cls: "hint",
195
+ fill: null
196
+ }));
197
+ }
198
+ function drawing(width, height, shapes) {
199
+ return {
200
+ width,
201
+ height: Math.round(height),
202
+ viewBox: `-2 -2 ${(width + 4).toFixed(1)} ${(height + 4).toFixed(1)}`,
203
+ shapes
204
+ };
205
+ }
206
+ function blocks(count, colours, width, hint) {
207
+ const n = edgeFor(count);
208
+ const { s, height, pad } = frame(width, n, hint);
209
+ const p = projector(n, s, pad);
210
+ const shapes = hint ? hintShapes(n, s) : [];
211
+ const cells = stackOrder(n).slice(0, Math.max(1, Math.min(count, n ** 3)));
212
+ if (cells.length < n ** 3) {
213
+ const b = box(p, [
214
+ 0,
215
+ 0,
216
+ 0
217
+ ], [
218
+ n,
219
+ n,
220
+ n
221
+ ]);
222
+ for (const f of [
223
+ "top",
224
+ "left",
225
+ "right"
226
+ ]) shapes.push({
227
+ points: fmt(b[f]),
228
+ cls: "room",
229
+ fill: null
230
+ });
231
+ }
232
+ const gap = .07;
233
+ cells.map((c, i) => ({
234
+ c,
235
+ colour: colours[i] ?? null
236
+ })).sort((a, b) => nearLast(a.c, b.c)).forEach(({ c, colour }) => {
237
+ const b = box(p, c.map((v) => v + gap), c.map((v) => v + 1 - gap));
238
+ for (const f of [
239
+ "top",
240
+ "left",
241
+ "right"
242
+ ]) shapes.push({
243
+ points: fmt(b[f]),
244
+ cls: colour ? `block ${f}` : `block unknown ${f}`,
245
+ fill: colour ? shade(colour, f) : null
246
+ });
247
+ });
248
+ return drawing(width, height, shapes);
249
+ }
250
+ function glass(count, colours, width, hint) {
251
+ const n = edgeFor(count);
252
+ const { s, height, pad } = frame(width, n, hint);
253
+ const p = projector(n, s, pad);
254
+ const shapes = hint ? hintShapes(n, s) : [];
255
+ for (const back of backOf(p, n)) shapes.push({
256
+ points: fmt(back),
257
+ cls: "glass-back",
258
+ fill: null
259
+ });
260
+ const inset = .24;
261
+ stackOrder(n).slice(0, Math.max(1, Math.min(count, n ** 3))).map((c, i) => ({
262
+ c,
263
+ colour: colours[i] ?? null
264
+ })).sort((a, b) => nearLast(a.c, b.c)).forEach(({ c, colour }) => {
265
+ const b = box(p, c.map((v) => v + inset), c.map((v) => v + 1 - inset));
266
+ for (const f of [
267
+ "top",
268
+ "left",
269
+ "right"
270
+ ]) shapes.push({
271
+ points: fmt(b[f]),
272
+ cls: colour ? `block ${f}` : `block unknown ${f}`,
273
+ fill: colour ? shade(colour, f) : null
274
+ });
275
+ });
276
+ const front = box(p, [
277
+ 0,
278
+ 0,
279
+ 0
280
+ ], [
281
+ n,
282
+ n,
283
+ n
284
+ ]);
285
+ for (const f of [
286
+ "top",
287
+ "left",
288
+ "right"
289
+ ]) shapes.push({
290
+ points: fmt(front[f]),
291
+ cls: `glass ${f}`,
292
+ fill: null
293
+ });
294
+ return drawing(width, height, shapes);
295
+ }
296
+ function bandsOf(colours) {
297
+ const counts = /* @__PURE__ */ new Map();
298
+ for (const c of colours) counts.set(c, (counts.get(c) ?? 0) + 1);
299
+ const known = [...counts.entries()].filter(([c]) => c !== null);
300
+ const unknown = counts.get(null);
301
+ return [...known, ...unknown ? [[null, unknown]] : []].map(([colour, k]) => ({
302
+ colour,
303
+ share: k / colours.length
304
+ }));
305
+ }
306
+ function ribbons(colours, width, hint) {
307
+ const n = 1;
308
+ const { s, height, pad } = frame(width, n, hint);
309
+ const p = projector(n, s, pad);
310
+ const shapes = hint ? hintShapes(n, s) : [];
311
+ let x = 0;
312
+ const bands = bandsOf(colours);
313
+ bands.forEach(({ colour, share }, i) => {
314
+ const x1 = i === bands.length - 1 ? 1 : x + share;
315
+ const b = box(p, [
316
+ x,
317
+ 0,
318
+ 0
319
+ ], [
320
+ x1,
321
+ 1,
322
+ 1
323
+ ]);
324
+ for (const f of ["top", "left"]) shapes.push({
325
+ points: fmt(b[f]),
326
+ cls: colour ? `band ${f}` : `band unknown ${f}`,
327
+ fill: colour ? shade(colour, f) : null
328
+ });
329
+ x = x1;
330
+ });
331
+ const last = bands[bands.length - 1]?.colour ?? null;
332
+ const end = box(p, [
333
+ 0,
334
+ 0,
335
+ 0
336
+ ], [
337
+ 1,
338
+ 1,
339
+ 1
340
+ ]).right;
341
+ shapes.push({
342
+ points: fmt(end),
343
+ cls: last ? "band right" : "band unknown right",
344
+ fill: last ? shade(last, "right") : null
345
+ });
346
+ return drawing(width, height, shapes);
347
+ }
348
+ function dot(p, f, u, v, r, n) {
349
+ const pts = [];
350
+ for (let i = 0; i < 20; i++) {
351
+ const a = i / 20 * 2 * Math.PI;
352
+ const du = u + r * Math.cos(a);
353
+ const dv = v + r * Math.sin(a);
354
+ if (f === "top") pts.push(p(du, dv, n));
355
+ else if (f === "left") pts.push(p(du, n, n - dv));
356
+ else pts.push(p(n, du, n - dv));
357
+ }
358
+ return pts;
359
+ }
360
+ function dots(count, colours, width, hint) {
361
+ let m = 1;
362
+ while (3 * m * m < count && m < MOST) m++;
363
+ const n = 1;
364
+ const { s, height, pad } = frame(width, n, hint);
365
+ const p = projector(n, s, pad);
366
+ const shapes = hint ? hintShapes(n, s) : [];
367
+ const body = box(p, [
368
+ 0,
369
+ 0,
370
+ 0
371
+ ], [
372
+ 1,
373
+ 1,
374
+ 1
375
+ ]);
376
+ for (const f of [
377
+ "top",
378
+ "left",
379
+ "right"
380
+ ]) shapes.push({
381
+ points: fmt(body[f]),
382
+ cls: `side ${f}`,
383
+ fill: null
384
+ });
385
+ const cell = 1 / m;
386
+ let i = 0;
387
+ for (const f of [
388
+ "top",
389
+ "left",
390
+ "right"
391
+ ]) for (let a = 0; a < m; a++) for (let b = 0; b < m; b++) {
392
+ const pts = dot(p, f, (b + .5) * cell, (a + .5) * cell, cell * .34, n);
393
+ if (i < count) {
394
+ const colour = colours[i] ?? null;
395
+ shapes.push({
396
+ points: fmt(pts),
397
+ cls: colour ? `dot ${f}` : `dot unknown ${f}`,
398
+ fill: colour ? shade(colour, f) : null
399
+ });
400
+ } else shapes.push({
401
+ points: fmt(pts),
402
+ cls: "place",
403
+ fill: null
404
+ });
405
+ i++;
406
+ }
407
+ return drawing(width, height, shapes);
408
+ }
409
+ function drawArt(art, count, colours, width, options = {}) {
410
+ const n = Math.max(1, count);
411
+ const cs = coloursFor(n, colours, options);
412
+ const hint = !!options.hint && n < 9;
413
+ switch (art) {
414
+ case "blocks": return blocks(n, cs, width, hint);
415
+ case "glass": return glass(n, cs, width, hint);
416
+ case "ribbons": return ribbons(cs, width, hint);
417
+ case "dots": return dots(n, cs, width, hint);
418
+ }
419
+ }
76
420
  var CubePicture = class CubePicture {
77
421
  count = input(1, ...ngDevMode ? [{ debugName: "count" }] : /* istanbul ignore next */ []);
78
422
  colours = input([], ...ngDevMode ? [{ debugName: "colours" }] : /* istanbul ignore next */ []);
@@ -80,11 +424,20 @@ var CubePicture = class CubePicture {
80
424
  hint = input(false, ...ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []);
81
425
  whole = input(false, ...ngDevMode ? [{ debugName: "whole" }] : /* istanbul ignore next */ []);
82
426
  rot = input(0, ...ngDevMode ? [{ debugName: "rot" }] : /* istanbul ignore next */ []);
427
+ art = input("stickers", ...ngDevMode ? [{ debugName: "art" }] : /* istanbul ignore next */ []);
83
428
  drawing = computed(() => drawCube(this.count(), this.colours(), this.width(), {
84
429
  hint: this.hint(),
85
430
  whole: this.whole(),
86
431
  rot: this.rot()
87
432
  }), ...ngDevMode ? [{ debugName: "drawing" }] : /* istanbul ignore next */ []);
433
+ artDrawing = computed(() => {
434
+ const art = this.art();
435
+ return drawArt(art === "stickers" ? "blocks" : art, this.count(), this.colours(), this.width(), {
436
+ hint: this.hint(),
437
+ whole: this.whole(),
438
+ rot: this.rot()
439
+ });
440
+ }, ...ngDevMode ? [{ debugName: "artDrawing" }] : /* istanbul ignore next */ []);
88
441
  static ɵfac = i0.ɵɵngDeclareFactory({
89
442
  minVersion: "12.0.0",
90
443
  version: "22.2.4",
@@ -141,34 +494,57 @@ var CubePicture = class CubePicture {
141
494
  isSignal: true,
142
495
  isRequired: false,
143
496
  transformFunction: null
497
+ },
498
+ art: {
499
+ classPropertyName: "art",
500
+ publicName: "art",
501
+ isSignal: true,
502
+ isRequired: false,
503
+ transformFunction: null
144
504
  }
145
505
  },
146
506
  ngImport: i0,
147
507
  template: `
148
- @let d = drawing();
149
- <svg
150
- [attr.viewBox]="d.viewBox"
151
- [attr.width]="d.width"
152
- [attr.height]="d.height"
153
- aria-hidden="true"
154
- >
155
- @for (q of d.hint; track $index) {
156
- <polygon class="hint" [attr.points]="q" />
157
- }
158
- @for (q of d.stickers; track $index) {
159
- <polygon [attr.points]="q.outer" [attr.class]="'side ' + q.face" />
160
- }
161
- @for (q of d.stickers; track $index) {
162
- <polygon
163
- [attr.points]="q.inner"
164
- [attr.class]="q.colour ? 'sticker' : 'sticker unknown'"
165
- [attr.fill]="q.colour"
166
- />
167
- }
168
- </svg>
508
+ @if (art() === 'stickers') {
509
+ @let d = drawing();
510
+ <svg
511
+ [attr.viewBox]="d.viewBox"
512
+ [attr.width]="d.width"
513
+ [attr.height]="d.height"
514
+ aria-hidden="true"
515
+ >
516
+ @for (q of d.hint; track $index) {
517
+ <polygon class="hint" [attr.points]="q" />
518
+ }
519
+ @for (q of d.stickers; track $index) {
520
+ <polygon [attr.points]="q.outer" [attr.class]="'side ' + q.face" />
521
+ }
522
+ @for (q of d.stickers; track $index) {
523
+ <polygon
524
+ [attr.points]="q.inner"
525
+ [attr.class]="q.colour ? 'sticker' : 'sticker unknown'"
526
+ [attr.fill]="q.colour"
527
+ />
528
+ }
529
+ </svg>
530
+ } @else {
531
+ @let a = artDrawing();
532
+ <svg
533
+ class="art"
534
+ [attr.viewBox]="a.viewBox"
535
+ [attr.width]="a.width"
536
+ [attr.height]="a.height"
537
+ [attr.data-art]="art()"
538
+ aria-hidden="true"
539
+ >
540
+ @for (q of a.shapes; track $index) {
541
+ <polygon [attr.points]="q.points" [attr.class]="q.cls" [style.fill]="q.fill" />
542
+ }
543
+ </svg>
544
+ }
169
545
  `,
170
546
  isInline: true,
171
- styles: [":host{display:inline-block;line-height:0}svg{overflow:visible}.hint{fill:none;stroke:var(--cube-hint, #87938c);stroke-width:1;stroke-dasharray:3 3;opacity:var(--cube-hint-opacity, .5)}.side{stroke:var(--cube-edge, #cdd8d0);stroke-width:var(--cube-edge-width, .6)}.top{fill:var(--cube-top, #f9fbf8)}.left{fill:var(--cube-left, #e9eee9)}.right{fill:var(--cube-right, #dfe6e0)}.sticker{stroke:var(--cube-sticker-edge, rgba(31, 45, 39, .28));stroke-width:1}.unknown{fill:var(--cube-unknown, #e3e7e1);stroke:var(--cube-unknown-edge, none)}\n"],
547
+ styles: [":host{display:inline-block;line-height:0}svg{overflow:visible}.hint{fill:none;stroke:var(--cube-hint, #87938c);stroke-width:1;stroke-dasharray:3 3;opacity:var(--cube-hint-opacity, .5)}.side{stroke:var(--cube-edge, #cdd8d0);stroke-width:var(--cube-edge-width, .6)}.top{fill:var(--cube-top, #f9fbf8)}.left{fill:var(--cube-left, #e9eee9)}.right{fill:var(--cube-right, #dfe6e0)}.sticker{stroke:var(--cube-sticker-edge, rgba(31, 45, 39, .28));stroke-width:1}.unknown{fill:var(--cube-unknown, #e3e7e1);stroke:var(--cube-unknown-edge, none)}.art polygon{stroke-linejoin:round}.art .room{fill:none;stroke:var(--cube-hint, #87938c);stroke-width:1;stroke-dasharray:3 3;opacity:var(--cube-hint-opacity, .5)}.art .block,.art .band,.art .dot{stroke:var(--cube-art-edge, rgba(31, 45, 39, .35));stroke-width:.8}.art .dot{stroke-width:.6}.art .unknown{fill:var(--cube-unknown, #e3e7e1);stroke:var(--cube-art-unknown-edge, #87938c);stroke-dasharray:2 2}.art .place{fill:none;stroke:var(--cube-art-unknown-edge, #87938c);stroke-width:.8;stroke-dasharray:2 2}.art .glass-back{fill:var(--cube-glass-back, rgba(42, 48, 45, .04));stroke:var(--cube-glass-edge, rgba(42, 48, 45, .18));stroke-width:.8}.art .glass{fill:var(--cube-glass, rgba(95, 154, 128, .06));stroke:var(--cube-glass-edge-front, rgba(42, 48, 45, .5));stroke-width:1.2}.art .glass.top{fill:var(--cube-glass-top, rgba(255, 255, 255, .35))}\n"],
172
548
  changeDetection: i0.ChangeDetectionStrategy.OnPush
173
549
  });
174
550
  };
@@ -182,30 +558,46 @@ i0.ɵɵngDeclareClassMetadata({
182
558
  args: [{
183
559
  selector: "cube-picture",
184
560
  template: `
185
- @let d = drawing();
186
- <svg
187
- [attr.viewBox]="d.viewBox"
188
- [attr.width]="d.width"
189
- [attr.height]="d.height"
190
- aria-hidden="true"
191
- >
192
- @for (q of d.hint; track $index) {
193
- <polygon class="hint" [attr.points]="q" />
194
- }
195
- @for (q of d.stickers; track $index) {
196
- <polygon [attr.points]="q.outer" [attr.class]="'side ' + q.face" />
197
- }
198
- @for (q of d.stickers; track $index) {
199
- <polygon
200
- [attr.points]="q.inner"
201
- [attr.class]="q.colour ? 'sticker' : 'sticker unknown'"
202
- [attr.fill]="q.colour"
203
- />
204
- }
205
- </svg>
561
+ @if (art() === 'stickers') {
562
+ @let d = drawing();
563
+ <svg
564
+ [attr.viewBox]="d.viewBox"
565
+ [attr.width]="d.width"
566
+ [attr.height]="d.height"
567
+ aria-hidden="true"
568
+ >
569
+ @for (q of d.hint; track $index) {
570
+ <polygon class="hint" [attr.points]="q" />
571
+ }
572
+ @for (q of d.stickers; track $index) {
573
+ <polygon [attr.points]="q.outer" [attr.class]="'side ' + q.face" />
574
+ }
575
+ @for (q of d.stickers; track $index) {
576
+ <polygon
577
+ [attr.points]="q.inner"
578
+ [attr.class]="q.colour ? 'sticker' : 'sticker unknown'"
579
+ [attr.fill]="q.colour"
580
+ />
581
+ }
582
+ </svg>
583
+ } @else {
584
+ @let a = artDrawing();
585
+ <svg
586
+ class="art"
587
+ [attr.viewBox]="a.viewBox"
588
+ [attr.width]="a.width"
589
+ [attr.height]="a.height"
590
+ [attr.data-art]="art()"
591
+ aria-hidden="true"
592
+ >
593
+ @for (q of a.shapes; track $index) {
594
+ <polygon [attr.points]="q.points" [attr.class]="q.cls" [style.fill]="q.fill" />
595
+ }
596
+ </svg>
597
+ }
206
598
  `,
207
599
  changeDetection: ChangeDetectionStrategy.OnPush,
208
- styles: [":host{display:inline-block;line-height:0}svg{overflow:visible}.hint{fill:none;stroke:var(--cube-hint, #87938c);stroke-width:1;stroke-dasharray:3 3;opacity:var(--cube-hint-opacity, .5)}.side{stroke:var(--cube-edge, #cdd8d0);stroke-width:var(--cube-edge-width, .6)}.top{fill:var(--cube-top, #f9fbf8)}.left{fill:var(--cube-left, #e9eee9)}.right{fill:var(--cube-right, #dfe6e0)}.sticker{stroke:var(--cube-sticker-edge, rgba(31, 45, 39, .28));stroke-width:1}.unknown{fill:var(--cube-unknown, #e3e7e1);stroke:var(--cube-unknown-edge, none)}\n"]
600
+ styles: [":host{display:inline-block;line-height:0}svg{overflow:visible}.hint{fill:none;stroke:var(--cube-hint, #87938c);stroke-width:1;stroke-dasharray:3 3;opacity:var(--cube-hint-opacity, .5)}.side{stroke:var(--cube-edge, #cdd8d0);stroke-width:var(--cube-edge-width, .6)}.top{fill:var(--cube-top, #f9fbf8)}.left{fill:var(--cube-left, #e9eee9)}.right{fill:var(--cube-right, #dfe6e0)}.sticker{stroke:var(--cube-sticker-edge, rgba(31, 45, 39, .28));stroke-width:1}.unknown{fill:var(--cube-unknown, #e3e7e1);stroke:var(--cube-unknown-edge, none)}.art polygon{stroke-linejoin:round}.art .room{fill:none;stroke:var(--cube-hint, #87938c);stroke-width:1;stroke-dasharray:3 3;opacity:var(--cube-hint-opacity, .5)}.art .block,.art .band,.art .dot{stroke:var(--cube-art-edge, rgba(31, 45, 39, .35));stroke-width:.8}.art .dot{stroke-width:.6}.art .unknown{fill:var(--cube-unknown, #e3e7e1);stroke:var(--cube-art-unknown-edge, #87938c);stroke-dasharray:2 2}.art .place{fill:none;stroke:var(--cube-art-unknown-edge, #87938c);stroke-width:.8;stroke-dasharray:2 2}.art .glass-back{fill:var(--cube-glass-back, rgba(42, 48, 45, .04));stroke:var(--cube-glass-edge, rgba(42, 48, 45, .18));stroke-width:.8}.art .glass{fill:var(--cube-glass, rgba(95, 154, 128, .06));stroke:var(--cube-glass-edge-front, rgba(42, 48, 45, .5));stroke-width:1.2}.art .glass.top{fill:var(--cube-glass-top, rgba(255, 255, 255, .35))}\n"]
209
601
  }]
210
602
  }],
211
603
  propDecorators: {
@@ -256,9 +648,93 @@ i0.ɵɵngDeclareClassMetadata({
256
648
  alias: "rot",
257
649
  required: false
258
650
  }]
651
+ }],
652
+ art: [{
653
+ type: i0.Input,
654
+ args: [{
655
+ isSignal: true,
656
+ alias: "art",
657
+ required: false
658
+ }]
259
659
  }]
260
660
  }
261
661
  });
662
+ function artFor(choices, app, start = "stickers") {
663
+ return choices.apps?.[app] ?? choices.all ?? start;
664
+ }
665
+ function chooseArt(choices, app, art) {
666
+ if (app === null) return {
667
+ all: art,
668
+ apps: {}
669
+ };
670
+ const apps = { ...choices.apps ?? {} };
671
+ if (art === null) delete apps[app];
672
+ else apps[app] = art;
673
+ return {
674
+ all: choices.all ?? null,
675
+ apps
676
+ };
677
+ }
678
+ function readArtChoices(text) {
679
+ if (!text) return {};
680
+ try {
681
+ const raw = JSON.parse(text);
682
+ const apps = {};
683
+ for (const [k, v] of Object.entries(raw.apps ?? {})) if (isArt(v)) apps[k] = v;
684
+ return {
685
+ all: isArt(raw.all) ? raw.all : null,
686
+ apps
687
+ };
688
+ } catch {
689
+ return {};
690
+ }
691
+ }
692
+ const ART_CHOICES_KEY = "cube-design.art";
693
+ var CubeArtChoices = class CubeArtChoices {
694
+ choices = signal(readArtChoices(read()), ...ngDevMode ? [{ debugName: "choices" }] : /* istanbul ignore next */ []);
695
+ artFor(app, start = "stickers") {
696
+ return artFor(this.choices(), app, start);
697
+ }
698
+ choose(app, art) {
699
+ const next = chooseArt(this.choices(), app, art);
700
+ this.choices.set(next);
701
+ try {
702
+ localStorage.setItem(ART_CHOICES_KEY, JSON.stringify(next));
703
+ } catch {}
704
+ }
705
+ static ɵfac = i0.ɵɵngDeclareFactory({
706
+ minVersion: "12.0.0",
707
+ version: "22.2.4",
708
+ ngImport: i0,
709
+ type: CubeArtChoices,
710
+ deps: [],
711
+ target: i0.ɵɵFactoryTarget.Injectable
712
+ });
713
+ static ɵprov = i0.ɵɵngDeclareInjectable({
714
+ minVersion: "12.0.0",
715
+ version: "22.2.4",
716
+ ngImport: i0,
717
+ type: CubeArtChoices,
718
+ providedIn: "root"
719
+ });
720
+ };
721
+ i0.ɵɵngDeclareClassMetadata({
722
+ minVersion: "12.0.0",
723
+ version: "22.2.4",
724
+ ngImport: i0,
725
+ type: CubeArtChoices,
726
+ decorators: [{
727
+ type: Injectable,
728
+ args: [{ providedIn: "root" }]
729
+ }]
730
+ });
731
+ function read() {
732
+ try {
733
+ return typeof localStorage === "undefined" ? null : localStorage.getItem(ART_CHOICES_KEY);
734
+ } catch {
735
+ return null;
736
+ }
737
+ }
262
738
  const CUBE_HOLD_MS = 520;
263
739
  const CUBE_HOLD_SLOP = 10;
264
740
  var CubeHold = class CubeHold {
@@ -462,13 +938,24 @@ const CUBE_WHEEL_QUIET_MS = 250;
462
938
  function startsWheelGesture(lastAt, now, quietMs = 250) {
463
939
  return now - lastAt >= quietMs;
464
940
  }
941
+ const CUBE_WHEEL_STEP = 2;
942
+ function wheelWay(deltaY, sum, least = 2) {
943
+ const by = Math.abs(deltaY) >= least ? deltaY : Math.abs(sum) >= 3 * least ? sum : 0;
944
+ return by < 0 ? "in" : by > 0 ? "out" : null;
945
+ }
465
946
  const stream = {
466
947
  wheelAt: -Infinity,
467
948
  gestureAt: -Infinity,
468
949
  heard: null,
469
950
  heardAfter: -Infinity,
470
- ownedUntil: -Infinity
951
+ ownedUntil: -Infinity,
952
+ sum: 0,
953
+ decided: false
471
954
  };
955
+ function begin() {
956
+ stream.sum = 0;
957
+ stream.decided = false;
958
+ }
472
959
  let listening = false;
473
960
  function listenToThePage(quietMs) {
474
961
  const w = globalThis.window;
@@ -480,6 +967,7 @@ function listenToThePage(quietMs) {
480
967
  stream.heard = e;
481
968
  stream.heardAfter = stream.wheelAt;
482
969
  stream.wheelAt = now;
970
+ if (now - stream.heardAfter >= quietMs) begin();
483
971
  if (now - stream.heardAfter < quietMs && now < stream.ownedUntil + quietMs) {
484
972
  stream.ownedUntil = now;
485
973
  e.preventDefault();
@@ -543,12 +1031,15 @@ var CubePinch = class CubePinch {
543
1031
  if (this.cubePinchDisabled() || !e.ctrlKey) return;
544
1032
  e.preventDefault();
545
1033
  const now = performance.now();
546
- const starts = startsWheelGesture(stream.heard === e ? stream.heardAfter : stream.wheelAt, now, this.cubePinchQuietMs());
1034
+ if (startsWheelGesture(stream.heard === e ? stream.heardAfter : stream.wheelAt, now, this.cubePinchQuietMs())) begin();
547
1035
  stream.wheelAt = now;
548
1036
  stream.ownedUntil = now;
549
- if (!starts || e.deltaY === 0) return;
550
- if (e.deltaY < 0) this.emit("in", pointAt(e.clientX, e.clientY), "wheel", e);
551
- else this.emit("out", pointAt(e.clientX, e.clientY), "wheel", e);
1037
+ if (stream.decided) return;
1038
+ stream.sum += e.deltaY;
1039
+ const way = wheelWay(e.deltaY, stream.sum);
1040
+ if (!way) return;
1041
+ stream.decided = true;
1042
+ this.emit(way, pointAt(e.clientX, e.clientY), "wheel", e);
552
1043
  }
553
1044
  gestureStart(e) {
554
1045
  if (this.cubePinchDisabled()) return;
@@ -1715,6 +2206,21 @@ function tellLevel(words) {
1715
2206
  tile("not-known", null, w?.notKnown, "not-known")
1716
2207
  ];
1717
2208
  }
2209
+ function artLevel(now, look, words, arts = CUBE_ARTS) {
2210
+ return arts.map((a) => ({
2211
+ key: "art:" + a,
2212
+ title: words.arts?.[a]?.title ?? a,
2213
+ line: a === now ? null : words.arts?.[a]?.line ?? null,
2214
+ icon: "art",
2215
+ inUse: a === now,
2216
+ data: a,
2217
+ art: {
2218
+ art: a,
2219
+ count: Math.max(1, look.count),
2220
+ colours: look.colours
2221
+ }
2222
+ }));
2223
+ }
1718
2224
  function insideOf(source, piece) {
1719
2225
  const seen = /* @__PURE__ */ new Set();
1720
2226
  const walk = [...source.partsOf(piece)];
@@ -2796,6 +3302,9 @@ function contextIcon(tile) {
2796
3302
  if (tile.icon === "hide") return "shown";
2797
3303
  return "face";
2798
3304
  }
3305
+ function contextArtWidth(level) {
3306
+ return level <= 0 ? 72 : level <= 2 ? 30 : 22;
3307
+ }
2799
3308
  var ContextAttrs = class ContextAttrs {
2800
3309
  ccAttrs = input(...ngDevMode ? [void 0, { debugName: "ccAttrs" }] : /* istanbul ignore next */ []);
2801
3310
  el = inject(ElementRef);
@@ -2884,6 +3393,7 @@ var CubeContext = class CubeContext {
2884
3393
  keyOf = (t) => t.key;
2885
3394
  inUseWord = computed(() => (this.words() ?? this.givenWords)?.inUse ?? null, ...ngDevMode ? [{ debugName: "inUseWord" }] : /* istanbul ignore next */ []);
2886
3395
  iconOf = contextIcon;
3396
+ artWidth = contextArtWidth;
2887
3397
  constructor() {
2888
3398
  effect(() => {
2889
3399
  if (this.level() === null) untracked(() => this.out.emit());
@@ -3019,7 +3529,17 @@ var CubeContext = class CubeContext {
3019
3529
  [attr.title]="level >= 3 ? t.title : null"
3020
3530
  (click)="tap(t, $any($event.currentTarget))"
3021
3531
  >
3022
- <span class="cc-icon"><cube-icon [icon]="iconOf(t)" [inUse]="!!t.inUse" /></span>
3532
+ @if (t.art; as a) {
3533
+ <span class="cc-icon cc-art"
3534
+ ><cube-picture
3535
+ [art]="a.art"
3536
+ [count]="a.count"
3537
+ [colours]="$any(a.colours)"
3538
+ [width]="artWidth(level)"
3539
+ /></span>
3540
+ } @else {
3541
+ <span class="cc-icon"><cube-icon [icon]="iconOf(t)" [inUse]="!!t.inUse" /></span>
3542
+ }
3023
3543
  @if (level < 4) {
3024
3544
  <span class="cc-t">{{ t.title }}</span>
3025
3545
  }
@@ -3063,6 +3583,20 @@ var CubeContext = class CubeContext {
3063
3583
  selector: "cube-icon",
3064
3584
  inputs: ["icon", "inUse"]
3065
3585
  },
3586
+ {
3587
+ kind: "component",
3588
+ type: CubePicture,
3589
+ selector: "cube-picture",
3590
+ inputs: [
3591
+ "count",
3592
+ "colours",
3593
+ "width",
3594
+ "hint",
3595
+ "whole",
3596
+ "rot",
3597
+ "art"
3598
+ ]
3599
+ },
3066
3600
  {
3067
3601
  kind: "component",
3068
3602
  type: CubeSquare,
@@ -3110,6 +3644,7 @@ i0.ɵɵngDeclareClassMetadata({
3110
3644
  selector: "cube-context",
3111
3645
  imports: [
3112
3646
  CubeIcon,
3647
+ CubePicture,
3113
3648
  CubeSquare,
3114
3649
  CubeSquareTile,
3115
3650
  ContextAttrs
@@ -3137,7 +3672,17 @@ i0.ɵɵngDeclareClassMetadata({
3137
3672
  [attr.title]="level >= 3 ? t.title : null"
3138
3673
  (click)="tap(t, $any($event.currentTarget))"
3139
3674
  >
3140
- <span class="cc-icon"><cube-icon [icon]="iconOf(t)" [inUse]="!!t.inUse" /></span>
3675
+ @if (t.art; as a) {
3676
+ <span class="cc-icon cc-art"
3677
+ ><cube-picture
3678
+ [art]="a.art"
3679
+ [count]="a.count"
3680
+ [colours]="$any(a.colours)"
3681
+ [width]="artWidth(level)"
3682
+ /></span>
3683
+ } @else {
3684
+ <span class="cc-icon"><cube-icon [icon]="iconOf(t)" [inUse]="!!t.inUse" /></span>
3685
+ }
3141
3686
  @if (level < 4) {
3142
3687
  <span class="cc-t">{{ t.title }}</span>
3143
3688
  }
@@ -3405,7 +3950,8 @@ var CubeLoading = class CubeLoading {
3405
3950
  "width",
3406
3951
  "hint",
3407
3952
  "whole",
3408
- "rot"
3953
+ "rot",
3954
+ "art"
3409
3955
  ]
3410
3956
  },
3411
3957
  {
@@ -3786,6 +4332,6 @@ i0.ɵɵngDeclareClassMetadata({
3786
4332
  args: [{ providedIn: "root" }]
3787
4333
  }]
3788
4334
  });
3789
- export { CONTEXT_CUBE_SOURCE, CONTEXT_CUBE_WORDS, CONTEXT_LAST_PARTS, CONTEXT_PART_ORDER, CUBE_CARRY_CLASSES, CUBE_CARRY_MOVE, CUBE_DROP_OUT, CUBE_HOLD_MS, CUBE_HOLD_SLOP, CUBE_ICON_NAMES, CUBE_LOADING_COLOURS, CUBE_LOADING_LEVELS, CUBE_LOADING_STEP_MS, CUBE_LOADING_STICKERS, CUBE_LOADING_WAYS, CUBE_LOADING_WIDTH, CUBE_PINCH_APART, CUBE_PINCH_TOGETHER, CUBE_WHEEL_QUIET_MS, CubeCarry, CubeContext, CubeHold, CubeIcon, CubeLoading, CubePicture, CubePinch, CubeSquare, CubeSquareTile, JUST_SAVED_MINUTES, MINE_SORT, PART_ICONS, REPORT_APP, REPORT_INCIDENTS_KEPT, REPORT_INCIDENTS_MS, REPORT_KINDS, ReportClient, ReportDiagnostics, ReportDraft, ReportErrorHandler, SQUARE_LEAST_CELL, SQUARE_LEAST_TALL, SQUARE_LIST_ROW, SQUARE_MAX_SIDE, SQUARE_ROOM_BELOW, TEXT_ORDERS, TURNING_BELOW, TURNING_NUDGE_UNTIL, TURNING_SIDES, VIEW_KEYS, addLevel, bringLevel, bringOf, contextIcon, contextLevelFor, contextOf, contextSquare, cubeIconCells, directionWords, drawCube, environmentOf, errorLine, findJustSaved, gridFor, hideLevel, insideOf, isView, loadingStickers, loadingWayFor, moveBefore, namesLevel, orderLevel, orderOf, orderParts, partsLevel, placesOf, provideReportDiagnostics, refusalOf, reportContext, reportInterceptor, reportRefusal, reportRequest, routePattern, scrubbedPath, sizeFor, sortDirectionsLevel, sortItems, sortLevel, squareGap, squareLayout, squareLeast, squareLevelFor, squareTall, startsWheelGesture, stillStep, technicalLines, tellLevel, turningFront, turningRows, viewLevel, whereLevel, wouldLoop };
4335
+ export { ART_CHOICES_KEY, CONTEXT_CUBE_SOURCE, CONTEXT_CUBE_WORDS, CONTEXT_LAST_PARTS, CONTEXT_PART_ORDER, CUBE_ARTS, CUBE_CARRY_CLASSES, CUBE_CARRY_MOVE, CUBE_DROP_OUT, CUBE_HOLD_MS, CUBE_HOLD_SLOP, CUBE_ICON_NAMES, CUBE_LOADING_COLOURS, CUBE_LOADING_LEVELS, CUBE_LOADING_STEP_MS, CUBE_LOADING_STICKERS, CUBE_LOADING_WAYS, CUBE_LOADING_WIDTH, CUBE_PINCH_APART, CUBE_PINCH_TOGETHER, CUBE_WHEEL_QUIET_MS, CUBE_WHEEL_STEP, CubeArtChoices, CubeCarry, CubeContext, CubeHold, CubeIcon, CubeLoading, CubePicture, CubePinch, CubeSquare, CubeSquareTile, JUST_SAVED_MINUTES, MINE_SORT, PART_ICONS, REPORT_APP, REPORT_INCIDENTS_KEPT, REPORT_INCIDENTS_MS, REPORT_KINDS, ReportClient, ReportDiagnostics, ReportDraft, ReportErrorHandler, SQUARE_LEAST_CELL, SQUARE_LEAST_TALL, SQUARE_LIST_ROW, SQUARE_MAX_SIDE, SQUARE_ROOM_BELOW, TEXT_ORDERS, TURNING_BELOW, TURNING_NUDGE_UNTIL, TURNING_SIDES, VIEW_KEYS, addLevel, artFor, artLevel, bringLevel, bringOf, chooseArt, contextArtWidth, contextIcon, contextLevelFor, contextOf, contextSquare, cubeIconCells, directionWords, drawArt, drawCube, environmentOf, errorLine, findJustSaved, gridFor, hideLevel, insideOf, isArt, isView, loadingStickers, loadingWayFor, moveBefore, namesLevel, orderLevel, orderOf, orderParts, partsLevel, placesOf, provideReportDiagnostics, readArtChoices, refusalOf, reportContext, reportInterceptor, reportRefusal, reportRequest, routePattern, scrubbedPath, sizeFor, sortDirectionsLevel, sortItems, sortLevel, squareGap, squareLayout, squareLeast, squareLevelFor, squareTall, startsWheelGesture, stillStep, technicalLines, tellLevel, turningFront, turningRows, viewLevel, wheelWay, whereLevel, wouldLoop };
3790
4336
 
3791
4337
  //# sourceMappingURL=selimssevgi-cube-design-angular.mjs.map