Commit b8c0944c authored by satan's avatar satan
Browse files
parent f13cec7c
<template>
<div id="centered">
<div id="title">
<h1>EWO Escape Room</h1>
</div>
<div id="input-field">
<p>{{ pin }}</p>
<input type="password" v-model="pin" />
<p v-show="correct">Correct!</p>
</div>
</div>
<div id="title">
<h1>EWO Escape Room</h1>
</div>
<div id="input-field">
<p>{{ pin }}</p>
<input type="password" v-model="pin" />
<p v-show="correct">Correct!</p>
</div>
<Lock v-model="pin" :dial-count="4" @enter="checkPin" />
</div>
</template>
<script lang="ts">
......@@ -38,13 +39,14 @@ function equals<T extends Uint16Array>(a: T, b: T): boolean {
</script>
<script setup lang="ts">
import Lock from "./components/Lock.vue";
const pin = ref<string>("");
const correct = ref(false);
watchEffect(async () => {
async function checkPin(pin: string) {
const hash = new Uint16Array(await sha256(unref(pin)));
console.log(hash);
correct.value = equals(hash, unref(correctHash));
});
}
</script>
<template>
<div class="myCenter">
<div id="lock" ref="lock" class="myLock">
<div class="lockInset">
<div class="lockLine"></div>
<div class="lockWrapper">
<div class="dial" v-for="(digit, dial) in selection">
<ol
@click="dialMove(dial)"
@wheel="dialMove(dial, { change: Math.sign($event.deltaY) })"
>
<template v-for="d in generateDigits(digit)" :key="d">
<li v-text="d" />
</template>
</ol>
</div>
<div class="shadow"></div>
</div>
</div>
<div class="btnEnter button" @click="emits('enter', combo)">Enter</div>
</div>
</div>
</template>
<script lang="ts">
import { ref, toRef, Ref, computed, unref } from "vue";
import { useVModel } from "../util";
type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
function* generateDigits(selected: Digit): Generator<Digit, void, void> {
for (let i = 0; i < 10; i++) {
yield ((selected + i + 9) % 10) as Digit;
}
}
</script>
<script setup lang="ts">
const props = defineProps<{ modelValue: string; dialCount?: number }>();
const emits = defineEmits<{
(e: "update:modelValue", code: string): void;
(e: "enter", code: string): void;
}>();
const combo = useVModel(props, "modelValue", emits);
const dialCount = toRef(props, "dialCount");
const selection = computed(() => {
const selection: Digit[] = [];
for (let i = 0; i < dialCount.value; i++) {
let digit = parseInt(combo.value[i]);
if (Number.isNaN(digit)) {
digit = 0;
}
selection.push(digit as Digit);
}
console.log(selection);
return selection;
});
const lock: Ref<any> = ref(null);
function dialMove(
dial: number,
{ to, change = 1 }: { to?: number; change?: number } = {}
): void {
console.info({ dial, to, change });
const before = unref(combo).padEnd(dialCount.value, "0");
to ??= +before[dial] + change + 10;
const after = before.substr(0, dial) + (to % 10) + before.substr(dial + 1);
console.log({ before, after });
combo.value = after;
}
</script>
<style scoped>
.myCenter {
/* position: absolute; */
text-align: center;
margin: auto;
height: 390px;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
}
.myLock {
display: inline-block;
text-align: center;
height: 310px;
padding: 40px 50px 40px 50px;
margin: auto;
background: white;
background: linear-gradient(white, #dcd3ca);
border-radius: 25px;
box-shadow: inset 0 -4px 4px #b1aaa1, 0 20px 40px rgba(0, 0, 0, 0.5),
0 2px 5px 1px rgba(0, 0, 0, 0.7);
}
.myLock .lockInset {
display: inline-block;
position: relative;
padding: 23px;
background: linear-gradient(white, #dcd3ca);
border-radius: 15px;
box-shadow: inset 0 -8px 4px -4px #b1aaa1, 0 7px 10px rgba(0, 0, 0, 0.07),
0 14px 10px rgba(0, 0, 0, 0.07), 0 20px 10px rgba(0, 0, 0, 0.07),
0 27px 10px rgba(0, 0, 0, 0.07), 0 34px 10px rgba(0, 0, 0, 0.07),
0 2px 3px 1px rgba(0, 0, 0, 0.5);
}
.myLock .lockLine {
position: absolute;
margin: auto -23px;
width: 100%;
top: 0px;
bottom: 0px;
height: 4px;
background: linear-gradient(
rgba(0, 0, 0, 0.2) 1px,
transparent 1px,
transparent 3px,
rgba(0, 0, 0, 0.3) 3px
);
}
.myLock .lockWrapper {
text-align: center;
position: relative;
background: rgba(0, 0, 0, 0.85);
background: linear-gradient(
black 13%,
#403c3a,
black 75%,
#110c14,
black 85%
);
border-radius: 8px;
height: 150px;
box-shadow: inset 0 0 10px 2px black;
}
.myLock .dial {
display: inline-block;
vertical-align: top;
height: 150px;
width: 84px;
padding-top: -50px;
margin: 0px 7px;
background: linear-gradient(
#000000 0%,
#000006 3%,
#08000d 4%,
#292527 7%,
#55514c 9%,
#847f76 11%,
#979289 12%,
#bab3a9 15%,
#d9cfc6 17%,
#f4eae1 19%,
#fff4ec 20%,
#fffffc 22%,
#ffffff 24%,
#fffffe 33%,
#fffdf5 35%,
#fef3eb 37%,
#d4ccc2 45%,
#ada69d 54%,
#726d66 65%,
#595550 71%,
#4f4b47 74%,
#4b4743 76%,
#4b4743 79%,
#4f4b47 80%,
#6a665f 84%,
#6d6861 85%,
#6a665f 88%,
#65605a 89%,
#54504b 91%,
#0d0711 98%,
#02000a 99%,
#000004 100%
);
border: 5px solid rgba(0, 0, 0, 0.25);
border-top: none;
border-bottom: none;
border-left-image: linear-gradient(white, black);
overflow: hidden;
font-size: 45px;
font-family: arial;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5), 0 -1px 0 rgba(0, 0, 0, 0.5),
0 -2px 0 rgba(255, 255, 255, 0.1);
color: #827d74;
cursor: pointer;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2), 0 8px 10px rgba(0, 0, 0, 0.2),
0 13px 10px rgba(0, 0, 0, 0.2);
}
.myLock .dial ol {
display: inline;
position: relative;
top: -50px;
}
.myLock .dial ol li {
display: inline-block;
position: relative;
font-weight: 600;
display: block;
margin: 0 auto;
height: 51px;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.myLock .shadow {
pointer-events: none;
position: absolute;
top: 0px;
background: linear-gradient(
black 5%,
transparent 40%,
transparent 60%,
black 100%
);
border-radius: 8px;
height: 150px;
width: 100%;
}
.myLock .btnEnter {
font-size: 45px;
font-family: arial;
font-weight: 600;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5), 0 -1px 0 rgba(0, 0, 0, 0.5),
0 -2px 0 rgba(255, 255, 255, 0.1);
color: #333;
cursor: pointer;
margin: auto;
width: 350px;
height: 50px;
margin-top: 15px;
display: block;
padding: 23px;
background: linear-gradient(white, #dcd3ca);
border-radius: 15px;
border: 1px solid #999;
box-shadow: inset 0 -8px 4px -4px #b1aaa1, 0 7px 10px rgba(0, 0, 0, 0.07),
0 14px 10px rgba(0, 0, 0, 0.07), 0 20px 10px rgba(0, 0, 0, 0.07),
0 27px 10px rgba(0, 0, 0, 0.07), 0 34px 10px rgba(0, 0, 0, 0.07),
0 2px 3px 1px rgba(0, 0, 0, 0.5);
}
.myLock .btnEnter:active {
font-size: 44px;
background: linear-gradient(white, #dcd3ca);
border-radius: 15px;
border: 1px solid #999;
vertical-align: -5px;
box-shadow: inset 0 7px 10px rgba(0, 0, 0, 0.07),
inset 0 14px 10px rgba(0, 0, 0, 0.07), inset 0 20px 10px rgba(0, 0, 0, 0.07),
inset 0 27px 10px rgba(0, 0, 0, 0.07), inset 0 34px 10px rgba(0, 0, 0, 0.07),
inset 0 2px 3px 1px rgba(0, 0, 0, 0.5), inset 0 -8px 4px -4px #b1aaa1;
}
</style>
import { ref, Ref, watch } from "vue";
export function useVModel<P extends object, K extends keyof P & string>(
props: P,
key: K,
emit: (event: `update:${K}`, v: P[K]) => void
): Ref<P[K]> {
const value = ref(props[key]) as Ref<P[K]>;
watch(
() => props[key],
v => (value.value = v)
);
watch(value, v => {
if (v === props[key]) return;
emit(`update:${key}`, v);
});
return value;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment