proto-sudoku-wc 0.0.690 → 0.0.692
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/dist/cjs/{index-4683daff.js → index-af8bf740.js} +15 -4
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/proto-sudoku-wc.cjs.js +2 -2
- package/dist/cjs/proto-sudoku.cjs.entry.js +352 -352
- package/dist/collection/collection-manifest.json +1 -1
- package/dist/collection/components/proto-sudoku/alert.js +2 -2
- package/dist/collection/components/proto-sudoku/alerts.js +3 -3
- package/dist/collection/components/proto-sudoku/alien.js +5 -5
- package/dist/collection/components/proto-sudoku/button.js +10 -10
- package/dist/collection/components/proto-sudoku/cell.js +20 -20
- package/dist/collection/components/proto-sudoku/eswat2-io.js +1 -1
- package/dist/collection/components/proto-sudoku/fingerprint.js +5 -5
- package/dist/collection/components/proto-sudoku/header.js +1 -1
- package/dist/collection/components/proto-sudoku/keys.js +10 -10
- package/dist/collection/components/proto-sudoku/proto-sudoku.js +62 -62
- package/dist/collection/components/proto-sudoku/spinner.js +5 -5
- package/dist/collection/components/proto-sudoku/sudoku-board.js +6 -6
- package/dist/collection/components/proto-sudoku/tool-bar.js +8 -8
- package/dist/collection/components/proto-sudoku/tw-label.js +1 -1
- package/dist/collection/utils/bag.js +23 -23
- package/dist/collection/utils/store.js +209 -209
- package/dist/collection/utils/tw.js +1 -1
- package/dist/esm/{index-3ccc3f4a.js → index-e105e4de.js} +15 -4
- package/dist/esm/loader.js +2 -2
- package/dist/esm/proto-sudoku-wc.js +3 -3
- package/dist/esm/proto-sudoku.entry.js +352 -352
- package/dist/proto-sudoku-wc/{p-4ab7e5a2.js → p-5c418b3c.js} +1 -1
- package/dist/proto-sudoku-wc/{p-4a14cce4.entry.js → p-c8bb72eb.entry.js} +1 -1
- package/dist/proto-sudoku-wc/proto-sudoku-wc.esm.js +1 -1
- package/dist/types/components/proto-sudoku/alert.d.ts +3 -3
- package/dist/types/components/proto-sudoku/button.d.ts +3 -3
- package/dist/types/components/proto-sudoku/cell.d.ts +4 -4
- package/dist/types/components/proto-sudoku/proto-sudoku.d.ts +4 -4
- package/dist/types/stencil-public-runtime.d.ts +8 -0
- package/dist/types/utils/bag.d.ts +10 -10
- package/dist/types/utils/store.d.ts +5 -5
- package/dist/types/utils/types.d.ts +33 -33
- package/package.json +5 -5
@@ -1,15 +1,15 @@
|
|
1
|
-
import { h, g as getRenderingRef, f as forceUpdate, r as registerInstance } from './index-
|
1
|
+
import { h, g as getRenderingRef, f as forceUpdate, r as registerInstance } from './index-e105e4de.js';
|
2
2
|
|
3
3
|
const Alien = props => {
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
4
|
+
const hex = props.hex || 'currentColor';
|
5
|
+
const klass = props.class;
|
6
|
+
const label = props.label || 'alien';
|
7
|
+
const size = props.size || 24;
|
8
|
+
return (h("svg", { class: klass, width: size, height: size, viewBox: "0 0 24 24", role: "img", "aria-label": "title" },
|
9
|
+
h("title", null, label),
|
10
|
+
h("g", { fill: hex },
|
11
|
+
h("path", { d: "M10.31 10.93C11.33 12.57 11.18 14.5 9.96 15.28C8.74 16.04 6.92 15.33\n 5.89 13.69C4.87 12.05 5.03 10.1 6.25 9.34C7.47 8.58 9.29 9.29 10.31\n 10.93M12 17.75C14 17.75 14.5 17 14.5 17C14.5 17 14 19 12 19C10 19 9.5\n 17.03 9.5 17C9.5 17 10 17.75 12 17.75M17.75 9.34C18.97 10.1 19.13 12.05\n 18.11 13.69C17.08 15.33 15.26 16.04 14.04 15.28C12.82 14.5 12.67 12.57\n 13.69 10.93C14.71 9.29 16.53 8.58 17.75 9.34M12 20C14.5 20 20 14.86 20\n 11C20 7.14 16.41 4 12 4C7.59 4 4 7.14 4 11C4 14.86 9.5 20 12 20M12 2C17.5\n 2 22 6.04 22 11C22 15.08 16.32 22 12 22C7.68 22 2 15.08 2 11C2 6.04 6.5 2\n 12 2Z" })),
|
12
|
+
h("path", { d: "M0 0h24v24H0z", fill: "none" })));
|
13
13
|
};
|
14
14
|
|
15
15
|
const KEY = 'proto-sudoku';
|
@@ -17,38 +17,38 @@ const DATA = `${KEY}::data`;
|
|
17
17
|
const INPUTS = `${KEY}::inputs`;
|
18
18
|
const PICK = `${KEY}::pick`;
|
19
19
|
const getForKey = (key) => {
|
20
|
-
|
21
|
-
|
20
|
+
const json = localStorage.getItem(key);
|
21
|
+
return json ? JSON.parse(json) : undefined;
|
22
22
|
};
|
23
23
|
const storeForKey = (key, value) => {
|
24
|
-
|
25
|
-
|
24
|
+
const json = JSON.stringify(value);
|
25
|
+
localStorage.setItem(key, json);
|
26
26
|
};
|
27
27
|
const bag = {
|
28
|
-
get: () => {
|
29
|
-
return getForKey(DATA);
|
30
|
-
},
|
31
|
-
store: value => {
|
32
|
-
storeForKey(DATA, value);
|
33
|
-
},
|
34
|
-
inputs: {
|
35
28
|
get: () => {
|
36
|
-
|
37
|
-
return [...line];
|
29
|
+
return getForKey(DATA);
|
38
30
|
},
|
39
|
-
store:
|
40
|
-
|
31
|
+
store: value => {
|
32
|
+
storeForKey(DATA, value);
|
41
33
|
},
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
34
|
+
inputs: {
|
35
|
+
get: () => {
|
36
|
+
const line = getForKey(INPUTS);
|
37
|
+
return [...line];
|
38
|
+
},
|
39
|
+
store: (value) => {
|
40
|
+
storeForKey(INPUTS, value.join(''));
|
41
|
+
},
|
47
42
|
},
|
48
|
-
|
49
|
-
|
43
|
+
pick: {
|
44
|
+
get: () => {
|
45
|
+
const pick = getForKey(PICK);
|
46
|
+
return pick !== null ? pick : undefined;
|
47
|
+
},
|
48
|
+
store: (value) => {
|
49
|
+
storeForKey(PICK, value >= 0 && value < 81 ? value : null);
|
50
|
+
},
|
50
51
|
},
|
51
|
-
},
|
52
52
|
};
|
53
53
|
|
54
54
|
const CHECK = 'Check ?';
|
@@ -794,452 +794,452 @@ const ky = createInstance();
|
|
794
794
|
|
795
795
|
// --------------------------------------------------------[ mutable store ]
|
796
796
|
const storeDef = {
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
797
|
+
list: [],
|
798
|
+
keys: [],
|
799
|
+
locs: [],
|
800
|
+
loading: false,
|
801
|
+
solved: false,
|
802
|
+
error: undefined,
|
803
|
+
pick: undefined,
|
804
|
+
data: undefined,
|
805
805
|
};
|
806
806
|
const { state } = createStore(storeDef);
|
807
807
|
// --------------------------------------------------------[ geometry ]
|
808
808
|
// NOTE: by using Sets here, we don't have to worry about clearing geometry...
|
809
809
|
const geometry = new Map([
|
810
|
-
|
811
|
-
|
812
|
-
|
810
|
+
['row', new Map()],
|
811
|
+
['column', new Map()],
|
812
|
+
['box', new Map()],
|
813
813
|
]);
|
814
814
|
const keyValues = ['1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
815
815
|
const computeBox = (row, column) => {
|
816
|
-
|
817
|
-
|
818
|
-
}
|
819
|
-
else {
|
820
|
-
if (column < 6) {
|
821
|
-
return row < 3 ? 1 : row < 6 ? 4 : 7;
|
816
|
+
if (column < 3) {
|
817
|
+
return row < 3 ? 0 : row < 6 ? 3 : 6;
|
822
818
|
}
|
823
819
|
else {
|
824
|
-
|
820
|
+
if (column < 6) {
|
821
|
+
return row < 3 ? 1 : row < 6 ? 4 : 7;
|
822
|
+
}
|
823
|
+
else {
|
824
|
+
return row < 3 ? 2 : row < 6 ? 5 : 8;
|
825
|
+
}
|
825
826
|
}
|
826
|
-
}
|
827
827
|
};
|
828
828
|
const computeLocs = (index, row, column, box) => {
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
829
|
+
const data = new Map([
|
830
|
+
['row', row],
|
831
|
+
['column', column],
|
832
|
+
['box', box],
|
833
|
+
]);
|
834
|
+
const locs = new Set();
|
835
|
+
data.forEach((value, key) => {
|
836
|
+
geometry
|
837
|
+
.get(key)
|
838
|
+
.get(value)
|
839
|
+
.forEach(indx => {
|
840
|
+
indx !== index && locs.add(indx);
|
841
|
+
});
|
841
842
|
});
|
842
|
-
|
843
|
-
return Array.from(locs);
|
843
|
+
return Array.from(locs);
|
844
844
|
};
|
845
845
|
const computeKeys = locs => {
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
846
|
+
const { list } = state;
|
847
|
+
const found = new Set();
|
848
|
+
locs.map(indx => {
|
849
|
+
const { key } = list[indx];
|
850
|
+
if (key != '.') {
|
851
|
+
found.add(key);
|
852
|
+
}
|
853
|
+
});
|
854
|
+
const keys = keyValues.filter(key => !found.has(key));
|
855
|
+
return keys;
|
856
856
|
};
|
857
857
|
const updateGeometry = (index, row, column, box) => {
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
858
|
+
const data = new Map([
|
859
|
+
['row', row],
|
860
|
+
['column', column],
|
861
|
+
['box', box],
|
862
|
+
]);
|
863
|
+
data.forEach((value, key) => {
|
864
|
+
const map = geometry.get(key);
|
865
|
+
if (map.has(value)) {
|
866
|
+
// looking at the set specification, it should be sufficient to just call add
|
867
|
+
// https://tc39.es/ecma262/#sec-set.prototype.add
|
868
|
+
map.get(value).add(index);
|
869
|
+
}
|
870
|
+
else {
|
871
|
+
map.set(value, new Set([index]));
|
872
|
+
}
|
873
|
+
});
|
874
874
|
};
|
875
875
|
const updateFromInputs = list => {
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
876
|
+
const inputs = bag.inputs.get();
|
877
|
+
inputs.forEach((key, indx) => {
|
878
|
+
const cell = list[indx];
|
879
|
+
const { isClue } = cell;
|
880
|
+
if (!isClue) {
|
881
|
+
cell.key = key;
|
882
|
+
}
|
883
|
+
});
|
884
884
|
};
|
885
885
|
// --------------------------------------------------------[ process ]
|
886
886
|
const processData = (next) => {
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
887
|
+
if (next) {
|
888
|
+
const { puzzle, ref } = next;
|
889
|
+
const cells = puzzle ? [...puzzle] : [];
|
890
|
+
const line = ref ? atob(ref) : undefined; // decrypt the solution... [ base64 ]
|
891
|
+
const solution = line ? [...line] : [];
|
892
|
+
const list = cells.map((key, indx) => {
|
893
|
+
const value = solution[indx];
|
894
|
+
const isClue = key === value;
|
895
|
+
const row = Math.floor(indx / 9);
|
896
|
+
const column = indx % 9;
|
897
|
+
const box = computeBox(row, column);
|
898
|
+
updateGeometry(indx, row, column, box);
|
899
|
+
return { key, isClue, value, indx, row, column, box };
|
900
|
+
});
|
901
|
+
// NOTE: this only happens once on data change...
|
902
|
+
updateFromInputs(list);
|
903
|
+
state.data = next;
|
904
|
+
state.list = list;
|
905
|
+
}
|
906
|
+
else {
|
907
|
+
state.data = undefined;
|
908
|
+
state.list = [];
|
909
|
+
}
|
910
910
|
};
|
911
911
|
const processPick = (next) => {
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
912
|
+
if (next !== undefined && next.indx != state.pick) {
|
913
|
+
const { isClue, indx, row, column, box } = next;
|
914
|
+
const locs = computeLocs(indx, row, column, box);
|
915
|
+
const keys = isClue ? [] : computeKeys(locs);
|
916
|
+
state.pick = indx;
|
917
|
+
state.keys = keys;
|
918
|
+
state.locs = locs;
|
919
|
+
// NOTE: we could auto-pick if there's only one key...
|
920
|
+
// (keys.length === 1) && next.key = keys[0];
|
921
|
+
}
|
922
|
+
else {
|
923
|
+
state.pick = undefined;
|
924
|
+
state.keys = [];
|
925
|
+
state.locs = [];
|
926
|
+
}
|
927
|
+
savePick(state.pick);
|
928
928
|
};
|
929
929
|
// --------------------------------------------------------[ utils ]
|
930
930
|
let api = undefined;
|
931
931
|
const platformPrefix = {
|
932
|
-
|
933
|
-
|
932
|
+
netlify: '/.netlify/functions',
|
933
|
+
vercel: 'https://sudoku-rust-api.vercel.app/api',
|
934
934
|
};
|
935
935
|
const getPrefixFor = (platform) => {
|
936
|
-
|
937
|
-
|
938
|
-
|
936
|
+
const keys = Object.keys(platformPrefix);
|
937
|
+
const target = keys.includes(platform) ? platform : 'vercel';
|
938
|
+
return platformPrefix[target];
|
939
939
|
};
|
940
940
|
const initApi = (platform) => {
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
941
|
+
const prefix = getPrefixFor(platform);
|
942
|
+
api = ky.extend({
|
943
|
+
hooks: {
|
944
|
+
beforeRequest: [
|
945
|
+
request => {
|
946
|
+
request.headers.set('X-Requested-With', 'ky');
|
947
|
+
request.headers.set('X-Custom-Header', 'foobar');
|
948
|
+
},
|
949
|
+
],
|
948
950
|
},
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
timeout: 10000,
|
953
|
-
});
|
951
|
+
prefixUrl: prefix,
|
952
|
+
timeout: 10000,
|
953
|
+
});
|
954
954
|
};
|
955
955
|
const saveInputs = (inputs) => {
|
956
|
-
|
956
|
+
bag.inputs.store(inputs);
|
957
957
|
};
|
958
958
|
const savePick = (pick) => {
|
959
|
-
|
959
|
+
bag.pick.store(pick);
|
960
960
|
};
|
961
961
|
const clearStore = (loading = false) => {
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
962
|
+
state.list = [];
|
963
|
+
state.keys = [];
|
964
|
+
state.locs = [];
|
965
|
+
state.loading = loading;
|
966
|
+
state.solved = false;
|
967
|
+
state.error = undefined;
|
968
|
+
state.pick = undefined;
|
969
|
+
state.data = undefined;
|
970
970
|
};
|
971
971
|
const updateStore = (data, save = true) => {
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
972
|
+
const { puzzle, ref } = data;
|
973
|
+
if (save) {
|
974
|
+
bag.inputs.store([]);
|
975
|
+
bag.store(data);
|
976
|
+
}
|
977
|
+
processData({ puzzle, ref });
|
978
978
|
};
|
979
979
|
// --------------------------------------------------------[ actions ]
|
980
980
|
const initApp = (platform) => {
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
981
|
+
initApi(platform);
|
982
|
+
clearStore();
|
983
|
+
// this retrieves the last data we stored in the bag...
|
984
|
+
const data = bag.get();
|
985
|
+
const pick = bag.pick.get();
|
986
|
+
if (data) {
|
987
|
+
updateStore(data, false);
|
988
|
+
if (pick >= 0) {
|
989
|
+
const { list } = state;
|
990
|
+
const cell = list[pick];
|
991
|
+
processPick(cell);
|
992
|
+
}
|
992
993
|
}
|
993
|
-
}
|
994
994
|
};
|
995
995
|
const refresh = async () => {
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
996
|
+
clearStore(true);
|
997
|
+
saveInputs([]);
|
998
|
+
savePick(state.pick);
|
999
|
+
try {
|
1000
|
+
// fetch a new puzzle from the api...
|
1001
|
+
const data = await api.get('puzzle').json();
|
1002
|
+
updateStore(data);
|
1003
|
+
}
|
1004
|
+
catch (err) {
|
1005
|
+
// handle error...
|
1006
|
+
const { message } = err;
|
1007
|
+
console.log('-- ', message);
|
1008
|
+
console.log(err);
|
1009
|
+
state.error = message;
|
1010
|
+
}
|
1011
|
+
finally {
|
1012
|
+
// always executed
|
1013
|
+
state.loading = false;
|
1014
|
+
}
|
1015
1015
|
};
|
1016
1016
|
const select = (cell) => {
|
1017
|
-
|
1017
|
+
processPick(cell);
|
1018
1018
|
};
|
1019
1019
|
const redraw = (list) => {
|
1020
|
-
|
1021
|
-
|
1020
|
+
state.list = [...list];
|
1021
|
+
list.length = 0;
|
1022
1022
|
};
|
1023
1023
|
const check = () => {
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1024
|
+
const { list } = state;
|
1025
|
+
const inputs = [];
|
1026
|
+
let errors = 0;
|
1027
|
+
let found = 0;
|
1028
|
+
let clues = 0;
|
1029
|
+
list.forEach(cell => {
|
1030
|
+
const { key, value, isClue } = cell;
|
1031
|
+
if (!isClue) {
|
1032
|
+
if (key !== '.') {
|
1033
|
+
if (key !== value) {
|
1034
|
+
errors = errors + 1;
|
1035
|
+
cell.key = '.';
|
1036
|
+
}
|
1037
|
+
else {
|
1038
|
+
found = found + 1;
|
1039
|
+
}
|
1040
|
+
}
|
1036
1041
|
}
|
1037
1042
|
else {
|
1038
|
-
|
1043
|
+
clues = clues + 1;
|
1039
1044
|
}
|
1040
|
-
|
1045
|
+
inputs.push(cell.key);
|
1046
|
+
});
|
1047
|
+
const total = clues + found;
|
1048
|
+
found ? saveInputs(inputs) : saveInputs([]);
|
1049
|
+
if (errors > 0) {
|
1050
|
+
redraw(list);
|
1041
1051
|
}
|
1042
1052
|
else {
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
});
|
1047
|
-
const total = clues + found;
|
1048
|
-
found ? saveInputs(inputs) : saveInputs([]);
|
1049
|
-
if (errors > 0) {
|
1050
|
-
redraw(list);
|
1051
|
-
}
|
1052
|
-
else {
|
1053
|
-
if (total === 81) {
|
1054
|
-
state.solved = true;
|
1053
|
+
if (total === 81) {
|
1054
|
+
state.solved = true;
|
1055
|
+
}
|
1055
1056
|
}
|
1056
|
-
}
|
1057
1057
|
};
|
1058
1058
|
const input = (key) => {
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1059
|
+
const { pick, list } = state;
|
1060
|
+
const cell = list[pick];
|
1061
|
+
cell.key = key;
|
1062
|
+
redraw(list);
|
1063
1063
|
};
|
1064
1064
|
const actions = {
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1065
|
+
initApp,
|
1066
|
+
refresh,
|
1067
|
+
select,
|
1068
|
+
check,
|
1069
|
+
input,
|
1070
1070
|
};
|
1071
1071
|
|
1072
1072
|
// WARNING: generated file...
|
1073
1073
|
const TW_VERSION = '3.3.5';
|
1074
1074
|
|
1075
1075
|
const tw = (...classes) => {
|
1076
|
-
|
1076
|
+
return classes.filter(Boolean).join(' ');
|
1077
1077
|
};
|
1078
1078
|
|
1079
1079
|
const Spinner = props => {
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1080
|
+
const hex = props.hex || 'currentColor';
|
1081
|
+
const klass = props.class || '';
|
1082
|
+
const label = props.label || 'loading...';
|
1083
|
+
const size = props.size || 24;
|
1084
|
+
return (h("svg", { class: tw(klass, 'animate-spin'), width: size, height: size, fill: "none", viewBox: "0 0 24 24", role: "img", "aria-label": "title" },
|
1085
|
+
h("title", null, label),
|
1086
|
+
h("g", null,
|
1087
|
+
h("circle", { class: "opacity-25", cx: "12", cy: "12", r: "10", stroke: hex, "stroke-width": "4" }),
|
1088
|
+
h("path", { class: "opacity-75", fill: hex, d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })),
|
1089
|
+
h("path", { d: "M0 0h24v24H0z", fill: "none" })));
|
1090
1090
|
};
|
1091
1091
|
|
1092
1092
|
const Alert = props => {
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1093
|
+
const { message, salute, spinner = false } = props;
|
1094
|
+
return (h("div", { class: "mt-5 flex h-24px flex-row items-center" },
|
1095
|
+
spinner ? h(Spinner, { class: "mr-2" }) : h(Alien, { class: "mr-2" }),
|
1096
|
+
salute ? h("label", { class: "mr-1 font-bold" },
|
1097
|
+
salute,
|
1098
|
+
":") : '',
|
1099
|
+
h("label", { class: "italic" }, message)));
|
1100
1100
|
};
|
1101
1101
|
|
1102
1102
|
const Alerts = _props => {
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1103
|
+
const { solved, loading, error } = state;
|
1104
|
+
const play = !loading && !error && !solved;
|
1105
|
+
return (h("div", { class: "flex flex-col" },
|
1106
|
+
play ? h(Alert, { message: "Welcome, are you ready to play?..." }) : '',
|
1107
|
+
loading ? h(Alert, { message: "Loading...", spinner: true }) : '',
|
1108
|
+
error ? h(Alert, { message: error, salute: "ERROR" }) : '',
|
1109
|
+
solved ? h(Alert, { message: "You solved the puzzle!!" }) : ''));
|
1110
1110
|
};
|
1111
1111
|
|
1112
1112
|
const Fingerprint = props => {
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1113
|
+
const hex = props.hex || 'currentColor';
|
1114
|
+
const klass = props.class;
|
1115
|
+
const label = props.label || 'fingerprint';
|
1116
|
+
const size = props.size || 24;
|
1117
|
+
return (h("svg", { class: klass, width: size, height: size, viewBox: "0 0 24 24", role: "img", "aria-label": "title" },
|
1118
|
+
h("title", null, label),
|
1119
|
+
h("g", { fill: hex },
|
1120
|
+
h("path", { d: "M17.81,4.47C17.73,4.47 17.65,4.45 17.58,4.41C15.66,3.42 14,3\n 12,3C10.03,3 8.15,3.47 6.44,4.41C6.2,4.54 5.9,4.45 5.76,4.21C5.63,3.97\n 5.72,3.66 5.96,3.53C7.82,2.5 9.86,2 12,2C14.14,2 16,2.47\n 18.04,3.5C18.29,3.65 18.38,3.95 18.25,4.19C18.16,4.37 18,4.47\n 17.81,4.47M3.5,9.72C3.4,9.72 3.3,9.69 3.21,9.63C3,9.47 2.93,9.16\n 3.09,8.93C4.08,7.53 5.34,6.43 6.84,5.66C10,4.04 14,4.03\n 17.15,5.65C18.65,6.42 19.91,7.5 20.9,8.9C21.06,9.12 21,9.44\n 20.78,9.6C20.55,9.76 20.24,9.71 20.08,9.5C19.18,8.22 18.04,7.23\n 16.69,6.54C13.82,5.07 10.15,5.07 7.29,6.55C5.93,7.25 4.79,8.25\n 3.89,9.5C3.81,9.65 3.66,9.72 3.5,9.72M9.75,21.79C9.62,21.79 9.5,21.74\n 9.4,21.64C8.53,20.77 8.06,20.21 7.39,19C6.7,17.77 6.34,16.27\n 6.34,14.66C6.34,11.69 8.88,9.27 12,9.27C15.12,9.27 17.66,11.69\n 17.66,14.66A0.5,0.5 0 0,1 17.16,15.16A0.5,0.5 0 0,1\n 16.66,14.66C16.66,12.24 14.57,10.27 12,10.27C9.43,10.27 7.34,12.24\n 7.34,14.66C7.34,16.1 7.66,17.43 8.27,18.5C8.91,19.66 9.35,20.15\n 10.12,20.93C10.31,21.13 10.31,21.44 10.12,21.64C10,21.74 9.88,21.79\n 9.75,21.79M16.92,19.94C15.73,19.94 14.68,19.64 13.82,19.05C12.33,18.04\n 11.44,16.4 11.44,14.66A0.5,0.5 0 0,1 11.94,14.16A0.5,0.5 0 0,1\n 12.44,14.66C12.44,16.07 13.16,17.4 14.38,18.22C15.09,18.7 15.92,18.93\n 16.92,18.93C17.16,18.93 17.56,18.9 17.96,18.83C18.23,18.78 18.5,18.96\n 18.54,19.24C18.59,19.5 18.41,19.77 18.13,19.82C17.56,19.93 17.06,19.94\n 16.92,19.94M14.91,22C14.87,22 14.82,22 14.78,22C13.19,21.54 12.15,20.95\n 11.06,19.88C9.66,18.5 8.89,16.64 8.89,14.66C8.89,13.04 10.27,11.72\n 11.97,11.72C13.67,11.72 15.05,13.04 15.05,14.66C15.05,15.73 16,16.6\n 17.13,16.6C18.28,16.6 19.21,15.73 19.21,14.66C19.21,10.89 15.96,7.83\n 11.96,7.83C9.12,7.83 6.5,9.41 5.35,11.86C4.96,12.67 4.76,13.62\n 4.76,14.66C4.76,15.44 4.83,16.67 5.43,18.27C5.53,18.53 5.4,18.82\n 5.14,18.91C4.88,19 4.59,18.87 4.5,18.62C4,17.31 3.77,16\n 3.77,14.66C3.77,13.46 4,12.37 4.45,11.42C5.78,8.63 8.73,6.82\n 11.96,6.82C16.5,6.82 20.21,10.33 20.21,14.65C20.21,16.27 18.83,17.59\n 17.13,17.59C15.43,17.59 14.05,16.27 14.05,14.65C14.05,13.58 13.12,12.71\n 11.97,12.71C10.82,12.71 9.89,13.58 9.89,14.65C9.89,16.36 10.55,17.96\n 11.76,19.16C12.71,20.1 13.62,20.62 15.03,21C15.3,21.08 15.45,21.36\n 15.38,21.62C15.33,21.85 15.12,22 14.91,22Z" })),
|
1121
|
+
h("path", { d: "M0 0h24v24H0z", fill: "none" })));
|
1122
1122
|
};
|
1123
1123
|
|
1124
1124
|
const url = 'https://eswat2.dev';
|
1125
1125
|
const who = 'eswat2';
|
1126
1126
|
const Eswat2Io = _props => {
|
1127
|
-
|
1128
|
-
|
1127
|
+
return (h("a", { class: "absolute right-0 top-0 text-clrs-gray hover:text-clrs-navy", href: url, "aria-label": who, target: "blank", title: who },
|
1128
|
+
h(Fingerprint, { label: who })));
|
1129
1129
|
};
|
1130
1130
|
|
1131
1131
|
const Header = (_props, children) => {
|
1132
|
-
|
1132
|
+
return (h("h1", { class: tw('text-center uppercase text-clrs-red', 'mb-11 ml-0 mr-0 mt-11', 'text-6xl font-thin') }, children));
|
1133
1133
|
};
|
1134
1134
|
|
1135
1135
|
const Button = props => {
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1136
|
+
const { label, callback, matched = false } = props;
|
1137
|
+
return (h("button", { class: tw('rounded-md border border-solid border-clrs-slate4 font-bold', label === CHECK
|
1138
|
+
? 'mr-2 bg-clrs-yellow px-3 py-2 text-clrs-navy'
|
1139
|
+
: label === NEW_PUZZLE
|
1140
|
+
? 'mr-2 bg-clrs-navy px-3 py-2 text-white'
|
1141
|
+
: label === DELETE
|
1142
|
+
? 'mr-1 bg-clrs-red px-2 py-1 text-white'
|
1143
|
+
: matched
|
1144
|
+
? 'mr-1 bg-clrs-slate4 px-2 py-1 text-white'
|
1145
|
+
: 'mr-1 bg-gray-50 px-2 py-1 text-clrs-navy'), onClick: callback }, label));
|
1146
1146
|
};
|
1147
1147
|
|
1148
1148
|
const Keys = _props => {
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1149
|
+
const { keys, list, pick, solved } = state;
|
1150
|
+
const genHandler = (key) => {
|
1151
|
+
return () => {
|
1152
|
+
actions.input(key);
|
1153
|
+
};
|
1153
1154
|
};
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
})));
|
1155
|
+
const values = solved ? [] : keys;
|
1156
|
+
const cell = pick != undefined ? list[pick] : undefined;
|
1157
|
+
return (h("div", { class: "mt-2 flex flex-row justify-end" },
|
1158
|
+
!solved && cell && !cell.isClue && cell.key != '.' ? (h(Button, { label: DELETE, callback: genHandler('.') })) : (''),
|
1159
|
+
values.map((key) => {
|
1160
|
+
return (h(Button, { label: key, callback: genHandler(key), matched: cell.key === key }));
|
1161
|
+
})));
|
1162
1162
|
};
|
1163
1163
|
|
1164
1164
|
// NOTE: building indx mapping for the border highlighting...
|
1165
1165
|
const borderRight = [
|
1166
|
-
|
1166
|
+
2, 5, 11, 14, 20, 23, 29, 32, 38, 41, 47, 50, 56, 59, 65, 68, 74, 77,
|
1167
1167
|
];
|
1168
1168
|
const borderLeft = borderRight.map(key => key + 1);
|
1169
1169
|
const borderBottom = [
|
1170
|
-
|
1170
|
+
18, 19, 20, 21, 22, 23, 24, 25, 26, 45, 46, 47, 48, 49, 50, 51, 52, 53,
|
1171
1171
|
];
|
1172
1172
|
const borderTop = borderBottom.map(key => key + 9);
|
1173
1173
|
// Functional components return JSX...
|
1174
1174
|
const Cell = props => {
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1175
|
+
const { cell, focus, selected, solved } = props;
|
1176
|
+
const { key, isClue, indx } = cell;
|
1177
|
+
const clue = key != '.' ? key : '';
|
1178
|
+
const genHandler = (cell, solved) => {
|
1179
|
+
return () => {
|
1180
|
+
if (!solved) {
|
1181
|
+
actions.select(cell);
|
1182
|
+
}
|
1183
|
+
};
|
1183
1184
|
};
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
: 'border-clrs-gray'), onClick: genHandler(cell, solved) }, clue));
|
1185
|
+
return (h("label", { class: tw(`cell-${indx}`, borderRight.includes(indx) ? 'border-xbr-clrs-navy' : '', borderLeft.includes(indx) ? 'border-xbl-clrs-navy' : '', borderBottom.includes(indx) ? 'border-xbb-clrs-navy' : '', borderTop.includes(indx) ? 'border-xbt-clrs-navy' : '', 'h-8 w-8 border border-solid text-center leading-8', selected
|
1186
|
+
? 'border-clrs-red bg-clrs-red-a50 text-clrs-red'
|
1187
|
+
: focus
|
1188
|
+
? 'border-clrs-gray bg-clrs-green-a50 font-bold'
|
1189
|
+
: isClue
|
1190
|
+
? 'border-clrs-gray bg-clrs-silver'
|
1191
|
+
: clue !== ''
|
1192
|
+
? 'border-clrs-gray text-clrs-red'
|
1193
|
+
: 'border-clrs-gray'), onClick: genHandler(cell, solved) }, clue));
|
1194
1194
|
};
|
1195
1195
|
|
1196
1196
|
const SudokuBoard = _props => {
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1197
|
+
const { list, pick, locs, solved } = state;
|
1198
|
+
return (h("div", { class: tw('flex flex-row flex-wrap', 'border border-solid border-clrs-navy', 'h-76p5 w-76p5 text-lg') }, list.map((cell, index) => {
|
1199
|
+
const selected = solved ? false : index === pick;
|
1200
|
+
const focus = solved ? false : locs.includes(index);
|
1201
|
+
return (h(Cell, { cell: cell, focus: focus, selected: selected, solved: solved }));
|
1202
|
+
})));
|
1203
1203
|
};
|
1204
1204
|
|
1205
1205
|
const TwLabel = _props => {
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1206
|
+
return (h("label", { class: "ml-auto align-top text-xs italic text-clrs-slate4" },
|
1207
|
+
"Tailwind ",
|
1208
|
+
TW_VERSION));
|
1209
1209
|
};
|
1210
1210
|
|
1211
1211
|
const handleRefresh = (actions) => {
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1212
|
+
return () => {
|
1213
|
+
actions.refresh();
|
1214
|
+
};
|
1215
1215
|
};
|
1216
1216
|
const handleCheck = (actions) => {
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1217
|
+
return () => {
|
1218
|
+
actions.check();
|
1219
|
+
};
|
1220
1220
|
};
|
1221
1221
|
const ToolBar = _props => {
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1222
|
+
const { list, solved } = state;
|
1223
|
+
return (h("div", { class: "flex flex-row" },
|
1224
|
+
h(Button, { label: NEW_PUZZLE, callback: handleRefresh(actions) }),
|
1225
|
+
list.length === 81 && !solved ? (h(Button, { label: CHECK, callback: handleCheck(actions) })) : (''),
|
1226
|
+
h(TwLabel, null)));
|
1227
1227
|
};
|
1228
1228
|
|
1229
1229
|
const protoSudokuCss = "*,::before,::after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scroll-snap-strictness:proximity;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / 0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;}::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scroll-snap-strictness:proximity;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / 0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;}.ds1-main{margin:1.5rem;display:flex;flex-direction:column;font-family:ui-sans-serif,\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n 'Segoe UI',\n Roboto,\n 'Helvetica Neue',\n Arial,\n 'Noto Sans',\n sans-serif,\n 'Apple Color Emoji',\n 'Segoe UI Emoji',\n 'Segoe UI Symbol',\n 'Noto Color Emoji';color:var(--clrs-navy, #001f3f);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.absolute{position:absolute}.relative{position:relative}.right-0{right:0px}.top-0{top:0px}.mb-11{margin-bottom:2.75rem}.ml-0{margin-left:0px}.ml-auto{margin-left:auto}.mr-0{margin-right:0px}.mr-1{margin-right:0.25rem}.mr-2{margin-right:0.5rem}.mt-11{margin-top:2.75rem}.mt-2{margin-top:0.5rem}.mt-5{margin-top:1.25rem}.flex{display:flex}.h-24px{height:24px}.h-76p5{height:19.125rem}.h-8{height:2rem}.w-76p5{width:19.125rem}.w-8{width:2rem}.max-w-min{max-width:-moz-min-content;max-width:min-content}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-end{justify-content:flex-end}.rounded-md{border-radius:0.375rem}.border{border-width:1px}.border-solid{border-style:solid}.border-clrs-gray{border-color:var(--clrs-gray, #aaaaaa)}.border-clrs-navy{border-color:var(--clrs-navy, #001f3f)}.border-clrs-red{border-color:var(--clrs-red, #ff4136)}.border-clrs-slate4{border-color:var(--clrs-slate4, #4e5964)}.bg-clrs-green-a50{background-color:var(--clrs-green-a50, #2ecc4050)}.bg-clrs-navy{background-color:var(--clrs-navy, #001f3f)}.bg-clrs-red{background-color:var(--clrs-red, #ff4136)}.bg-clrs-red-a50{background-color:var(--clrs-red-a50, #ff413650)}.bg-clrs-silver{background-color:var(--clrs-silver, #dddddd)}.bg-clrs-slate4{background-color:var(--clrs-slate4, #4e5964)}.bg-clrs-yellow{background-color:var(--clrs-yellow, #ffdc00)}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.p-0{padding:0px}.p-0\\.5{padding:0.125rem}.px-2{padding-left:0.5rem;padding-right:0.5rem}.px-3{padding-left:0.75rem;padding-right:0.75rem}.py-1{padding-top:0.25rem;padding-bottom:0.25rem}.py-2{padding-top:0.5rem;padding-bottom:0.5rem}.text-center{text-align:center}.align-top{vertical-align:top}.text-6xl{font-size:3.75rem;line-height:1}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-xs{font-size:0.75rem;line-height:1rem}.font-bold{font-weight:700}.font-thin{font-weight:100}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-8{line-height:2rem}.text-clrs-gray{color:var(--clrs-gray, #aaaaaa)}.text-clrs-navy{color:var(--clrs-navy, #001f3f)}.text-clrs-red{color:var(--clrs-red, #ff4136)}.text-clrs-slate4{color:var(--clrs-slate4, #4e5964)}.text-white{--tw-text-opacity:1;color:rgb(255 255 255 / var(--tw-text-opacity))}.opacity-25{opacity:0.25}.opacity-75{opacity:0.75}.shadow{--tw-shadow:0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),\n 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),\n var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)}.border-xbb-clrs-navy{border-bottom:1px solid var(--clrs-navy, #001f3f) !important}.border-xbt-clrs-navy{border-top:1px solid var(--clrs-navy, #001f3f) !important}.border-xbl-clrs-navy{border-left:1px solid var(--clrs-navy, #001f3f) !important}.border-xbr-clrs-navy{border-right:1px solid var(--clrs-navy, #001f3f) !important}.hover\\:text-clrs-navy:hover{color:var(--clrs-navy, #001f3f)}";
|
1230
1230
|
|
1231
1231
|
const ProtoSudoku = class {
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1232
|
+
constructor(hostRef) {
|
1233
|
+
registerInstance(this, hostRef);
|
1234
|
+
this.tag = 'proto-sudoku';
|
1235
|
+
this.platform = 'vercel';
|
1236
|
+
}
|
1237
|
+
componentDidLoad() {
|
1238
|
+
actions.initApp(this.platform);
|
1239
|
+
}
|
1240
|
+
render() {
|
1241
|
+
return (h("div", { id: "app", class: "ds1-main relative max-w-min p-0.5" }, h(Eswat2Io, null), h(Header, null, "Sudoku"), h(SudokuBoard, null), h(Keys, null), h("hr", { class: "ml-0 mr-0" }), h(ToolBar, null), h(Alerts, null)));
|
1242
|
+
}
|
1243
1243
|
};
|
1244
1244
|
ProtoSudoku.style = protoSudokuCss;
|
1245
1245
|
|