mirror of
https://github.com/go-shiori/shiori.git
synced 2025-09-06 13:05:30 +08:00
142 lines
No EOL
4.1 KiB
HTML
142 lines
No EOL
4.1 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<base href="$$.$$">
|
|
<title>Login - Shiori</title>
|
|
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="res/apple-touch-icon-152x152.png">
|
|
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="res/apple-touch-icon-144x144.png">
|
|
<link rel="icon" type="image/png" href="res/favicon-32x32.png" sizes="32x32">
|
|
<link rel="icon" type="image/png" href="res/favicon-16x16.png" sizes="16x16">
|
|
<link rel="icon" type="image/x-icon" href="res/favicon.ico">
|
|
|
|
<link href="css/source-sans-pro.min.css" rel="stylesheet">
|
|
<link href="css/fontawesome.min.css" rel="stylesheet">
|
|
<link href="css/stylesheet.css" rel="stylesheet">
|
|
|
|
<script src="js/vue.min.js"></script>
|
|
<script src="js/url.min.js"></script>
|
|
</head>
|
|
|
|
<body>
|
|
<div id="login-scene" :class="{night: nightMode}">
|
|
<p class="error-message" v-if="error !== ''">{{error}}</p>
|
|
<div id="login-box">
|
|
<div id="logo-area">
|
|
<p id="logo">
|
|
<span>栞</span>shiori
|
|
</p>
|
|
<p id="tagline">simple bookmark manager</p>
|
|
</div>
|
|
<div id="input-area">
|
|
<label for="username">Username: </label>
|
|
<input type="text" name="username" v-model.trim="username" placeholder="Username" tabindex="1">
|
|
<label for="password">Password: </label>
|
|
<input type="password" name="password" v-model.trim="password" placeholder="Password" tabindex="2" @keyup.enter="login">
|
|
<label class="checkbox-field"><input type="checkbox" name="remember" v-model="remember" tabindex="3">Remember me</label>
|
|
</div>
|
|
<div id="button-area">
|
|
<a v-if="loading">
|
|
<i class="fas fa-fw fa-spinner fa-spin"></i>
|
|
</a>
|
|
<a v-else class="button" tabindex="4" @click="login" @keyup.enter="login">Log In</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="module">
|
|
var app = new Vue({
|
|
el: "#login-scene",
|
|
data: {
|
|
error: "",
|
|
loading: false,
|
|
username: "",
|
|
password: "",
|
|
remember: false,
|
|
nightMode: false,
|
|
},
|
|
methods: {
|
|
async getErrorMessage(err) {
|
|
switch (err.constructor) {
|
|
case Error:
|
|
return err.message;
|
|
case Response:
|
|
var text = await err.text();
|
|
return `${text} (${err.status})`;
|
|
default:
|
|
return err;
|
|
}
|
|
},
|
|
login() {
|
|
// Validate input
|
|
if (this.username === "") {
|
|
this.error = "Username must not empty";
|
|
return;
|
|
}
|
|
|
|
// Remove old cookie
|
|
document.cookie = `session-id=; Path=${document.baseURI}; Expires=Thu, 01 Jan 1970 00:00:00 GMT;`;
|
|
|
|
// Send request
|
|
this.loading = true;
|
|
var sessionAge = this.remember ? 12 : 1;
|
|
|
|
fetch(new URL("api/login", document.baseURI), {
|
|
method: "post",
|
|
body: JSON.stringify({
|
|
username: this.username,
|
|
password: this.password,
|
|
remember: sessionAge,
|
|
}),
|
|
headers: { "Content-Type": "application/json" },
|
|
}).then(response => {
|
|
if (!response.ok) throw response;
|
|
return response.json();
|
|
}).then(json => {
|
|
// Save session id
|
|
var expTime = new Date(Date.now() + sessionAge * 3600 * 1000).toUTCString();
|
|
document.cookie = `session-id=${json.session}; Path=${document.baseURI}; Expires=${expTime}`;
|
|
|
|
// Save account data
|
|
localStorage.setItem("shiori-account", JSON.stringify(json.account));
|
|
|
|
// Go to destination page
|
|
var currentUrl = new Url,
|
|
dstUrl = currentUrl.query.dst,
|
|
dstPage = currentUrl.hash || "home";
|
|
|
|
if (dstPage !== "home" && dstPage !== "setting") {
|
|
dstPage = "";
|
|
}
|
|
|
|
var newUrl = new Url(dstUrl || document.baseURI);
|
|
newUrl.hash = dstPage;
|
|
location.href = newUrl;
|
|
}).catch(err => {
|
|
this.loading = false;
|
|
this.getErrorMessage(err).then(msg => {
|
|
this.error = msg;
|
|
})
|
|
});
|
|
},
|
|
loadSetting() {
|
|
var opts = JSON.parse(localStorage.getItem("shiori-setting")) || {},
|
|
nightMode = (typeof opts.nightMode === "boolean") ? opts.nightMode : false;
|
|
|
|
this.nightMode = nightMode;
|
|
}
|
|
},
|
|
mounted() {
|
|
// Load setting
|
|
this.loadSetting();
|
|
localStorage.removeItem("shiori-account");
|
|
}
|
|
})
|
|
</script>
|
|
</body>
|
|
|
|
</html> |