123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563 |
- <script setup>
- import { ref, onMounted } from 'vue';
- import { service } from './util/http';
- import { message, getLang } from './util/locale';
- import { store } from './util/store';
- const model = ref({
- type: '',
- forward: '',
- index: 0,
- speak: 0,
- welcome: [],
- inputs: [],
- focus: {
- index: 0,
- auto: true,
- },
- submit: false,
- invalid: '',
- forget: false,
- interval: 0,
- });
- const inputs = { 'in': ['username', 'password'], 'up': ['username', 'nick', 'password', 'repeat'], 'forget': ['username', 'email', 'code', 'newpass', 'repeat'] };
- const language = (lang) => {
- store.language = lang;
- localStorage.setItem('language', lang);
- window.location.reload();
- };
- const type = (i, j) => {
- if (model.value.interval)
- clearInterval(model.value.interval);
- if ((i === 0 && j === 2) || (i === 1 && j === 1)) {
- model.value = {
- type: i === 1 && j === 1 ? 'forget' : (model.value.type === 'up' || model.value.type === 'forget' ? 'in' : 'up'),
- forward: model.value.forward,
- index: 0,
- speak: 0,
- welcome: [],
- inputs: [],
- focus: {
- index: 0,
- auto: true,
- },
- submit: false,
- invalid: '',
- forget: false,
- };
- model.value.interval = setInterval(next, model.value.type === 'in' ? 50 : 100);
- }
- };
- const next = () => {
- if (model.value.submit || speak())
- return;
- model.value.index++;
- model.value.speak = 0;
- };
- const speak = () => {
- if (model.value.index === 0) {
- let welcome = message('welcome.' + model.value.type);
- if (model.value.speak > welcome.length)
- return false;
- model.value.welcome = welcome.substring(0, model.value.speak++).split('\n');
- return true;
- }
- let index = model.value.index - 1;
- if (model.value.focus.auto)
- model.value.focus.index = index;
- if (index < inputs[model.value.type].length) {
- let label = message(inputs[model.value.type][index]);
- if (index === 0) {
- label = message('username.' + model.value.type);
- } else if (index === 1 && model.value.type === 'in')
- label += '\n' + message('forget');
- if (model.value.speak > label.length) {
- if (model.value.inputs[index].step === 0)
- model.value.inputs[index].step = 1;
- return model.value.inputs[index].step < 3;
- }
- if (model.value.inputs.length < model.value.index) {
- let input = {
- label: [],
- value: '',
- placeholder: '',
- invalid: '',
- step: 0,
- password: index >= (model.value.type === 'up' ? 2 : (model.value.type === 'in' ? 1 : 3)),
- };
- if (index === 0) {
- if (model.value.type === 'in')
- input.placeholder = message('username-email');
- else if (model.value.type === 'up')
- input.placeholder = message('username.placeholder');
- }
- model.value.inputs.push(input);
- }
- model.value.inputs[index].label = label.substring(0, model.value.speak++).split('\n');
- return true;
- }
- return true;
- };
- const input = (index) => {
- let value = model.value.inputs[index].value;
- length = value.length;
- if (index === 0) {
- if (model.value.type === 'up') {
- model.value.inputs[index].invalid = length < 4 || length > 15 ? message('username.invalid.up') : '';
- if (!model.value.inputs[index].invalid) {
- service('/user/auth/exists', { uid: value }, data => {
- model.value.inputs[index].step = data ? 2 : 1;
- model.value.inputs[index].invalid = data ? '' : message('username.invalid.up');
- });
- }
- } else {
- model.value.inputs[index].invalid = '';
- model.value.inputs[index].step = 2;
- }
- } else if (index === 1) {
- if (model.value.type === 'up') {
- model.value.inputs[index].invalid = length < 2 || length > 14 ? message('nick.invalid') : '';
- model.value.inputs[index].step = length < 2 || length > 14 ? 1 : 2;
- } else if (model.value.type === 'in') {
- model.value.inputs[index].invalid = length < 7 || length > 20 ? message('password.invalid') : '';
- model.value.inputs[index].step = length < 7 || length > 20 ? 1 : 2;
- } else if (model.value.type === 'forget') {
- let valid = /^(?:\w+\.?-?)*\w+@(?:\w+\.?-?)*\w+$/.test(value);
- model.value.inputs[index].invalid = !valid ? message('email.invalid') : '';
- model.value.inputs[index].step = !valid ? 1 : 2;
- }
- } else if (index === 2) {
- if (model.value.type === 'up') {
- model.value.inputs[index].invalid = length < 7 || length > 20 ? message('password.invalid') : '';
- model.value.inputs[index].step = length < 7 || length > 20 ? 1 : 2;
- } else if (model.value.type === 'forget') {
- model.value.inputs[index].invalid = length === 8 ? '' : message('code.invalid');
- model.value.inputs[index].step = length === 8 ? 2 : 1;
- }
- } else if (index === 3) {
- if (model.value.type === 'up') {
- model.value.inputs[index].invalid = value === model.value.inputs[index - 1].value ? '' : message('repeat.invalid');
- model.value.inputs[index].step = value === model.value.inputs[index - 1].value ? 2 : 1;
- } else if (model.value.type === 'forget') {
- model.value.inputs[index].invalid = length < 7 || length > 20 ? message('password.invalid') : '';
- model.value.inputs[index].step = length < 7 || length > 20 ? 1 : 2;
- }
- } else if (index === 4) {
- model.value.inputs[index].invalid = value === model.value.inputs[index - 1].value ? '' : message('repeat.invalid');
- model.value.inputs[index].step = value === model.value.inputs[index - 1].value ? 2 : 1;
- }
- };
- const confirm = (index, event, callback) => {
- if (event)
- event.target.blur();
- if (model.value.submit) {
- model.value.focus = { index: model.value.inputs.length + 1, auto: false };
- return;
- }
- if (model.value.type === 'forget' && !callback) {
- if (index === 1) {
- service('/home/forget-email', { uid: model.value.inputs[0].value, email: model.value.inputs[1].value, subject: message('forget.title'), lang: getLang() }, data => {
- model.value.invalid = message(data ? 'code.send' : 'email.failure');
- if (data)
- confirm(index, null, 1);
- });
- return;
- }
- if (index === 2) {
- service('/home/forget-code', { code: model.value.inputs[2].value }, data => {
- if (data)
- confirm(index, null, 1);
- model.value.invalid = data ? '' : message('code.invalid');
- });
- return;
- }
- }
- model.value.focus.auto = true;
- if (model.value.inputs[index].step === 2)
- model.value.inputs[index].step = 3;
- if (model.value.inputs[index].step === 3) {
- model.value.submit = (index === 1 && model.value.type === 'in') || (index === 3 && model.value.type === 'up') || (index === 4 && model.value.type === 'forget');
- if (model.value.submit)
- model.value.focus = { index: index + 1, auto: false };
- }
- };
- const focus = (index) => {
- model.value.focus = { index, auto: false };
- };
- const submit = () => {
- if (model.value.type === 'up') {
- service('/user/sign-up', {
- type: '',
- uid: model.value.inputs[0].value,
- nick: model.value.inputs[1].value,
- password: model.value.inputs[2].value,
- }, data => {
- if (data.id) {
- forward();
- } else {
- model.value.invalid = message('sign-up.invalid');
- }
- }, () => model.value.invalid = message('sign-up.invalid'));
- } else if (model.value.type === 'in') {
- service('/user/sign-in', {
- type: '',
- uid: model.value.inputs[0].value,
- password: model.value.inputs[1].value,
- }, data => {
- if (data.id) {
- forward();
- } else {
- model.value.invalid = message('sign-in.invalid');
- }
- }, () => model.value.invalid = message('sign-in.invalid'));
- } else if (model.value.type === 'forget') {
- service('/home/password', { code: model.value.inputs[2].value, password: model.value.inputs[3].value }, data => {
- model.value.forget = data;
- model.value.invalid = message('forget.' + (data ? 'success' : 'failure'));
- });
- }
- };
- const forward = () => {
- if (model.value.forward === 'parent') {
- window.parent.postMessage({ type: 'sign', value: '' }, '*');
- window.parent.postMessage({ type: 'session', value: localStorage.getItem('photon-session-id')}, '*')
- } else {
- location.href = model.value.forward;
- }
- };
- onMounted(() => {
- document.title = message('title');
- if (location.search && location.search.indexOf('?') > -1) {
- for (let param of location.search.substring(1).split('&')) {
- if (param.indexOf('type=') === 0) {
- model.value.type = param.substring(5);
- } else if (param.indexOf('forward=') === 0) {
- model.value.forward = decodeURIComponent(param.substring(8));
- }
- }
- }
- if (!model.value.type)
- model.value.type = 'in';
- if (!model.value.forward)
- model.value.forward = '/';
- model.value.interval = setInterval(next, model.value.type === 'in' ? 50 : 100);
- service('/user/sign', {}, data => {
- if (data.id){
- if(model.value.forward === 'parent'){
- window.parent.postMessage({ type: 'sign', value: data.id }, '*');
- window.parent.postMessage({ type: 'session', value: localStorage.getItem('photon-session-id')}, '*')
- }else{
- location.href = model.value.forward;
- }
- }
- });
- });
- </script>
- <template>
- <div class="stars">
- <div v-for="i in 6" class="star"></div>
- </div>
- <div class="sign-in-up">
- <div class="nav">
- <img src="./assets/logo.png" />
- <div class="langs">
- <div @click="language('zh')"><span>中</span></div>
- <div @click="language('en')"><span>En</span></div>
- <div @click="language('jp')"><span>あ</span></div>
- </div>
- </div>
- <div>
- <div class="dialog">
- <div v-for="welcome in model.welcome" class="welcome">{{ welcome }}</div>
- <template v-for="(ip, index) in model.inputs">
- <div class="label">
- <span v-for="(label, li) in ip.label" :class="'label-' + (li === 0 ? '0' : (index + '' + li))"
- @click="type(index, li)">{{ label }}</span>
- </div>
- <div v-if="ip.step > 0" class="input">
- <div v-if="model.focus.index === index" class="arrow">→</div>
- <div v-else-if="model.type === 'up'" class="correct">√</div>
- <input :type="ip.password ? 'password' : 'text'" v-model="model.inputs[index].value"
- :placeholder="model.inputs[index].placeholder" @focus="focus(index)" @input="input(index)"
- @keypress.enter="confirm(index, $event)" />
- <div v-if="model.focus.index === index"
- :class="model.inputs[index].step === 2 ? 'button-valid' : 'button-invalid'" @click="confirm(index)">{{
- message('continue') }}</div>
- <div v-else class="button-empty">{{ message('continue') }}</div>
- </div>
- <div v-else-if="ip.step === 3" class="input">
- <div v-if="model.type === 'up'" class="correct">√</div>
- <div class="value">{{ model.inputs[index].password ? '********' : model.inputs[index].value }}</div>
- </div>
- </template>
- <div v-if="model.forget" class="submit" @click="type(0, 2)">{{ message('to-in') }}</div>
- <div v-else-if="model.submit" class="submit" @click="submit">{{ message('sign-' + model.type) }}</div>
- </div>
- <div v-if="model.inputs.length > 0 && model.inputs.length >= model.index" class="invalid">{{
- model.inputs[model.index - 1].invalid }}</div>
- <div v-if="model.invalid" class="invalid">{{ model.invalid }}</div>
- </div>
- </div>
- </template>
- <style scoped>
- .stars,
- .star {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- overflow: hidden;
- }
- .stars {
- background-color: #040d21;
- background-image: url(./assets/hero-glow.svg);
- background-size: cover;
- background-position: center center;
- }
- .star {
- background-image: radial-gradient(2px 2px at 50px 200px, #eee, rgba(0, 0, 0, 0)), radial-gradient(2px 2px at 40px 70px, #fff, rgba(0, 0, 0, 0)), radial-gradient(3px 4px at 120px 40px, #ddd, rgba(0, 0, 0, 0));
- background-repeat: repeat;
- background-size: 250px 250px;
- opacity: 0;
- animation: zoom 10s infinite;
- }
- .star:nth-child(1) {
- background-position: 10% 90%;
- animation-delay: 0s
- }
- .star:nth-child(2) {
- background-position: 20% 50%;
- background-size: 270px 500px;
- animation-delay: .3s
- }
- .star:nth-child(3) {
- background-position: 40% -80%;
- animation-delay: 1.2s
- }
- .star:nth-child(4) {
- background-position: -20% -30%;
- transform: rotate(60deg);
- animation-delay: 2.5s
- }
- .star:nth-child(5) {
- background-image: radial-gradient(2px 2px at 10px 100px, #eee, rgba(0, 0, 0, 0)), radial-gradient(2px 2px at 20px 10px, #fff, rgba(0, 0, 0, 0)), radial-gradient(3px 4px at 150px 40px, #ddd, rgba(0, 0, 0, 0));
- background-position: 80% 30%;
- animation-delay: 4s
- }
- .star:nth-child(6) {
- background-position: 50% 20%;
- animation-delay: 6s
- }
- @keyframes zoom {
- 0% {
- opacity: 0;
- transform: scale(0.5);
- transform: rotate(5deg);
- animation-timing-function: ease-in
- }
- 85% {
- opacity: 1
- }
- 100% {
- opacity: .2;
- transform: scale(2.2)
- }
- }
- @media(prefers-reduced-motion) {
- .star {
- animation: none
- }
- }
- .sign-in-up {
- position: absolute;
- top: 0;
- bottom: 0;
- display: flex;
- flex-direction: column;
- align-items: center;
- }
- @media screen and (max-width: 1080px) {
- .sign-in-up {
- left: 0;
- right: 0;
- }
- }
- @media screen and (min-width: 1080px) {
- .sign-in-up {
- left: 20vw;
- right: 20vw;
- }
- }
- .nav {
- width: calc(100% - 32px);
- padding: 16px;
- display: flex;
- justify-content: space-between;
- }
- .nav img {
- width: 32px;
- height: 32px;
- }
- .nav .langs{
- color:#8193b2;
- display: flex;
- column-gap: 8px;
- cursor: pointer;
- }
- .dialog {
- margin: 24px;
- padding: 24px;
- background-color: #0c162d;
- border: 1px solid #202637;
- border-radius: 6px;
- }
- .welcome {
- width: 33vw;
- min-width: 280px;
- color: #8193b2;
- text-align: center;
- }
- .label {
- margin-top: 24px;
- font-weight: 600;
- display: flex;
- align-items: center;
- }
- .label-0 {
- color: #00cfc8;
- }
- .label-01 {
- padding-left: 16px;
- color: #8193b2;
- }
- .label-02,
- .label-11 {
- color: #FF8DC0;
- cursor: pointer;
- }
- .label-11 {
- padding-left: 16px;
- }
- .input {
- display: flex;
- align-items: center;
- padding-top: 4px;
- }
- .arrow {
- color: #ea4aaa;
- }
- .correct {
- color: #20bb3d;
- padding-right: 8px;
- }
- .input input {
- flex-grow: 1;
- outline: none;
- border: 1px solid #0c162d;
- background: none;
- color: #fff;
- }
- .input input:focus {
- border: 1px solid rgb(9, 105, 218);
- }
- .value {
- color: #fff;
- }
- .button-invalid,
- .button-valid,
- .button-empty {
- padding: 4px 8px;
- border-radius: 6px;
- white-space: nowrap;
- }
- .button-invalid {
- color: #627597;
- border: 1px solid #627597;
- cursor: default;
- }
- .button-valid,
- .submit {
- color: #FF8DC0;
- border: 1px solid #FF8DC0;
- cursor: pointer;
- }
- .button-empty {
- color: #0c162d;
- border: 1px solid #0c162d;
- cursor: default;
- }
- .submit {
- text-align: center;
- padding: 8px 0;
- border-radius: 6px;
- margin-top: 24px;
- }
- .invalid {
- padding: 0 48px;
- color: #8193b2;
- }
- </style>
|