github.com/soulteary/pocket-bookcase@v0.0.0-20240428065142-0b5a9a0fc98a/internal/view/index.html (about) 1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <base href="$$.RootPath$$"> 6 <title>Shiori - Bookmarks Manager</title> 7 8 <meta charset="UTF-8"> 9 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 10 11 <link rel="apple-touch-icon-precomposed" sizes="152x152" href="assets/res/apple-touch-icon-152x152.png"> 12 <link rel="apple-touch-icon-precomposed" sizes="144x144" href="assets/res/apple-touch-icon-144x144.png"> 13 <link rel="icon" type="image/png" href="assets/res/favicon-32x32.png" sizes="32x32"> 14 <link rel="icon" type="image/png" href="assets/res/favicon-16x16.png" sizes="16x16"> 15 <link rel="icon" type="image/x-icon" href="assets/res/favicon.ico"> 16 17 <link href="assets/css/style.css" rel="stylesheet"> 18 19 <script src="assets/js/vue.min.js"></script> 20 <script src="assets/js/url.min.js"></script> 21 </head> 22 23 <body class="night"> 24 <div id="main-scene" :class="{night: appOptions.NightMode}"> 25 <div id="main-sidebar"> 26 <a v-for="item in sidebarItems" :title="item.title" :class="{active: activePage === item.page}" @click="switchPage(item.page)"> 27 <i class="fas fa-fw" :class="item.icon"></i> 28 </a> 29 <div class="spacer"></div> 30 <a title="Logout" @click="logout"> 31 <i class="fas fa-fw fa-sign-out-alt"></i> 32 </a> 33 </div> 34 <keep-alive> 35 <component :is="activePage" :active-account="activeAccount" :app-options="appOptions" @setting-changed="saveSetting"></component> 36 </keep-alive> 37 <custom-dialog v-bind="dialog" /> 38 </div> 39 40 <script type="module"> 41 import basePage from "./assets/js/page/base.js"; 42 import pageHome from "./assets/js/page/home.js"; 43 import pageSetting from "./assets/js/page/setting.js"; 44 import customDialog from "./assets/js/component/dialog.js"; 45 46 var app = new Vue({ 47 el: '#main-scene', 48 mixins: [basePage], 49 components: { 50 pageHome, 51 pageSetting, 52 customDialog 53 }, 54 data: { 55 activePage: "page-home", 56 sidebarItems: [{ 57 title: "Home", 58 icon: "fa-home", 59 page: "page-home", 60 }, { 61 title: "Setting", 62 icon: "fa-cog", 63 page: "page-setting", 64 }], 65 }, 66 methods: { 67 switchPage(page) { 68 var pageName = page.replace("page-", ""), 69 state = { activePage: page }, 70 url = new Url; 71 72 url.hash = pageName; 73 this.activePage = page; 74 history.pushState(state, page, url); 75 }, 76 logout() { 77 this.showDialog({ 78 title: "Log Out", 79 content: "Are you sure you want to log out ?", 80 mainText: "Yes", 81 secondText: "No", 82 mainClick: () => { 83 this.dialog.loading = true; 84 fetch(new URL("api/logout", document.baseURI), { 85 method: "post" 86 }).then(response => { 87 if (!response.ok) throw response; 88 return response; 89 }).then(() => { 90 localStorage.removeItem("shiori-account"); 91 localStorage.removeItem("shiori-token"); 92 document.cookie = `session-id=; Path=${new URL(document.baseURI).pathname}; Expires=Thu, 01 Jan 1970 00:00:00 GMT;`; 93 location.href = new URL("login", document.baseURI); 94 }).catch(err => { 95 this.dialog.loading = false; 96 this.getErrorMessage(err).then(msg => { 97 this.showErrorDialog(msg); 98 }) 99 }); 100 } 101 }); 102 }, 103 saveSetting(opts) { 104 this.appOptions = opts; 105 document.body.className = opts.config.NightMode ? "night" : ""; 106 }, 107 loadSetting() { 108 var opts = JSON.parse(localStorage.getItem("shiori-account")) || {}, 109 ShowId = (typeof opts.config.ShowId === "boolean") ? opts.config.ShowId : false, 110 ListMode = (typeof opts.config.ListMode === "boolean") ? opts.config.ListMode : false, 111 HideThumbnail = (typeof opts.config.HideThumbnail === "boolean") ? opts.config.HideThumbnail : false, 112 HideExcerpt = (typeof opts.config.HideExcerpt === "boolean") ? opts.config.HideExcerpt : false, 113 NightMode = (typeof opts.config.NightMode === "boolean") ? opts.config.NightMode : false, 114 KeepMetadata = (typeof opts.config.KeepMetadata === "boolean") ? opts.config.KeepMetadata : false, 115 UseArchive = (typeof opts.config.UseArchive === "boolean") ? opts.config.UseArchive : false, 116 CreateEbook = (typeof opts.config.CreateEbook === "boolean") ? opts.config.CreateEbook : false, 117 MakePublic = (typeof opts.config.MakePublic === "boolean") ? opts.config.MakePublic : false; 118 119 this.appOptions = { 120 ShowId: ShowId, 121 ListMode: ListMode, 122 HideThumbnail: HideThumbnail, 123 HideExcerpt: HideExcerpt, 124 NightMode: NightMode, 125 KeepMetadata: KeepMetadata, 126 UseArchive: UseArchive, 127 CreateEbook: CreateEbook, 128 MakePublic: MakePublic, 129 }; 130 131 document.body.className = NightMode ? "night" : ""; 132 }, 133 loadAccount() { 134 var account = JSON.parse(localStorage.getItem("shiori-account")) || {}, 135 id = (typeof account.id === "number") ? account.id : 0, 136 username = (typeof account.username === "string") ? account.username : "", 137 owner = (typeof account.owner === "boolean") ? account.owner : false; 138 139 this.activeAccount = { 140 id: id, 141 username: username, 142 owner: owner, 143 }; 144 } 145 }, 146 mounted() { 147 // Load setting 148 this.loadSetting(); 149 this.loadAccount(); 150 151 // Prepare history state watcher 152 var stateWatcher = (e) => { 153 var state = e.state || {}; 154 this.activePage = state.activePage || "page-home"; 155 } 156 157 window.addEventListener('popstate', stateWatcher); 158 this.$once('hook:beforeDestroy', function () { 159 window.removeEventListener('popstate', stateWatcher); 160 }) 161 162 // Set initial active page 163 var initialPage = (new Url).hash || "home"; 164 if (initialPage === "home" || initialPage === "setting") { 165 this.activePage = `page-${initialPage}`; 166 } else { 167 history.replaceState(null, "page-home", "/#home"); 168 } 169 } 170 }) 171 </script> 172 </body> 173 174 </html>