Implement initial setting page

This commit is contained in:
Radhi Fadlillah 2019-05-31 16:32:02 +07:00
parent 1b74d555ad
commit fcc77e2db8
11 changed files with 279 additions and 51 deletions

View file

@ -1 +1 @@
:root{--dialogHeaderBg:#292929;--colorDialogHeader:#FFF}.custom-dialog-overlay{display:-webkit-box;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-flow:column nowrap;-webkit-box-align:center;align-items:center;-webkit-box-pack:center;justify-content:center;min-width:0;min-height:0;overflow:hidden;position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:10001;background-color:rgba(0,0,0,0.6);padding:32px}.custom-dialog-overlay .custom-dialog{display:-webkit-box;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-flow:column nowrap;width:100%;max-width:400px;min-height:0;max-height:100%;overflow:auto;background-color:var(--contentBg);font-size:16px}.custom-dialog-overlay .custom-dialog .custom-dialog-header{padding:16px;color:var(--colorDialogHeader);background-color:var(--dialogHeaderBg);font-weight:600;font-size:1em;text-transform:uppercase;border-bottom:1px solid var(--border)}.custom-dialog-overlay .custom-dialog .custom-dialog-body{padding:16px;display:grid;max-height:100%;min-height:80px;min-width:0;overflow:auto;font-size:1em;grid-template-columns:max-content 1fr;-webkit-box-align:baseline;align-items:baseline;grid-gap:16px}.custom-dialog-overlay .custom-dialog .custom-dialog-body::after{content:"";display:block;min-height:1px;grid-column-end:-1;grid-column-start:1}.custom-dialog-overlay .custom-dialog .custom-dialog-body .custom-dialog-content{grid-column-end:-1;grid-column-start:1;color:var(--color);align-self:baseline}.custom-dialog-overlay .custom-dialog .custom-dialog-body>input,.custom-dialog-overlay .custom-dialog .custom-dialog-body>textarea{color:var(--color);padding:8px;font-size:1em;border:1px solid var(--border);background-color:var(--contentBg);min-width:0}.custom-dialog-overlay .custom-dialog .custom-dialog-body>textarea{height:6em;min-height:37px;resize:vertical}.custom-dialog-overlay .custom-dialog .custom-dialog-body>.suggestion{position:absolute;display:block;padding:8px;background-color:var(--contentBg);border:1px solid var(--border);color:var(--color);font-size:.9em}.custom-dialog-overlay .custom-dialog .custom-dialog-footer{padding:16px;display:-webkit-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-flow:row wrap;-webkit-box-pack:end;justify-content:flex-end;border-top:1px solid var(--border)}.custom-dialog-overlay .custom-dialog .custom-dialog-footer>a{padding:0 8px;font-size:.9em;font-weight:600;color:var(--color);text-transform:uppercase}.custom-dialog-overlay .custom-dialog .custom-dialog-footer>a:hover,.custom-dialog-overlay .custom-dialog .custom-dialog-footer>a:focus{outline:none;color:var(--main)}.custom-dialog-overlay .custom-dialog .custom-dialog-footer>i.fa-spinner.fa-spin{width:19px;line-height:19px;text-align:center}
:root{--dialogHeaderBg:#292929;--colorDialogHeader:#FFF}.custom-dialog-overlay{display:-webkit-box;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-flow:column nowrap;-webkit-box-align:center;align-items:center;-webkit-box-pack:center;justify-content:center;min-width:0;min-height:0;overflow:hidden;position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:10001;background-color:rgba(0,0,0,0.6);padding:32px}.custom-dialog-overlay .custom-dialog{display:-webkit-box;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-flow:column nowrap;width:100%;max-width:400px;min-height:0;max-height:100%;overflow:auto;background-color:var(--contentBg);font-size:16px}.custom-dialog-overlay .custom-dialog .custom-dialog-header{padding:16px;color:var(--colorDialogHeader);background-color:var(--dialogHeaderBg);font-weight:600;font-size:1em;text-transform:uppercase;border-bottom:1px solid var(--border)}.custom-dialog-overlay .custom-dialog .custom-dialog-body{padding:16px;display:grid;max-height:100%;min-height:80px;min-width:0;overflow:auto;font-size:1em;grid-template-columns:max-content 1fr;-webkit-box-align:baseline;align-items:baseline;grid-gap:16px}.custom-dialog-overlay .custom-dialog .custom-dialog-body::after{content:"";display:block;min-height:1px;grid-column-end:-1;grid-column-start:1}.custom-dialog-overlay .custom-dialog .custom-dialog-body .custom-dialog-content{grid-column-end:-1;grid-column-start:1;color:var(--color);align-self:baseline}.custom-dialog-overlay .custom-dialog .custom-dialog-body>input,.custom-dialog-overlay .custom-dialog .custom-dialog-body>textarea{color:var(--color);padding:8px;font-size:1em;border:1px solid var(--border);background-color:var(--contentBg);min-width:0}.custom-dialog-overlay .custom-dialog .custom-dialog-body>textarea{height:6em;min-height:37px;resize:vertical}.custom-dialog-overlay .custom-dialog .custom-dialog-body>.suggestion{position:absolute;display:block;padding:8px;background-color:var(--contentBg);border:1px solid var(--border);color:var(--color);font-size:.9em}.custom-dialog-overlay .custom-dialog .custom-dialog-footer{padding:16px;display:-webkit-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-flow:row wrap;-webkit-box-pack:end;justify-content:flex-end;border-top:1px solid var(--border)}.custom-dialog-overlay .custom-dialog .custom-dialog-footer>a{padding:0 8px;font-size:.9em;font-weight:600;color:var(--color);text-transform:uppercase}.custom-dialog-overlay .custom-dialog .custom-dialog-footer>a:hover,.custom-dialog-overlay .custom-dialog .custom-dialog-footer>a:focus{outline:none;color:var(--main)}.custom-dialog-overlay .custom-dialog .custom-dialog-footer>i.fa-spinner.fa-spin{width:19px;line-height:19px;text-align:center;color:var(--color)}

File diff suppressed because one or more lines are too long

View file

@ -22,8 +22,8 @@
</head>
<body>
<div class="home" id="app">
<div class="home-sidebar">
<div id="main-scene" :class="{night: displayOptions.nightMode}">
<div id="main-sidebar">
<a v-for="item in sidebarItems" :title="item.title" :class="{active: activePage === item.page}" @click="switchPage(item.page)">
<i class="fas fa-fw" :class="item.icon"></i>
</a>
@ -33,21 +33,23 @@
</a>
</div>
<keep-alive>
<component :is="activePage"></component>
<component :is="activePage" :display-options="displayOptions" @setting-changed="saveSetting"></component>
</keep-alive>
<custom-dialog v-bind="dialog" />
</div>
<script type="module">
import pageHome from "./js/page/home.js";
import basePage from "./js/page/base.js";
import pageHome from "./js/page/home.js";
import pageSetting from "./js/page/setting.js";
import customDialog from "./js/component/dialog.js";
var app = new Vue({
el: '#app',
el: '#main-scene',
mixins: [basePage],
components: {
pageHome,
pageSetting,
customDialog
},
data: {
@ -96,9 +98,28 @@
});
}
});
},
saveSetting(opts) {
localStorage.setItem("shiori-setting", JSON.stringify(opts));
this.displayOptions = opts;
},
loadSetting() {
var opts = JSON.parse(localStorage.getItem("shiori-setting")) || {},
showId = (typeof opts.showId === "boolean") ? opts.showId : false,
listMode = (typeof opts.listMode === "boolean") ? opts.listMode : false,
nightMode = (typeof opts.nightMode === "boolean") ? opts.nightMode : false;
this.displayOptions = {
showId: showId,
listMode: listMode,
nightMode: nightMode,
};
}
},
mounted() {
// Load setting
this.loadSetting();
// Prepare history state watcher
var stateWatcher = (e) => {
var state = e.state || {};

View file

@ -71,7 +71,7 @@ export default {
},
methods: {
tagClicked(name) {
this.$emit("tagClicked", name);
this.$emit("tag-clicked", name);
},
selectBookmark() {
this.$emit("select", this.eventItem);

View file

@ -1,11 +1,19 @@
export default {
props: {
displayOptions: {
type: Object,
default () {
return {
showId: false,
listMode: false,
nightMode: false,
};
}
}
},
data() {
return {
dialog: {},
displayOptions: {
showId: false,
listMode: false,
}
dialog: {}
}
},
methods: {

View file

@ -46,7 +46,7 @@ var template = `
:listMode="displayOptions.listMode"
:selected="isSelected(book.id)"
@select="toggleSelection"
@tagClicked="filterTag"
@tag-clicked="filterTag"
@edit="showDialogEdit"
@delete="showDialogDelete"
@update="showDialogUpdateArchive">

View file

@ -0,0 +1,53 @@
var template = `
<div id="page-setting">
<div class="page-header">
<p>Settings</p>
<a href="#" title="Refresh setting">
<i class="fas fa-fw fa-sync-alt"></i>
</a>
</div>
<div class="setting-container">
<details open class="setting-group" id="setting-display">
<summary>Display</summary>
<label>
<input type="checkbox" v-model="displayOptions.showId" @change="saveSetting">
Show bookmark's ID
</label>
<label>
<input type="checkbox" v-model="displayOptions.listMode" @change="saveSetting">
Display bookmarks as list
</label>
<label>
<input type="checkbox" v-model="displayOptions.nightMode" @change="saveSetting">
Use dark theme
</label>
</details>
</div>
<div class="loading-overlay" v-if="loading"><i class="fas fa-fw fa-spin fa-spinner"></i></div>
<custom-dialog v-bind="dialog"/>
</div>`;
import customDialog from "../component/dialog.js";
import basePage from "./base.js";
export default {
template: template,
mixins: [basePage],
components: {
customDialog
},
data() {
return {
loading: false,
}
},
methods: {
saveSetting() {
this.$emit("setting-changed", {
showId: this.displayOptions.showId,
listMode: this.displayOptions.listMode,
nightMode: this.displayOptions.nightMode,
});
}
}
}

View file

@ -120,6 +120,7 @@
width: 19px;
line-height: 19px;
text-align: center;
color: var(--color);
}
}
}

View file

@ -43,7 +43,7 @@ body {
overflow: hidden;
}
.login {
#login-scene {
height: 100vh;
padding: 16px;
overflow: auto;
@ -117,7 +117,6 @@ body {
>label {
color: var(--color);
font-size: 0.9em;
}
>input {
@ -125,8 +124,8 @@ body {
padding: 8px;
background-color: var(--contentBg);
border: 1px solid var(--border);
font-size: 0.9em;
min-width: 0;
font-size: 1em;
}
.checkbox-field {
@ -135,9 +134,14 @@ body {
flex-flow: row nowrap;
align-items: center;
justify-content: center;
font-size: 0.9em;
cursor: pointer;
&:hover,
&:focus {
text-decoration: underline;
text-decoration-color: var(--main);
}
>input[type="checkbox"] {
margin-right: 8px;
}
@ -154,7 +158,6 @@ body {
color: var(--color);
text-transform: uppercase;
text-align: center;
font-size: 0.9em;
font-weight: 600;
cursor: default;
@ -171,7 +174,7 @@ body {
}
}
.home {
#main-scene {
display: grid;
grid-template-rows: minmax(0, 1fr);
grid-template-columns: 60px minmax(0, 1fr);
@ -179,7 +182,7 @@ body {
width: 100vw;
height: 100vh;
.home-sidebar {
#main-sidebar {
display: flex;
flex-flow: column nowrap;
background-color: var(--sidebarBg);
@ -423,6 +426,10 @@ body {
.pagination-box {
padding: 16px 0;
&:first-child {
padding-top: 0;
}
}
@media (max-width: 600px) {
@ -471,4 +478,124 @@ body {
}
}
}
}
#page-setting {
min-height: 0;
max-height: 100%;
display: flex;
flex-flow: column nowrap;
.setting-container {
padding: 8px;
display: flex;
overflow: auto;
flex-flow: column nowrap;
flex: 1 0;
&::after {
content: "";
display: block;
min-height: 1px;
}
details.setting-group {
margin: 8px;
display: block;
max-width: 350px;
color: var(--color);
background-color: var(--contentBg);
border: 1px solid var(--border);
@media (max-width: 600px) {
max-width: 100%;
}
summary {
list-style: none;
font-weight: 600;
width: 100%;
padding: 12px 8px;
font-size: 1.1em;
cursor: pointer;
&:hover {
color: var(--main)
}
&::-webkit-details-marker {
display: none;
}
&::after {
content: "+";
margin-left: 8px;
font-weight: 600;
}
}
&[open] summary {
border-bottom: 1px solid var(--border);
::after {
content: "-";
}
}
div.setting-group-footer {
padding: 4px 8px;
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
border-top: 1px solid var(--border);
>a {
text-transform: uppercase;
padding: 8px 4px;
font-size: 0.9em;
font-weight: 600;
&:hover {
color: var(--mainDark);
}
&:focus {
outline: none;
color: var(--mainDark);
border-bottom: 1px dashed var(--mainDark);
}
}
}
}
}
#setting-display {
display: flex;
flex-flow: column nowrap;
padding-bottom: 8px;
summary {
margin-bottom: 8px;
}
label {
padding: 4px 8px;
color: var(--color);
display: flex;
flex-flow: row nowrap;
align-items: center;
cursor: pointer;
&:hover,
&:focus {
text-decoration: underline;
text-decoration-color: var(--main);
}
>input[type="checkbox"] {
margin-right: 8px;
}
}
}
}

View file

@ -20,7 +20,7 @@
</head>
<body>
<div class="login" id="app">
<div id="login-scene" :class="{night: nightMode}">
<p class="error-message" v-if="error !== ''">{{error}}</p>
<div id="login-box">
<div id="logo-area">
@ -47,13 +47,14 @@
<script type="module">
var app = new Vue({
el: "#app",
el: "#login-scene",
data: {
error: "",
loading: false,
username: "",
password: "",
remember: false,
nightMode: false,
},
methods: {
login() {
@ -92,9 +93,18 @@
this.error = `${msg} (${err.status})`;
})
});
},
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();
// Set initial URL
history.replaceState(null, "login", "login");
}

File diff suppressed because one or more lines are too long